[slf4j-user] Fail Silently on NOP implementation

Phillip Lord phillip.lord at russet.org.uk
Thu Apr 28 20:15:23 UTC 2016


Marshall Pierce <marshall at mpierce.org> writes:

>> I do not understand this distinction. I have some software which can
>> provides an interactive shell that I can use directly (i.e. a tool)
>> or which can be used as a dependency by downstream applications (i.e.
>> a library). Conclusion I should select a binding, and not include
>> one.
>
> Ah, well, it is a bit subtle, but it is there. Maybe it will be easier to draw
> parallels from a different language. Suppose you are writing yourself a figlet
> clone (phiglet, perhaps?) in C with the goal of being embeddable into other
> programs.
>
> As a polite C library author, you allow your users to specify their own
> malloc() implementation: some people will want jemalloc, others will want
> their own custom arena allocator, etc.
>
> In libphiglet.so, you need to *not* make those decisions.If you
> wanted both to exist in the same file, you would need to do some
> runtime histrionics to do the right thing (setting the malloc impl, or
> not) depending on how it was invoked.

In most cases, the operating system packaging will take care of this.
There are a couple of ways of dealing with this kind of optional
dependency. Either, require the user to make a decision, or have a
sensible default, which can be over-ridden.

If my reading of the release history is correct, SLF4J used to do the
former (by crashing) and now does the latter, which is sensible, as it
is by far the best in almost all circumstances.

I just want it to stop telling me that it has done this. If all the
optional or replaceable modules did this, that would be a lot of warning
messages.


> You have some requirements:
> - Provide a library for use in other projects
> - Provide a command-line (or whatever) tool that is usable stand-alone
>
> Is it also a requirement that these both be resident in literally the same
> artifact?

No. But, two artifacts would be entirely identical, differing *only* in
that one would include slf4j-nop and one would not. Both I and the
authors of the upstream dependency discussed this option. It does not
seem a good option to silence a warning message. None of the other
options seemed good either.

Hence, I am here.


> If so, you have a problem (and a very unusual requirement). If you
> provide more detail on how you expect your software to be consumed as
> a library and as a tool, perhaps we can find a solution that doesn’t
> involve classpath wizardry at runtime.

Okay. So, the tool is (sort of) a logic theorem prover. You can use it
directly as a tool if, for example, you want to test a few things. In
this sense, you would run a shell directly over the library with no
further dependencies.

Alternatively, for a large proof, you could create a new project, put
all of your statements in there, and use my library as a dependency.


>> Indeed. But, as a non-user of SLF4J would you really enjoy learning
>> about how to turn off an error message for a library that you are not
>> using, but which any of your transitive dependencies has chosen to use?
>
> You ARE using it, because your transitive dependencies use it. If you choose
> to approach transitive dependencies as “less real” than your explicitly
> specified dependencies, you are going to have a sad time.

Oh, they are not less real, but they are out of my direct control.


>> In fact, given the approach above, all you would need is to change your
>> advice: use slf4j-api when developing, but deploy your artifacts with
>> slf4j-silent. The hello world default case would behave as now. In
>> practice, I think, most library developers will need to use a different
>> dev dependency environment anyway (with logging on) and during
>> deployment (with logging off).
>
> No, now all your users would need to exclude the slf4j-silent dependency or
> risk confusing silence when logging isn’t working. That is a very bad outcome.

Actually, no. If the slf4j-silent dependency automatically gave way to
any other implementation, then the exclusion would not be needed.
Currently, the nop implementation nearly does this but sadly triggers
another error message if there is another binding present.

There would be a risk of a confusing silence when logging is failing. I
think this is a good compromise. It's quite normal to have to do
something to switch logging on, and certainly better than having an
error message for downstream users who are not even aware that there is
a logging library somewhere in the system.


> In library development, running the library consists of running tests (where
> logging can be easily configured by adding a test-only dependency) or running
> other standalone programs that use the library (where, again, configuring
> logging is trivial and completely separate from the library). In what sense
> are you “running a library during development” that is not one of those cases?

Oh, that's just a normal part of development. Open source code, evaluate
it, test it, change it, re-evaluate it. I do, occasionally, have to
develop in languages with a code-compile-test cycle, but I like to avoid
that if at all possible.

>> The clear gain is that the SLF4J is not going to printing error messages
>> to people who have not deliberately chosen to use it. I can understand,
>> of course, why it might prefer the needs of its users over those who are
>> not. But, it doesn't take too much googling to find quite a few people
>> asking "where is this error message coming from, and what is SLF4J”.
>
> You HAVE deliberately chosen to use it by using software that uses it.

This is not true. My library has around 70 dependencies, some of which I
have never heard of. As the recent debacle with left-pad and NPM has
shown, very few people are consciously aware of all their dependencies.

>> I'm writing in Clojure -- so all things have a main method. Also true of
>> scala, groovy, javascript and, indeed, Java from 1.9 onwards with
>> jshell. So, not an antipattern at all, just business as usual.
>> 
>> The JVM is a big ecosystem; bigger than Java.
>
> Yes it is, but we disagree about its antipattern-ness: libraries and
> standalone tools have different responsibilities. Just because it’s possible
> doesn’t mean it’s a good idea.

Having a REPL is good. Try it, if you have not.


>> Well, by this argument, SLF4J is being consumed in two different ways.
>> In which case, it should have two different artifacts. This seems, to
>> me, a more sensible approach than suggesting that all downstream
>> dependencies of SLF4J should have a "thing-with-slf4j-api" and
>> "thing-with-slf4j-nop" artifacts.
>
> I’m not sure what you mean here. There already ARE two parts to slf4j: the api
> and the set of different bindings.

Yes, although these do not equate to the artifacts. slf4j-api is
actually the API and the NOP logger. I would like a slf4j-silent
artifact that works nop but does not cause the "multiple binding"
warning, instead just defering to any other implementation.

I need to bottom out this discussion. Are you a dev, or is anyone else
reading this thread? Is there willingness to consider a solution? As
Steven Schlansker said, changing the default is unlikely. But a
slf4j-silent would be possible.

If not, I will just include slf4j-nop directly and leave it at that.

Phil


More information about the slf4j-user mailing list