Why a Logging Framework should not Log
Shortly after the release of Tawny-OWL 1.5.0 (n.d.a) I noticed a strange message being printed to screen, which looks like this:
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.
What strangeness is this? I had never heard of SLF4J before, and could not see why this was happening; so I googled around, and found out. The reason is that I had switched versions of the OWL API (n.d.b, =2019471) and this now uses the SLF4J API as a logging API. By default, it prints out this error message.
Slightly irritated by this, I tweeted
#slf4j I mean, who decided to print a message to tell me I am using a no-op
logger. How is that no-op?
To which the author of SLF4J Ceki Gülcü kindly replied:
@phillord if you place slf4j-nop.jar on the class path the nop message should
not appear.
But this seems unsatisfying to me. The reason for the message is that
SLF4J is a facade, and needs a logging backend. It prints this error
message when it cannot find one. The way to switch it off is to include
the slf4j-nop
dependency (which, ironically, does not contain the NOP
logger — that’s in slf4j-api
).
Normally, I would say that a library should not print to stderr in normal operation. But I can appreciate SLF4J logic here; it has to do something by default. For most libraries, my response would be “use a proper logger then!”, but, of course, SLF4J does not have that option — it cannot do this during bootstrap, and it either prints to stderr or just dumps all logs.
Okay, no worries, just include slf4j-nop in your project? Unfortunately, SLF4J say explicitly not to do this.
If you are packaging an application and you do not care about logging, then placing slf4j-nop.jar on the class path of your application will get rid of this warning message. Note that embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api
Now, for a library/application/textual UI like Tawny-OWL (n.d.c) the distinction between “library” and “end-user” is not that clear, so this advice is not that useful. SLF4J justify this by saying:
When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J’s purpose.
Of course, imposing a binding of the end-user is a negative thing, but then is not forcing users to choose a binding also an imposition? It is made worse in my case, because I also get this message from ELK, another dependency of Tawny-OWL:
log4j:WARN No appenders could be found for logger
(org.semanticweb.elk.config.ConfigurationFactory).
log4j:WARN Please initialize the log4j system properly.
A similar error message for a similar reason. I now have to explicitly pacify the logging from two libraries in my project!
The curious thing about the whole situation is that everyone is behaving entirely reasonably. I can fully appreciate the logic of SLF4J, I can fully understand why the OWL API uses it, and I hope that others appreciate why I do not want print outs to stderr. It’s another one of those situations which show that software is difficult, and that often there are only compromises; whether something is a solution or a problem depends on where you sit.
For what it is worth, my own advice is that libraries and framework
developers should always include the slf4j-nop
if they use
slf4j-api
. If their end-users want logging, they can always use
dependency
exclusions
to enable it.
I’d like to thank the members of the SLF4J users list, and Ceki for their helpful and polite responses to my questions. You can read the full thread on gmane. This article was, however, written without their endorsement.
- Update
I have written a followup to this article.
———. n.d.b. https://dl.acm.org/citation.cfm?id.
———. n.d.c. https://arxiv.org/abs/1303.0213.