You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by vy...@apache.org on 2020/07/11 20:41:47 UTC
[logging-log4j2] branch master updated: #335 Add
nullEventDelimiterEnabled flag.
This is an automated email from the ASF dual-hosted git repository.
vy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 7b5aaa8 #335 Add nullEventDelimiterEnabled flag.
7b5aaa8 is described below
commit 7b5aaa8434102307df4cb90540703b0deaec393b
Author: Volkan Yazıcı <vo...@gmail.com>
AuthorDate: Sat Jul 11 22:38:09 2020 +0200
#335 Add nullEventDelimiterEnabled flag.
---
.../layout/json/template/JsonTemplateLayout.java | 23 +++-
.../json/template/JsonTemplateLayoutDefaults.java | 9 ++
.../JsonTemplateLayoutNullEventDelimiterTest.java | 127 +++++++++++++++++++++
.../resources/gcFreeJsonTemplateLayoutLogging.xml | 17 +++
...nullEventDelimitedJsonTemplateLayoutLogging.xml | 39 +++++++
.../src/main/config-repo/log4j2.xml | 2 +-
src/site/asciidoc/manual/json-template-layout.adoc | 6 +
src/site/markdown/manual/cloud.md | 2 +-
8 files changed, 217 insertions(+), 8 deletions(-)
diff --git a/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayout.java b/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayout.java
index 7ff3ae9..355816e 100644
--- a/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayout.java
+++ b/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayout.java
@@ -92,7 +92,8 @@ public class JsonTemplateLayout implements StringLayout {
private JsonTemplateLayout(final Builder builder) {
this.charset = builder.charset;
this.contentType = "application/json; charset=" + charset;
- this.eventDelimiter = builder.eventDelimiter;
+ final String eventDelimiterSuffix = builder.isNullEventDelimiterEnabled() ? "\0" : "";
+ this.eventDelimiter = builder.eventDelimiter + eventDelimiterSuffix;
final Configuration configuration = builder.configuration;
final StrSubstitutor substitutor = configuration.getStrSubstitutor();
final JsonWriter jsonWriter = JsonWriter
@@ -215,11 +216,7 @@ public class JsonTemplateLayout implements StringLayout {
final StringBuilder stringBuilder = jsonWriter.getStringBuilder();
try {
eventResolver.resolve(event, jsonWriter);
- if (eventDelimiter != null && eventDelimiter.equalsIgnoreCase("null")) {
- stringBuilder.append('\0');
- } else {
- stringBuilder.append(eventDelimiter);
- }
+ stringBuilder.append(eventDelimiter);
return stringBuilder.toString();
} finally {
contextRecycler.release(context);
@@ -340,6 +337,10 @@ public class JsonTemplateLayout implements StringLayout {
private String eventDelimiter = JsonTemplateLayoutDefaults.getEventDelimiter();
@PluginBuilderAttribute
+ private boolean nullEventDelimiterEnabled =
+ JsonTemplateLayoutDefaults.isNullEventDelimiterEnabled();
+
+ @PluginBuilderAttribute
private int maxStringLength = JsonTemplateLayoutDefaults.getMaxStringLength();
@PluginBuilderAttribute
@@ -447,6 +448,16 @@ public class JsonTemplateLayout implements StringLayout {
return this;
}
+ public boolean isNullEventDelimiterEnabled() {
+ return nullEventDelimiterEnabled;
+ }
+
+ public Builder setNullEventDelimiterEnabled(
+ final boolean nullEventDelimiterEnabled) {
+ this.nullEventDelimiterEnabled = nullEventDelimiterEnabled;
+ return this;
+ }
+
public int getMaxStringLength() {
return maxStringLength;
}
diff --git a/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutDefaults.java b/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutDefaults.java
index adfe760..7c28b9f 100644
--- a/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutDefaults.java
+++ b/log4j-layout-json-template/src/main/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutDefaults.java
@@ -79,6 +79,11 @@ public enum JsonTemplateLayoutDefaults {;
"log4j.layout.jsonTemplate.eventDelimiter",
System.lineSeparator());
+ private static final boolean NULL_EVENT_DELIMITER_ENABLED =
+ PROPERTIES.getBooleanProperty(
+ "log4j.layout.jsonTemplate.nullEventDelimiterEnabled",
+ false);
+
private static final int MAX_STRING_LENGTH = readMaxStringLength();
private static final String TRUNCATED_STRING_SUFFIX =
@@ -189,6 +194,10 @@ public enum JsonTemplateLayoutDefaults {;
return EVENT_DELIMITER;
}
+ public static boolean isNullEventDelimiterEnabled() {
+ return NULL_EVENT_DELIMITER_ENABLED;
+ }
+
public static int getMaxStringLength() {
return MAX_STRING_LENGTH;
}
diff --git a/log4j-layout-json-template/src/test/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutNullEventDelimiterTest.java b/log4j-layout-json-template/src/test/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutNullEventDelimiterTest.java
new file mode 100644
index 0000000..2487b65
--- /dev/null
+++ b/log4j-layout-json-template/src/test/java/org/apache/logging/log4j/layout/json/template/JsonTemplateLayoutNullEventDelimiterTest.java
@@ -0,0 +1,127 @@
+package org.apache.logging.log4j.layout.json.template;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.assertj.core.api.Assertions;
+import org.awaitility.Awaitility;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.time.Duration;
+
+public class JsonTemplateLayoutNullEventDelimiterTest {
+
+ // Set the configuration.
+ static {
+ System.setProperty(
+ "log4j.configurationFile",
+ "nullEventDelimitedJsonTemplateLayoutLogging.xml");
+ }
+
+ // Note that this port is hardcoded in the configuration file too!
+ private static final int PORT = 50514;
+
+ @Test
+ public void test() throws Exception {
+
+ // Set the expected bytes.
+ final byte[] expectedBytes = {
+ '"', 'f', 'o', 'o', '"', '\0',
+ '"', 'b', 'a', 'r', '"', '\0'
+ };
+
+ // Start the TCP server.
+ try (final TcpServer server = new TcpServer(PORT)) {
+
+ // Produce log events.
+ final Logger logger = LogManager.getLogger(JsonTemplateLayoutNullEventDelimiterTest.class);
+ logger.log(Level.INFO, "foo");
+ logger.log(Level.INFO, "bar");
+
+ // Wait for the log events.
+ Awaitility
+ .await()
+ .atMost(Duration.ofSeconds(10))
+ .pollDelay(Duration.ofSeconds(2))
+ .until(() -> server.getTotalReadByteCount() >= expectedBytes.length);
+
+ // Verify the received log events.
+ final byte[] actualBytes = server.getReceivedBytes();
+ Assertions.assertThat(actualBytes).startsWith(expectedBytes);
+
+ }
+
+ }
+
+ private static final class TcpServer extends Thread implements AutoCloseable {
+
+ private final ServerSocket serverSocket;
+
+ private final ByteArrayOutputStream outputStream;
+
+ private volatile int totalReadByteCount = 0;
+
+ private volatile boolean closed = false;
+
+ private TcpServer(final int port) throws IOException {
+ this.serverSocket = new ServerSocket(port);
+ this.outputStream = new ByteArrayOutputStream();
+ serverSocket.setReuseAddress(true);
+ serverSocket.setSoTimeout(5_000);
+ setDaemon(true);
+ start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ try (final Socket socket = serverSocket.accept()) {
+ final InputStream inputStream = socket.getInputStream();
+ final byte[] buffer = new byte[1024];
+ // noinspection InfiniteLoopStatement
+ while (true) {
+ final int readByteCount = inputStream.read(buffer);
+ if (readByteCount > 0) {
+ synchronized (this) {
+ totalReadByteCount += readByteCount;
+ outputStream.write(buffer, 0, readByteCount);
+ }
+ }
+ }
+ }
+ } catch (final EOFException ignored) {
+ // Socket is closed.
+ } catch (final Exception error) {
+ if (!closed) {
+ throw new RuntimeException(error);
+ }
+ }
+ }
+
+ public synchronized byte[] getReceivedBytes() {
+ return outputStream.toByteArray();
+ }
+
+ public synchronized int getTotalReadByteCount() {
+ return totalReadByteCount;
+ }
+
+ @Override
+ public synchronized void close() throws InterruptedException {
+ if (closed) {
+ throw new IllegalStateException("shutdown has already been invoked");
+ }
+ closed = true;
+ interrupt();
+ join(3_000L);
+ }
+
+ }
+
+}
diff --git a/log4j-layout-json-template/src/test/resources/gcFreeJsonTemplateLayoutLogging.xml b/log4j-layout-json-template/src/test/resources/gcFreeJsonTemplateLayoutLogging.xml
index 0362308..245ff06 100644
--- a/log4j-layout-json-template/src/test/resources/gcFreeJsonTemplateLayoutLogging.xml
+++ b/log4j-layout-json-template/src/test/resources/gcFreeJsonTemplateLayoutLogging.xml
@@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
<Configuration status="OFF">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
diff --git a/log4j-layout-json-template/src/test/resources/nullEventDelimitedJsonTemplateLayoutLogging.xml b/log4j-layout-json-template/src/test/resources/nullEventDelimitedJsonTemplateLayoutLogging.xml
new file mode 100644
index 0000000..39d87a9
--- /dev/null
+++ b/log4j-layout-json-template/src/test/resources/nullEventDelimitedJsonTemplateLayoutLogging.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="OFF">
+ <Appenders>
+ <Socket name="Socket"
+ host="localhost"
+ port="50514"
+ protocol="TCP"
+ ignoreExceptions="false"
+ reconnectionDelay="100"
+ immediateFlush="true">
+ <JsonTemplateLayout eventTemplate='{"$resolver": "message"}'
+ eventDelimiter=""
+ nullEventDelimiterEnabled="true"
+ charset="US-ASCII"/>
+ </Socket>
+ </Appenders>
+ <Loggers>
+ <Root level="TRACE">
+ <AppenderRef ref="Socket"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
index 25c5ac8..a2afa70 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
@@ -106,7 +106,7 @@
port="12222"
protocol="tcp"
bufferedIo="true">
- <JsonTemplateLayout eventTemplateUri="classpath:EnhancedGelf.json" eventDelimiter="null">
+ <JsonTemplateLayout eventTemplateUri="classpath:EnhancedGelf.json" nullEventDelimiterEnabled="true">
<EventTemplateAdditionalFields>
<EventTemplateAdditionalField key="containerId" value="\${docker:containerId:-}"/>
<EventTemplateAdditionalField key="application" value="\${lower:${spring:spring.application.name:-spring}}"/>
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc b/src/site/asciidoc/manual/json-template-layout.adoc
index ff2904d..92ec635 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc
+++ b/src/site/asciidoc/manual/json-template-layout.adoc
@@ -207,6 +207,12 @@ appender.console.json.eventTemplateUri = classpath:LogstashJsonEventLayoutV1.jso
`System.lineSeparator()` set by `log4j.layout.jsonTemplate.eventDelimiter`
property)
+| nullEventDelimiterEnabled
+| boolean
+| append `\0` (`null`) character to the end of every emitted `eventDelimiter`
+ (defaults to `false` set by
+ `log4j.layout.jsonTemplate.nullEventDelimiterEnabled` property)
+
| maxStringLength
| int
| truncate string values longer than the specified limit (defaults to 16384 set
diff --git a/src/site/markdown/manual/cloud.md b/src/site/markdown/manual/cloud.md
index e4ad5c1..84fb63f 100644
--- a/src/site/markdown/manual/cloud.md
+++ b/src/site/markdown/manual/cloud.md
@@ -220,7 +220,7 @@ The logging configuration to use this template would be
port="12222"
protocol="tcp"
bufferedIo="true">
- <JsonTemplateLayout eventTemplateUri="classpath:EnhancedGelf.json" eventDelimiter="null">
+ <JsonTemplateLayout eventTemplateUri="classpath:EnhancedGelf.json" nullEventDelimiterEnabled="true">
<EventTemplateAdditionalFields>
<EventTemplateAdditionalField key="containerId" value="${docker:containerId:-}"/>
<EventTemplateAdditionalField key="application" value="${lower:${spring:spring.application.name:-spring}}"/>