Andy Lehane created LOG4J2-3152:
-----------------------------------

             Summary: JSONLayout - Add mechanism for registering additional 
modules (i.e. JodaModule)
                 Key: LOG4J2-3152
                 URL: https://issues.apache.org/jira/browse/LOG4J2-3152
             Project: Log4j 2
          Issue Type: Improvement
          Components: Layouts
    Affects Versions: 2.14.0
            Reporter: Andy Lehane


When I attempt to use a JsonLayout with the following configuration:

{{<JsonLayout compact="true" eventEol="true" properties="true" 
objectMessageAsJsonObject="true" />}}

 

and log an object with a Joda LocalDateTime property, I get the following 
exception:

 

{{2021-08-26 15:48:30,437 Log4j2-TF-67-AsyncLoggerConfig-6 ERROR 
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Joda date/time 
type `org.joda.time.LocalDateTime` not supported by default: add Module 
"com.fasterxml.jackson.datatype:jackson-datatype-joda" to enable handling 
(through reference chain: 
org.apache.logging.log4j.core.layout.AbstractJacksonLayout$LogEventWithAdditionalFields["logEvent"]->org.apache.logging.log4j.core.impl.Log4jLogEvent["message"]->com.mycompany.StartEvent["timeStamp"])2021-08-26
 15:48:30,437 Log4j2-TF-67-AsyncLoggerConfig-6 ERROR 
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Joda date/time 
type `org.joda.time.LocalDateTime` not supported by default: add Module 
"com.fasterxml.jackson.datatype:jackson-datatype-joda" to enable handling 
(through reference chain: 
org.apache.logging.log4j.core.layout.AbstractJacksonLayout$LogEventWithAdditionalFields["logEvent"]->org.apache.logging.log4j.core.impl.Log4jLogEvent["message"]->com.mycompany.StartEvent["timeStamp"])}}
{{     at 
com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)}}
{{     at 
com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)}}
{{     at 
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
 at 
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
 }}
{{     at 
com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3126) 
}}
{{     at 
com.fasterxml.jackson.core.base.GeneratorBase.writeObject(GeneratorBase.java:388)
 }}
{{     at 
org.apache.logging.log4j.core.jackson.ObjectMessageSerializer.serialize(ObjectMessageSerializer.java:44)
 }}
{{     at 
org.apache.logging.log4j.core.jackson.ObjectMessageSerializer.serialize(ObjectMessageSerializer.java:33)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter.serializeAsField(SimpleBeanPropertyFilter.java:208)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFieldsFiltered(BeanSerializerBase.java:822)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanSerializer.serialize(UnwrappingBeanSerializer.java:136)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter.serializeAsField(UnwrappingBeanPropertyWriter.java:127)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
 }}
{{     at 
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
 }}
{{     at 
com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1514)
 }}
{{     at 
com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1215)
 }}
{{     at 
com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1059) 
}}
{{     at 
org.apache.logging.log4j.core.layout.AbstractJacksonLayout.toSerializable(AbstractJacksonLayout.java:344)
 }}
{{     at 
org.apache.logging.log4j.core.layout.JsonLayout.toSerializable(JsonLayout.java:291)
 }}
{{     at 
org.apache.logging.log4j.core.layout.AbstractJacksonLayout.toSerializable(AbstractJacksonLayout.java:292)
 }}
{{     at 
org.apache.logging.log4j.core.layout.JsonLayout.toSerializable(JsonLayout.java:68)
 }}
{{     at 
org.apache.logging.log4j.core.layout.AbstractJacksonLayout.toSerializable(AbstractJacksonLayout.java:52)
 }}
{{     at 
org.apache.logging.log4j.core.layout.AbstractStringLayout.toByteArray(AbstractStringLayout.java:308)
 }}
{{     at 
org.apache.logging.log4j.core.layout.AbstractLayout.encode(AbstractLayout.java:210)
 }}
{{     at 
org.apache.logging.log4j.core.layout.AbstractLayout.encode(AbstractLayout.java:37)
 }}
{{     at 
org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:197)
 }}
{{     at 
org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
 }}
{{     at 
org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
 }}
{{     at 
org.apache.logging.log4j.core.appender.RollingFileAppender.append(RollingFileAppender.java:312)
 }}
{{     at 
org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
 }}
{{     at 
org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
 }}
{{     at 
org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
 }}
{{     at 
org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
 }}
{{     at 
org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:543)
 }}
{{     at 
org.apache.logging.log4j.core.async.AsyncLoggerConfig.callAppenders(AsyncLoggerConfig.java:127)
 }}
{{     at 
org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:502)
 }}
{{     at 
org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485) }}
{{     at 
org.apache.logging.log4j.core.async.AsyncLoggerConfig.log(AsyncLoggerConfig.java:121)
 }}
{{     at 
org.apache.logging.log4j.core.async.AsyncLoggerConfig.logToAsyncLoggerConfigsOnCurrentThread(AsyncLoggerConfig.java:169)
 }}
{{     at 
org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(AsyncLoggerConfigDisruptor.java:112)
 }}
{{     at 
org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(AsyncLoggerConfigDisruptor.java:98)
 }}
{{     at 
com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:169)
 }}
{{     at 
com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:126) }}
{{     at java.lang.Thread.run(Thread.java:748)}}
{{  }}

Looking through both the log4j2 documentation and code, there is no mechanism 
for being able to add further modules to the Jackson ObjectMapper object that 
the JsonAppender uses, i.e:

{{public Log4jJsonObjectMapper(final boolean encodeThreadContextAsList, final 
boolean includeStacktrace, final boolean stacktraceAsString, final boolean 
objectMessageAsJsonObject) {}}

{{{{    this.registerModule(new 
Log4jJsonModule(encodeThreadContextAsList,}}}}{{{{    includeStacktrace, 
stacktraceAsString, objectMessageAsJsonObject));}}}}

{{    *{{this.registerModule(new JodaModule());}}*}}

{{{{    this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);}}}}
{{}}}

 

Perhaps the config could look something like:

 

{{<JsonLayout compact="true" eventEol="true" properties="true" 
objectMessageAsJsonObject="true">}}

{{  <module class="com.fasterxml.jackson.datatype.joda.JodaModule">}}

{{</JsonLayout>}}

 

I've been able to work around this by creating my own versions of the following 
classes:

 - JSONLayout,

 - JacksonFactory,

 - Log4jJsonObjectMapper

but this is not ideal as it's brittle to internal log4j changes.

 



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to