-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve logging context integration #71
Comments
I think this is related to apache/logging-log4j2#2213. |
@vy It seems so, but I'm unsatisfied by the answers in the discussion. Let me see if I can illustrate my use case with a generic example. Assume we have this setup:
Inside However, inside If The thread or coroutine attached context works well for |
@rocketraman, AFAIC, the problem is the lack of a dynamically scoped variable (you might be familiar with this concept if you have ever used a Lisp dialect), and hence, we use the one closest to that: a thread-local one. Imagine |
@vy Yes, I think so. Or I am :-) If you look back at my example, logging in |
I think the ideal solution for this would look something like this, and could leverage the solution we come up with for #36:
|
Please see #2385 as this should do what you want - for Java. I am not sure how to incorporate this into Kotlin. You can now do:
or you can do
In addition, nesting is supported as are arbitrary objects. To include the key/value pairs of the parent you would do:
If the object implements the Renderable interface then it can control the formatting of the object. Otherwise, toString() is used. |
There are already two sources for context data:
<Logger name="resource">
<Property name="resourceId" value="abcd"/>
</Logger> Is this what you are missing? |
@rgoers I think you missed the class-scoped (not thread-scoped) context in my example. @ppkarwasz Ah interesting -- if I could bind |
@rocketraman I guess I am not grasping at all what you want. With my PR you can now do:
In this example the value of "context" when bar is logged would be "thread" and would be "resource" when foo is logged. so everything inside the run method, and only inside the run method contains the data. In the example above the value of context will vary depending on which ScopedContext you are executing in. Isn't this what you wanted? Note, that while the PR uses a ThreadLocal it has to do that to make it thread-safe. Each Thread has its own stack of contexts. Now it would be great if instead you could annotate the class or method with the scope but due to their limitations I am not sure how you could actually populate the context since properties associated with annotations have to be known at compile time. |
@rgoers Yes, in my original post I proposed a method
I think with some kind of LogBuilder-type API this could be possible. |
@rocketraman Again, I don't understand. ScopedContext IS a builder. Each where method adds a new key/value pair to the context. The run and call methods are, in essence, the builders. Of course, that isn't strictly true since newInstance creates the object, but the ScopedContext cannot reallly be used for anything until run or call are called. I also don't see how a builder could be leveraged from an Java annotation. Note: I very loosely used Java 21 ScopedValues for the API for this, although ScopedContext is quite a bit simpler IMO. The where method in scoped variables creates a new immutable ScopedValue.Carrier - I believe the JDK has gone a bit overboard in making things immutable. |
I think we should discuss it in |
@rgoers
|
OK. Personally, I see little value in adding context data to a logger. That simply wouldn't fit with any use cases I work with. However, it might if Logger names were more generic instead of using class names as is done now by convention. |
@rgoers For context (pun intended, hah!), I've recently run into this situation in a project which manages TCP/IP connections and the related state of a networking protocol. The The
This is the first project in which I've used MDC extensively, and when encountering this gap with the former of the two context sources above, I was honestly surprised it didn't already have a good, simple solution. It seems like a common use case to me. I think traditionally most developers would just include the connection context in the message of each log, and then search/grep for it. This works of course, but is brittle (easy to mess up) and far inferior to populating the context when using structured logging. |
@rocketraman I understand your example but I am not sure how it works in practice. I have to presume that the Connection class can operate on multiple Connection instances. A Logger is a singleton - there will only be one instance no matter how many Connection instances you create (to do otherwise would create an insane number of Logger instances in the system). We generally recommend it be declared as static as to do otherwise means a call is made to locate the Logger instance every time a new instance of the class is created. What this means is that you can't really have a per-resource context attached to a Logger. From inside Log4j we would have no idea which instance of the object was used and would not be able to locate the context. However, you could create an instance of the ScopedContext I proposed and attach it to each instance of your Connection and then invoke the logic for every method inside of a run method. It should be possible to use AOP to use an annotation to cause that to happen automatically. |
@rgoers I'm talking about a builder which is not static. So imagine if you will a static logger in the usual way. Then on top of that, you create an object-level LogBuilder which contains your object-level context, which all subsequent logging sites use as a starting point. For example in pseudo-code:
Yes, this is what I was proposing in my OP with This is an ok solution but its verbose, and I personally dislike using AOP. In my experience, AOP is almost always obviated by good architecture and APIs. Kotlin's trailing lambda syntax and delegation support makes AOP even more redundant for Kotlin users. You may disagree but I don't think log4j2 should require users to bring AOP into a project in order to have a clean API surface. |
Using log4j2 context seems a bit limited for non-thread use cases. The assumption that context will always be set at the Thread or coroutine level is IMO false, and sometimes we just want to set context for a particular block of code, or for a particular logger.
We should have a way to do something like this outside of a coroutine / suspending context:
Possible implementations (only map shown here, but similar for stack)?
Could also be related to #36. We may want to do something like:
The text was updated successfully, but these errors were encountered: