From 8685c62a6dab659f9aa4b5cc414e7f0fb640a99f Mon Sep 17 00:00:00 2001 From: Antoine DESSAIGNE Date: Thu, 16 Nov 2023 12:16:23 +0100 Subject: [PATCH] Use a DateTimeFormatter in AlfJsonLayout instead of SimpleDateFormat to be thread-safe. --- .../alf/log4j2/layout/AlfJsonLayout.java | 23 +++++------ .../alf/log4j2/layout/AlfJsonLayoutTest.java | 39 +++++++++++++++++++ .../axway/alf/log4j2/layout/package-info.java | 4 ++ 3 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/AlfJsonLayoutTest.java create mode 100644 alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/package-info.java diff --git a/alf-log4j2/src/main/java/io/axway/alf/log4j2/layout/AlfJsonLayout.java b/alf-log4j2/src/main/java/io/axway/alf/log4j2/layout/AlfJsonLayout.java index f14e307..c2e352a 100644 --- a/alf-log4j2/src/main/java/io/axway/alf/log4j2/layout/AlfJsonLayout.java +++ b/alf-log4j2/src/main/java/io/axway/alf/log4j2/layout/AlfJsonLayout.java @@ -2,9 +2,9 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import javax.annotation.*; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -49,8 +49,8 @@ public Builder() { @Override public AlfJsonLayout build() { - DateFormat dateFormat = m_dateFormat == null ? null : new SimpleDateFormat(m_dateFormat); - return new AlfJsonLayout(getConfiguration(), getCharset(), getHeaderSerializer(), getFooterSerializer(), dateFormat, m_threadPrinting, + DateTimeFormatter dateTimeFormatter = m_dateFormat == null ? null : DateTimeFormatter.ofPattern(m_dateFormat).withZone(ZoneId.systemDefault()); + return new AlfJsonLayout(getConfiguration(), getCharset(), getHeaderSerializer(), getFooterSerializer(), dateTimeFormatter, m_threadPrinting, m_levelPrinting, m_loggerPrinting, m_contextPrinting, m_messageKey); } @@ -91,17 +91,18 @@ public static > B newBuilder() { } @Nullable - private final DateFormat m_dateFormat; + private final DateTimeFormatter m_dateTimeFormatter; private final boolean m_threadPrinting; private final boolean m_levelPrinting; private final boolean m_loggerPrinting; private final boolean m_contextPrinting; private final String m_messageKey; - public AlfJsonLayout(Configuration config, Charset aCharset, Serializer headerSerializer, Serializer footerSerializer, @Nullable DateFormat dateFormat, - boolean threadPrinting, boolean levelPrinting, boolean loggerPrinting, boolean contextPrinting, String messageKey) { + public AlfJsonLayout(Configuration config, Charset aCharset, Serializer headerSerializer, Serializer footerSerializer, + @Nullable DateTimeFormatter dateTimeFormatter, boolean threadPrinting, boolean levelPrinting, boolean loggerPrinting, + boolean contextPrinting, String messageKey) { super(config, aCharset, headerSerializer, footerSerializer); - m_dateFormat = dateFormat; + m_dateTimeFormatter = dateTimeFormatter; m_threadPrinting = threadPrinting; m_levelPrinting = levelPrinting; m_loggerPrinting = loggerPrinting; @@ -114,8 +115,8 @@ public String toSerializable(LogEvent event) { StringBuilder sb = new StringBuilder(128); JsonWriter jsonWriter = new JsonWriter(sb); - if (m_dateFormat != null) { - jsonWriter.add("time", m_dateFormat.format(new Date(event.getTimeMillis()))); + if (m_dateTimeFormatter != null) { + jsonWriter.add("time", m_dateTimeFormatter.format(Instant.ofEpochMilli(event.getTimeMillis()))); } else { jsonWriter.add("time", event.getTimeMillis()); } diff --git a/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/AlfJsonLayoutTest.java b/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/AlfJsonLayoutTest.java new file mode 100644 index 0000000..64df3f5 --- /dev/null +++ b/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/AlfJsonLayoutTest.java @@ -0,0 +1,39 @@ +package io.axway.alf.log4j2.layout; + +import java.text.SimpleDateFormat; +import java.util.*; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.time.MutableInstant; +import org.apache.logging.log4j.message.SimpleMessage; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AlfJsonLayoutTest { + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss,SSS"; + + @Test + public void shouldFormatTime() { + long now = System.currentTimeMillis(); + + // Given a AlfJsonLayout + AlfJsonLayout layout = AlfJsonLayout.newBuilder() + .withDateFormat(DATE_FORMAT) + .withThreadPrinting(false) + .withLevelPrinting(false) + .withLoggerPrinting(false) + .build(); + + // And a log event + MutableInstant mutableInstant = new MutableInstant(); + mutableInstant.initFromEpochMilli(now, 0); + Log4jLogEvent event = Log4jLogEvent.newBuilder().setMessage(new SimpleMessage("Just testing")).setInstant(mutableInstant).build(); + + // When formatting the event + String output = layout.toSerializable(event); + + // Then it should be the expected one (using SimpleDateFormat to ensure compatibility) + String expected = "{\"time\": \"" + new SimpleDateFormat(DATE_FORMAT).format(new Date(now)) + "\", \"message\": \"Just testing\"}"; + assertThat(output).isEqualToIgnoringNewLines(expected); + } +} diff --git a/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/package-info.java b/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/package-info.java new file mode 100644 index 0000000..c342580 --- /dev/null +++ b/alf-log4j2/src/test/java/io/axway/alf/log4j2/layout/package-info.java @@ -0,0 +1,4 @@ +@ParametersAreNonnullByDefault +package io.axway.alf.log4j2.layout; + +import javax.annotation.*;