From f1671674311fa96f2430860ad5e891998a1c5e10 Mon Sep 17 00:00:00 2001 From: bparmar-splunk Date: Wed, 12 Oct 2022 10:01:25 +0530 Subject: [PATCH] Modification of exception processing in an event Update: - Hard casting of particular exception class are removed. - Updated in all three appender classes Log4j2, Logback, Java Logging. --- .../HttpEventCollectorLog4jAppender.java | 31 +++++++------ .../HttpEventCollectorLogbackAppender.java | 38 ++++++++------- .../HttpEventCollectorLoggingHandler.java | 46 +++++++++++-------- .../HttpEventCollector_JavaLoggingTest.java | 27 +++++++++++ .../java/HttpEventCollector_Log4j2Test.java | 28 +++++++++++ .../java/HttpEventCollector_LogbackTest.java | 27 +++++++++++ 6 files changed, 150 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java index 6e4f28c..18126bb 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java @@ -266,30 +266,35 @@ public void append(final LogEvent event) { */ private String generateErrorDetail(final LogEvent event) { - String exceptionDetail = null; + String exceptionDetail = ""; /* Exception details are only populated when any ERROR OR FATAL event occurred */ - if (Level.ERROR.equals(event.getLevel()) || Level.FATAL.equals(event.getLevel())) { - if (event.getThrown() == null && (((MutableLogEvent) event).getParameters()).length <= 0) { - return exceptionDetail; - } + try { // Exception thrown in application is wrapped with relevant information instead of just a message. Map exceptionDetailMap = new LinkedHashMap<>(); - if (event.getThrown() != null) { + + if (Level.ERROR.equals(event.getLevel()) || Level.FATAL.equals(event.getLevel())) { Throwable throwable = event.getThrown(); + if (throwable == null) { + return exceptionDetail; + } + exceptionDetailMap.put("detailMessage", throwable.getMessage()); exceptionDetailMap.put("exceptionClass", throwable.getClass().toString()); - } else if ((((MutableLogEvent) event).getParameters()).length > 0) { - exceptionDetailMap.put("exceptionClass", Arrays.toString(Arrays.stream(((MutableLogEvent) event).getParameters()).toArray())); + StackTraceElement[] elements = throwable.getStackTrace(); + // Retrieving first element from elements array is because the throws exception detail would be available as a first element. + if (elements != null && elements.length > 0 && elements[0] != null) { + exceptionDetailMap.put("fileName", elements[0].getFileName()); + exceptionDetailMap.put("methodName", elements[0].getMethodName()); + exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getLineNumber())); + } + exceptionDetail = new Gson().toJson(exceptionDetailMap); } - - exceptionDetailMap.put("fileName", event.getSource().getFileName()); - exceptionDetailMap.put("methodName", event.getSource().getMethodName()); - exceptionDetailMap.put("lineNumber", String.valueOf(event.getSource().getLineNumber())); - exceptionDetail = new Gson().toJson(exceptionDetailMap); + } catch (Exception e) { + // No action here } return exceptionDetail; } diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java index 6288533..f77c164 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java @@ -18,6 +18,7 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.pattern.MarkerConverter; import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.StackTraceElementProxy; import ch.qos.logback.core.AppenderBase; import ch.qos.logback.core.Layout; @@ -164,23 +165,28 @@ private void sendEvent(ILoggingEvent event) { /* Exception details are only populated when any ERROR encountered & exception is actually thrown */ - if (Level.ERROR.isGreaterOrEqual(event.getLevel()) && event.getThrowableProxy() != null) { - // Exception thrown in application is wrapped with relevant information instead of just a message. - Map exceptionDetailMap = new LinkedHashMap<>(); - - StackTraceElementProxy[] elements = event.getThrowableProxy().getStackTraceElementProxyArray(); - exceptionDetailMap.put("detailMessage", event.getThrowableProxy().getMessage()); - exceptionDetailMap.put("exceptionClass", event.getThrowableProxy().getClassName()); - - // Retrieving first element from elements array is because the throws exception detail would be available as a first element. - if (elements != null && elements.length > 0 && elements[0] != null) { - exceptionDetailMap.put("fileName", elements[0].getStackTraceElement().getFileName()); - exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getStackTraceElement().getLineNumber())); - exceptionDetailMap.put("methodName", elements[0].getStackTraceElement().getMethodName()); + try { + IThrowableProxy throwableProxy = event.getThrowableProxy(); + if (Level.ERROR.isGreaterOrEqual(event.getLevel()) && throwableProxy != null) { + // Exception thrown in application is wrapped with relevant information instead of just a message. + Map exceptionDetailMap = new LinkedHashMap<>(); + + exceptionDetailMap.put("detailMessage", throwableProxy.getMessage()); + exceptionDetailMap.put("exceptionClass", throwableProxy.getClassName()); + + // Retrieving first element from elements array is because the throws exception detail would be available as a first element. + StackTraceElementProxy[] elements = throwableProxy.getStackTraceElementProxyArray(); + if (elements != null && elements.length > 0 && elements[0] != null) { + exceptionDetailMap.put("fileName", elements[0].getStackTraceElement().getFileName()); + exceptionDetailMap.put("methodName", elements[0].getStackTraceElement().getMethodName()); + exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getStackTraceElement().getLineNumber())); + } + + exceptionDetail = new Gson().toJson(exceptionDetailMap); + isExceptionOccured = true; } - - exceptionDetail = new Gson().toJson(exceptionDetailMap); - isExceptionOccured = true; + } catch (Exception e) { + // No actions here } MarkerConverter c = new MarkerConverter(); diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java index f50c85c..145ff5f 100644 --- a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java +++ b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java @@ -243,25 +243,31 @@ public void publish(LogRecord record) { String formatConfiguration = null; String formattedMessage = null; Object messageFormatter; + /* - Exception details are only populated when any SEVERE error occurred & exception is actually thrown + Exception details are only populated when any SEVERE error occurred & exception is actually thrown */ - if (Level.SEVERE.equals(record.getLevel()) && record.getThrown() != null) { - - // Exception thrown in application is wrapped with relevant information instead of just a message. - Map exceptionDetailMap = new LinkedHashMap<>(); - StackTraceElement[] elements = record.getThrown().getStackTrace(); - exceptionDetailMap.put("detailMessage", record.getThrown().getMessage()); - exceptionDetailMap.put("exceptionClass", record.getThrown().getClass().toString()); - - // Retrieving first element from elements array is because the throws exception detail would be available as a first element. - if (elements != null && elements.length > 0 && elements[0] != null) { - exceptionDetailMap.put("fileName", elements[0].getFileName()); - exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getLineNumber())); - exceptionDetailMap.put("methodName", elements[0].getMethodName()); + try { + Throwable throwable = record.getThrown(); + if (Level.SEVERE.equals(record.getLevel()) && throwable != null) { + + // Exception thrown in application is wrapped with relevant information instead of just a message. + Map exceptionDetailMap = new LinkedHashMap<>(); + exceptionDetailMap.put("detailMessage", throwable.getMessage()); + exceptionDetailMap.put("exceptionClass", throwable.getClass().toString()); + + // Retrieving first element from elements array is because the throws exception detail would be available as a first element. + StackTraceElement[] elements = throwable.getStackTrace(); + if (elements != null && elements.length > 0 && elements[0] != null) { + exceptionDetailMap.put("fileName", elements[0].getFileName()); + exceptionDetailMap.put("methodName", elements[0].getMethodName()); + exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getLineNumber())); + } + exceptionDetail = new Gson().toJson(exceptionDetailMap); + isExceptionOccured = true; } - exceptionDetail = new Gson().toJson(exceptionDetailMap); - isExceptionOccured = true; + } catch (Exception e) { + // No actions here. } /* @@ -275,8 +281,12 @@ public void publish(LogRecord record) { try { messageFormatter = Class.forName(formatConfiguration).newInstance(); formattedMessage = ((Formatter) messageFormatter).format(record); - } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { - throw new RuntimeException(e); + } catch (Exception e) { + messageFormatter = getFormatter(); + if (messageFormatter == null) { + messageFormatter = new SimpleFormatter(); + } + formattedMessage = ((Formatter) messageFormatter).formatMessage(record); } } else { messageFormatter = getFormatter(); diff --git a/src/test/java/HttpEventCollector_JavaLoggingTest.java b/src/test/java/HttpEventCollector_JavaLoggingTest.java index 6f013f0..9e6d14c 100644 --- a/src/test/java/HttpEventCollector_JavaLoggingTest.java +++ b/src/test/java/HttpEventCollector_JavaLoggingTest.java @@ -26,6 +26,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; public final class HttpEventCollector_JavaLoggingTest { @@ -60,6 +61,32 @@ public void canSendEventUsingJavaLogging() throws Exception { TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); } + /** + * sending a message via httplogging using java.logging to splunk + */ + @Test + public void canSendExceptionUsingJavaLogging() throws Exception { + TestUtil.enableHttpEventCollector(); + + String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); + + String loggerName = "splunkLoggerNoOptions"; + HashMap userInputs = new HashMap(); + userInputs.put("user_httpEventCollector_token", token); + userInputs.put("user_logger_name", loggerName); + TestUtil.resetJavaLoggingConfiguration("logging_template.properties", "logging.properties", userInputs); + + Date date = new Date(); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for java logging canSendEventUsingJavaLogging}", date.toString()); + + Logger logger = Logger.getLogger(loggerName); + logger.log(Level.SEVERE, jsonMsg, new RuntimeException("This is RuntimeException")); + + TestUtil.verifyOneAndOnlyOneEventSentToSplunk(jsonMsg); + + TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); + } + /** * Sending a message via httplogging using java.logging to Splunk. * diff --git a/src/test/java/HttpEventCollector_Log4j2Test.java b/src/test/java/HttpEventCollector_Log4j2Test.java index aa8431c..e3be845 100644 --- a/src/test/java/HttpEventCollector_Log4j2Test.java +++ b/src/test/java/HttpEventCollector_Log4j2Test.java @@ -66,6 +66,34 @@ public void canSendEventUsingLog4j2() throws Exception { System.out.println("====================== Test pass========================="); } + /** + * sending a message via httplogging using log4j2 to splunk + */ + @Test + public void canSendExceptionUsingLog4j2() throws Exception { + TestUtil.enableHttpEventCollector(); + String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); + String loggerName = "splunkLogger4j2"; + HashMap userInputs = new HashMap<>(); + userInputs.put("user_logger_name", loggerName); + userInputs.put("user_httpEventCollector_token", token); + org.apache.logging.log4j.core.LoggerContext context = TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs); + //use httplogger + List msgs = new ArrayList<>(); + + Date date = new Date(); + + Logger logger = context.getLogger(loggerName); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test error for log4j2}", date); + logger.error(jsonMsg, new RuntimeException("This is RuntimeException")); + msgs.add(jsonMsg); + + TestUtil.verifyEventsSentToSplunk(msgs); + + TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); + System.out.println("====================== Test pass========================="); + } + /** * Sending a message via httplogging using log4j2 to Splunk. * diff --git a/src/test/java/HttpEventCollector_LogbackTest.java b/src/test/java/HttpEventCollector_LogbackTest.java index d34e9a4..579ca36 100644 --- a/src/test/java/HttpEventCollector_LogbackTest.java +++ b/src/test/java/HttpEventCollector_LogbackTest.java @@ -70,6 +70,33 @@ public void canSendEventUsingLogback() throws Exception { TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); } + /** + * sending a message via httplogging using logback to splunk + */ + @Test + public void canSendExceptionUsingLogback() throws Exception { + TestUtil.enableHttpEventCollector(); + String token = TestUtil.createHttpEventCollectorToken(httpEventCollectorName); + + String loggerName = "logBackLogger"; + HashMap userInputs = new HashMap(); + userInputs.put("user_logger_name", loggerName); + userInputs.put("user_httpEventCollector_token", token); + userInputs.put("user_defined_httpEventCollector_token", token); + TestUtil.resetLogbackConfiguration("logback_template.xml", "logback.xml", userInputs); + + List msgs = new ArrayList(); + + Date date = new Date(); + String jsonMsg = String.format("{EventDate:%s, EventMsg:'this is a test event for Logback Test}", date.toString()); + Logger logger = LoggerFactory.getLogger(loggerName); + logger.error(jsonMsg, new RuntimeException("This is RuntimeException")); + msgs.add(jsonMsg); + + TestUtil.verifyEventsSentToSplunk(msgs); + TestUtil.deleteHttpEventCollectorToken(httpEventCollectorName); + } + /** * Sending a commented string messages via httplogging using logback to Splunk *