I had asked this question to prevent my needing to trace through the Logback source code, but as the initial answers were inadequate I wound up having to do so anyway. So let me explain the initialization of the SLF4J+Logback system and how it relates to context selectors.
SLF4J is a logging API that allows various implementations, one of them being Logback.
When the first request is made to org.slf4j.LoggerFactory.getLogger(...)
, the SLF4J framework is initialized by creating a org.slf4j.impl.StaticLoggerBinder
. The trick is that StaticLoggerBinder
is not distributed with SLF4J; it is actually implemented in whichever logging implementation is being used (e.g. Logback). This is a somewhat cumbersome approach to loading a specific implementation (a service loader might have been a better choice), but that's somewhat beside the point here.
Logback's implementation of StaticLoggerBinder
creates a singleton ch.qos.logback.classic.util.ContextSelectorStaticBinder
. This is the class that sets up the context selector. The logic goes something like is outlined below.
a. If the "logback.ContextSelector" system property contains "JNDI", use a ContextJNDISelector
.
b. If the "logback.ContextSelector"
system property contains anything else, assume the value is the name of a context selector class and try to instantiate that.
c. Otherwise if there is no "logback.ContextSelector"
system property, use a DefaultContextSelector
.
If a custom ContextSelector
is used, ContextSelectorStaticBinder
will instantiate it using a constructor that takes a LoggerContext
as a parameter, and will pass it the default LoggerContext
which StaticLoggerBinder
has created and auto-configured. (Changing the default configuration strategy is a separate subject I won't cover here.)
As Pieter points out in another answer, the way to install a custom context selector is to provide the name of the implementing class in the "logback.ContextSelector"
system property. Unfortunately this approach is a bit precarious, and it obviously has to be done 1) manually and 2) before any SLF4J calls are made. (Here again a service loader mechanism would be been much better; I have filed issue LOGBACK-1196 for this improvement.)
If you manage to get your custom Logback context selector installed, you'll probably want to store the LoggerContext
you receive in the constructor so that you can return it in ContextSelector.getDefaultLoggerContext()
. Other than this, the most important method in ContextSelector
is ContextSelector.getLoggerContext()
; from this method you will determine what logger context is appropriate for the current context and return it.
The LoggerContext
which is so important here is ch.qos.logback.classic.LoggerContext
, which implements ILoggerFactory
. When you access the main org.slf4j.LoggerFactory.getLogger(...)
method, it uses the singleton StaticLoggerBinder
(discussed above) to look up the logger factory. For Logback StaticLoggerBinder
will use the singleton ContextSelectorStaticBinder
(also discussed above) which hopefully will return to your now installed custom LoggerContext
.
(The ContextSelector.getLoggerContext(String name)
, ContextSelector.detachLoggerContext(String loggerContextName)
, and ContextSelector.getContextNames()
methods seem to only be used in a situation such as the JNDI context selector in which you wish to keep track of context selectors using names. If you don't need named context selectors, it appears you can safely return null
and an empty list as appropriate for these methods.)
Thus the custom ContextSelector
need simply provide some LoggerContext
appropriately configured for the calling thread; this LoggerContext
will serve as the ILoggerFactory
that creates a logger based upon the LoggerContext
configuration. Configuration is covered in the Logback documentation; perhaps this discussion here makes clearer what the Logback logger context is all about.
As for the actual mechanics of associating a LoggerContext
with a thread, that was never an issue for me. It's simple: I'll be using my own Csar library, which handles such things with ease. And now that I've figured out how to hook into the logger context selection process, I've already implemented this in a logging assistance library named Clogr which uses Csar and which I have now publicly released.
Because I wound up having to do all the research myself, I'll be marking my own answer as the accepted answer unless someone points out something important in one of the other answers which I didn't cover in my own.