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>

Reply via email to