apache / apache/logging-log4j2
DefaultLogBuilder ignores a throwable inferred by created Message
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 1.7k
- Avg merge
- 21h 30m
- Merged PRs (30d)
- 27
Description
## Description
When using `DefaultLogBuilder` log* methods, `throwable` information that might have been inferred by the created `Message` object is lost - and `DefaultLogBuilder` only passes the explicit `throwable` that was set via `LogBuilder.withThrowable(Throwable)`.
This is in contradiction to the regular use of `Logger` methods that accept message+args - which creates a `Message` using the configured factory, and then uses `Message.getThrowable()` to extract the throwable.
This was initially assumed as a bug in `log4j-transform-maven-plugin` (which converts regular `Logger` calls to `LogBuilder`):
https://github.com/apache/logging-log4j-transform/issues/169
but I realized that it might be a stretch for the plugin to infer this data at build-time to be able to pass it to `.withThrowable`.
## Suggested Fix
Change `DefaultLogBuilder`'s `logMessage(Message)` code
from `logger.logMessage(level, marker, fqcn, location, message, throwable);`
to `logger.logMessage(level, marker, fqcn, location, message, throwable != null ? throwable : message.getThrowable());`
## Configuration
**Version:** 2.24.3
**Operating system:** macOS Sonoma 14.7.2
**JDK:** eclipse-temurin 17.0.13
## Logs
Consider the following code:
```
Throwable throwable = new Exception("Oh oh");
String messageFormat = "Hello, {}!";
String arg = "Problem";
logger.error(messageFormat, arg, throwable);
logger.atError().log(messageFormat, arg, throwable);
```
results in the following output:
```
14:30:53.223 [main] ERROR net.kundas.Main - Hello, Problem!
java.lang.Exception: Oh oh
at net.kundas.Main.main(Main.java:11) [classes/:?]
14:30:53.233 [main] ERROR net.kundas.Main - Hello, Problem!
```
## Reproduction
I've tried recreating it in a unit test, but they seem to be using `org.apache.logging.log4j.test.TestLogger`, which does this inference in its `log` method:
```
final Throwable t;
if (throwable == null
&& params != null
&& params.length > 0
&& params[params.length - 1] instanceof Throwable) {
t = (Throwable) params[params.length - 1];
} else {
t = throwable;
}
if (t != null) {
sb.append(' ');
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
t.printStackTrace(new PrintStream(baos));
sb.append(baos);
}
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at DefaultLogBuilder's logMessage(Message) method and inspect how it passes the explicit throwable to logger.logMessage. Reproduce the logger.error and logger.atError().log examples, then verify that the builder preserves the throwable inferred by Message when no explicit throwable was set; note that TestLogger performs its own inference in its log method.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, observability
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100