- slf4j-api contains the SLF4J API, i.e. all the classes that an application or library using SLF4J directly depends on.
- A number of bindings that implement the SLF4J API either based on an existing logging framework (slf4j-log4j12, slf4j-jdk14 and slf4j-jcl) or using a native implementation developed specifically for SLF4J (slf4j-nop and slf4j-simple).
- A number of bridges that adapt SLF4J to existing logging facades (jul-to-slf4j) or emulate existing logging facades or implementations (jcl-over-slf4j and log4j-over-slf4j).
- The project must have a dependency on slf4j-api. If the project itself uses SLF4J and doesn't depend on any binding or bridge, then this should be a direct dependency. If SLF4J is used by one or more dependencies of the project, but not the project itself, then one may prefer to let Maven's dependency management system include it as a transitive dependency.
- If the project produces an executable artifact (JAR with Main-Class, WAR, EAR or binary distribution), then it must have a dependency on one and only one of the bindings. Indeed, a binding is always required at runtime, but the presence of multiple bindings would result in unpredictable behavior.
- The project may have any number of dependencies on SLF4J bridges, excluding the bridge for the API used by the binding. E.g. if slf4j-log4j12 is used as a binding, then the project must not depend on log4j-over-slf4j. Otherwise the application may crash because of infinite recursions.
- If the project has a dependency on a bridge that emulates an existing logging API, then it must not have at the same time a dependency on this API. E.g. if jcl-over-slf4j is used, then the project must not have a dependency on commons-logging. Otherwise the behavior will be unpredictable.
- The dependencies must not mix artifacts from SLF4J 1.4.x with artifacts from 1.5.x, since they are incompatible with each other.
Alas, the world is not perfect and there are many third-party libraries that do have dependencies on particular SLF4J bindings and logging implementations. If a projects starts depending on this type of libraries, things get easily out of control if no countermeasures are taken. This is true especially for complex projects with lots of dependencies, which will almost certainly run into a situation where one of the five conditions above is no longer satisfied.
Unfortunately, Maven doesn't have the necessary features that would allow to enforce these conditions a priori, and enforcing them requires some discipline and manual intervention. On the other hand, there is a strategy that is quite simple and effective when applied systematically:
An example of this would look as follows:
- Make sure that in projects under your control, the policies described above are always followed.
- For third-party libraries that don't follow best practices, use exclusions on the corresponding dependency declarations to remove transitive dependencies on SLF4J bindings. Note that if the library is used in several modules of a multi-module Maven project, then it is handy to declare these exclusions in the dependency management section in the parent POM, so that it is not required to repeat it every time the dependency is used.