For this purpose, I slightly changed the JSONLayout
class and created the new JSONLayoutV2
class.
You can use the JSONLayoutV2
class to customize these attributes until the JSONLayout
class is modified.
<JSONLayoutV2 objectMessageAsJsonObject="true" thread="true" threadId="true" eventEol="true" complete="true" compact="false" properties="true" />
JSONLayoutV2
class:
package org.apache.logging.log4j.core.layout;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.util.KeyValuePair;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Plugin(
name = "JsonLayoutV2",
category = "Core",
elementType = "layout",
printObject = true
)
public final class JsonLayoutV2 extends AbstractJacksonLayout {
private static final String DEFAULT_FOOTER = "]";
private static final String DEFAULT_HEADER = "[";
static final String CONTENT_TYPE = "application/json";
/** @deprecated */
@Deprecated
protected JsonLayoutV2(final Configuration config, final boolean locationInfo, final boolean properties, final boolean encodeThreadContextAsList, final boolean complete, final boolean compact, final boolean eventEol, final String endOfLine, final String headerPattern, final String footerPattern, final Charset charset, final boolean includeStacktrace) {
super(config, (new JacksonFactory.JSON(encodeThreadContextAsList, includeStacktrace, false, false)).newWriter(locationInfo, properties, compact), charset, compact, complete, eventEol, endOfLine, PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern("[").build(), PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern("]").build(), false, (KeyValuePair[])null);
}
private JsonLayoutV2(final Configuration config, final boolean locationInfo, final boolean properties, final boolean encodeThreadContextAsList, final boolean complete, final boolean compact, final boolean eventEol, final String endOfLine, final String headerPattern, final String footerPattern, final Charset charset, final boolean includeStacktrace, final boolean stacktraceAsString, final boolean includeNullDelimiter, final boolean includeTimeMillis, final KeyValuePair[] additionalFields, final boolean objectMessageAsJsonObject,
final boolean instant, final boolean loggerFqcn, final boolean endOfBatch, final boolean loggerName, final boolean thread, final boolean threadId, final boolean threadPriority) {
// super(config, (new JacksonFactory.JSON(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject)).newWriter(locationInfo, properties, compact, includeTimeMillis), charset, compact, complete, eventEol, endOfLine, PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern("[").build(), PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern("]").build(), includeNullDelimiter, additionalFields);
super(config, newWriter((new JacksonFactory.JSON(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject)), locationInfo, properties, compact, includeTimeMillis,
instant, loggerFqcn, endOfBatch, loggerName, thread, threadId, threadPriority), charset, compact, complete, eventEol, endOfLine, PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern("[").build(), PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern("]").build(), includeNullDelimiter, additionalFields);
}
static ObjectWriter newWriter(JacksonFactory.JSON jacksonFactory, final boolean locationInfo, final boolean properties, final boolean compact, final boolean includeMillis,
final boolean instant, final boolean loggerFqcn, final boolean endOfBatch, final boolean loggerName, final boolean thread, final boolean threadId, final boolean threadPriority) {
SimpleFilterProvider filters = new SimpleFilterProvider();
Set<String> except = new HashSet(3);
if (!locationInfo) {
except.add(jacksonFactory.getPropertNameForSource());
}
if (!properties) {
except.add(jacksonFactory.getPropertNameForContextMap());
}
if (includeMillis) {
except.add(jacksonFactory.getPropertyNameForInstant());
} else {
except.add(jacksonFactory.getPropertyNameForTimeMillis());
}
if (!instant) except.add("instant");
if (!loggerFqcn) except.add("loggerFqcn");
if (!endOfBatch) except.add("endOfBatch");
if (!loggerName) except.add("loggerName");
if (!thread) except.add("thread");
if (!threadId) except.add("threadId");
if (!threadPriority) except.add("threadPriority");
except.add(jacksonFactory.getPropertNameForNanoTime());
filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
ObjectWriter writer = jacksonFactory.newObjectMapper().writer(compact ? jacksonFactory.newCompactPrinter() : jacksonFactory.newPrettyPrinter());
return writer.with(filters);
}
public byte[] getHeader() {
if (!this.complete) {
return null;
} else {
StringBuilder buf = new StringBuilder();
String str = this.serializeToString(this.getHeaderSerializer());
if (str != null) {
buf.append(str);
}
buf.append(this.eol);
return this.getBytes(buf.toString());
}
}
public byte[] getFooter() {
if (!this.complete) {
return null;
} else {
StringBuilder buf = new StringBuilder();
buf.append(this.eol);
String str = this.serializeToString(this.getFooterSerializer());
if (str != null) {
buf.append(str);
}
buf.append(this.eol);
return this.getBytes(buf.toString());
}
}
public Map<String, String> getContentFormat() {
Map<String, String> result = new HashMap();
result.put("version", "2.0");
return result;
}
public String getContentType() {
return "application/json; charset=" + this.getCharset();
}
/** @deprecated */
// @Deprecated
// public static JsonLayoutV2 createLayout(final Configuration config, final boolean locationInfo, final boolean properties, final boolean propertiesAsList, final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, final String footerPattern, final Charset charset, final boolean includeStacktrace) {
// boolean encodeThreadContextAsList = properties && propertiesAsList;
// return new JsonLayoutV2(config, locationInfo, properties, encodeThreadContextAsList, complete, compact, eventEol, (String)null, headerPattern, footerPattern, charset, includeStacktrace, false, false, false, (KeyValuePair[])null, false);
// }
@PluginBuilderFactory
public static <B extends Builder<B>> B newBuilder() {
return (B) new Builder();
}
public static JsonLayoutV2 createDefaultLayout() {
return new JsonLayoutV2(new DefaultConfiguration(), false, false, false, false, false, false, (String)null, "[", "]", StandardCharsets.UTF_8, true, false, false, false, (KeyValuePair[])null, false,
false,false,false,false,false,false,false);
}
public void toSerializable(final LogEvent event, final Writer writer) throws IOException {
if (this.complete && this.eventCount > 0L) {
writer.append(", ");
}
super.toSerializable(event, writer);
}
public static class Builder<B extends Builder<B>> extends AbstractJacksonLayout.Builder<B> implements org.apache.logging.log4j.core.util.Builder<JsonLayoutV2> {
@PluginBuilderAttribute
private boolean propertiesAsList;
@PluginBuilderAttribute
private boolean objectMessageAsJsonObject;
@PluginElement("AdditionalField")
private KeyValuePair[] additionalFields;
@PluginBuilderAttribute
private boolean instant;
@PluginBuilderAttribute
private boolean loggerFqcn;
@PluginBuilderAttribute
private boolean endOfBatch;
@PluginBuilderAttribute
private boolean loggerName;
@PluginBuilderAttribute
private boolean thread;
@PluginBuilderAttribute
private boolean threadId;
@PluginBuilderAttribute
private boolean threadPriority;
public Builder() {
this.setCharset(StandardCharsets.UTF_8);
}
public JsonLayoutV2 build() {
boolean encodeThreadContextAsList = this.isProperties() && this.propertiesAsList;
String headerPattern = this.toStringOrNull(this.getHeader());
String footerPattern = this.toStringOrNull(this.getFooter());
return new JsonLayoutV2(this.getConfiguration(), this.isLocationInfo(), this.isProperties(), encodeThreadContextAsList, this.isComplete(), this.isCompact(), this.getEventEol(), this.getEndOfLine(), headerPattern, footerPattern, this.getCharset(), this.isIncludeStacktrace(), this.isStacktraceAsString(), this.isIncludeNullDelimiter(), this.isIncludeTimeMillis(), this.getAdditionalFields(), this.getObjectMessageAsJsonObject(),
instant, loggerFqcn, endOfBatch, loggerName, thread, threadId, threadPriority);
}
public boolean isPropertiesAsList() {
return this.propertiesAsList;
}
public B setPropertiesAsList(final boolean propertiesAsList) {
this.propertiesAsList = propertiesAsList;
return this.asBuilder();
}
public boolean getObjectMessageAsJsonObject() {
return this.objectMessageAsJsonObject;
}
public B setObjectMessageAsJsonObject(final boolean objectMessageAsJsonObject) {
this.objectMessageAsJsonObject = objectMessageAsJsonObject;
return this.asBuilder();
}
public KeyValuePair[] getAdditionalFields() {
return this.additionalFields;
}
public B setAdditionalFields(final KeyValuePair[] additionalFields) {
this.additionalFields = additionalFields;
return this.asBuilder();
}
}
}