First, lets consider the two usages you highlighted

1. In theory it is possible to add properties to a Logger. In practice, we only 
allow this from the LoggerConfig. While the values of those properties can 
include Lookup references this isn’t going to help much since there is no way 
for the Lookup to reference any specific object instance. While the user could 
override Logger they would also have to override AsyncLogger for a complete 
solution, but even doing that isn’t going to help much since nothing in 
Logger/AbstractLogger creates a LogEvent so does not provide any place to add 
properties associated with the instance. Creating a context at the class level 
is certainly level but the only way to locate it is via a ThreadLocal. This 
introduces problems of having objects tied to classes and ClassLoaders and 
means Thread termination may hang if everything isn’t recycled correctly.  In 
short, the solution for this is complex.

2. The links you provide describe the problem of passing contexts to threads 
magnificently. Unfortunately, they solve it by requiring you NOT to use 
standard JDK tooling for managing threads. I am not prepared to be dependent on 
any specific framework other than the JDK. 

Specifics about your solutions:

1. Again, adding Property elements to a Logger doesn’t really help for the use 
cases requested. We support this now and if it was sufficient we wouldn’t have 
these requests.
2. As I noted, adding a wrapper around a Logger doesn’t accomplish anything, at 
least in terms of getting data into LogEvents.
3. As I stated, I am not prepared to provide a solution that is dependent on 
another framework. However that framework is welcome to integrate with us.

Other items of note:
SLF4J has recently introduced 
https://www.slf4j.org/apidocs-2.1.0-alpha0/org.slf4j/org/slf4j/MDCAmbit.html 
which to me looks like a horrible way to add a “scope-based” context as it 
relies on the user to perform cleanup.
Java 21 introduces ScopedValues - 
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ScopedValue.html.
 It does allow ScopedValues to be passed to child threads but I haven’t 
experimented with it enough yet to know how it really works.

In the meantime, I provided https://github.com/apache/logging-log4j2/pull/2385 
which I very loosely modeled after ScopedValues. ScopedContext allows you to do:

public class SomeClass {

        private static final Logger LOGGER = 
LogManager.getLogger(SomeClass.class);

        public void someMethod(String arg1, Request request) {
                ScopedContext.INITIAL_CONTEXT
                        .where(“param”, “arg1”)
                        .where(“loginId”, request.getLoginid())
                        .run(() -> {
                                LOGGER.info <http://logger.info/>(“This will 
include param and loginId in the LogEvent’s ThreadContext Map”);
                });
} 

Nesting of ScopedContext’s is allowed. They can be used in place of 
ScoedVallues but also allow them to included in the LogEvent. A ScopedContext 
can also be saved and passed to another thread. Because ScopedContexts are 
immutable there is no risk in them being shared across threads. It simply 
requires the ScopedContext’s run method be called on the child thread to 
register it and ensure it is cleaned up when no longer needed.

Ralph

> On Mar 18, 2024, at 2:39 AM, Piotr P. Karwasz <piotr.karw...@gmail.com> wrote:
> 
> Hi,
> 
> Given the ongoing context data propagation in three Github
> issues/PRs/discussions (cf. [1], [2] and [3]). I think we should move
> the debate to the mailing list, which guarantees the maximal reachout.
> 
> == Problem summary
> 
> We have two different problems regarding context data in log files:
> 
> 1. Raman and Mikko would like to bind context data to an object
> implementing the `Logger` interface or more generally to a service
> object (e.g. resource manager, DAO and variants),
> 2. Other users would like to bind context data to a processing
> pipeline, regardless of which threads it uses.
> 
> == Possible solutions
> 
> As far as I know there are currently the following approaches we can
> take for problem 1:
> 
> * we can add a list of `<Property>` elements in the configuration of a
> `<Logger>`, which will add the given keys to all loggers using that
> configuration. This is something we can do for very static data, e.g.
> we can add to each log statement the name of the library that issued
> it.
> * we can create a `Logger` wrapper "bound" to context data as Mikko
> does. This wrapper will take care of setting the `ThreadContext`
> before the logger call and restore it after it.
> 
> For problem 2, the traditional solution was provided by the
> inheritability of `ThreadLocal`s, but this approach only works if the
> current thread creates new ones, it does not work with thread pools.
> 
> Now there seems to be another emerging solution provided by the
> `context-propagation` [9] library and explained by Dariusz Jędrzejczyk
> in his blog series ([6], [7] and [8]), that allows "context-aware
> runnables" to propagate context data, when they jump threads.
> The library allows users to register `ThreadLocalAccessor`s that take
> the snapshot of a `ThreadLocal` containing context data before a jump
> and restore it on the new thread. It is used by at least Spring
> Reactor.
> 
> == My preferences
> 
> Personally I think that in the short term we should:
> 
> 1. deprecate `isThreadContextMapInheritable`, because it does not
> correspond any more to the current pattern of concurrent programming.
> It also provides a false sense of safety: a unit test using
> `isThreadContextMapInheritable` will probably succeed, since each test
> creates its own thread pool, but the context will be lost in
> production,
> 2. provide a direct access to the thread locals used by
> `ThreadContextMap`, so that we can submit a Log4j specific
> `ThreadLocalAccessor` to the `context-propagation` project,
> 
> Regarding problem 1, I don't know what the best approach would be.
> Maybe we can add `withContextData` to `LogBuilder` and create a
> `BoundLogger` interface with methods to create `LogBuilder` instance
> pre-filled with some context data.
> 
> Piotr
> 
> [1] https://github.com/apache/logging-log4j2/discussions/2214
> [2] https://github.com/apache/logging-log4j2/pull/2385
> [3] https://github.com/apache/logging-log4j-kotlin/issues/71
> [4] https://stackoverflow.com/q/76498742/11748454
> [5] 
> https://spring.io/blog/2023/03/28/context-propagation-with-project-reactor-1-the-basics
> [6] 
> https://spring.io/blog/2023/03/29/context-propagation-with-project-reactor-2-the-bumpy-road-of-spring-cloud
> [7] 
> https://spring.io/blog/2023/03/30/context-propagation-with-project-reactor-3-unified-bridging-between-reactive
> [8] https://github.com/micrometer-metrics/context-propagation

Reply via email to