Affects: all
Spring has an exception called NestedRuntimeException
. We use log4j2 with a JSON logger. That exception (and its many children) cannot be logged, they blow up the logger because getMostSpecificCause
returns a self-reference if there is no cause on the exception.
I guess this falls somewhere between a bug report and a feature request. I think that many people use JSON logging and log exceptions, therefore it would be nice if all exceptions could be serialized safely with Jackson.
I just need an annotation on that method to tell Jackson to ignore it.
Thanks!
Comment From: sdeleuze
Hi, and sorry for the delay. Could you please provide a reproducer (as an archive or a Git repository) to allow us to see the behavior you are describing?
Comment From: adamzr
@sdeleuze To reproduce make an exception that extends NestedRuntimeException
(or use one of the many existing ones). Throw that exception and log it out.
Use log4j2 by adding the following to your pom.xml
file (if you use Maven).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Put a file in src/main/resources
called log4j2.xml
(or something similar):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<CustomLevels>
<!-- Int level should be between DEBUG (500) and TRACE (600) -->
<CustomLevel name="CLIENT_DATA" intLevel="550"/>
</CustomLevels>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT" follow="true">
<JsonLayout eventEol="true" compact="true"
properties="true" includeTimeMillis="true"
objectMessageAsJsonObject="true">
<KeyValuePair key="java-version"
value="${java:version}" />
<KeyValuePair key="java-runtime"
value="${java:runtime}" />
<KeyValuePair key="java-vm"
value="${java:vm}" />
<KeyValuePair key="java-os"
value="${java:os}" />
<KeyValuePair key="java-locale"
value="${java:locale}" />
<KeyValuePair key="java-hw"
value="${java:hw}" />
</JsonLayout>
</Console>
</Appenders>
<Loggers>
<asyncLogger
name="org.springframework"
level="debug" />
<asyncRoot level="debug">
<AppenderRef ref="STDOUT" />
</asyncRoot>
</Loggers>
</Configuration>
I do not believe that this is unique to Log4j2.
I think you need to:
- Throw an exception that extends
NestedRuntimeException
- Log it out
- Configure your logger to log only JSON
NestedRuntimeException
has a circular reference. It cannot easily be converted to JSON and it therefore crashes the logger.
Comment From: sbrannen
@adamzr, thanks for providing the additional information.
Please note that NestedRuntimeException
is not designed for recursive introspection of its getter methods. In addition, getMostSpecificCause()
is documented to return a reference to the "present exception if there is no root cause".
Thus, NestedRuntimeException
works as designed.
I just need an annotation on that method to tell Jackson to ignore it.
We unfortunately cannot add a Jackson-specific annotation to NestedRuntimeException
.
To address the recursion you are encountering, you will either need to ask the maintainers of JsonLayout
to introduce support for excluding specific properties or implement your own extension of JsonLayout
that allows you to do that.
Examples of the latter can be found on the Internet -- for example, How to customize or remove default attributes in Log4j2 - JSON Layout.
I believe JsonTemplateLayout
may also be a viable alternative for you.
In light of that, I am closing this issue.
Comment From: adamzr
@sbrannen I think you should keep this ticket open as a feature request rather than as a bug.
As you noted NestedRuntimeException is not designed for recursive introspection of its getter methods. I am asking to change that design.
Logging exceptions is one of the most common kind of objects to log.
Outputting logs in JSON is a best practice and one of the most common ways of emitting structured log messages. It is recommended by Loggly, Elastic, Loki, Splunk, and pretty much every other logging system.
So, while I agree that this issue can be worked around, I think it is a common issue that Spring should help people avoid.