From a03b747f27faece46b08b47097ac22c26fd841f5 Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Tue, 9 Nov 2021 16:08:54 +0000 Subject: [PATCH 1/2] Use the Event Time information from the log event If no header/body serializer provides time information, and the log event contains a time value, then set that into the JSON header. This allows accurate logging of time information, rather than just using the batch arrival time as the timestamp. --- .../serialization/HecJsonSerializer.java | 4 + src/test/java/HecJsonSerializerTest.java | 82 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/test/java/HecJsonSerializerTest.java diff --git a/src/main/java/com/splunk/logging/serialization/HecJsonSerializer.java b/src/main/java/com/splunk/logging/serialization/HecJsonSerializer.java index 64ba99d8..cdc4b06e 100644 --- a/src/main/java/com/splunk/logging/serialization/HecJsonSerializer.java +++ b/src/main/java/com/splunk/logging/serialization/HecJsonSerializer.java @@ -63,6 +63,10 @@ public String serialize(HttpEventCollectorEventInfo info) { } else { event.put("event", info); } + if (!event.containsKey("time") && info.getTime() > 0) { + // We haven't figured any other time - so use the time from the event. + event.put("time", String.format(Locale.US, "%.3f", info.getTime())); + } return gson.toJson(event); } diff --git a/src/test/java/HecJsonSerializerTest.java b/src/test/java/HecJsonSerializerTest.java new file mode 100644 index 00000000..d756dc08 --- /dev/null +++ b/src/test/java/HecJsonSerializerTest.java @@ -0,0 +1,82 @@ +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.splunk.logging.EventBodySerializer; +import com.splunk.logging.HttpEventCollectorEventInfo; +import com.splunk.logging.serialization.HecJsonSerializer; +import org.junit.Assert; +import org.junit.Test; + +@SuppressWarnings("unchecked") +public class HecJsonSerializerTest { + private final Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .create(); + + private final HttpEventCollectorEventInfo event = new HttpEventCollectorEventInfo(1636473405870L, "INFO", "Test Message", "MyLogger", "Thread", Collections.emptyMap(), null, null); + + @Test + public void itShouldPopulateTheTime() { + HecJsonSerializer serializer = new HecJsonSerializer(Collections.emptyMap()); + String result = serializer.serialize(event); + Map map = (Map) gson.fromJson(result, Map.class); + Assert.assertEquals("1636473405.870", map.get("time")); + } + + @Test + @SuppressWarnings("unchecked") + public void itShouldNotPopulateTheTimeIfAlreadyPopulated() { + HecJsonSerializer serializer = new HecJsonSerializer(Collections.singletonMap("time", "1234.567")); + String result = serializer.serialize(event); + Map map = (Map) gson.fromJson(result, Map.class); + Assert.assertEquals("1234.567", map.get("time")); + } + + @Test + @SuppressWarnings("unchecked") + public void itShouldNotPopulateTheTimeIfHeaderPopulates() { + HecJsonSerializer serializer = new HecJsonSerializer(Collections.emptyMap()); + serializer.setEventHeaderSerializer((eventInfo, metadata) -> new HashMap<>(Collections.singletonMap("time", "12345.678"))); + String result = serializer.serialize(event); + Map map = (Map) gson.fromJson(result, Map.class); + Assert.assertEquals("12345.678", map.get("time")); + } + + @Test + @SuppressWarnings("unchecked") + public void itShouldNotPopulateTheTimeIfBodyPopulates() { + HecJsonSerializer serializer = new HecJsonSerializer(Collections.emptyMap()); + serializer.setEventBodySerializer(new EventBodySerializer() { + @Override + public String serializeEventBody(final HttpEventCollectorEventInfo eventInfo, final Object formattedMessage) { + return "XXX"; + } + + @Override + public double getEventTime(final HttpEventCollectorEventInfo eventInfo) { + return 1.0d; + } + }); + String result = serializer.serialize(event); + Map map = (Map) gson.fromJson(result, Map.class); + Assert.assertEquals("1.000", map.get("time")); + } + + @Test + @SuppressWarnings("unchecked") + public void itShouldPopulateTheTimeIfBodyOverrideDoesntSetTime() { + HecJsonSerializer serializer = new HecJsonSerializer(Collections.emptyMap()); + serializer.setEventBodySerializer(new EventBodySerializer() { + @Override + public String serializeEventBody(final HttpEventCollectorEventInfo eventInfo, final Object formattedMessage) { + return "XXX"; + } + }); + String result = serializer.serialize(event); + Map map = (Map) gson.fromJson(result, Map.class); + Assert.assertEquals("1636473405.870", map.get("time")); + } +} From 53bba9c35ec0f0a60f51ae2bd1e57bdb1da0eb6f Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Tue, 9 Nov 2021 16:22:23 +0000 Subject: [PATCH 2/2] Simplify test --- src/test/java/HecJsonSerializerTest.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/java/HecJsonSerializerTest.java b/src/test/java/HecJsonSerializerTest.java index d756dc08..fee50429 100644 --- a/src/test/java/HecJsonSerializerTest.java +++ b/src/test/java/HecJsonSerializerTest.java @@ -69,12 +69,7 @@ public double getEventTime(final HttpEventCollectorEventInfo eventInfo) { @SuppressWarnings("unchecked") public void itShouldPopulateTheTimeIfBodyOverrideDoesntSetTime() { HecJsonSerializer serializer = new HecJsonSerializer(Collections.emptyMap()); - serializer.setEventBodySerializer(new EventBodySerializer() { - @Override - public String serializeEventBody(final HttpEventCollectorEventInfo eventInfo, final Object formattedMessage) { - return "XXX"; - } - }); + serializer.setEventBodySerializer((eventInfo, formattedMessage) -> "XXX"); String result = serializer.serialize(event); Map map = (Map) gson.fromJson(result, Map.class); Assert.assertEquals("1636473405.870", map.get("time"));