Repository: logging-log4j2 Updated Branches: refs/heads/master f55daa01c -> b0daba63f
LOG4J-1724 Using variables in GelfLayout's additional fields at runtime Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/b0daba63 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/b0daba63 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/b0daba63 Branch: refs/heads/master Commit: b0daba63f8bb103dc46f537f44b7d482e0732dcc Parents: f55daa0 Author: Mikael Ståldal <[email protected]> Authored: Thu Jan 5 18:56:32 2017 +0100 Committer: Mikael Ståldal <[email protected]> Committed: Thu Jan 5 19:28:11 2017 +0100 ---------------------------------------------------------------------- .../logging/log4j/core/layout/GelfLayout.java | 61 ++++++++++++++------ .../log4j/core/layout/GelfLayoutTest.java | 59 +++++++++++++------ .../log4j/core/layout/GelfLayoutTest2.java | 2 + .../src/test/resources/GelfLayoutTest2.xml | 1 + .../log4j/perf/jmh/GelfLayoutBenchmark.java | 3 + src/changes/changes.xml | 3 + src/site/xdoc/manual/layouts.xml.vm | 7 ++- 7 files changed, 98 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java index f7826d0..302be59 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java @@ -28,8 +28,10 @@ import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPOutputStream; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Node; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -37,9 +39,11 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 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.lookup.StrSubstitutor; import org.apache.logging.log4j.core.net.Severity; import org.apache.logging.log4j.core.util.JsonUtils; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.StringBuilderFormattable; @@ -108,6 +112,7 @@ public final class GelfLayout extends AbstractStringLayout { private final CompressionType compressionType; private final String host; private final boolean includeStacktrace; + private final boolean includeThreadContext; public static class Builder<B extends Builder<B>> extends AbstractStringLayout.Builder<B> implements org.apache.logging.log4j.core.util.Builder<GelfLayout> { @@ -127,6 +132,9 @@ public final class GelfLayout extends AbstractStringLayout { @PluginBuilderAttribute private boolean includeStacktrace = true; + @PluginBuilderAttribute + private boolean includeThreadContext = true; + public Builder() { super(); setCharset(StandardCharsets.UTF_8); @@ -134,7 +142,7 @@ public final class GelfLayout extends AbstractStringLayout { @Override public GelfLayout build() { - return new GelfLayout(getConfiguration(), host, additionalFields, compressionType, compressionThreshold, includeStacktrace); + return new GelfLayout(getConfiguration(), host, additionalFields, compressionType, compressionThreshold, includeStacktrace, includeThreadContext); } public String getHost() { @@ -153,12 +161,16 @@ public final class GelfLayout extends AbstractStringLayout { return includeStacktrace; } + public boolean isIncludeThreadContext() { + return includeThreadContext; + } + public KeyValuePair[] getAdditionalFields() { return additionalFields; } /** - * The value of the <code>host</code> property (mandatory). + * The value of the <code>host</code> property (optional, defaults to local host name). * * @return this builder */ @@ -199,6 +211,16 @@ public final class GelfLayout extends AbstractStringLayout { } /** + * Whether to include thread context as additional fields (optional, default to true). + * + * @return this builder + */ + public B setIncludeThreadContext(boolean includeThreadContext) { + this.includeThreadContext = includeThreadContext; + return asBuilder(); + } + + /** * Additional fields to set on each log event. * * @return this builder @@ -215,22 +237,18 @@ public final class GelfLayout extends AbstractStringLayout { @Deprecated public GelfLayout(final String host, final KeyValuePair[] additionalFields, final CompressionType compressionType, final int compressionThreshold, final boolean includeStacktrace) { - super(StandardCharsets.UTF_8); - this.host = host; - this.additionalFields = additionalFields; - this.compressionType = compressionType; - this.compressionThreshold = compressionThreshold; - this.includeStacktrace = includeStacktrace; + this(((LoggerContext) LogManager.getContext(false)).getConfiguration(), host, additionalFields, compressionType, compressionThreshold, includeStacktrace, true); } private GelfLayout(final Configuration config, final String host, final KeyValuePair[] additionalFields, final CompressionType compressionType, - final int compressionThreshold, final boolean includeStacktrace) { + final int compressionThreshold, final boolean includeStacktrace, final boolean includeThreadContext) { super(config, StandardCharsets.UTF_8, null, null); - this.host = host; + this.host = host != null ? host : NetUtils.getLocalHostname(); this.additionalFields = additionalFields; this.compressionType = compressionType; this.compressionThreshold = compressionThreshold; this.includeStacktrace = includeStacktrace; + this.includeThreadContext = includeThreadContext; } /** @@ -248,7 +266,7 @@ public final class GelfLayout extends AbstractStringLayout { @PluginAttribute(value = "includeStacktrace", defaultBoolean = true) final boolean includeStacktrace) { // @formatter:on - return new GelfLayout(null, host, additionalFields, compressionType, compressionThreshold, includeStacktrace); + return new GelfLayout(((LoggerContext) LogManager.getContext(false)).getConfiguration(), host, additionalFields, compressionType, compressionThreshold, includeStacktrace, true); } @PluginBuilderFactory @@ -325,15 +343,20 @@ public final class GelfLayout extends AbstractStringLayout { JsonUtils.quoteAsString(event.getLoggerName(), builder); builder.append(QC); } - - for (final KeyValuePair additionalField : additionalFields) { - builder.append(QU); - JsonUtils.quoteAsString(additionalField.getKey(), builder); - builder.append("\":\""); - JsonUtils.quoteAsString(toNullSafeString(additionalField.getValue()), builder); - builder.append(QC); + if (additionalFields.length > 0) { + final StrSubstitutor strSubstitutor = getConfiguration().getStrSubstitutor(); + for (final KeyValuePair additionalField : additionalFields) { + builder.append(QU); + JsonUtils.quoteAsString(additionalField.getKey(), builder); + builder.append("\":\""); + final String value = strSubstitutor.replace(event, additionalField.getValue()); + JsonUtils.quoteAsString(toNullSafeString(value), builder); + builder.append(QC); + } + } + if (includeThreadContext) { + event.getContextData().forEach(WRITE_KEY_VALUES_INTO, builder); } - event.getContextData().forEach(WRITE_KEY_VALUES_INTO, builder); if (event.getThrown() != null) { builder.append("\"full_message\":\""); if (includeStacktrace) { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java index 68d77f9..73667ba 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java @@ -23,7 +23,9 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.*; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.layout.GelfLayout.CompressionType; +import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.junit.ThreadContextRule; import org.apache.logging.log4j.test.appender.EncodingListAppender; import org.apache.logging.log4j.test.appender.ListAppender; @@ -57,7 +59,6 @@ public class GelfLayoutTest { private static final String MDCVALUE1 = "MdcValue1"; private static final String MDCVALUE2 = "MdcValue2"; private static final String VALUE1 = "Value1"; - private static final String VALUE2 = "Value2"; @Rule public final ThreadContextRule threadContextRule = new ThreadContextRule(); @@ -78,19 +79,22 @@ public class GelfLayoutTest { Logger root = ctx.getRootLogger(); - private void testCompressedLayout(final CompressionType compressionType, final boolean includeStacktrace) throws IOException { + private void testCompressedLayout(final CompressionType compressionType, final boolean includeStacktrace, + final boolean includeThreadContext, String host) throws IOException { for (final Appender appender : root.getAppenders().values()) { root.removeAppender(appender); } // set up appenders final GelfLayout layout = GelfLayout.newBuilder() - .setHost(HOSTNAME) + .setConfiguration(ctx.getConfiguration()) + .setHost(host) .setAdditionalFields(new KeyValuePair[] { new KeyValuePair(KEY1, VALUE1), - new KeyValuePair(KEY2, VALUE2), }) + new KeyValuePair(KEY2, "${java:runtime}"), }) .setCompressionType(compressionType) .setCompressionThreshold(1024) .setIncludeStacktrace(includeStacktrace) + .setIncludeThreadContext(includeThreadContext) .build(); final ListAppender eventAppender = new ListAppender("Events", null, null, true, false); final ListAppender rawAppender = new ListAppender("Raw", null, layout, true, true); @@ -101,6 +105,10 @@ public class GelfLayoutTest { formattedAppender.start(); encodedAppender.start(); + if (host == null) host = NetUtils.getLocalHostname(); + + final JavaLookup javaLookup = new JavaLookup(); + // set appenders on root and set level to debug root.addAppender(eventAppender); root.addAppender(rawAppender); @@ -129,29 +137,32 @@ public class GelfLayoutTest { //@formatter:off assertJsonEquals("{" + "\"version\": \"1.1\"," + - "\"host\": \"" + HOSTNAME + "\"," + + "\"host\": \"" + host + "\"," + "\"timestamp\": " + GelfLayout.formatTimestamp(events.get(0).getTimeMillis()) + "," + "\"level\": 7," + "\"_thread\": \"" + threadName + "\"," + "\"_logger\": \"\"," + "\"short_message\": \"" + LINE1 + "\"," + "\"_" + KEY1 + "\": \"" + VALUE1 + "\"," + - "\"_" + KEY2 + "\": \"" + VALUE2 + "\"" + + "\"_" + KEY2 + "\": \"" + javaLookup.getRuntime() + "\"" + "}", messages.get(0)); assertJsonEquals("{" + "\"version\": \"1.1\"," + - "\"host\": \"" + HOSTNAME + "\"," + + "\"host\": \"" + host + "\"," + "\"timestamp\": " + GelfLayout.formatTimestamp(events.get(1).getTimeMillis()) + "," + "\"level\": 6," + "\"_thread\": \"" + threadName + "\"," + "\"_logger\": \"\"," + "\"short_message\": \"" + LINE2 + "\"," + + (includeThreadContext ? + "\"_" + MDCKEY1 + "\": \"" + MDCVALUE1 + "\"," + + "\"_" + MDCKEY2 + "\": \"" + MDCVALUE2 + "\"," + : + "") + "\"_" + KEY1 + "\": \"" + VALUE1 + "\"," + - "\"_" + KEY2 + "\": \"" + VALUE2 + "\"," + - "\"_" + MDCKEY1 + "\": \"" + MDCVALUE1 + "\"," + - "\"_" + MDCKEY2 + "\": \"" + MDCVALUE2 + "\"" + + "\"_" + KEY2 + "\": \"" + javaLookup.getRuntime() + "\"" + "}", messages.get(1)); //@formatter:on @@ -186,7 +197,7 @@ public class GelfLayoutTest { //@formatter:off final String expected = "{" + "\"version\": \"1.1\"," + - "\"host\": \"" + HOSTNAME + "\"," + + "\"host\": \"" + host + "\"," + "\"timestamp\": " + GelfLayout.formatTimestamp(events.get(2).getTimeMillis()) + "," + "\"level\": 3," + "\"_thread\": \"" + threadName + "\"," + @@ -194,10 +205,12 @@ public class GelfLayoutTest { "\"short_message\": \"" + LINE3 + "\"," + "\"full_message\": \"" + String.valueOf(JsonStringEncoder.getInstance().quoteAsString( includeStacktrace ? GelfLayout.formatThrowable(exception).toString() : exception.toString())) + "\"," + + (includeThreadContext ? + "\"_" + MDCKEY1 + "\": \"" + MDCVALUE1 + "\"," + + "\"_" + MDCKEY2 + "\": \"" + MDCVALUE2 + "\"," + : "") + "\"_" + KEY1 + "\": \"" + VALUE1 + "\"," + - "\"_" + KEY2 + "\": \"" + VALUE2 + "\"," + - "\"_" + MDCKEY1 + "\": \"" + MDCVALUE1 + "\"," + - "\"_" + MDCKEY2 + "\": \"" + MDCVALUE2 + "\"" + + "\"_" + KEY2 + "\": \"" + javaLookup.getRuntime() + "\"" + "}"; //@formatter:on assertJsonEquals(expected, uncompressedString); @@ -206,22 +219,32 @@ public class GelfLayoutTest { @Test public void testLayoutGzipCompression() throws Exception { - testCompressedLayout(CompressionType.GZIP, true); + testCompressedLayout(CompressionType.GZIP, true, true, HOSTNAME); } @Test public void testLayoutNoCompression() throws Exception { - testCompressedLayout(CompressionType.OFF, true); + testCompressedLayout(CompressionType.OFF, true, true, HOSTNAME); } @Test public void testLayoutZlibCompression() throws Exception { - testCompressedLayout(CompressionType.ZLIB, true); + testCompressedLayout(CompressionType.ZLIB, true, true, HOSTNAME); } @Test public void testLayoutNoStacktrace() throws Exception { - testCompressedLayout(CompressionType.OFF, false); + testCompressedLayout(CompressionType.OFF, false, true, HOSTNAME); + } + + @Test + public void testLayoutNoThreadContext() throws Exception { + testCompressedLayout(CompressionType.OFF, true, false, HOSTNAME); + } + + @Test + public void testLayoutNoHost() throws Exception { + testCompressedLayout(CompressionType.OFF, true, true, null); } @Test http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java index edbf7b1..64d3118 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java @@ -21,6 +21,7 @@ import java.io.IOException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.ClassRule; import org.junit.Test; @@ -42,6 +43,7 @@ public class GelfLayoutTest2 { assertEquals("Message", json.get("short_message").asText()); assertEquals("myhost", json.get("host").asText()); assertEquals("FOO", json.get("_foo").asText()); + assertEquals(new JavaLookup().getRuntime(), json.get("_runtime").asText()); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/log4j-core/src/test/resources/GelfLayoutTest2.xml ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/resources/GelfLayoutTest2.xml b/log4j-core/src/test/resources/GelfLayoutTest2.xml index f501185..558a22a 100644 --- a/log4j-core/src/test/resources/GelfLayoutTest2.xml +++ b/log4j-core/src/test/resources/GelfLayoutTest2.xml @@ -21,6 +21,7 @@ <List name="list"> <GelfLayout host="myhost"> <KeyValuePair key="foo" value="FOO"/> + <KeyValuePair key="runtime" value="$${java:runtime}"/> </GelfLayout> </List> </Appenders> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java index 9ab0fc2..98d347a 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/GelfLayoutBenchmark.java @@ -21,6 +21,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.NullConfiguration; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.GelfLayout; import org.apache.logging.log4j.core.util.KeyValuePair; @@ -79,11 +80,13 @@ public class GelfLayoutBenchmark { System.setProperty("log4j2.enable.direct.encoders", "true"); appender = new DemoAppender(GelfLayout.newBuilder() + .setConfiguration(new NullConfiguration()) .setHost("host") .setAdditionalFields(ADDITIONAL_FIELDS) .setCompressionType(GelfLayout.CompressionType.OFF) .setCompressionThreshold(0) .setIncludeStacktrace(true) + .setIncludeThreadContext(true) .build()); j = 0; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 09be0a8..a1280fc 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -24,6 +24,9 @@ </properties> <body> <release version="2.8" date="2017-MM-DD" description="GA Release 2.8"> + <action issue="LOG4J2-1724" dev="mikes" type="fix" due-to="Alexander K"> + Using variables in GelfLayout's additional fields at runtime. + </action> <action issue="LOG4J2-1762" dev="mikes" type="fix"> Add Builder to GelfLayout. </action> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b0daba63/src/site/xdoc/manual/layouts.xml.vm ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm index ba0dc20..8c5ea8a 100644 --- a/src/site/xdoc/manual/layouts.xml.vm +++ b/src/site/xdoc/manual/layouts.xml.vm @@ -215,7 +215,7 @@ logger.debug("one={}, two={}, three={}", 1, 2, 3); <tr> <td>host</td> <td>String</td> - <td>The value of the <code>host</code> property (mandatory).</td> + <td>The value of the <code>host</code> property (optional, defaults to local host name).</td> </tr> <tr> <td>compressionType</td> @@ -234,6 +234,11 @@ logger.debug("one={}, two={}, three={}", 1, 2, 3); If set to false, only the class name and message of the #javadoc('java/lang', 'Throwable') will be included.</td> </tr> + <tr> + <td>includeThreadContext</td> + <td>boolean</td> + <td>Whether to include thread context as additional fields (optional, default to true).</td> + </tr> <caption align="top">GELF Layout Parameters</caption> </table> <p>
