Skip to content

Commit 27f862d

Browse files
Multiple scenarios of throwing exception handled
Update: - Processing exception message from the exception object thrown in any way while logging error. - Updated in all appenders.
1 parent 229c3a3 commit 27f862d

File tree

3 files changed

+102
-65
lines changed

3 files changed

+102
-65
lines changed

src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.google.gson.Gson;
1919
import com.splunk.logging.hec.MetadataTags;
20+
import org.apache.logging.log4j.Level;
2021
import org.apache.logging.log4j.core.Filter;
2122
import org.apache.logging.log4j.core.Layout;
2223
import org.apache.logging.log4j.core.LogEvent;
@@ -239,24 +240,9 @@ public static HttpEventCollectorLog4jAppender createAppender(
239240
* @param event The Log event.
240241
*/
241242
@Override
242-
public void append(final LogEvent event)
243-
{
244-
boolean isExceptionThrown = false;
245-
// Exception thrown in application is wrapped with relevant information instead of just a message.
246-
Map<String, String> exceptionDetailMap = new LinkedHashMap<>();
247-
if (event.getThrown() != null) {
248-
Throwable throwable = event.getThrown();
249-
isExceptionThrown = true;
250-
exceptionDetailMap.put("detailMessage", throwable.getMessage());
251-
exceptionDetailMap.put("exceptionClass", throwable.getClass().toString());
252-
253-
} else if ((((MutableLogEvent) event).getParameters()).length > 0) {
254-
isExceptionThrown = true;
255-
exceptionDetailMap.put("exceptionClass", Arrays.toString(Arrays.stream(((MutableLogEvent) event).getParameters()).toArray()));
256-
}
257-
exceptionDetailMap.put("fileName", event.getSource().getFileName());
258-
exceptionDetailMap.put("lineNumber", String.valueOf(event.getSource().getLineNumber()));
259-
exceptionDetailMap.put("methodName", event.getSource().getMethodName());
243+
public void append(final LogEvent event) {
244+
245+
String exceptionDetail = generateErrorDetail(event);
260246

261247
// if an exception was thrown
262248
this.sender.send(
@@ -266,9 +252,46 @@ public void append(final LogEvent event)
266252
includeLoggerName ? event.getLoggerName() : null,
267253
includeThreadName ? event.getThreadName() : null,
268254
includeMDC ? event.getContextData().toMap() : null,
269-
(includeException && isExceptionThrown) ? new Gson().toJson(exceptionDetailMap) : null,
255+
includeException ? exceptionDetail : null,
270256
includeMarker ? event.getMarker() : null
271257
);
258+
259+
}
260+
261+
/**
262+
* Method used to generate proper exception message if any exception encountered.
263+
*
264+
* @param event
265+
* @return the processed string of all exception detail
266+
*/
267+
private String generateErrorDetail(final LogEvent event) {
268+
269+
String exceptionDetail = null;
270+
271+
/*
272+
Exception details are only populated when any ERROR OR FATAL event occurred
273+
*/
274+
if (Level.ERROR.equals(event.getLevel()) || Level.FATAL.equals(event.getLevel())) {
275+
if (event.getThrown() == null && (((MutableLogEvent) event).getParameters()).length <= 0) {
276+
return exceptionDetail;
277+
}
278+
// Exception thrown in application is wrapped with relevant information instead of just a message.
279+
Map<String, String> exceptionDetailMap = new LinkedHashMap<>();
280+
if (event.getThrown() != null) {
281+
Throwable throwable = event.getThrown();
282+
exceptionDetailMap.put("detailMessage", throwable.getMessage());
283+
exceptionDetailMap.put("exceptionClass", throwable.getClass().toString());
284+
285+
} else if ((((MutableLogEvent) event).getParameters()).length > 0) {
286+
exceptionDetailMap.put("exceptionClass", Arrays.toString(Arrays.stream(((MutableLogEvent) event).getParameters()).toArray()));
287+
}
288+
289+
exceptionDetailMap.put("fileName", event.getSource().getFileName());
290+
exceptionDetailMap.put("methodName", event.getSource().getMethodName());
291+
exceptionDetailMap.put("lineNumber", String.valueOf(event.getSource().getLineNumber()));
292+
exceptionDetail = new Gson().toJson(exceptionDetailMap);
293+
}
294+
return exceptionDetail;
272295
}
273296

274297
public void flush() {

src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* under the License.
1616
*/
1717

18+
import ch.qos.logback.classic.Level;
1819
import ch.qos.logback.classic.pattern.MarkerConverter;
1920
import ch.qos.logback.classic.spi.ILoggingEvent;
2021
import ch.qos.logback.classic.spi.StackTraceElementProxy;
@@ -157,9 +158,16 @@ private void sendEvent(ILoggingEvent event) {
157158
event.getCallerData();
158159
}
159160

160-
// Exception thrown in application is wrapped with relevant information instead of just a message.
161-
Map<Object, Object> exceptionDetailMap = new LinkedHashMap<>();
162-
if (event.getThrowableProxy() != null) {
161+
boolean isExceptionOccured = false;
162+
String exceptionDetail = null;
163+
164+
/*
165+
Exception details are only populated when any ERROR encountered & exception is actually thrown
166+
*/
167+
if (Level.ERROR.isGreaterOrEqual(event.getLevel()) && event.getThrowableProxy() != null) {
168+
// Exception thrown in application is wrapped with relevant information instead of just a message.
169+
Map<Object, Object> exceptionDetailMap = new LinkedHashMap<>();
170+
163171
StackTraceElementProxy[] elements = event.getThrowableProxy().getStackTraceElementProxyArray();
164172
exceptionDetailMap.put("detailMessage", event.getThrowableProxy().getMessage());
165173
exceptionDetailMap.put("exceptionClass", event.getThrowableProxy().getClassName());
@@ -170,6 +178,9 @@ private void sendEvent(ILoggingEvent event) {
170178
exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getStackTraceElement().getLineNumber()));
171179
exceptionDetailMap.put("methodName", elements[0].getStackTraceElement().getMethodName());
172180
}
181+
182+
exceptionDetail = new Gson().toJson(exceptionDetailMap);
183+
isExceptionOccured = true;
173184
}
174185

175186
MarkerConverter c = new MarkerConverter();
@@ -181,7 +192,7 @@ private void sendEvent(ILoggingEvent event) {
181192
_includeLoggerName ? event.getLoggerName() : null,
182193
_includeThreadName ? event.getThreadName() : null,
183194
_includeMDC ? event.getMDCPropertyMap() : null,
184-
(!_includeException || event.getThrowableProxy() == null) ? null : new Gson().toJson(exceptionDetailMap),
195+
(_includeException && isExceptionOccured) ? exceptionDetail : null,
185196
c.convert(event)
186197
);
187198
}

src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,8 @@
8383
import com.google.gson.Gson;
8484
import com.splunk.logging.hec.MetadataTags;
8585

86-
import java.util.HashMap;
87-
import java.util.LinkedHashMap;
88-
import java.util.Locale;
89-
import java.util.Map;
90-
import java.util.logging.Handler;
91-
import java.util.logging.LogManager;
92-
import java.util.logging.LogRecord;
86+
import java.util.*;
87+
import java.util.logging.*;
9388

9489
/**
9590
* An input handler for Splunk http event collector. This handler can be used by
@@ -98,27 +93,27 @@
9893
*/
9994
public final class HttpEventCollectorLoggingHandler extends Handler {
10095
private HttpEventCollectorSender sender = null;
101-
private final String IncludeLoggerNameConfTag = "include_logger_name";
96+
private final String includeLoggerNameConfTag = "include_logger_name";
10297
private final boolean includeLoggerName;
103-
private final String IncludeThreadNameConfTag = "include_thread_name";
98+
private final String includeThreadNameConfTag = "include_thread_name";
10499
private final boolean includeThreadName;
105-
private final String IncludeExceptionConfTag = "include_exception";
106-
private final boolean includeException;
100+
private final String includeExceptionConfTag = "include_exception";
101+
private boolean includeException;
107102

108103

109-
private final String BatchDelayConfTag = "batch_interval";
110-
private final String BatchCountConfTag = "batch_size_count";
111-
private final String BatchSizeConfTag = "batch_size_bytes";
112-
private final String RetriesOnErrorTag = "retries_on_error";
113-
private final String UrlConfTag = "url";
114-
private final String SendModeTag = "send_mode";
115-
private final String MiddlewareTag = "middleware";
104+
private final String batchDelayConfTag = "batch_interval";
105+
private final String batchCountConfTag = "batch_size_count";
106+
private final String batchSizeConfTag = "batch_size_bytes";
107+
private final String retriesOnErrorTag = "retries_on_error";
108+
private final String urlConfTag = "url";
109+
private final String sendModeTag = "send_mode";
110+
private final String middlewareTag = "middleware";
116111

117-
private final String ConnectTimeoutConfTag = "connect_timeout";
118-
private final String CallTimeoutConfTag = "call_timeout";
119-
private final String ReadTimeoutConfTag = "read_timeout";
120-
private final String WriteTimeoutConfTag = "write_timeout";
121-
private final String TerminationTimeoutConfTag = "termination_timeout";
112+
private final String connectTimeoutConfTag = "connect_timeout";
113+
private final String callTimeoutConfTag = "call_timeout";
114+
private final String readTimeoutConfTag = "read_timeout";
115+
private final String writeTimeoutConfTag = "write_timeout";
116+
private final String terminationTimeoutConfTag = "termination_timeout";
122117

123118
/** HttpEventCollectorLoggingHandler c-or */
124119
public HttpEventCollectorLoggingHandler() {
@@ -141,7 +136,7 @@ public HttpEventCollectorLoggingHandler() {
141136
getConfigurationProperty(MetadataTags.MESSAGEFORMAT, null));
142137

143138
// http event collector endpoint properties
144-
String url = getConfigurationProperty(UrlConfTag, null);
139+
String url = getConfigurationProperty(urlConfTag, null);
145140

146141
// app token
147142
String token = getConfigurationProperty("token", null);
@@ -153,26 +148,26 @@ public HttpEventCollectorLoggingHandler() {
153148
String type = getConfigurationProperty("type", null);
154149

155150
// batching properties
156-
long delay = getConfigurationNumericProperty(BatchDelayConfTag, HttpEventCollectorSender.DefaultBatchInterval);
157-
long batchCount = getConfigurationNumericProperty(BatchCountConfTag, HttpEventCollectorSender.DefaultBatchCount);
158-
long batchSize = getConfigurationNumericProperty(BatchSizeConfTag, HttpEventCollectorSender.DefaultBatchSize);
159-
long retriesOnError = getConfigurationNumericProperty(RetriesOnErrorTag, 0);
160-
String sendMode = getConfigurationProperty(SendModeTag, "sequential");
151+
long delay = getConfigurationNumericProperty(batchDelayConfTag, HttpEventCollectorSender.DefaultBatchInterval);
152+
long batchCount = getConfigurationNumericProperty(batchCountConfTag, HttpEventCollectorSender.DefaultBatchCount);
153+
long batchSize = getConfigurationNumericProperty(batchSizeConfTag, HttpEventCollectorSender.DefaultBatchSize);
154+
long retriesOnError = getConfigurationNumericProperty(retriesOnErrorTag, 0);
155+
String sendMode = getConfigurationProperty(sendModeTag, "sequential");
161156
String eventHeaderSerializer = getConfigurationProperty("eventHeaderSerializer", "");
162-
String middleware = getConfigurationProperty(MiddlewareTag, null);
157+
String middleware = getConfigurationProperty(middlewareTag, null);
163158
String eventBodySerializer = getConfigurationProperty("eventBodySerializer", null);
164159
String errorCallbackClass = getConfigurationProperty("errorCallback", null);
165160

166-
includeLoggerName = getConfigurationBooleanProperty(IncludeLoggerNameConfTag, true);
167-
includeThreadName = getConfigurationBooleanProperty(IncludeThreadNameConfTag, true);
168-
includeException = getConfigurationBooleanProperty(IncludeExceptionConfTag, true);
161+
includeLoggerName = getConfigurationBooleanProperty(includeLoggerNameConfTag, true);
162+
includeThreadName = getConfigurationBooleanProperty(includeThreadNameConfTag, true);
163+
includeException = getConfigurationBooleanProperty(includeExceptionConfTag, true);
169164

170165
HttpEventCollectorSender.TimeoutSettings timeoutSettings = new HttpEventCollectorSender.TimeoutSettings(
171-
getConfigurationNumericProperty(ConnectTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CONNECT_TIMEOUT),
172-
getConfigurationNumericProperty(CallTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CALL_TIMEOUT),
173-
getConfigurationNumericProperty(ReadTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_READ_TIMEOUT),
174-
getConfigurationNumericProperty(WriteTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT),
175-
getConfigurationNumericProperty(TerminationTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_TERMINATION_TIMEOUT)
166+
getConfigurationNumericProperty(connectTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CONNECT_TIMEOUT),
167+
getConfigurationNumericProperty(callTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CALL_TIMEOUT),
168+
getConfigurationNumericProperty(readTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_READ_TIMEOUT),
169+
getConfigurationNumericProperty(writeTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT),
170+
getConfigurationNumericProperty(terminationTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_TERMINATION_TIMEOUT)
176171
);
177172

178173
if ("raw".equalsIgnoreCase(type)) {
@@ -240,9 +235,15 @@ public HttpEventCollectorLoggingHandler() {
240235
@Override
241236
public void publish(LogRecord record) {
242237

243-
// Exception thrown in application is wrapped with relevant information instead of just a message.
244-
Map<Object, Object> exceptionDetailMap = new LinkedHashMap<>();
245-
if (record.getThrown() != null) {
238+
boolean isExceptionOccured = false;
239+
String exceptionDetail = null;
240+
/*
241+
Exception details are only populated when any SEVERE error occurred & exception is actually thrown
242+
*/
243+
if (Level.SEVERE.equals(record.getLevel()) && record.getThrown() != null) {
244+
245+
// Exception thrown in application is wrapped with relevant information instead of just a message.
246+
Map<Object, Object> exceptionDetailMap = new LinkedHashMap<>();
246247
StackTraceElement[] elements = record.getThrown().getStackTrace();
247248
exceptionDetailMap.put("detailMessage", record.getThrown().getMessage());
248249
exceptionDetailMap.put("exceptionClass", record.getThrown().getClass().toString());
@@ -253,6 +254,8 @@ public void publish(LogRecord record) {
253254
exceptionDetailMap.put("lineNumber", String.valueOf(elements[0].getLineNumber()));
254255
exceptionDetailMap.put("methodName", elements[0].getMethodName());
255256
}
257+
exceptionDetail = new Gson().toJson(exceptionDetailMap);
258+
isExceptionOccured = true;
256259
}
257260

258261
this.sender.send(
@@ -262,7 +265,7 @@ public void publish(LogRecord record) {
262265
includeLoggerName ? record.getLoggerName() : null,
263266
includeThreadName ? String.format(Locale.US, "%d", record.getThreadID()) : null,
264267
null, // no property map available
265-
(!includeException || record.getThrown() == null) ? null : new Gson().toJson(exceptionDetailMap),
268+
(includeException && isExceptionOccured) ? exceptionDetail : null,
266269
null // no marker available
267270
);
268271
}

0 commit comments

Comments
 (0)