From b9b945e3261d79852b29b2c44d28695f69f7b32c Mon Sep 17 00:00:00 2001 From: Louis Chu Date: Fri, 1 Mar 2024 08:54:08 -0800 Subject: [PATCH] Add java docs and update ut Signed-off-by: Louis Chu --- .../flint/core/logging/CustomJsonLayout.java | 26 ++++-- .../flint/core/logging/CustomLogging.java | 36 ++++++++ .../HttpStatusCodeResultPredicate.java | 1 + .../core/logging/CustomJsonLayoutTest.java | 82 ++++++++++++------- 4 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 flint-core/src/main/java/org/opensearch/flint/core/logging/CustomLogging.java diff --git a/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomJsonLayout.java b/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomJsonLayout.java index 98715c2c2..40e72c99f 100644 --- a/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomJsonLayout.java +++ b/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomJsonLayout.java @@ -18,6 +18,13 @@ import java.util.HashMap; import java.util.Map; +/** + * CustomJsonLayout is a plugin for formatting log events as JSON strings. + * + *

The layout is designed to be used with OpenSearch Flint logging. It extracts environment-specific information, + * such as the cluster name, from the environment variable "FLINT_CLUSTER_NAME" and splits it into domain name and client ID.

+ * + */ @Plugin(name = "CustomJsonLayout", category = "Core", elementType = Layout.ELEMENT_TYPE, printObject = true) public class CustomJsonLayout extends AbstractStringLayout { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -41,24 +48,33 @@ protected CustomJsonLayout(Charset charset) { super(charset); } + /** + * Plugin factory method to create an instance of CustomJsonLayout. + * + * @param charset The charset for encoding the log event. If not specified, defaults to UTF-8. + * @return A new instance of CustomJsonLayout with the specified charset. + */ @PluginFactory public static CustomJsonLayout createLayout(@PluginAttribute(value = "charset", defaultString = "UTF-8") Charset charset) { return new CustomJsonLayout(charset); } + /** + * Converts the log event to a JSON string. + * If the log event's message does not follow the expected format, it returns the formatted message directly. + * + * @param event the log event to format. + * @return A string representation of the log event in JSON format. + */ @Override public String toSerializable(LogEvent event) { - if (!(event.getMessage() instanceof OperationMessage)) { - return event.getMessage().getFormattedMessage() + System.lineSeparator(); - } - Map logEventMap = new HashMap<>(); logEventMap.put("timestamp", event.getTimeMillis()); logEventMap.put("message", event.getMessage().getFormattedMessage()); logEventMap.put("domainName", DOMAIN_NAME); logEventMap.put("clientId", CLIENT_ID); - if (event.getMessage().getParameters().length == 1) { + if (event.getMessage() instanceof OperationMessage && event.getMessage().getParameters().length == 1) { logEventMap.put("StatusCode", event.getMessage().getParameters()[0]); } diff --git a/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomLogging.java b/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomLogging.java new file mode 100644 index 000000000..de3879b1d --- /dev/null +++ b/flint-core/src/main/java/org/opensearch/flint/core/logging/CustomLogging.java @@ -0,0 +1,36 @@ +package org.opensearch.flint.core.logging; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * CustomLogging class using the {@link CustomJsonLayout} for logging. + */ +public class CustomLogging { + // Define a static logger variable so that it references the custom logger + private static final Logger logger = LogManager.getLogger(CustomLogging.class); + + public static void logDebug(String message) { + logger.debug(message); + } + + public static void logInfo(String message) { + logger.info(message); + } + + public static void logWarning(String message) { + logger.warn(message); + } + + public static void logWarning(String message, Throwable e) { + logger.warn(message, e); + } + + public static void logError(String message) { + logger.error(message); + } + + public static void logError(String message, Throwable throwable) { + logger.error(message, throwable); + } +} \ No newline at end of file diff --git a/flint-core/src/main/scala/org/opensearch/flint/core/http/handler/HttpStatusCodeResultPredicate.java b/flint-core/src/main/scala/org/opensearch/flint/core/http/handler/HttpStatusCodeResultPredicate.java index ee2a23e3f..fa82e3655 100644 --- a/flint-core/src/main/scala/org/opensearch/flint/core/http/handler/HttpStatusCodeResultPredicate.java +++ b/flint-core/src/main/scala/org/opensearch/flint/core/http/handler/HttpStatusCodeResultPredicate.java @@ -18,6 +18,7 @@ * @param result type (supposed to be HttpResponse for OS client) */ public class HttpStatusCodeResultPredicate implements CheckedPredicate { + private static final Logger LOG = Logger.getLogger(HttpStatusCodeResultPredicate.class.getName()); /** diff --git a/flint-core/src/test/java/org/opensearch/flint/core/logging/CustomJsonLayoutTest.java b/flint-core/src/test/java/org/opensearch/flint/core/logging/CustomJsonLayoutTest.java index 271f00a06..c936677c0 100644 --- a/flint-core/src/test/java/org/opensearch/flint/core/logging/CustomJsonLayoutTest.java +++ b/flint-core/src/test/java/org/opensearch/flint/core/logging/CustomJsonLayoutTest.java @@ -1,51 +1,76 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - package org.opensearch.flint.core.logging; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.message.Message; +import org.junit.Before; import org.junit.Test; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; - public class CustomJsonLayoutTest { - @Test - public void testSuccessfulLogPlainMessage() { - LogEvent event = mock(LogEvent.class); - when(event.getMessage()).thenReturn(mock(Message.class)); - when(event.getMessage().getFormattedMessage()).thenReturn("Test message"); + private Map writeableEnvironmentVariables; - CustomJsonLayout layout = CustomJsonLayout.createLayout(StandardCharsets.UTF_8); - String result = layout.toSerializable(event); - assertNotNull(result); - assertEquals(result, "Test message" + System.lineSeparator()); - } - - @Test - public void testSuccessfulLogOperationMessage() throws NoSuchFieldException, IllegalAccessException { + @Before + public void setUp() throws NoSuchFieldException, IllegalAccessException { + // Setup writable environment variables Class classOfMap = System.getenv().getClass(); Field field = classOfMap.getDeclaredField("m"); field.setAccessible(true); - Map writeableEnvironmentVariables = (Map)field.get(System.getenv()); + writeableEnvironmentVariables = (Map) field.get(System.getenv()); writeableEnvironmentVariables.put("FLINT_CLUSTER_NAME", "1234567890:testDomain"); + } + private void cleanUp() { + // Clean up environment variables + writeableEnvironmentVariables.remove("FLINT_CLUSTER_NAME"); + } + + private LogEvent setupLogEvent(Class messageClass, String formattedMessage, Object... parameters) { LogEvent event = mock(LogEvent.class); when(event.getTimeMillis()).thenReturn(System.currentTimeMillis()); - when(event.getMessage()).thenReturn(mock(OperationMessage.class)); - when(event.getMessage().getFormattedMessage()).thenReturn("Test message"); - when(event.getMessage().getParameters()).thenReturn(new Object[] {new Integer(200)}); + + Message message = mock(messageClass); + when(message.getFormattedMessage()).thenReturn(formattedMessage); + if (parameters.length > 0) { + when(message.getParameters()).thenReturn(parameters); + } + when(event.getMessage()).thenReturn(message); + + Exception mockException = new Exception("Test exception message"); + when(event.getThrown()).thenReturn(mockException); + + return event; + } + + @Test + public void testSuccessfulLogPlainMessage() { + LogEvent event = setupLogEvent(Message.class, "Test message"); + + try { + CustomJsonLayout layout = CustomJsonLayout.createLayout(StandardCharsets.UTF_8); + + String result = layout.toSerializable(event); + assertNotNull(result); + assertTrue(result.contains("\"message\":\"Test message\"")); + assertTrue(result.contains("\"clientId\":\"1234567890\"")); + assertTrue(result.contains("\"domainName\":\"testDomain\"")); + assertFalse(result.contains("\"StatusCode\"")); + assertTrue(result.contains("\"Exception\":\"java.lang.Exception\"")); + assertTrue(result.contains("\"ExceptionMessage\":\"Test exception message\"")); + } finally { + cleanUp(); + } + } + + @Test + public void testSuccessfulLogOperationMessage() { + LogEvent event = setupLogEvent(OperationMessage.class, "Test message", 200); try { CustomJsonLayout layout = CustomJsonLayout.createLayout(StandardCharsets.UTF_8); @@ -56,9 +81,10 @@ public void testSuccessfulLogOperationMessage() throws NoSuchFieldException, Ill assertTrue(result.contains("\"clientId\":\"1234567890\"")); assertTrue(result.contains("\"domainName\":\"testDomain\"")); assertTrue(result.contains("\"StatusCode\":200")); + assertTrue(result.contains("\"Exception\":\"java.lang.Exception\"")); + assertTrue(result.contains("\"ExceptionMessage\":\"Test exception message\"")); } finally { - // since system environment is shared by other tests. Make sure to remove them before exiting. - writeableEnvironmentVariables.remove("FLINT_CLUSTER_NAME"); + cleanUp(); } } }