[slf4j-dev] Plan for SLF4J 2.0

Joern Huxhorn jhuxhorn at googlemail.com
Mon Mar 8 14:49:34 CET 2010

Hello everybody.

On 06.03.2010, at 18:13, Ceki Gülcü wrote:

> On 06/03/2010 4:29 PM, Joern Huxhorn wrote:
>> On 06.03.2010, at 14:48, Ceki Gülcü wrote:
>>> Hello all,
>>> Here are the 4 items I'd like to address in SLF4J 2.0:
>>> 1) Varargs for Logger methods
>>> http://bugzilla.slf4j.org/show_bug.cgi?id=31
>>> Require JDK 1.5 and remain binary compatible as explained in my
>>> comment #31 dated 2009-03-25
>>> 2) logging exception if last argument, as exaplined by Joern in
>>> http://bugzilla.slf4j.org/show_bug.cgi?id=43
>>> 3) Avoid bogus incompatibility warnings
>>> http://bugzilla.slf4j.org/show_bug.cgi?id=154
>>> 4) fix http://bugzilla.slf4j.org/show_bug.cgi?id=170 possibly with a
>>> nop implementation of org.apache.log4j.NDC
>>> Are there any other major items? Is everyone OK with requiring JDK  
>>> 1.5
>>> in SLF4J 2.0?
>> Hi Ceki,
>> While I'm a big fan of #31 and #43 and personally don't need <1.5
>> compatibility, I fear that dropping it might seriously hurt libraries
>> using it right now.
> That's the $64k question. If library lA depends on SLF4J and target
> JDK 1.4, nothing prevents lA from continuing to use SLF4J version
> 1.5.11. It gets a little trickier when library lB targets JDK 1.5 and
> depended on SLF4J v2 and if some application aX requires both lA and
> lB. Since SLF4J v2 is intended to be binary compatible with SLF4J
> 1.5.x, aX can use SLF4J v2 and lA will run just fine (without
> recompilation or anything). Where it gets really hairy is when an app
> server like Geronimo, JBoss or Spring DM bundle some version of SLF4J,
> say v1.5.11. If the end-user cannot freely chose the version of SLF4J
> (and this happens quite frequently) because the the app server imposes
> its version of SLF4J, then we might run into serious problems, unless
> SLF4J v2 and 1.5.x are binary compatible.
> As mentioned in comment #10 dated 2007-10-10 on bug 31, we can have
> binary compatibility as long as
> logger.trace|debug|info|warn|error(String, Object[])
> logger.trace|debug|info|warn|error(Marker, String, Object[])
> are changed to
> logger.trace|debug|info|warn|error(String, Object...)
> logger.trace|debug|info|warn|error(Marker, String, Object...)
> with all the other methods remaining unchanged.

That's not entirely true.
As you stated in that comment, compatibility is not the case if  
someone compiles against SLF4J v2 (with varargs) but the container  
uses JDK 1.4.
I fear that SLF4J v2 might sneak up on some people by either not RTFM  
of SLF4J v2 or by some dependency where the developers did not RTFM  
the SLF4J v2 manual.
It wouldn't be our fault in both cases but it would boil down to  
"Updating xyz broke my build" subjects in mailinglists with the  
explanation that it was because of the SLF4J dependency.

> If the assumption about binary compatibility is wrong, SLF4J will
> probably not survive the shitstorm ensuing the release of v2.
>> I also guess that lots of people using SLF4J aren't following this
>> mailinglist so this should probably also be discussed on
>> slf4j-user at qos.ch .
>> We'd still miss lots of users and I guess this will result in crying
>> after the fact.
> True. As Gunnar Wagenknecht observed, the BasicMDCAdapter class since
> it was introduced in early 2008, withing its remove() method invokes a
> method new to JDK 1.5. Thus, whenever the MDC.remove method is called
> under JDK 1.4, for any binding other than logback (which has its own
> MDCAdapter implementation and anyhow requires JDK 1.5) will cause an
> exception to be thrown. As far as I can remember no one has complained
> about this bug before Gunnar. So either no one is using
> org.slf4j.MDC#remove under JDK 1.4 or those who do, do not care enough
> to complain.  Here is the link to BasicMDCAdapter dating from
> 2008-01-15: http://tinyurl.com/yherxp9
> I find this BasicMDCAdapter.remove episode really puzzling. The only
> simple explanation I see is that few SLF4J users run under JDK
> 1.4 or more accurately the overlap of org.slf4j.MDC and JDK 1.4 use
> corresponds to a very small number of users.

You're right.
But there's also the possibility that people are only putting values  
into MDC without ever removing them again, overwriting them instead.

Before I switched all my stuff to SLF4J I was using commons-logging.  
This was the case for all the projects I was involved in. CL did not  
support MDC and I think that this is one of the reasons why MDC is -  
even now - quite underused.
Lots of people switched their codebase over to SLF4J by a simple  
search & destroy, I guess.

>> It's a shame that there's no tool to analyze the whole central Maven2
>> repository concerning this, or is there?
>> It would be great if there was a way to find out which modules  
>> depend on
>> SLF4J (either directly or transitively) and are still 1.4.
> Let's google it. :-)

Did you succeed?

>> If we'd consider my alternative suggestion in
>> http://bugzilla.slf4j.org/show_bug.cgi?id=31 , i.e.
>> http://github.com/huxi/slf4j/tree/slf4j-redesign , we'd stay binary
>> compatible, keep JDK<1.5 support and would still support 1) and 2) -
>> it's a win-win.
> If we are going to re-implement org.slf4j.Logger under
> org.slf4j.n.Logger, we might as well call it org.newslf4j.Logger and
> start over from scratch. Copying the API to new packages avoids
> conflicts but otherwise constitutes a radical break.

Yes, it does. But it also cleans up the API and adds some very  
substantial features.

There are lots of methods that aren't necessary anymore with varargs  
and exception support built in.

Additional ones would be extremely nice to have.
Methods supporting the (or a) Message interface would enable the user  
to define his own application-specific message implementation which  
would bring a whole new level to the framework. He could access those  
special messages without parsing in specifically written appenders.

I've also added log(Level,....) and isEnabled(Level[,Marker])-methods  
for cases where the actual level a call uses is determined  
This is something that we needed on several occasions, too.

But additional methods can't be added to the original SLF4J because,  
as you correctly enforce, SLF4J API is frozen and must stay that way.

What I suggest is a bit like the junit package switch. With JUnit 4  
the package changed from junit to org.junit. The original junit keeps  
working as before but new stuff was added in org.junit.

You are right: the package could be named anything.

The only reasons I choose org.slf4j.n was
a) making a switch easy by just adding .n to import statements
b) using the SLF4J brand because it's established and people already  
believe/put trust in it
c) it was merely a suggestion

The main point, though, is, that there would be zero impact on any  
existing code base. Everything, even SLF4J implementations, don't have  
to do anything. The new API would be supported anyway.

In case of JDK>=1.5 implementations like Logback, it does make a lot  
of sense to implement the new API directly (so the Message reaches the  
appenders - instead of an String) and wrapping the other way around,  
i.e. using a wrapper to support the original SLF4J API (which is  
already provided in the new Logger interface via getOldLogger()  
method). But this isn't required for org.slf4j.n to work.

>> Concerning 4), I've also implemented an NDC in my branch which uses  
>> the
>> same Message (and, therefore, cheap, parameterized messages like  
>> SLF4J)
>> as my suggested Logger interface.
>> This means it's much more powerful than the log4j one (which  
>> expects one
>> word per entry without enforcing it - I derive this from the way  
>> NDC is
>> formatted in log4j xml) but log4j NDC can be implemented easily by
>> wrapping it.
>> It would only be available in the new SLF4J API - that was my plan,  
>> at
>> least. In case of log4j-over-slf4j, we could use the new SLF4J NDC if
>> available (i.e. in case of Java 1.5), falling back to an NOP
>> implementation otherwise.
>> As I stated before, I'm a big fan of NDC and see it as a very good
>> supplement to MDC. We actually use the NDC version available in  
>> Lilith
>> in our production environment and it's quite helpful.
>> I really don't understand why it was omitted from SLF4J. It's  
>> comparable
>> to a manual, semantic stacktrace.
> If you are used to log4j's NDC, having NDC in SLF4J is more  
> comfortable
> than not having it. Otherwise, since MDC is semantically richer than
> NDC (one can trivially implement NDC over MDC), one can always get by
> using MDC instead of NDC. Another reason was that by scrapping NDC in
> SLF4J there was one less piece of code to maintain.

True, but that way the NDC kind of "pollutes" the MDC.

Also, an NDC implementation is quite trivial.

The one I provided in the prototype handles the same Messages (incl.  
the same parameterized message format as a shortcut) as logging - with  
the same positive aspects concerning performance, i.e. the formatted  
message is only actually created if it is requested, not while  
something is put on the NDC. If the NDC is ignored by appenders, it  
won't be formatted, ever.
In case of MDC the formatting would always need to be performed.
We'd use it for trace-like stuff, e.g. putting "Inside method xyz with  
arguments {}, {}, {}" on the NDC. In that case, my suggested NDC would  
make a significant difference, especially if it's actually ignored.


More information about the slf4j-dev mailing list