Skip to content

Commit

Permalink
Modification of exception processing in an event
Browse files Browse the repository at this point in the history
Update:
- Hard casting of particular exception class are removed.
- Updated in all three appender classes Log4j2, Logback, Java Logging.
  • Loading branch information
bparmar-splunk committed Oct 12, 2022
1 parent 066dbe8 commit f167167
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 47 deletions.
Expand Up @@ -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<String, String> 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;
}
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Object, Object> 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<Object, Object> 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();
Expand Down
Expand Up @@ -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<Object, Object> 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<Object, Object> 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.
}

/*
Expand All @@ -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();
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/HttpEventCollector_JavaLoggingTest.java
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String, String> userInputs = new HashMap<String, String>();
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.
*
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/HttpEventCollector_Log4j2Test.java
Expand Up @@ -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<String, String> 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<String> 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.
*
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/HttpEventCollector_LogbackTest.java
Expand Up @@ -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<String, String> userInputs = new HashMap<String, String>();
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<String> msgs = new ArrayList<String>();

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
*
Expand Down

0 comments on commit f167167

Please sign in to comment.