apache / apache/logging-log4j2

DefaultLogBuilder ignores a throwable inferred by created Message

Open
#3,473 8 comments 0 reactions 0 assignees View on GitHub
api bug waiting-for-maintainer
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.