
Hi, I am in the process of choosing a logging framework for an OSGi-based project and obviously SLF4J is a strong contender. It is nearly ubiquitous now and has an OSGi LogService bridge, as well as a very interesting implementation (Logback). However, the design of SLF4J, as it is, is somewhat OSGi unfriendly: we have the API bundle depending on its implementation -- and the opposite. This cyclic dependency is the consequence of trying to make it extremely easy in regular Java environments to plug a SLF4J implementation to the LoggerFactory, simply by "dropping a jar" in the runtime classpath. I don't know if the following points have been already discussed, and I could not find anything in the archives. I understand this solution is inherited from Log4J, and that it was itself a solution to the classloading problems in JCL. Dynamic binding and classloader hacks are clearly problematic in some setups, and there is no "one size fits all", because Java allows many styles and SLF4J, as a universal logging facade, should definitely work best everywhere possible. I believe SLF4J could become more universal/ubiquitous if the static binding approach was ad-hoc and not part of the "API side": OSGi/Guice/Spring folks like me could then use ILoggerFactory/IMarkerFactory as service specifications and use the more natural "dynamic binding" provided in their framework. For instance, component frameworks for OSGi providing DI could easily inject a logger by component instance (in the spirit of [1]). In OSGi particularly, the best practices are that an "active" service is provided only when the bundle is active but stateful singletons like LoggerFactory don't follow these rules. The FAQ entry "Is it possible to retrieve loggers without going through the static methods in LoggerFactory?"[2] partly addresses this: yes it is already possible to ignore LoggerFactory and static binding. Unfortunately this is still not fully OSGi-friendly (and I think it applies to any module system): * the current SLF4J bundle imports the package org.slf4j.impl with a mandatory resolution. It means there *must* be an implementation providing that package, and that the package *must* be exported. Best practices recommend making implementation packages private and thus non-usable by external bundles at all, even for reflection. * if we were to specify the resolution of org.slf4j.impl as optional, then any piece of code using LoggerFactory directly will default to a no-op logger with a message on stderr. This doesn't look like a big problem, but ideally in an OSGi context I would not want to provide that class at all and someone trying to use LoggerFactory.getLogger() would simply not get their component to build. Only people using static binding should have the class in their build classpath. I think there is not much to do to address these issues: it should be enough to separate binding logic (e.g LoggerFactory / MarkerFactory and the .spi package) into another JAR. For legacy reasons, so that OSGi projects already using SLF4J's static binding are not broken, and because split packages are generally unsupported in OSGi, LoggerFactory and MarkerFactory should move to another package like org.slf4j.staticfactories (or whatever). If they move to another package, there should still be LoggerFactory and MarkerFactory classes that redirect to the "new" ones for compatibility reasons (though deprecated and scheduled for removal at the next backwards compatibility break). The new modules available would be: * slf4j-api: purely API, no wiring, no state, no singletons. Default implementations could still be packaged here. * slf4j-staticbindings: providing the LoggerFactory / MarkerFactory classes in a new package. Only this JAR should reference org.slf4j.impl. * slf4j-compat: providing bridge between org.slf4j.{Logger,Marker}Factory and org.slf4j.staticfactories.{Logger,Marker}Factory. * all the existing slf4j implementations could provide both bridging to OSGi and through static factories. To sum up: for non-OSGi users we could keep backwards compatible for code, but there would be two new JARs on the classpath. It is also possible to merge them in a all-in-one JAR as of now. OSGi users could benefit from having multiple concurrent SLF4J implementations, or even multiple SLF4J API versions. I'm not really sure how this proposal is going to be received (because this is obviously a central design choice in SLF4J). I truly think this is best for SLF4J to let users pick how they want to do their binding: it is a facade after all, it should be as abstract as possible. It will also make SLF4J more durable, because these questions will also happen when Jigsaw comes with Java 9: it is imo better to prepare early to avoid forks/fragmentation. My proposal will not break source compatibility but will make all the calls to LoggerFactory.getLogger() deprecated. The migrator tool could replace those easily, and it would still be possible to provide a compat jar. The cost of the indirection at class loading, especially compared to the classpath scanning of static binding, is negligible. The real problematic consequence would be for people not adding the new JARs to their classpath... This could be justification enough to bump the version to 2.0.0, to so that people know the scope of the JARs have been redefined (e.g, the API is backwards-compatible but the JARs are not). Please let me know if you think the proposal makes sense or not :), I would be willing to provide the necessary patches / updates to the FAQ. Cheers, Simon [1] http://www.tzavellas.com/techblog/2007/03/31/implementing-seam-style-logger-... [2] http://www.slf4j.org/faq.html#noLoggerFactory