Skip to content

Commit

Permalink
Release 1.6.2
Browse files Browse the repository at this point in the history
  • Loading branch information
ljiang1 committed Oct 30, 2018
2 parents 5279f6d + 4d6191e commit 5a23602
Show file tree
Hide file tree
Showing 18 changed files with 214 additions and 60 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,11 @@
# Splunk Logging for Java Changelog

## Version 1.6.2

* Add support to allow users to define their own event body serializer for HTTP event adapter: Simply create a class implementing `com.splunk.logging.EventBodySerializer`,
and add the full class name as a property (`eventBodySerializer`) to the adapter.
Default will be a JSON event body containing message, severity, and other properties. [#86](https://github.com/splunk/splunk-library-javalogging/pull/86).

## Version 1.6.1

* TcpAppender performance improvement, prevents 100% CPU usage [#85](https://github.com/splunk/splunk-library-javalogging/pull/85).
Expand Down
4 changes: 3 additions & 1 deletion README.md
@@ -1,6 +1,6 @@
# Splunk Logging for Java

#### Version 1.6.1
#### Version 1.6.2

This project provides utilities to easily log data using Splunk's recommended
best practices to any supported logger, using any of the three major Java
Expand Down Expand Up @@ -84,6 +84,8 @@ LOGGER.info("hello world");
#### Message Format
An event message format could be configured for HTTP event appender in logging framework configuration. It could have one of the two possible values - text, json. It is an optional property with default value as 'text'. Message format 'json' is used where the event message could be in json format.

It is also possible to use a custom event body serializer for the HTTP event adapter, to format the logging event however you please. Simply create a class implementing `com.splunk.logging.EventBodySerializer`, and add the full class name as a property (`eventBodySerializer`) to the adapter. Default will be a JSON event body containing message, severity, and other properties.

For more information, see http://dev.splunk.com/view/SP-CAAAE2K.

# License
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -6,7 +6,7 @@

<groupId>com.splunk.logging</groupId>
<artifactId>splunk-library-javalogging</artifactId>
<version>1.6.1</version>
<version>1.6.2</version>
<packaging>jar</packaging>

<name>Splunk Logging for Java</name>
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/com/splunk/logging/EventBodySerializer.java
@@ -0,0 +1,46 @@
package com.splunk.logging;

import java.io.Serializable;
import java.util.Map;
import org.json.simple.JSONObject;

public interface EventBodySerializer {

String serializeEventBody(
HttpEventCollectorEventInfo eventInfo,
Object formattedMessage
);

class Default implements EventBodySerializer {

@Override
public String serializeEventBody(
final HttpEventCollectorEventInfo eventInfo,
final Object formattedMessage
) {
final JSONObject body = new JSONObject();
HttpEventCollectorSender.putIfPresent(body, "severity", eventInfo.getSeverity());
HttpEventCollectorSender.putIfPresent(body, "message", formattedMessage);
HttpEventCollectorSender.putIfPresent(body, "logger", eventInfo.getLoggerName());
HttpEventCollectorSender.putIfPresent(body, "thread", eventInfo.getThreadName());
// add an exception record if and only if there is one
// in practice, the message also has the exception information attached
if (eventInfo.getExceptionMessage() != null) {
HttpEventCollectorSender.putIfPresent(body, "exception", eventInfo.getExceptionMessage());
}

// add properties if and only if there are any
final Map<String, String> props = eventInfo.getProperties();
if (props != null && !props.isEmpty()) {
body.put("properties", props);
}
// add marker if and only if there is one
final Serializable marker = eventInfo.getMarker();
if (marker != null) {
HttpEventCollectorSender.putIfPresent(body, "marker", marker.toString());
}

return body.toString();
}
}
}
Expand Up @@ -68,7 +68,8 @@ private HttpEventCollectorLog4jAppender(final String name,
long retriesOnError,
String sendMode,
String middleware,
final String disableCertificateValidation)
final String disableCertificateValidation,
final String eventBodySerializer)
{
super(name, filter, layout, ignoreExceptions);
Dictionary<String, String> metadata = new Hashtable<String, String>();
Expand All @@ -84,7 +85,13 @@ private HttpEventCollectorLog4jAppender(final String name,
if (middleware != null && !middleware.isEmpty()) {
try {
this.sender.addMiddleware((HttpEventCollectorMiddleware.HttpSenderMiddleware)(Class.forName(middleware).newInstance()));
} catch (Exception e) {}
} catch (Exception ignored) {}
}

if (eventBodySerializer != null && !eventBodySerializer.isEmpty()) {
try {
this.sender.setEventBodySerializer((EventBodySerializer) Class.forName(eventBodySerializer).newInstance());
} catch (final Exception ignored) {}
}

// plug resend middleware
Expand Down Expand Up @@ -128,6 +135,7 @@ public static HttpEventCollectorLog4jAppender createAppender(
@PluginAttribute("send_mode") final String sendMode,
@PluginAttribute("middleware") final String middleware,
@PluginAttribute("disableCertificateValidation") final String disableCertificateValidation,
@PluginAttribute("eventBodySerializer") final String eventBodySerializer,
@PluginAttribute(value = "includeLoggerName", defaultBoolean = true) final boolean includeLoggerName,
@PluginAttribute(value = "includeThreadName", defaultBoolean = true) final boolean includeThreadName,
@PluginAttribute(value = "includeMDC", defaultBoolean = true) final boolean includeMDC,
Expand Down Expand Up @@ -174,7 +182,9 @@ public static HttpEventCollectorLog4jAppender createAppender(
parseInt(retriesOnError, 0),
sendMode,
middleware,
disableCertificateValidation);
disableCertificateValidation,
eventBodySerializer
);
}


Expand Down
Expand Up @@ -46,6 +46,7 @@ public class HttpEventCollectorLogbackAppender<E> extends AppenderBase<E> {
private String _type;
private String _disableCertificateValidation;
private String _middleware;
private String _eventBodySerializer;
private long _batchInterval = 0;
private long _batchCount = 0;
private long _batchSize = 0;
Expand Down Expand Up @@ -81,7 +82,13 @@ public void start() {
if (_middleware != null && !_middleware.isEmpty()) {
try {
this.sender.addMiddleware((HttpEventCollectorMiddleware.HttpSenderMiddleware)(Class.forName(_middleware).newInstance()));
} catch (Exception e) {}
} catch (Exception ignored) {}
}

if (_eventBodySerializer != null && !_eventBodySerializer.isEmpty()) {
try {
this.sender.setEventBodySerializer((EventBodySerializer) Class.forName(_eventBodySerializer).newInstance());
} catch (final Exception ignored) {}
}

// plug resend middleware
Expand Down Expand Up @@ -120,7 +127,7 @@ private void sendEvent(ILoggingEvent event) {
}

MarkerConverter c = new MarkerConverter();
if (event != null && started) {
if (this.started) {
this.sender.send(
event.getLevel().toString(),
_layout.doLayout((E) event),
Expand Down Expand Up @@ -257,6 +264,10 @@ public String getIndex() {
return this._index;
}

public String getEventBodySerializer() {
return _eventBodySerializer;
}

public void setDisableCertificateValidation(String disableCertificateValidation) {
this._disableCertificateValidation = disableCertificateValidation;
}
Expand Down Expand Up @@ -289,6 +300,10 @@ public String getDisableCertificateValidation() {
return _disableCertificateValidation;
}

public void setEventBodySerializer(String eventBodySerializer) {
this._eventBodySerializer = eventBodySerializer;
}

private static long parseLong(String string, int defaultValue) {
try {
return Long.parseLong(string);
Expand Down
Expand Up @@ -149,6 +149,7 @@ public HttpEventCollectorLoggingHandler() {
long retriesOnError = getConfigurationNumericProperty(RetriesOnErrorTag, 0);
String sendMode = getConfigurationProperty(SendModeTag, "sequential");
String middleware = getConfigurationProperty(MiddlewareTag, "");
String eventBodySerializer = getConfigurationProperty("eventBodySerializer", "");

includeLoggerName = getConfigurationBooleanProperty(IncludeLoggerNameConfTag, true);
includeThreadName = getConfigurationBooleanProperty(IncludeThreadNameConfTag, true);
Expand All @@ -162,7 +163,16 @@ public HttpEventCollectorLoggingHandler() {
if (middleware != null && !middleware.isEmpty()) {
try {
this.sender.addMiddleware((HttpEventCollectorMiddleware.HttpSenderMiddleware)(Class.forName(middleware).newInstance()));
} catch (Exception e) {}
} catch (Exception ignored) {}
}

if (eventBodySerializer != null && !eventBodySerializer.isEmpty()) {
try {
this.sender.setEventBodySerializer((EventBodySerializer) Class.forName(eventBodySerializer).newInstance());
} catch (final Exception ex) {
//output error msg but not fail, it will default to use the default EventBodySerializer
System.out.println(ex);
}
}

// plug retries middleware
Expand Down
42 changes: 14 additions & 28 deletions src/main/java/com/splunk/logging/HttpEventCollectorSender.java
Expand Up @@ -50,7 +50,7 @@
/**
* This is an internal helper class that sends logging events to Splunk http event collector.
*/
final class HttpEventCollectorSender extends TimerTask implements HttpEventCollectorMiddleware.IHttpSender {
public class HttpEventCollectorSender extends TimerTask implements HttpEventCollectorMiddleware.IHttpSender {
public static final String MetadataTimeTag = "time";
public static final String MetadataHostTag = "host";
public static final String MetadataIndexTag = "index";
Expand Down Expand Up @@ -99,6 +99,7 @@ public enum SendMode
private SendMode sendMode = SendMode.Sequential;
private HttpEventCollectorMiddleware middleware = new HttpEventCollectorMiddleware();
private final MessageFormat messageFormat;
private EventBodySerializer eventBodySerializer;

/**
* Initialize HttpEventCollectorSender
Expand Down Expand Up @@ -135,12 +136,12 @@ public HttpEventCollectorSender(
this.maxEventsBatchCount = maxEventsBatchCount;
this.maxEventsBatchSize = maxEventsBatchSize;
this.metadata = metadata;

final String format = metadata.get(MetadataMessageFormatTag);
// Get MessageFormat enum from format string. Do this once per instance in constructor to avoid expensive operation in
// each event sender call
this.messageFormat = MessageFormat.fromFormat(format);

if (sendModeStr != null) {
if (sendModeStr.equals(SendModeSequential))
this.sendMode = SendMode.Sequential;
Expand Down Expand Up @@ -239,8 +240,12 @@ public void disableCertificateValidation() {
disableCertificateValidation = true;
}

public void setEventBodySerializer(EventBodySerializer eventBodySerializer) {
this.eventBodySerializer = eventBodySerializer;
}

@SuppressWarnings("unchecked")
private static void putIfPresent(JSONObject collection, String tag, Object value) {
public static void putIfPresent(JSONObject collection, String tag, Object value) {
if (value != null) {
if (value instanceof String && ((String) value).length() == 0) {
// Do not add blank string
Expand All @@ -263,34 +268,15 @@ private String serializeEventInfo(HttpEventCollectorEventInfo eventInfo) {
putIfPresent(event, MetadataIndexTag, metadata.get(MetadataIndexTag));
putIfPresent(event, MetadataSourceTag, metadata.get(MetadataSourceTag));
putIfPresent(event, MetadataSourceTypeTag, metadata.get(MetadataSourceTypeTag));

// Parse message on the basis of format
final Object parsedMessage = this.messageFormat.parse(eventInfo.getMessage());

// event body
JSONObject body = new JSONObject();
putIfPresent(body, "severity", eventInfo.getSeverity());
putIfPresent(body, "message", parsedMessage);
putIfPresent(body, "logger", eventInfo.getLoggerName());
putIfPresent(body, "thread", eventInfo.getThreadName());
// add an exception record if and only if there is one
// in practice, the message also has the exception information attached
if (eventInfo.getExceptionMessage() != null) {
putIfPresent(body, "exception", eventInfo.getExceptionMessage());
}

// add properties if and only if there are any
final Map<String,String> props = eventInfo.getProperties();
if (props != null && !props.isEmpty()) {
body.put("properties", props);
if (eventBodySerializer == null) {
eventBodySerializer = new EventBodySerializer.Default();
}
// add marker if and only if there is one
final Serializable marker = eventInfo.getMarker();
if (marker != null) {
putIfPresent(body, "marker", marker.toString());
}
// join event and body
event.put("event", body);

event.put("event", eventBodySerializer.serializeEventBody(eventInfo, parsedMessage));
return event.toString();
}

Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/splunk/logging/MessageFormat.java
Expand Up @@ -30,7 +30,6 @@ enum MessageFormat {
*
*
* @param message the message string
* @param format the message format
*
* @return parsed message object based on format
*/
Expand Down
5 changes: 4 additions & 1 deletion src/test/java/HttpEventCollectorUnitTest.java
Expand Up @@ -43,6 +43,7 @@ public void log4j_simple() throws Exception {
userInputs.put("user_middleware", "HttpEventCollectorUnitTestMiddleware");
userInputs.put("user_batch_size_count", "1");
userInputs.put("user_batch_size_bytes", "0");
userInputs.put("user_eventBodySerializer", "DoesNotExistButShouldNotCrashTest");
TestUtil.resetLog4j2Configuration("log4j2_template.xml", "log4j2.xml", userInputs);
org.apache.logging.log4j.Logger LOG4J = org.apache.logging.log4j.LogManager.getLogger(loggerName);

Expand Down Expand Up @@ -71,6 +72,7 @@ public void logback_simple() throws Exception {
userInputs.put("user_logger_name", loggerName);
userInputs.put("user_httpEventCollector_token", "11111111-2222-3333-4444-555555555555");
userInputs.put("user_middleware", "HttpEventCollectorUnitTestMiddleware");
userInputs.put("user_eventBodySerializer", "DoesNotExistButShouldNotCrashTest");
TestUtil.resetLogbackConfiguration("logback_template.xml", "logback.xml", userInputs);
org.slf4j.Logger LOGBACK = org.slf4j.LoggerFactory.getLogger(loggerName);

Expand Down Expand Up @@ -101,7 +103,8 @@ public void java_util_logger_simple() {
"com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_count=0\n" +
"com.splunk.logging.HttpEventCollectorLoggingHandler.batch_size_bytes=0\n" +
"com.splunk.logging.HttpEventCollectorLoggingHandler.batch_interval=0\n" +
"com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n"
"com.splunk.logging.HttpEventCollectorLoggingHandler.middleware=HttpEventCollectorUnitTestMiddleware\n" +
"com.splunk.logging.HttpEventCollectorLoggingHandler.eventBodySerializer=DoesNotExistButShouldNotCrashTest\n"
);

// send 3 events
Expand Down

0 comments on commit 5a23602

Please sign in to comment.