Hi Ceki, thanks for the reply!

>The method signatures of classes in the org.slf4j package such as

>Logger, LoggerFactory, Marker, MDC, etc. are the same since 2005.


No they are not. I did a diff between 1.2 and the latest and it seems a few 
trace() methods got added. This is only a minor problem but still. This change 
is perfectly backward compatible, but it's not forward compatible. If there is 
any new signature added/changed in a newer version which we will not yet use, 
then we would just crash if a plugin uses the newer version. Now this is highly 
unlikely. But I've seen this with commons logging and I've seen this with the 
LocationAwareLoger as you already mentioned below. This is btw exactly the 
reason why we shade in all commons-* stuff to private packages...


> this means that the minor version of the SLF4J binding 
> must match that of the slf4j-api. The "maintenance" 
> number is unimportant.

That's perfectly fine that way! Please understand that this is nothing against 
slf4j! I just like to avoid that we introduce build problems to existing 
projects. As highlighted in my previous post there ARE ways to do that (by 
shielding via ClassWorlds), but this is not in place in trunk yet. Also there 
are zero integration tests for it atm! 

>> ad 1.) maven provides slf4j-api-1.6 but a plugin uses slf4j-api-1.5,
>> 1.4, etc  This might cause class cast exceptions ("Cannot cast class
>> Logger to class Logger") by having different versions of the slf4j-api
>> classes in different ClassLoaders
>
>This problem is independent of the version of the slf4j-api
>used. According to Section 4.3.4 of the Java Language Specification,
>two classes loaded by different class loaders are considered distinct
>and hence incompatible.

Maven uses a child-first classloading strategy (with exceptions) - a plugin 
would only see exactly 1 version. Currently (again: there is atm no shielding 
in place yet) if a plugin would would provide it's own slf4j-api-1.4.2 then the 
plugin would get this version of the Class. And if the plugin would invoke 
LoggerFactory.getLogger(this.class()) then what would happen? Most probably a 
classcast exception, right? There is a minor chance that we do not blow up as 
there is a complex ClassLoading environment in place. But we only know after we 
have some IT in place which do not exist yet. All the change got committed 
without a single IT, thus my -1 in the first place.


>> 2.) if you use slf4j, then ALL the funnels and logging backends must
>> have the very same version number than the slf4j-api. Otherwise you
>> are pretty much doomed. Ceki, is this correct as well?
>
>I would not go as far as "doomed". For example, the following
>combination will work fine: slf4j-api-1.7.2.jar,
>sfl4j-simple-1.6.5.jar, log4j-over-slf4j-1.6.2.jar,
>jcl-ocer-slf4j-1.7.1.jar and jul-to-slf4j-1.6.0.jar. In other words,
>you can freely mix artifacts in the 1.6.x and 1.7.x families.

But can you freely mix 1.5.x and 1.6.x? or 1.7 and 1.5 or 1.4? No you cannot as 
far as I've seen. So we cannot make a general assumption on that! The only safe 
rule is to not mix slf4j parts with diverging major or minor number. Is this 
correct?


>Sounds good. I would recommend isolation regardless of the version of
>the discovered slf4j dependency. The plugin author probably wishes
>logging isolation. Maven should let the plugin have its own separate
>logging environment distinct from Maven's own logging.

But that would actually be a big step backwards imo.
Currently any plugin is forced to 'funnel' the output into the logger it 
obtains via getLogger() itself. This is an instance of 
org.apache.maven.plugin.logging.Log and we have it perfectly under our own 
control. It's not a perfectly convenient logging api but it works and shields 
us from all implementation details!

If we would isolate away all the logging of a plugin (because it contains a 
diverging slf4j version)
then we would loose all this logs, right?



It is perfectly valid for any plugin to use slf4j right now. All it needs to do 
is to funnel it into our own maven logging api. We could e.g. provide a 
slf4j-maven-logging backend so users could use it even more easily.



LieGrue,
strub



----- Original Message -----
> From: ceki <c...@qos.ch>
> To: Maven Developers List <dev@maven.apache.org>
> Cc: 
> Sent: Wednesday, October 10, 2012 6:01 PM
> Subject: Re: SLF4J integration
> 
> On 10.10.2012 15:42, Mark Struberg wrote:
> 
> Hi Mark,
> 
>>  Hi!
> 
>>  Here are a few basic observations about slf4j.  slf4j really rocks for
>>  end user applications, but when it comes to deep container core stuff
>>  you must take care about classloader clashes much more than within an
>>  end-user project. We just don't know what a user defined in his
>>  <plugin> sections...
>> 
>>  If we like to use slf4j as maven logging api and export it in the core
>>  classloader then we might probably face the following problematic
>>  spots
>> 
>>  1.) slf4j-api <=1.5 and >=1.6 are not fully binary compatible
>>  afaik. Ceki, is this correct? Afair there have been a few minor
>>  changes between those versions. They do not always cause problems but
>>  I've seen those in the wild already.
> 
> The method signatures of classes in the org.slf4j package such as
> Logger, LoggerFactory, Marker, MDC, etc. are the same since 2005.
> Client code which only imports the Logger, LoggerFactory, Marker, MDC
> classes will run fine with any version of slf4j-api, 1.0.x onwards.
> 
> SLF4J bindings such as slf4j-simple, slf4j-log4j etc import classes
> from the org.slf4j.spi and org.slf4j.helpers packages which offer
> lesser guarantees with respect to stability of method signatures. For
> instance, as you mentioned, a method signature in the
> org.slf4j.spi.LocationAwareLogger class changed between 1.5 and
> 1.6. Assuming a "major.minor.maintenance" versioning scheme, this
> means that the minor version of the SLF4J binding must match that of
> the slf4j-api. The "maintenance" number is unimportant.
> 
> As a client only importing from the org.slf4j package, you don't have
> to worry about the version of the slf4j-api with which some other
> dependency was compiled with.
> 
>>  2.) if you use slf4j, then ALL the funnels and logging backends must
>>  have the very same version number than the slf4j-api. Otherwise you
>>  are pretty much doomed. Ceki, is this correct as well?
> 
> I would not go as far as "doomed". For example, the following
> combination will work fine: slf4j-api-1.7.2.jar,
> sfl4j-simple-1.6.5.jar, log4j-over-slf4j-1.6.2.jar,
> jcl-ocer-slf4j-1.7.1.jar and jul-to-slf4j-1.6.0.jar. In other words,
> you can freely mix artifacts in the 1.6.x and 1.7.x families.
> 
>>  3.) if we would provide a sfl4j funnel (e.g. log4j-over-slf4j) and a
>>  plugin brings his own log4j.jar then we will have class path clashes
>>  as well.
> 
> There is no need for Maven to provide slf4j bridges (or funnels as you
> say) to plugins, is there?
> 
>>  I'm happy if someone tells me the above observations are wrong and I
>>  just failed to setup the stuff properly. If not, then we still can use
>>  slf4j for maven BUT we need to isolate it really well via
>>  classworlds. And of course that would mean that we miss maven logging
>>  for those 'isolated' plugins, right?
> 
> Most plugins should be able to see org.slf4j.* classes exported by
> maven-core.  For the rare few plug-ins which declare their own version
> of slf4j artifacts, isolating the org.slf4j.* classes makes
> sense. Such isolation would serve two purposes. 1) it would avoid any
> version mismatch problem 2) it would isolate the plugin's logging from
> the logging in Maven core probably as intended by the plugin author.
> 
>>  I'll first sum up the problems which will occur if the upper
>>  assumptions are correct.
> 
>>  ad 1.) maven provides slf4j-api-1.6 but a plugin uses slf4j-api-1.5,
>>  1.4, etc  This might cause class cast exceptions ("Cannot cast class
>>  Logger to class Logger") by having different versions of the slf4j-api
>>  classes in different ClassLoaders
> 
> This problem is independent of the version of the slf4j-api
> used. According to Section 4.3.4 of the Java Language Specification,
> two classes loaded by different class loaders are considered distinct
> and hence incompatible.
> 
>>  ad 2.) we provide slf4j-simple-1.6 and user provides
>>  slf4j-xxx-1.4. This will most probably end up in a big *boom*. And we
>>  do not know all slf4j-** as any user might easily add his own backend.
> 
> If I understand correctly, by default maven uses a "self-first" class
> loading strategy. Plugin's class loader will load slf4j classes
> defined in the plugin and everything may/should work seamlessly for
> legacy plugins. For non legacy plugins requesting slf4j logger
> injection via annotations and simultaneously declaring dependencies to
> slf4j classes, class cast exceptions are likely to be thrown.
> 
>>  ad 3.) We will face class path clashes since a few slf4j funnels are
>>  not fully binary compatible with the original impls. So funneling is
>>  hard to do in maven. If others think it is possible, then please point
>>  out a way to do this properly, thanks!
> 
> As mentioned earlier, I don't think Maven should use, declare or
> export any slf4j bridges.
> 
>>  Now for the workaround we could implement:
>> 
> 
>>  While discussing this topic with Stephen he had the idea to scan
>>  whether a plugin uses slf4j by unzipping all plugin dependencies and
>>  do some checks. E.g. check whether there is a
>>  org.slf4j.impl.StaticLoggerBinder.class If we detect this or any slf4j
>>  with a version != the version used in maven-core, then we must isolate
>>  away slf4j provided by the maven core via ClassWorlds.
> 
> Sounds good. I would recommend isolation regardless of the version of
> the discovered slf4j dependency. The plugin author probably wishes
> logging isolation. Maven should let the plugin have its own separate
> logging environment distinct from Maven's own logging.
> 
> I hope you find the above helpful.
> 
> -- Ceki
> 65% of statistics are made up on the spot
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@maven.apache.org
> For additional commands, e-mail: dev-h...@maven.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@maven.apache.org
For additional commands, e-mail: dev-h...@maven.apache.org

Reply via email to