
Firstly, as this is my first post, thanks for an overall great library! Having just read the section on TurboFilters, they are (almost) just what I need. I fear that the way they are implemented puts undue penalty and difficulty on their performance. I did scan the past several months in the archive and did not find any mention of TurboFilter, even still, this may be something someone else has already suggested. If so, I apologize for the noise. In any case, here is my suggestion: Why not put TurboFilters on Loggers instead of the global context? That is, the example from the (very helpful and well done) manual: <configuration> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> <appender name="STDOUT" class="..."> ... snip ... </appender> <root> <appender-ref ref="STDOUT" /> </root> </configuration> Would change to: <configuration> <appender name="STDOUT" class="..."> ... snip ... </appender> <root> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> <appender-ref ref="STDOUT" /> </root> </configuration> Almost the same, and it would achieve the same result as the original. In my case, however, I could apply a TurboFilter to only the loggers that need it: <configuration> <appender name="STDOUT" class="..."> ... snip ... </appender> <root> <appender-ref ref="STDOUT" /> </root> <logger name="foo"> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> </logger> <logger name="foo.bar"> </logger> </configuration> In this case, the "foo.bar" logger would inherit the TurboFilter from the "foo" logger. In essence, each Logger object would have its own collection of TurboFilter objects that are the concatenation of any filters configured on itself, followed by its parent, grand-parent, etc. on up to the root of hierarchy. This approach should greatly reduce the total penalty for using such a powerful mechanism and at the same time give finer grained control over which filters apply to which loggers. Any thoughts? Best regards, Don

Hello Don, Thank you for the compliment abut logback. Your proposal is quite interesting and has pros as well as cons. On the pros side, it would indeed eliminate the need for evaluating TurboFilters for loggers which do not inherit any. Also, as you have stated, inherited filters allow for finer grained control. However, such flexibility comes at a cost. On the cons side, each logger would need to walk the hierarchy for determine the filters that would apply. Walking this hierarchy in a multi-threaded environment does not come totally free. Thus, I would like to ask you whether you could describe your use-case in more detail. Could you describe your use-case please? Don Griffin wrote:
Firstly, as this is my first post, thanks for an overall great library!
Having just read the section on TurboFilters, they are (almost) just what I need. I fear that the way they are implemented puts undue penalty and difficulty on their performance.
I did scan the past several months in the archive and did not find any mention of TurboFilter, even still, this may be something someone else has already suggested. If so, I apologize for the noise. In any case, here is my suggestion:
Why not put TurboFilters on Loggers instead of the global context? That is, the example from the (very helpful and well done) manual:
<configuration> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter>
<appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <appender-ref ref="STDOUT" /> </root> </configuration>
Would change to:
<configuration> <appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> <appender-ref ref="STDOUT" /> </root> </configuration>
Almost the same, and it would achieve the same result as the original. In my case, however, I could apply a TurboFilter to only the loggers that need it:
<configuration> <appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <appender-ref ref="STDOUT" /> </root>
<logger name="foo"> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> </logger>
<logger name="foo.bar"> </logger> </configuration>
In this case, the "foo.bar" logger would inherit the TurboFilter from the "foo" logger. In essence, each Logger object would have its own collection of TurboFilter objects that are the concatenation of any filters configured on itself, followed by its parent, grand-parent, etc. on up to the root of hierarchy.
This approach should greatly reduce the total penalty for using such a powerful mechanism and at the same time give finer grained control over which filters apply to which loggers.
Any thoughts?
Best regards, Don

Hi Ceki, Thanks for the reply. On the hierarchy walking part, you are correct about costs. Of course, one could flatten and cache the result. Since changes in Logger behavior on-the-fly are rare (in comparison to log statements), one could store the flattened TurboFilter[] on a Logger and invalidate it (set to null) for all children in the event of a change on a parent. For simplicity, this could be done with an AtomicReference to avoid undesirable lock hierarchies. Of course, using AtomicReference and TurboFilter[] (as opposed to a Collection), the hierarchy walking may not be too terrible. Oh well, I am sure you know what they say about premature optimization. ;) Just thoughts from one who is completely unfamiliar/ignorant of how the internals work. I'm sure you'll have much better insight on how such a feature might be implemented. In my particular use case, I'm working in a server environment. We have several objects that we would like to use to adjust the logging in a TurboFilter kind of way (as opposed to an Appender). Say, per user or per group or maybe by some other property of our application objects. We think we can force-fit the data we need in to the MDC. Someday I'll post a question/suggestion related to MDC, but for the sake of this thread, I'll save that one for another time. :) Again, thanks! Best, Don Ceki Gulcu wrote:
Hello Don,
Thank you for the compliment abut logback.
Your proposal is quite interesting and has pros as well as cons.
On the pros side, it would indeed eliminate the need for evaluating TurboFilters for loggers which do not inherit any. Also, as you have stated, inherited filters allow for finer grained control. However, such flexibility comes at a cost. On the cons side, each logger would need to walk the hierarchy for determine the filters that would apply. Walking this hierarchy in a multi-threaded environment does not come totally free.
Thus, I would like to ask you whether you could describe your use-case in more detail. Could you describe your use-case please?
Don Griffin wrote:
Firstly, as this is my first post, thanks for an overall great library!
Having just read the section on TurboFilters, they are (almost) just what I need. I fear that the way they are implemented puts undue penalty and difficulty on their performance.
I did scan the past several months in the archive and did not find any mention of TurboFilter, even still, this may be something someone else has already suggested. If so, I apologize for the noise. In any case, here is my suggestion:
Why not put TurboFilters on Loggers instead of the global context? That is, the example from the (very helpful and well done) manual:
<configuration> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter>
<appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <appender-ref ref="STDOUT" /> </root> </configuration>
Would change to:
<configuration> <appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> <appender-ref ref="STDOUT" /> </root> </configuration>
Almost the same, and it would achieve the same result as the original. In my case, however, I could apply a TurboFilter to only the loggers that need it:
<configuration> <appender name="STDOUT" class="..."> ... snip ... </appender>
<root> <appender-ref ref="STDOUT" /> </root>
<logger name="foo"> <turboFilter class="chapter6.SampleTurboFilter"> <Marker>sample</Marker> </turboFilter> </logger>
<logger name="foo.bar"> </logger> </configuration>
In this case, the "foo.bar" logger would inherit the TurboFilter from the "foo" logger. In essence, each Logger object would have its own collection of TurboFilter objects that are the concatenation of any filters configured on itself, followed by its parent, grand-parent, etc. on up to the root of hierarchy.
This approach should greatly reduce the total penalty for using such a powerful mechanism and at the same time give finer grained control over which filters apply to which loggers.
Any thoughts?
Best regards, Don
_______________________________________________ Logback-user mailing list Logback-user@qos.ch http://qos.ch/mailman/listinfo/logback-user

Comments inline. Don Griffin wrote:
On the hierarchy walking part, you are correct about costs. Of course, one could flatten and cache the result. Since changes in Logger behavior on-the-fly are rare (in comparison to log statements), one could store the flattened TurboFilter[] on a Logger and invalidate it (set to null) for all children in the event of a change on a parent. For simplicity, this could be done with an AtomicReference to avoid undesirable lock hierarchies.
I am not familiar with AtomicReferences. They sound like "fun".
Of course, using AtomicReference and TurboFilter[] (as opposed to a Collection), the hierarchy walking may not be too terrible. Oh well, I am sure you know what they say about premature optimization.
Yes, premature optimization is the root of all long discussions.
Just thoughts from one who is completely unfamiliar/ignorant of how the internals work. I'm sure you'll have much better insight on how such a feature might be implemented.
Well, maybe, but your analysis above was pretty good.
In my particular use case, I'm working in a server environment. We have several objects that we would like to use to adjust the logging in a TurboFilter kind of way (as opposed to an Appender). Say, per user or per group or maybe by some other property of our application objects.
Ignoring performance considerations, i.e root of all long discussions, if you wish to filter per user or per group, does it also make sense to add per logger filtering on top of filters based on the user? Does your use case call for "user+logger"-based filters or just user-based filters? If your use case calls for user-based filters, then is it accurate to say that your request for "user+logger"-filters is essentially motivated by improving filtering performance?
We think we can force-fit the data we need in to the MDC. Someday I'll post a question/suggestion related to MDC, but for the sake of this thread, I'll save that one for another time. :)
As you wish.
Again, thanks!
My pleasure.

Hi Ceki, Thanks again for the thoughtful reply. Ceki Gulcu wrote:
Ignoring performance considerations, i.e root of all long discussions, if you wish to filter per user or per group, does it also make sense to add per logger filtering on top of filters based on the user? Does your use case call for "user+logger"-based filters or just user-based filters?
I'm not sure I follow the "per logger filtering on top of" part. Are you describing a logger-based appender filter that would follow an appender filter for user (or other context)?
If your use case calls for user-based filters, then is it accurate to say that your request for "user+logger"-filters is essentially motivated by improving filtering performance?
You are correct - the primary reason for the request is performance. The secondary and tertiary reasons are simplification of configuration and filter implementation. In typical use our sever will be handling high request volume. This is what really attracted us to the TurboFilter concept. With it we can avoid message building for all appenders by controlling the verbosity primarily at the logger level. We tend to view all appenders as equivalent, differing primarily by where/how the log data is stored. We may occasionally want to select different messages for different targets, but that is far down on our list of use cases. In our system we are likely to have dozens of per-class loggers, fewer per-package loggers and a handful of other "shared" loggers. What we are wanting to accomplish with filters is to govern certain loggers based on application-level context (such as "user", but other objects as well). The logger in question may be a parent or perhaps package-level logger that we want to tune to control logging for all components of the package. Of course, we have several sub-systems that may have different criteria governing their logging. This would most naturally be realized using multiple filter instances. Since these are global, they must filter not only based on the application-relevant context, but also on the logger. We were concerned that having multiple such filters could easily become a performance problem. Especially since (in our case) most filters do not apply to most logger instances. The additional coding to include the logger selection criteria and the resulting configuration data to manage it were of some concern, but we didn't rank them very high (no system is a perfect fit for everyone's environment). Best regards, Don
participants (3)
-
Ceki Gulcu
-
Ceki Gulcu
-
Don Griffin