How to get slf4j console output when no implementation is present? - java

We have many "parent" (or "library") projects. They only have the slf4j-api in the classpath, but no implementation like logback.
I often want to write a quick temporary main method to test something, and get
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
How can I get output without adding a logging implementation dependency?

You can't get around having some logging dependency available if you want log output. What you can do, however, is to use the simple binding and set the dependency as <optional>true</optional>. This effectively prevents the dependency from being added transitively to client projects while making it available when you run a main method in that specific module.

Slf4j provides APIs (interfaces), not an implementation, so without adding some implementation / rolling your own IMO it would be impossible to see something being actually printed on console and in general to get around this warning an make it work in a way you ask.
If you don't need a logback, you can use slf4j simple binding for example.
Another option is to use some kind of bridge to adapt the slf4j apis to Java Util logging and then there is an implementation in JDK (like slf4j-jdk14-1.8.0-beta4.jar)
If you want tests you can use the dependency in scope "test" (assuming you use maven, for example) so it won't propagate to the artifact.

To your question, "How can I get output without adding a logging implementation dependency?". It is not possible in SLF4J. There has to be one logging implementation. If I go by the Bible of SLF4J, it says "The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time".
As Mark mentioned, you can use .jdk14.jar file to eliminate the warning and to print. But in case of any library, you have to add it.
For more reference, you can check below.
https://www.slf4j.org/
https://www.slf4j.org/manual.html

Related

log4j2 changing configuration during runtime - already supported or custom class needed?

I'm new to logging and wanted to use slf4j with log4j2 in a project of mine.
The configuration is using a json file.
I know that you can create a configuration during runtime with a ConfigurationFactory or use a file that will be checked if it has changed every time a log statement is made and a given time (or none) has passed.
My question is regarding the json file. Will i have to write my own class to change that file using a json parser or will slf4j/log4j2 change the file for me somehow? If so how?
I was reading through the documentation and googled, but didn't find the answer.
I hope you can help me out. :)
First write you code against the slf4j API. It's mostly a bunch of interfaces, and you don't want to "pollute" your code with non-slf4j API if you're using the slf4j logging interface.
Then you want to package / run with log4j-slf4j-impl-2.0.jar which adapts the slf4j API to the log4j2 API. Then you can configure your log4j2 system like you would if you never used slf4j.
Do not use the log4j-to-slf4j-2.0.jar, as that is intended to make code written to log to log4j loggers put their logging on the slf4j API, and if slf4j then implements that with a slf4j logger, your logging events will be passed between slf4j and log4j in an endless loop.
---- Editing post to address question, as it would be too much to put in a comment ----
slf4j is a logging suite with three main kinds of components.
A set of "input adapters" that take one logging system and pipe it into the slf4j API.
An slf4j API that doesn't make any assumptions about how logging is implemented.
A set of "output adapters" that take the slf4j API calls and cram them into some "other" logging system.
The input adapters typically have names like "logsystem-to-slf4j-version.jar", and should be used when you want to migrate to slf4j but haven't rewritten your code to stop using the "old" logging interface.
The output adapters typically have names like "logsystem-slf4j-impl-version.jar" and only one should be provided to slf4j at runtime.
Because slf4j is unaware of which logging adapter it might use to actually process the log messages, it is unaware of the configuration capabilities of that logging system.
Even worse, while logging typically has a semi-similar interface for the submission of log messages, they have vastly different interfaces for configuring the handling of such messages.
In short, if slf4j only adapts the handling of log messages, not the handling of configuration (which is vastly different between say System.out.println(...) and log4j)
This means that at best, you can filter your log messages at the slf4j API layer; but, there is no guarantee that they will be presented; because the underlying logging implementation may be configured to filter even more messages, or may be replaced with a "no logging at all" implementation.
Within some bounds it is possible to have log4j2 react on runtime values: With properties (which can grab entries from System config or ThreadContext), it's simple enough to inject some dynamism.

Java slf4j implementation: logback vs log4j

I received a project done by another developer (whom I cannot get in touch with right now). In that project, slf4j is used for logging. But I see log4j-1.2.17.jar along with logback-access-1.0.9.jar,logback-classic-1.0.9.jar,logback-core-1.0.9.jar in the classpath. Also both log4j.properties and logback.xml files are in the resources. Now I am confused which implementation is actually used. Can anyone suggest anything?
Update
There is also slf4j-api-1.7.2.jar and slf4j-log4j12-1.7.2.jar in classpath
If you don't see slf4j-api.jar in the class path then, as mentioned below, SLF4J will default to a no-operation implementation. It seems like the other developer was using SLF4J to plug in log4j-1.2.17.jar(log4j) along with logback-access-1.0.9.jar , logback-classic-1.0.9.jar and logback-core-1.0.9.jar(logback) at deployment time.
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
Before you start using SLF4J, we highly recommend that you read the two-page SLF4J user manual.
Note that SLF4J-enabling your library implies the addition of only a single mandatory dependency, namely slf4j-api.jar. If no binding is found on the class path, then SLF4J will default to a no-operation implementation.
- From SLF4J - Simple Logging Facade for Java

What logging system I use?

How to determine, what logging system given project uses?
It has signs of log4j, slf4jand logback. Looks like active config file is log4j.properties. The loggers are created in classes by
private static Logger log = LoggerFactory.getLogger(MyClass.class);
the full type of logger is org.slf4j.Logger and the type of factory is org.slf4j.LoggerFactory.
But there are also jars logback-core-0.9.26.jar and logback-classic-0.9.26.jar.
Other jars are slf4j-log4j12-1.6.1.jar, slf4j-api-1.6.1.jar, log4j-1.2.16.jar and commons-logging-1.1.1.jar.
What defines that logback is apparently inactive? How to activate it?
sl4j is a facade, there is no actual implementation. In other words sl4j cannot work alone, underlying logging framework can be log4j, logback, java util logging and so on.
slf4j-log4j12-1.6.1.jar dependency implies that the underlying logging implementation is log4j.
Advantage of this approach is that later on you can switch your logging implementation from Log4j to logback(which is claimed to be better by many) or any other logging framework. Your classes are not tightly coupled to logging framework.
Given the jars you mentioned, I assume the logging system is log4j, accessed through either slf4j or commons logging (maybe provided to satisfy other frameworks' dependencies).
The key here is slf4j-log4j12-1.6.1.jar which instradates slf4j through log4j.
If project code uses slf4j, then asking what logging system it uses is asking a wrong question, in a way. It will use whatever logging framework slf4j finds at runtime. If you are unsure, turn on debugging information on all the relevant libraries:
For log4j, add -Dlog4j.debug to java command line.
For slf4j I remember adding debug code and there printing the class name of ILoggerFactory instance (returned by LoggerFactory.getILoggerFactory()), which reveals what actual logger it will use.
Not sure how to debug logback or commons logging, but I'm sure their docs tell that.
The situation you describe where both logback-classic.jar and slf4j-log4j12.jar are present on the class path is an instance of the "multiple-bindings problem" mentioned in the SLF4J error code documentation. The explication for the relevant error code states:
The warning emitted by SLF4J is just that, a warning. Even when
multiple bindings are present, SLF4J will pick one logging
framework/implementation and bind with it. The way SLF4J picks a
binding is determined by the JVM and for all practical purposes should
be considered random. As of version 1.6.6, SLF4J will name the
framework/implementation class it is actually bound to.
Strangely enough you did not mention this error message in your question. If as you say both logback-classic.jar and slf4j-log4j12.jar are really present on the class path, then SLF4J will definitely print "Multiple bindings were found on the class path" as a warning. If it does not, then only one binding is actually present on the class path.

SLF4j and Logback in Application which can be embeddable

I am using SLF4j and Logback in my application. Now I have the requirement that my application should be embedabble in other applications. This means, that the application can be used as a library in other applications. Everything works as expected except the Logger part. I just can't figure out how to completely disable Logback (this is because the user should bring its own logger implementation). I tried also to find information if it is possible to run Logback in something like a "delegation mode" to allow other SLF4j implementations to hook in, but I did not find anything.
Another approach would be to write a custom Classloader which gets rid of logback when the application starts, but this is very complicated (afaik it is not possible without hacks to remove loaded classes from classloader while the application is running).
Does anyone see a possibility to do this without splitting my application in different modules?
At compile time, you should only have slf4j-api in your classpath.
At runtime, you can choose to add logback in your runtime classpath, and slf4j will use it.
If the other application uses e.g. log4j, they need to add slf4j-log4j instead of logback, as well as slf4j-api and your module.
If they use java.util.logging, they need to add slf4j-jdk14 instead of logback.
In both cases, you might want to tell them which logging categories you use, so they can add it in their log4j or java.util.logging configuration.

Logback native VS Logback via SLF4J

I have gone through the following article regarding the logging frameworks available for Java:
http://michaelandrews.typepad.com/the_technical_times/2011/04/java-logging-reconsidered.html
The author has mentioned using SLF4J with Logback. How is that different from using Logback directly. Wouldn't it be better if one uses Logback directly rather than going for SLF4J, since Logback is built on top of SLF4J.
SLF4J is adding zero overhead to Logback since it is simply the interface that is implemented by Logback without any additional layer.
You should use SLF4J simply because...
It enables you to switch away from Logback if you ever need to
It does not cost you anything, even the imports are smaller ;)
Other people will love you for using SLF4J and hate you for using a specific logging framework directly if you ever release your code into the wild.
The only place where you'd access Logback directly would be while (re)configuring your logging manually in an application. The need for this arises occasionally but even in that case, working with Logback would be restricted to a single class or even method.
As a rule of thumb: libraries should always use a logging abstraction while applications define the logging they are using, optionally accessing it directly.
SLF4J adds almost no overhead and Logback has a native bindings to it.
If you know by 100% that you will not need to switch to other logging framework in the future, go with logback native. But SLF4J allows you some abstraction and you can switch logging backends in a blink.
Logback is not build on top of SLF4J. SLF4J is an abstraction framework for logging. It doesn't do any logging itself. It just provides unified interface for logging.

Categories