biz.paluch.logging.gelf.log4j.GelfLayout Maven / Gradle / Ivy
The newest version!
package biz.paluch.logging.gelf.log4j;
import static biz.paluch.logging.gelf.LogMessageField.NamedLogField.*;
import java.util.*;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import biz.paluch.logging.gelf.LogMessageField;
import biz.paluch.logging.gelf.MdcGelfMessageAssembler;
import biz.paluch.logging.gelf.intern.ConfigurationSupport;
import biz.paluch.logging.gelf.intern.GelfMessage;
/**
* Log-Formatter for JSON using fields specified within GELF. This formatter will produce a JSON object for each log event.
* Example:
*
*
{
"NDC": "ndc message",
"timestamp": "1439319236.722",
"SourceClassName": "biz.paluch.logging.gelf.wildfly.WildFlyGelfLogFormatterTest",
"SourceMethodName": "testDefaults",
"level": "6",
"SourceSimpleClassName": "WildFlyGelfLogFormatterTest",
"facility": "logstash-gelf",
"full_message": "foo bar test log message",
"short_message": "foo bar test log message",
"MySeverity": "INFO",
"LoggerName": "biz.paluch.logging.gelf.wildfly.WildFlyGelfLogFormatterTest",
"Thread": "main",
"MyTime": "2015-08-11 20:53:56,0722"
}
*
*
* Following parameters are supported/needed:
*
* - lineBreak (Optional): End of line, platform dependent default value, see {@code System.getProperty("line.separator")}
* - fields (Optional): Comma-separated list of log event fields that should be included in the JSON. Defaults to
* {@code Time, Severity, ThreadName, SourceClassName, SourceMethodName, SourceSimpleClassName, LoggerName, NDC}
* - originHost (Optional): Originating Hostname, default FQDN Hostname
* - extractStackTrace (Optional): Post Stack-Trace to StackTrace field (true/false/throwable reference [0 = throwable, 1 =
* throwable.cause, -1 = root cause]), default false
* - filterStackTrace (Optional): Perform Stack-Trace filtering (true/false), default false
* - includeLocation (Optional): Include source code location, default true
* - mdcProfiling (Optional): Perform Profiling (Call-Duration) based on MDC Data. See MDC
* Profiling, default false
* - facility (Optional): Name of the Facility, default gelf-java
* - additionalFields(number) (Optional): Post additional fields. Eg. fieldName=Value,field2=value2
* - additionalFieldTypes (Optional): Type specification for additional and MDC fields. Supported types: String, long, Long,
* double, Double and discover (default if not specified, discover field type on parseability). Eg. field=String,field2=double
* - mdcFields (Optional): Post additional fields, pull Values from MDC. Name of the Fields are comma-separated
* Application,Version,SomeOtherFieldName
* - dynamicMdcFields (Optional): Dynamic MDC Fields allows you to extract MDC values based on one or more regular
* expressions. Multiple regex are comma-separated. The name of the MDC entry is used as GELF field name. mdc.*,[mdc|MDC]fields
* - dynamicMdcFieldTypes (Optional): Pattern-based type specification for additional and MDC fields. Key-value pairs are
* comma-separated. Supported types: String, long, Long, double, Double. Eg. my_field.*=String,business\..*\.field=double
* - includeFullMdc (Optional): Include all fields from the MDC, default false
*
* MDC Profiling
*
* MDC Profiling allows to calculate the runtime from request start up to the time until the log message was generated. You must
* set one value in the MDC:
*
* - profiling.requestStart.millis: Time Millis of the Request-Start (Long or String)
*
*
* Two values are set by the formatter:
*
*
* - profiling.requestEnd: End-Time of the Request-End in Date.toString-representation
* - profiling.requestDuration: Duration of the request (e.g. 205ms, 16sec)
*
*
* @author Kai Geisselhardt
* @author Mark Paluch
*/
public class GelfLayout extends Layout {
public static final String MULTI_VALUE_DELIMITTER = ",";
public static final Set SUPPORTED_FIELDS;
private final MdcGelfMessageAssembler gelfMessageAssembler = new MdcGelfMessageAssembler();
private String lineBreak = Layout.LINE_SEP;
private boolean wasSetFieldsCalled = false;
static {
Set supportedFields = new LinkedHashSet<>();
supportedFields.add(Time);
supportedFields.add(Severity);
supportedFields.add(ThreadName);
supportedFields.add(SourceClassName);
supportedFields.add(SourceMethodName);
supportedFields.add(SourceLineNumber);
supportedFields.add(SourceSimpleClassName);
supportedFields.add(LoggerName);
supportedFields.add(NDC);
supportedFields.add(Server);
SUPPORTED_FIELDS = Collections.unmodifiableSet(supportedFields);
}
public GelfLayout() {
super();
}
@Override
public String format(LoggingEvent loggingEvent) {
if (!wasSetFieldsCalled) {
addFields(SUPPORTED_FIELDS);
}
GelfMessage gelfMessage = gelfMessageAssembler.createGelfMessage(new Log4jLogEvent(loggingEvent));
return gelfMessage.toJson("") + lineBreak;
}
@Override
public boolean ignoresThrowable() {
return false;
}
@Override
public void activateOptions() {
// nothing to do
}
public void setFields(String fieldSpec) {
String[] properties = fieldSpec.split(MULTI_VALUE_DELIMITTER);
List fields = new ArrayList<>();
for (String field : properties) {
LogMessageField.NamedLogField namedLogField = LogMessageField.NamedLogField.byName(field.trim());
if (namedLogField == null) {
throw new IllegalArgumentException("Cannot resolve field name '" + field
+ "' to a field. Supported field names are: " + SUPPORTED_FIELDS);
}
if (!SUPPORTED_FIELDS.contains(namedLogField)) {
throw new IllegalArgumentException("Field '" + field + "' is not supported. Supported field names are: "
+ SUPPORTED_FIELDS);
}
fields.add(namedLogField);
}
addFields(fields);
}
private void addFields(Collection fields) {
gelfMessageAssembler.addFields(LogMessageField.getDefaultMapping(fields
.toArray(new LogMessageField.NamedLogField[fields.size()])));
wasSetFieldsCalled = true;
}
public void setAdditionalFields(String spec) {
ConfigurationSupport.setAdditionalFields(spec, gelfMessageAssembler);
}
public void setAdditionalFieldTypes(String spec) {
ConfigurationSupport.setAdditionalFieldTypes(spec, gelfMessageAssembler);
}
public void setMdcFields(String spec) {
ConfigurationSupport.setMdcFields(spec, gelfMessageAssembler);
}
public void setDynamicMdcFields(String spec) {
ConfigurationSupport.setDynamicMdcFields(spec, gelfMessageAssembler);
}
public void setDynamicMdcFieldTypes(String spec) {
ConfigurationSupport.setDynamicMdcFieldTypes(spec, gelfMessageAssembler);
}
public boolean isMdcProfiling() {
return gelfMessageAssembler.isMdcProfiling();
}
public void setMdcProfiling(boolean mdcProfiling) {
gelfMessageAssembler.setMdcProfiling(mdcProfiling);
}
public boolean isIncludeFullMdc() {
return gelfMessageAssembler.isIncludeFullMdc();
}
public void setIncludeFullMdc(boolean includeFullMdc) {
gelfMessageAssembler.setIncludeFullMdc(includeFullMdc);
}
public String getOriginHost() {
return gelfMessageAssembler.getOriginHost();
}
public void setOriginHost(String originHost) {
gelfMessageAssembler.setOriginHost(originHost);
}
public String getFacility() {
return gelfMessageAssembler.getFacility();
}
public void setFacility(String facility) {
gelfMessageAssembler.setFacility(facility);
}
public String getExtractStackTrace() {
return gelfMessageAssembler.getExtractStackTrace();
}
public void setExtractStackTrace(String extractStacktrace) {
gelfMessageAssembler.setExtractStackTrace(extractStacktrace);
}
public boolean isFilterStackTrace() {
return gelfMessageAssembler.isFilterStackTrace();
}
public void setFilterStackTrace(boolean filterStackTrace) {
gelfMessageAssembler.setFilterStackTrace(filterStackTrace);
}
public boolean isIncludeLocation() {
return gelfMessageAssembler.isIncludeLocation();
}
public void setIncludeLocation(boolean includeLocation) {
gelfMessageAssembler.setIncludeLocation(includeLocation);
}
public String getTimestampPattern() {
return gelfMessageAssembler.getTimestampPattern();
}
public void setTimestampPattern(String timestampPattern) {
gelfMessageAssembler.setTimestampPattern(timestampPattern);
}
public String getVersion() {
return gelfMessageAssembler.getVersion();
}
public void setVersion(String version) {
gelfMessageAssembler.setVersion(version);
}
public String getLineBreak() {
return lineBreak;
}
public void setLineBreak(String lineBreak) {
this.lineBreak = lineBreak;
}
}