Skip to content

feature request: objectMessageAsJsonObject #187

Open
@hdevalke

Description

@hdevalke

Log4j2 ObjectMessages are automatically converted to json objects.
This makes the log statements fail, if the object cannot be converted to json or it generates invalid json.

I would propose a objectMessageAsJsonObject config.
Putting it to false would just put the objects toString() result into the message field, as described in the documentation of log4j2.

e.g.

public class EcsLogTest {

    static class A {
        String getA() {
            Objects.requireNonNull(null);
            return null;
        }
    }

    @Test
    void test() {
        LogManager.getLogger().info(new A());
    }
}

produces:

{"@timestamp":"2022-05-16T12:06:08.284Z", "log.level": "INFO",   , "ecs.version": "1.2.0","process.thread.name":"main","log.logger":"EcsLogTest"}

This patch would probably enough to implement this feature:

diff --git a/log4j2-ecs-layout/src/main/java/co/elastic/logging/log4j2/EcsLayout.java b/log4j2-ecs-layout/src/main/java/co/elastic/logging/log4j2/EcsLayout.java
index 1a99742..41937c7 100644
--- a/log4j2-ecs-layout/src/main/java/co/elastic/logging/log4j2/EcsLayout.java
+++ b/log4j2-ecs-layout/src/main/java/co/elastic/logging/log4j2/EcsLayout.java
@@ -79,9 +79,10 @@ public class EcsLayout extends AbstractStringLayout {
     private final boolean includeOrigin;
     private final PatternFormatter[] exceptionPatternFormatter;
     private final ConcurrentMap<Class<? extends MultiformatMessage>, Boolean> supportsJson = new ConcurrentHashMap<Class<? extends MultiformatMessage>, Boolean>();
+    private final boolean objectMessageAsJsonObject;
 
     private EcsLayout(Configuration config, String serviceName, String serviceVersion, String serviceEnvironment, String serviceNodeName, String eventDataset, boolean includeMarkers,
-                      KeyValuePair[] additionalFields, boolean includeOrigin, String exceptionPattern, boolean stackTraceAsArray) {
+                      KeyValuePair[] additionalFields, boolean includeOrigin, String exceptionPattern, boolean stackTraceAsArray, boolean objectMessageAsJsonObject) {
         super(config, UTF_8, null, null);
         this.serviceName = serviceName;
         this.serviceVersion = serviceVersion;
@@ -92,6 +93,7 @@ public class EcsLayout extends AbstractStringLayout {
         this.includeOrigin = includeOrigin;
         this.stackTraceAsArray = stackTraceAsArray;
         this.additionalFields = additionalFields;
+        this.objectMessageAsJsonObject = objectMessageAsJsonObject;
         fieldValuePatternFormatter = new PatternFormatter[additionalFields.length][];
         for (int i = 0; i < additionalFields.length; i++) {
             KeyValuePair additionalField = additionalFields[i];
@@ -253,7 +255,7 @@ public class EcsLayout extends AbstractStringLayout {
             } else {
                 serializeSimpleMessage(builder, gcFree, message, thrown);
             }
-        } else if (JACKSON_SERIALIZER != null && message instanceof ObjectMessage) {
+        } else if (JACKSON_SERIALIZER != null && message instanceof ObjectMessage && objectMessageAsJsonObject) {
             final StringBuilder jsonBuffer = EcsJsonSerializer.getMessageStringBuilder();
             JACKSON_SERIALIZER.formatTo(jsonBuffer, (ObjectMessage) message);
             addJson(builder, jsonBuffer);
@@ -377,6 +379,8 @@ public class EcsLayout extends AbstractStringLayout {
         private KeyValuePair[] additionalFields = new KeyValuePair[]{};
         @PluginBuilderAttribute("includeOrigin")
         private boolean includeOrigin = false;
+        @PluginBuilderAttribute("objectMessageAsJsonObject")
+        private boolean objectMessageAsJsonObject = true;
 
         Builder() {
         }
@@ -428,6 +432,10 @@ public class EcsLayout extends AbstractStringLayout {
             return exceptionPattern;
         }
 
+        public boolean isObjectMessageAsJsonObject() {
+            return objectMessageAsJsonObject;
+        }
+
         /**
          * Additional fields to set on each log event.
          *
@@ -483,11 +491,16 @@ public class EcsLayout extends AbstractStringLayout {
             return this;
         }
 
+        public EcsLayout.Builder setObjectMessageAsJsonObject(boolean objectMessageAsJsonObject) {
+            this.objectMessageAsJsonObject = objectMessageAsJsonObject;
+            return this;
+        }
+
         @Override
         public EcsLayout build() {
             return new EcsLayout(getConfiguration(), serviceName, serviceVersion, serviceEnvironment, serviceNodeName,
                     EcsJsonSerializer.computeEventDataset(eventDataset, serviceName),
-                    includeMarkers, additionalFields, includeOrigin, exceptionPattern, stackTraceAsArray);
+                    includeMarkers, additionalFields, includeOrigin, exceptionPattern, stackTraceAsArray, objectMessageAsJsonObject);
         }
     }
 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-javacommunityIssues and PRs created by the communitytriageIssues and PRs that need to be triaged

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions