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 2021/05/06 09:10:15 UTC

[logging-log4j2] branch master updated: LOG4J2-3087 Fix race in JsonTemplateLayout where a timestamp could end up unquoted (#489)

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 ee3201d  LOG4J2-3087 Fix race in JsonTemplateLayout where a timestamp could end up unquoted (#489)
ee3201d is described below

commit ee3201d9a582a325547a26d2706c0f6160c868e9
Author: Anton Klarén <an...@neotechnology.com>
AuthorDate: Thu May 6 10:58:35 2021 +0200

    LOG4J2-3087 Fix race in JsonTemplateLayout where a timestamp could end up unquoted (#489)
---
 .../template/json/resolver/TimestampResolver.java  | 10 +++-
 .../json/resolver/TimestampResolverTest.java       | 65 ++++++++++++++++++++++
 src/changes/changes.xml                            |  3 +
 3 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolver.java
index 402f713..c0dbce3 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolver.java
@@ -230,7 +230,6 @@ public final class TimestampResolver implements EventResolver {
             this.timestampFormat = timestampFormat;
             this.formattedTimestampBuilder = new StringBuilder();
             this.calendar = Calendar.getInstance(timeZone, locale);
-            timestampFormat.format(calendar, formattedTimestampBuilder);
         }
 
         private static FormatResolverContext fromConfig(
@@ -311,7 +310,7 @@ public final class TimestampResolver implements EventResolver {
 
             // Format timestamp if it doesn't match the last cached one.
             final long timestampMillis = logEvent.getTimeMillis();
-            if (formatResolverContext.calendar.getTimeInMillis() != timestampMillis) {
+            if (formatResolverContext.formattedTimestampBuilder.length() == 0 || formatResolverContext.calendar.getTimeInMillis() != timestampMillis) {
 
                 // Format the timestamp.
                 formatResolverContext.formattedTimestampBuilder.setLength(0);
@@ -505,4 +504,11 @@ public final class TimestampResolver implements EventResolver {
         internalResolver.resolve(logEvent, jsonWriter);
     }
 
+    /**
+     * Visible for tests
+     */
+    Calendar getCalendar() {
+        return ((FormatResolver) internalResolver).formatResolverContext.calendar;
+    }
+
 }
diff --git a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolverTest.java b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolverTest.java
new file mode 100644
index 0000000..522c62f
--- /dev/null
+++ b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TimestampResolverTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.layout.template.json.resolver;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TimestampResolverTest
+{
+    private static final TemplateResolverConfig TEMPLATE_RESOLVER_CONFIG = new TemplateResolverConfig(
+            Collections.singletonMap("pattern", Collections.singletonMap("format", "yyyy-MM-dd")));
+
+    /**
+     * Tests LOG4J2-3087 race when creating layout on the same instant as the log event would result in an unquoted date in the JSON
+     */
+    @Test
+    void test_timestamp_pattern_race() {
+        JsonWriter jsonWriter = JsonWriter.newBuilder()
+                .setMaxStringLength(32)
+                .setTruncatedStringSuffix("…")
+                .build();
+
+        final TimestampResolver resolver = new TimestampResolver(TEMPLATE_RESOLVER_CONFIG);
+
+        final LogEvent logEvent = createLogEvent(resolver.getCalendar().getTimeInMillis() );
+
+        resolver.resolve(logEvent, jsonWriter);
+
+        assertThat(jsonWriter.getStringBuilder().toString()).matches("\"\\d{4}-\\d{2}-\\d{2}\"");
+    }
+
+    private static LogEvent createLogEvent(final long timeMillis) {
+        return Log4jLogEvent
+                .newBuilder()
+                .setLoggerName("a.B")
+                .setLoggerFqcn("f.q.c.n")
+                .setLevel(Level.DEBUG)
+                .setMessage(new SimpleMessage("LogEvent message"))
+                .setTimeMillis(timeMillis)
+                .setNanoTime(timeMillis * 2)
+                .build();
+    }
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1f4f835..19f07fd 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -205,6 +205,9 @@
         Allow a PatternSelector to be specified on GelfLayout.
       </action>
       <!-- FIXES -->
+      <action issue="LOG4J2-3087" dev="vy" type="fix" due-to="Anton Klarén">
+        Fix race in JsonTemplateLayout where a timestamp could end up unquoted.
+      </action>
       <action issue="LOG4J2-3070" dev="vy" type="fix" due-to="Romain Manni-Bucau">
         Ensure EncodingPatternConverter#handlesThrowable is implemented.
       </action>