Fail Silently on NOP implementation

classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Fail Silently on NOP implementation

Phillip Lord


The currently implementation of SLF4J prints a message on usage of the
NOP implementation. This is not very friendly at all, as it means that
if any dependency of my project includes a a dependency on SLF4J, I
suddenly get an error message whether I wish it or not.

It seems poor to me that I should have to add a dependency to slf4j-nop
in my project -- I now have to check everytime I update my dependencies
to see whether this is still necessary, so it's an ongoing cost, in
addition to the initial cost of finding out what this error message is
about in the first place.

I would like to suggest that this message be suppressed unless
explicitly asked for; users of slf4j could them choose to be warned when
they wanted. They could also ask for a fail early implementation as was
requested earlier on this mailing list.

http://mailman.qos.ch/pipermail/slf4j-user/2015-September/001478.html

This could be implemented in a number of ways -- you could make a
slf4j-api-with-noisy dependency, you could look for an environment
variable, or a system property. Users who need the warning would get it,
and end-users who are not using slf4j explicitly would be untroubled by
its presence,


Alternatively, I'd suggest updating this advice:


Embedded components such as libraries or frameworks should not declare a
dependency on any SLF4J binding but only depend on slf4j-api. 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.

to include

However, we would suggest that libraries and frameworks including a
runtime dependency on slf4j-nop; this can be excluded by end-users
should they wish to replace it with another binding at runtime.

Thanks!

Phil


_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Steven Schlansker

> On Apr 27, 2016, at 1:00 AM, Phillip Lord <[hidden email]> wrote:
>
>
>
> The currently implementation of SLF4J prints a message on usage of the
> NOP implementation. This is not very friendly at all, as it means that
> if any dependency of my project includes a a dependency on SLF4J, I
> suddenly get an error message whether I wish it or not.

Wow, you run Java apps without wanting slf4j logging?  Who even does that
nowadays? ;)

>
> It seems poor to me that I should have to add a dependency to slf4j-nop
> in my project -- I now have to check everytime I update my dependencies
> to see whether this is still necessary, so it's an ongoing cost, in
> addition to the initial cost of finding out what this error message is
> about in the first place.
>
> I would like to suggest that this message be suppressed unless
> explicitly asked for; users of slf4j could them choose to be warned when
> they wanted. They could also ask for a fail early implementation as was
> requested earlier on this mailing list.
>
> http://mailman.qos.ch/pipermail/slf4j-user/2015-September/001478.html
>
> This could be implemented in a number of ways -- you could make a
> slf4j-api-with-noisy dependency, you could look for an environment
> variable, or a system property. Users who need the warning would get it,
> and end-users who are not using slf4j explicitly would be untroubled by
> its presence,
I suspect that changing the default behavior is out of the question, at
least until a 2.x.x major release.  Additionally, some of the pushback
I received with the earlier approach was about the difficulty of managing
and lack of visibility associated with system properties.

So how about this:

slf4j-api retains current behavior.  Log if nop / duplicate implementation.

-> Introduce a "slf4j-silent" jar which modifies the slf4j logger binding
   process to be silent

-> Introduce a "slf4j-strict" jar which modifies the slf4j logger binding
   process to fail explosively on any trivial misconfiguration

This probably only requires a single hook inside of the LoggerFactory,
same way you hook StaticLoggerBinder there could be a
StaticLoggerBindingConfiguration which is provided by one of these jars
(or silently absent, in the "default" case)

Then, assuming the end user has good control of their build process, they
can elect to introduce one or the other (Personally, I would include
"slf4j-strict" in our default Maven parent POM globally)

The biggest downside is you wanted a "no additional configuration necessary"
solution, but I don't think that is possible -- the default case is already
defined and likely won't change.

Would this approach be welcome by the developers?  Would it solve your
problem satisfactorily, even though it's not 100% what you wanted?

Best,
Steven


_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user

signature.asc (817 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
Steven Schlansker <[hidden email]> writes:

>> On Apr 27, 2016, at 1:00 AM, Phillip Lord <[hidden email]> wrote:
>>
>>
>>
>> The currently implementation of SLF4J prints a message on usage of the
>> NOP implementation. This is not very friendly at all, as it means that
>> if any dependency of my project includes a a dependency on SLF4J, I
>> suddenly get an error message whether I wish it or not.
>
> Wow, you run Java apps without wanting slf4j logging?  Who even does that
> nowadays? ;)

Not wishing to be rude, but I'd never heard of slf4j till it started
print messages out to me. Not the greatest introduction, although it
seems like a nice thing otherwise!

Actually, I'm using the JVM rather than Java per se. I'm also writing a
piece of software that is an "end-user" tool (so, should include a slf4j
binding) and is usable as a library (so, should not include a slf4j
binding).


>> This could be implemented in a number of ways -- you could make a
>> slf4j-api-with-noisy dependency, you could look for an environment
>> variable, or a system property. Users who need the warning would get it,
>> and end-users who are not using slf4j explicitly would be untroubled by
>> its presence,
>
> I suspect that changing the default behavior is out of the question, at
> least until a 2.x.x major release.  Additionally, some of the pushback
> I received with the earlier approach was about the difficulty of managing
> and lack of visibility associated with system properties.

System properties are, indeed, a disaster. And using them to specify a
binding never works well. That's why I suggested several options. You'd
probably need all of them.

None of this is for defining the binding -- it's simple to enable the
"you've got no bindings" message (and probably the "you've got >1
bindings" message also).


> So how about this:
>
> slf4j-api retains current behavior.  Log if nop / duplicate
> implementation.

It doesn't "log" -- it dumps a message to standard error. If it was
logging, I could turn it off!


> -> Introduce a "slf4j-silent" jar which modifies the slf4j logger binding
>    process to be silent
>
> -> Introduce a "slf4j-strict" jar which modifies the slf4j logger binding
>    process to fail explosively on any trivial misconfiguration
>
> This probably only requires a single hook inside of the LoggerFactory,
> same way you hook StaticLoggerBinder there could be a
> StaticLoggerBindingConfiguration which is provided by one of these jars
> (or silently absent, in the "default" case)

This would seem reasonable -- assuming these are maven dependencies as
well as jars. Another possibility would which works like -nop (i.e.
shuts up the "no bindings" message), but does not cause the multiple
bindings error message (i.e. it gives way silently).


> Then, assuming the end user has good control of their build process, they
> can elect to introduce one or the other (Personally, I would include
> "slf4j-strict" in our default Maven parent POM globally)

I don't understand the idea of the "end user" in this sense. Some one
has to make the decision about what to do for an implementation. In
fact, slf4j-api DOES make this decision (i.e. it nops), if no one else
does. Should I make the decision for my library? Or should I leave it
downstream project? Some of them are mine, but some are not.


> The biggest downside is you wanted a "no additional configuration necessary"
> solution, but I don't think that is possible -- the default case is already
> defined and likely won't change.

I think I could easily convince the upstream project which has
introduced the slf4j-api dependency to switch to an
slf4j-api-and-silent-nop. At the moment, they are not so happy about
adding a slf4j-nop dependency directly, because it trades the certainty
of one error message, for the risk of another. I think this is a good
trade, but a solution which does not have this risk would be nicer.

> Would this approach be welcome by the developers?  Would it solve your
> problem satisfactorily, even though it's not 100% what you wanted?

If I have understood your suggestion correctly, yes, I think it would
help.

Thanks for the reply.

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Marshall Pierce
The job of slf4j-api is just to be the developer-side interface to logging. It purposely delegates the decision of what to do with those logs to the end user. I think it is a mistake to include policy mechanisms like these into the API.

If you’re writing a library, don’t include a binding. If you’re writing a tool, select a binding. It is an error to not include a binding, and that’s why it prints to stderr. If you’re writing a tool and you want silence, use nop. If you’re not writing a tool, it’s not your decision.

Regarding slf4j-silent / slf4j-strict: This is just another “policy via classpath” mechanism. If you want to control the output of calls made via slf4j-api, we already have a mechanism for this. What happens when both are on the classpath? As a new user to SLF4J, would you really enjoy learning how to use dependency excludes as a debugging tool during your “why won’t my logging show up” journey rather than having a clear error message that informs you that you’re doing it wrong, and pointing you towards the URL with more info? This complicates logging, and the debugging thereof, without a clear gain.

The fundamental issue is that you’re trying to use the same artifact as both a library and an end-user tool (which I’ll define as “a thing with a main method or equivalent”). This is an antipattern because there are conflicting goals for libraries and tools, as you’ve correctly identified. If your users will consume your code in two different ways, then it is sensible to have two different artifacts.

-Marshall

> On Apr 27, 2016, at 3:23 PM, Phillip Lord <[hidden email]> wrote:
>
> Steven Schlansker <[hidden email]> writes:
>
>>> On Apr 27, 2016, at 1:00 AM, Phillip Lord <[hidden email]> wrote:
>>>
>>>
>>>
>>> The currently implementation of SLF4J prints a message on usage of the
>>> NOP implementation. This is not very friendly at all, as it means that
>>> if any dependency of my project includes a a dependency on SLF4J, I
>>> suddenly get an error message whether I wish it or not.
>>
>> Wow, you run Java apps without wanting slf4j logging?  Who even does that
>> nowadays? ;)
>
> Not wishing to be rude, but I'd never heard of slf4j till it started
> print messages out to me. Not the greatest introduction, although it
> seems like a nice thing otherwise!
>
> Actually, I'm using the JVM rather than Java per se. I'm also writing a
> piece of software that is an "end-user" tool (so, should include a slf4j
> binding) and is usable as a library (so, should not include a slf4j
> binding).
>
>
>>> This could be implemented in a number of ways -- you could make a
>>> slf4j-api-with-noisy dependency, you could look for an environment
>>> variable, or a system property. Users who need the warning would get it,
>>> and end-users who are not using slf4j explicitly would be untroubled by
>>> its presence,
>>
>> I suspect that changing the default behavior is out of the question, at
>> least until a 2.x.x major release.  Additionally, some of the pushback
>> I received with the earlier approach was about the difficulty of managing
>> and lack of visibility associated with system properties.
>
> System properties are, indeed, a disaster. And using them to specify a
> binding never works well. That's why I suggested several options. You'd
> probably need all of them.
>
> None of this is for defining the binding -- it's simple to enable the
> "you've got no bindings" message (and probably the "you've got >1
> bindings" message also).
>
>
>> So how about this:
>>
>> slf4j-api retains current behavior.  Log if nop / duplicate
>> implementation.
>
> It doesn't "log" -- it dumps a message to standard error. If it was
> logging, I could turn it off!
>
>
>> -> Introduce a "slf4j-silent" jar which modifies the slf4j logger binding
>>   process to be silent
>>
>> -> Introduce a "slf4j-strict" jar which modifies the slf4j logger binding
>>   process to fail explosively on any trivial misconfiguration
>>
>> This probably only requires a single hook inside of the LoggerFactory,
>> same way you hook StaticLoggerBinder there could be a
>> StaticLoggerBindingConfiguration which is provided by one of these jars
>> (or silently absent, in the "default" case)
>
> This would seem reasonable -- assuming these are maven dependencies as
> well as jars. Another possibility would which works like -nop (i.e.
> shuts up the "no bindings" message), but does not cause the multiple
> bindings error message (i.e. it gives way silently).
>
>
>> Then, assuming the end user has good control of their build process, they
>> can elect to introduce one or the other (Personally, I would include
>> "slf4j-strict" in our default Maven parent POM globally)
>
> I don't understand the idea of the "end user" in this sense. Some one
> has to make the decision about what to do for an implementation. In
> fact, slf4j-api DOES make this decision (i.e. it nops), if no one else
> does. Should I make the decision for my library? Or should I leave it
> downstream project? Some of them are mine, but some are not.
>
>
>> The biggest downside is you wanted a "no additional configuration necessary"
>> solution, but I don't think that is possible -- the default case is already
>> defined and likely won't change.
>
> I think I could easily convince the upstream project which has
> introduced the slf4j-api dependency to switch to an
> slf4j-api-and-silent-nop. At the moment, they are not so happy about
> adding a slf4j-nop dependency directly, because it trades the certainty
> of one error message, for the risk of another. I think this is a good
> trade, but a solution which does not have this risk would be nicer.
>
>> Would this approach be welcome by the developers?  Would it solve your
>> problem satisfactorily, even though it's not 100% what you wanted?
>
> If I have understood your suggestion correctly, yes, I think it would
> help.
>
> Thanks for the reply.
>
> Phil
> _______________________________________________
> slf4j-user mailing list
> [hidden email]
> http://mailman.qos.ch/mailman/listinfo/slf4j-user

_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
Marshall Pierce <[hidden email]> writes:

> The job of slf4j-api is just to be the developer-side interface to logging. It
> purposely delegates the decision of what to do with those logs to the end
> user. I think it is a mistake to include policy mechanisms like these into the
> API.
>
> If you’re writing a library, don’t include a binding. If you’re writing a
> tool, select a binding.

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.

> It is an error to not include a binding, and that’s why it prints to
> stderr. If you’re writing a tool and you want silence, use nop. If
> you’re not writing a tool, it’s not your decision.

I am writing both.


> Regarding slf4j-silent / slf4j-strict: This is just another “policy via
> classpath” mechanism. If you want to control the output of calls made via
> slf4j-api, we already have a mechanism for this. What happens when both are on
> the classpath? As a new user to SLF4J, would you really enjoy learning how to
> use dependency excludes as a debugging tool during your “why won’t my logging
> show up” journey rather than having a clear error message that informs you
> that you’re doing it wrong, and pointing you towards the URL with more info?

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?

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).

> This complicates logging, and the debugging thereof, without a clear gain.

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".

> The fundamental issue is that you’re trying to use the same artifact as both a
> library and an end-user tool (which I’ll define as “a thing with a main method
> or equivalent”). This is an antipattern because there are conflicting goals
> for libraries and tools, as you’ve correctly identified.

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.


> If your users will consume your code in two different ways, then it is
> sensible to have two different artifacts.


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.

Anyway, it would be good to know if there is any chance of finding a
solution to this at the SLF4J level. Otherwise, I'll just put a nop
binding into my artifact and leave it at that.

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Marshall Pierce

> On Apr 28, 2016, at 8:13 AM, Phillip Lord <[hidden email]> wrote:
>
> Marshall Pierce <[hidden email]> writes:
>
>> The job of slf4j-api is just to be the developer-side interface to logging. It
>> purposely delegates the decision of what to do with those logs to the end
>> user. I think it is a mistake to include policy mechanisms like these into the
>> API.
>>
>> If you’re writing a library, don’t include a binding. If you’re writing a
>> tool, select a binding.
>
> 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.

However, you also want to provide a /usr/bin/phiglet executable in addition to /usr/lib/libphiglet.so so that people can use your new, fancy, ascii-art-text capabilities. Let’s brush aside for the moment that executables and shared objects have different file formats (a distinction that doesn’t exist for the JVM). In the phiglet executable, you need to make decisions about allocators and such things. 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.

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? 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.

>> It is an error to not include a binding, and that’s why it prints to
>> stderr. If you’re writing a tool and you want silence, use nop. If
>> you’re not writing a tool, it’s not your decision.
>
> I am writing both.

Yes, but it’s probably not the case that they must live in the same artifact.

>> Regarding slf4j-silent / slf4j-strict: This is just another “policy via
>> classpath” mechanism. If you want to control the output of calls made via
>> slf4j-api, we already have a mechanism for this. What happens when both are on
>> the classpath? As a new user to SLF4J, would you really enjoy learning how to
>> use dependency excludes as a debugging tool during your “why won’t my logging
>> show up” journey rather than having a clear error message that informs you
>> that you’re doing it wrong, and pointing you towards the URL with more info?
>
> 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.

> 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.

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?

>> This complicates logging, and the debugging thereof, without a clear gain.
>
> 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.

>> The fundamental issue is that you’re trying to use the same artifact as both a
>> library and an end-user tool (which I’ll define as “a thing with a main method
>> or equivalent”). This is an antipattern because there are conflicting goals
>> for libraries and tools, as you’ve correctly identified.
>
> 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. (It’s quite possible to do in Java, FWIW: just shove some main methods in various classes in your library. I’ve seen it more often than I would wish.) If you want to have both types of usage coexist in the exact same artifact, be prepared for sadness and complexity.

>> If your users will consume your code in two different ways, then it is
>> sensible to have two different artifacts.
>
>
> 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.

_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord

Marshall Pierce <[hidden email]> 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
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Joachim Durchholz
Am 28.04.2016 um 22:15 schrieb Phillip Lord:
>
> 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 agree with your sentiment that one shouldn't need to bother that much
about indirect dependencies; I think logging has become because it's a
cross-cutting concern, just like the availability of stdout and whether
it's a tty or a pipe.

Now if you're writing a library you should never bother with logging
configuration. Maybe make sure it doesn't clutter your unit-testing
output, but that's more cosmetic than anything else.

If, on the other hand, you're writing an application, you definitely
need to configure logging.
The good news is that the NOP logger message you are seeing is just a
misconfiguration. I don't know who's responsible; you need to check
direct and indirect dependencies and see what libraries are pulling in a
backend, and exclude dependencies (many libraries are misguided in that
they declare a dependency on a logging backend, and you need to exclude
that).
Dependency sanitizing is something that you need to do, occasionally,
even if you shouldn't have to if everybody were doing things right.

> Yes, although these do not equate to the artifacts. slf4j-api is
> actually the API and the NOP logger.

Last time I looked these were different libraries. I dimly recall that
slf4j-api didn't even pull in any logger as a dependency; it certainly
shouldn't, though it's possible that it does just to be able to simply
output messages in case of misconfiguration - which is what I assume you
are seeing.

Anyway - did the SLF4J artifacts change their composition or their
dependencies?

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

 From the keywords I have seen, you're getting messages because you have
more than one logging backend in your classpath, slf4j-nop and something
else. Including slf4j-nop will not change anything about that.

I'm just guessing about details though; let us know how things worked
out for you.
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Ceki Gulcu
In reply to this post by Marshall Pierce

In short, I agree 100% with Marshall's reasoning.

On 4/28/2016 15:35, Marshall Pierce wrote:

 > The job of slf4j-api is just to be the developer-side interface to
 > logging. It purposely delegates the decision of what to do with those
 > logs to the end user. I think it is a mistake to include policy
 > mechanisms like these into the API.
 >
 > If you’re writing a library, don’t include a binding. If you’re
 > writing a tool, select a binding. It is an error to not include a
 > binding, and that’s why it prints to stderr. If you’re writing a tool
 > and you want silence, use nop. If you’re not writing a tool, it’s not
 > your decision.

Yes.

 > Regarding slf4j-silent / slf4j-strict: This is just another “policy
 > via classpath” mechanism. If you want to control the output of
 > calls made via slf4j-api, we already have a mechanism for this. What
 > happens when both are on the classpath? As a new user to SLF4J, would
 > you really enjoy learning how to use dependency excludes as a
 > debugging tool during your “why won’t my logging show up”
 > journey rather than having a clear error message that informs you that
 > you’re doing it wrong, and pointing you towards the URL with more
 > info? This complicates logging, and the debugging thereof, without a
 > clear gain.

Yes. Well put.

 > The fundamental issue is that you’re trying to use the same artifact
 > as both a library and an end-user tool (which I’ll define as “a
 > thing with a main method or equivalent”). This is an antipattern
 > because there are conflicting goals for libraries and tools, as you’ve
 > correctly identified. If your users will consume your code in two
 > different ways, then it is sensible to have two different artifacts.

Yes, having two artifacts seems reasonable to me. However, it may be
asking too much of someone two create two artifacts just to tame
logging. In any case, SLF4J implicitly assumes that there is a clear
distinction between code packaged as a library and code packaged as an
application.

--
Ceki

_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
In reply to this post by Joachim Durchholz
Joachim Durchholz <[hidden email]> writes:

> Am 28.04.2016 um 22:15 schrieb Phillip Lord:
>>
>> 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 agree with your sentiment that one shouldn't need to bother that much about
> indirect dependencies; I think logging has become because it's a cross-cutting
> concern, just like the availability of stdout and whether it's a tty or a
> pipe.

Logging is, I agree, a difficult one, and what to do during bootstrap of
the logger is particularly nasty.


> Now if you're writing a library you should never bother with logging
> configuration. Maybe make sure it doesn't clutter your unit-testing
> output, but that's more cosmetic than anything. If, on the other hand,
> you're writing an application, you definitely need to configure
> logging.

As I have said, this distinction is artificial.


> The good news is that the NOP logger message you are seeing is just a
> misconfiguration.

No, the logger message is coming directly from slf4j-api. The code
is here, in LoggerFactory.java.

      if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
        INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
        Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
        Util.report("Defaulting to no-operation (NOP) logger implementation");
        Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
      }



> many libraries are misguided in that they declare a dependency on a
> logging backend, and you need to exclude that

I think including an explict dependency on the slf4j-nop backend is the
correct thing to do. Otherwise, slf4j-api prints an error message.


>> Yes, although these do not equate to the artifacts. slf4j-api is
>> actually the API and the NOP logger.
>
> Last time I looked these were different libraries.

I'm sorry to contradict you again, but I'm afraid you are wrong. The
NOPLogger is in org.slf4j.helpers.NOPLogger, and it's packaged as part
of slf4j-api. It would have to be, else how could slf4j-api fallback to
it?

slf4j-nop simply provides the StaticLoggerBinder which, erm, binds the
logger statically. Having done so, slf4j-api finds
org.slf4j.helpers.NOPLoggerFactory through reflection at runtime, rather
than at compile time, and in the process supresses the warning.


> I dimly recall that slf4j-api didn't even pull in any logger as a
> dependency

It doesn't. It just includes the NOPLogger directly.

>> If not, I will just include slf4j-nop directly and leave it at that.
>
> From the keywords I have seen, you're getting messages because you have more
> than one logging backend in your classpath, slf4j-nop and something else.
> Including slf4j-nop will not change anything about that.

I'm getting error messages because there is no binding. I want to stop
this. The simple way to do this with slf4j is to include slf4j-nop.

The only other solutions that I can see are:

1) Ask the slf4j developers to not print an error message.

2) Replacing System.err with a PrintStream that looks for the error
   messages from slf4j and filters them.

3) Creating a slf4j binding which looks for other bindings in the same
   way as StaticLoggerBinder, automatically defers to one if it finds it
   (and without complaining to System.err), falls back to nop otherwise.

4) Forking slf4j and removing the error message there.

This is in approximately decreasing order of sanity.

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Robert Elliot

>
> As I have said, this distinction is artificial.

It isn’t, in my opinion. The distinction between a process and a library is fundamental. A process must, of its nature, have resolved all its dependencies to concrete implementations. A library should, of its nature, couple as lightly as possible to implementations of APIs it depends on in order to free the hands of the process depending on that library.

It is of course easy to create an artefact that can be both be run as a process and depended on as a library, but that conflates two separate concerns and doing so is inherently problematic.

Unless your dependency mechanism allows for defining different dependencies for an artefact when it is running as a process or acting as a library for a different process (and Maven’s transitive dependency system, which has become the de facto standard, does not) there is no perfect solution for this. In the case of SLF4J there are the following options:

1) Add a dependency on slf4j-nop to the artefact. This will badly affect anyone who depends on your artefact as a library to their process; they will find themselves with multiple SLF4J implementations on the classpath, which will at a minimum print an error and 50% of the time will ‘win’ and remove all their logging output and require them to work out how to exclude slf4j-nop to get it back. As Maven in XML has no (non-hacky) means of global dependency exclusion this may be a significant headache for them.

2) Silently do a nop in SLF4J if no implementation is present. This will give no hint to the unaware user as to why they are getting no logging feedback from their process and what they should do to fix it.

3) Exit the process aggressively (via an exception) if no logging implementation is present

4) Separate the artefact into two artefacts - one a library containing 99% of the logic and depending on slf4j-api alone, and the other a main method that depends on the library and slf4j-nop, and document which the user should use depending on whether they want a library or a process.

5) Print some description as to how to provide an SLF4J implementation and otherwise allow the process to carry on

There are other approaches, and possibly better ones, to logging than SLF4J - I’m far from convinced that the static procedural approach where the implementation is looked up and used without the caller having control is a good one. But we are where we are, and libraries routinely statically depend on slf4j, so 5) seems to me the least bad .

Rob

_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Steven Schlansker

> On Apr 28, 2016, at 3:58 PM, Robert Elliot <[hidden email]> wrote:
>
>
>>
>> As I have said, this distinction is artificial.
>
> Unless your dependency mechanism allows for defining different dependencies for an artefact when it is running as a process or acting as a library for a different process (and Maven’s transitive dependency system, which has become the de facto standard, does not) there is no perfect solution for this. In the case of SLF4J there are the following options:
>
> 1) Add a dependency on slf4j-nop to the artefact. This will badly affect anyone who depends on your artefact as a library to their process; they will find themselves with multiple SLF4J implementations on the classpath, which will at a minimum print an error and 50% of the time will ‘win’ and remove all their logging output and require them to work out how to exclude slf4j-nop to get it back. As Maven in XML has no (non-hacky) means of global dependency exclusion this may be a significant headache for them.

Could you simply declare an "optional" dependency on your implementation of choice?

This will be present when the JAR is invoked as an application, but will not
participate in the transitive dependencies inherited when used as a library?


_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user

signature.asc (817 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Joachim Durchholz
In reply to this post by Phillip Lord
 >> Now if you're writing a library you should never bother with logging
 >> configuration. Maybe make sure it doesn't clutter your unit-testing
 >> output, but that's more cosmetic than anything. If, on the other hand,
 >> you're writing an application, you definitely need to configure
 >> logging.
 >
 > As I have said, this distinction is artificial.

Decisions like detail level and where to finally write the logs are made
on a per-application basis, so if libraries start to assume or decide
things in this area it's going to be a source of eternal conflict.
Ceki has another argument:
http://www.slf4j.org/faq.html#configure_logging
Essentially, both arguments hinge on the fact that libraries are reused
in different contexts with different logging targets, and that they need
to adapt which they can't if they make global logging decisions; an
application, on the other hand, needs to make a logging decision or give
the administrator a way to decide about logging.
So I strongly disagree that the distinction is artificial; in fact it's
unavoidable. If you insist on declaring a dependency on a specific
logger you still burden your library consumers with excluding that
dependency - that's exactly what you hated about having to bother about
indirect dependencies.

Now you have a case where your library can also stand as an application.
The best advice is to pull the application part out into a separate
artifact. Let the application have a hard dependency on whatever backend
you prefer.
You mentioned that you have a REPL; it should actually go into the
library, too. The main program just configures logging and starts the
REPL. That way, people who write something more elaborate (say, a GUI
around your REPL) can easily call the REPL without having to worry about
the logging decisions that were right for your application.

 >> The good news is that the NOP logger message you are seeing is just a
 >> misconfiguration.
 >
 > No, the logger message is coming directly from slf4j-api. The code
 > is here, in LoggerFactory.java.
 >
 >        if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
 >          INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
 >          Util.report("Failed to load class
\"org.slf4j.impl.StaticLoggerBinder\".");
 >          Util.report("Defaulting to no-operation (NOP) logger
implementation");
 >          Util.report("See " + NO_STATICLOGGERBINDER_URL + " for
further details.");
 >        }

All SLF4J backend jars contain an implementation of
org.slf4j.impl.StaticLoggerBinder.
Just include one in your build and the message should go away; you can
start with slf4j-nop.jar which is an extremely thin thing (I guess it
just provides a StaticLoggerBinder class to make the message go away and
otherwise makes SLF4J fall back to its builting NOP logging). Or you
might want to use SimpleLogger because occasionally log messages are
indeed interesting, at least for your debugging configurations.

 >> many libraries are misguided in that they declare a dependency on a
 >> logging backend, and you need to exclude that
 >
 > I think including an explict dependency on the slf4j-nop backend is the
 > correct thing to do. Otherwise, slf4j-api prints an error message.

Actually it's already the case.
You're getting the message as a hint that tells you that you should
really have made an explicit decision about the logging backend. That's
because for the vast majority of cases, NOP logging is not what you want
but SLF4J can't reasonably tell which backend is the right one to use.

 >>> Yes, although these do not equate to the artifacts. slf4j-api is
 >>> actually the API and the NOP logger.
 >>
 >> Last time I looked these were different libraries.
 >
 > I'm sorry to contradict you again, but I'm afraid you are wrong. The
 > NOPLogger is in org.slf4j.helpers.NOPLogger, and it's packaged as part
 > of slf4j-api. It would have to be, else how could slf4j-api fallback to
 > it?
 >
 > slf4j-nop simply provides the StaticLoggerBinder which, erm, binds the
 > logger statically. Having done so, slf4j-api finds
 > org.slf4j.helpers.NOPLoggerFactory through reflection at runtime, rather
 > than at compile time, and in the process supresses the warning.

Well, as I said above, then that's exactly what it's supposed to do:
slf4j-nop essentially just records the fact that the main application
consciously decided to ignore all log messages.

 >> I dimly recall that slf4j-api didn't even pull in any logger as a
 >> dependency
 >
 > It doesn't. It just includes the NOPLogger directly.

Good to hear that my memory served me right.

 >>> If not, I will just include slf4j-nop directly and leave it at that.
 >>
 >>  From the keywords I have seen, you're getting messages because you
have more
 >> than one logging backend in your classpath, slf4j-nop and something
else.
 >> Including slf4j-nop will not change anything about that.
 >
 > I'm getting error messages because there is no binding. I want to stop
 > this.

Yes, I saw that.

 > The simple way to do this with slf4j is to include slf4j-nop.

That's the simple way for you.
It's making things more complicated for everybody who does not use nop
logging. And there's another simple way for you: include slf4j-nop.

 > The only other solutions that I can see are:
 >
 > 1) Ask the slf4j developers to not print an error message.

The message is to remind application developers that they did not yet
decide what logging backend to use.

 > 2) Replacing System.err with a PrintStream that looks for the error
 >     messages from slf4j and filters them.
 > 3) Creating a slf4j binding which looks for other bindings in the same
 >     way as StaticLoggerBinder, automatically defers to one if it finds it
 >     (and without complaining to System.err), falls back to nop otherwise.
 > 4) Forking slf4j and removing the error message there.
 >
 > This is in approximately decreasing order of sanity.

Heh. Indeed.
I'd like to add this:

0) Include slf4j-nop in the class path of the main application.

No insanity at all here.
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
In reply to this post by Ceki Gulcu

Ceki, thanks for taking the time to reply (again!)


Ceki Gulcu <[hidden email]> writes:

As a new user to SLF4J, would
>> you really enjoy learning how to use dependency excludes as a
>> debugging tool during your “why won’t my logging show up”
>> journey rather than having a clear error message that informs you that
>> you’re doing it wrong, and pointing you towards the URL with more
>> info? This complicates logging, and the debugging thereof, without a
>> clear gain.
>
> Yes. Well put.

There is a clear gain. Including a dependency on slf4j directly or
indirectly causes an immediate error message to standard err which, I
suspect, causes confusion to indirect users of slf4j.

I do understand why it does this -- any other library that did this I
would say "well use a logger and turn it off-by-default", which is
clearly not an option for you. At the same token, with its current
behaviour, I would not choose to use slf4j myself.


> Yes, having two artifacts seems reasonable to me. However, it may be asking
> too much of someone two create two artifacts just to tame logging.

I think that it is too much.

> In any case, SLF4J implicitly assumes that there is a clear
> distinction between code packaged as a library and code packaged as an
> application.


The only reason that this distinction is an issue is because SLF4J
prints to stderr by default. Would you be willing to consider providing
a mechanism to pacify this error message? Then, downstream library
authors could choose to do this, without having to include the nop
binding and face being asked to "mend their ways".

This could be achieved with very little code.

If you are not prepared to do this then, of course, that is entirely
your decision, and I can respect the reasons. I will just include the
slf4-nop dependency and move on!

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
In reply to this post by Robert Elliot
Robert Elliot <[hidden email]> writes:

>>
>> As I have said, this distinction is artificial.
>
> 5) Print some description as to how to provide an SLF4J implementation and
> otherwise allow the process to carry on
>

6) Provide an option which allows direct users of slf4j to pacify error
messages without causing multiple binding errors and let them choose.

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
In reply to this post by Steven Schlansker
Steven Schlansker <[hidden email]> writes:

>> On Apr 28, 2016, at 3:58 PM, Robert Elliot <[hidden email]> wrote:
>
> Could you simply declare an "optional" dependency on your implementation of
> choice?
>
> This will be present when the JAR is invoked as an application, but will not
> participate in the transitive dependencies inherited when used as a library?


That would be possible -- although in Clojure I would just do this with
a "dev dependency". But, unfortunately, this means that any users of my
application as a library get forced to make the same decision. I do not
believe in solving a problem by making it someone elses problem.

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
In reply to this post by Joachim Durchholz
Joachim Durchholz <[hidden email]> writes:
> Now you have a case where your library can also stand as an application.
> The best advice is to pull the application part out into a separate artifact.
> Let the application have a hard dependency on whatever backend you prefer.
> You mentioned that you have a REPL; it should actually go into the library,
> too. The main program just configures logging and starts the REPL.

Alas, I don't control the main program. Like most lisps, a REPL is an
intrinsic part of Clojure, as it is most lisps. And, there are several
ways of starting the REPL -- depending on whether you want it to
interact with the command line, through a socket or so forth. So the
REPL isn't mine.


> That way, people who write something more elaborate (say, a GUI around
> your REPL) can easily call the REPL without having to worry about the
> logging decisions that were right for your application.

In fact, I have actually done this -- I have plugged my library into a
GUI which then gives a REPL to change the data structures of the GUI
application, either accessable in a widget or via a socket.

>> I think including an explict dependency on the slf4j-nop backend is the
>> correct thing to do. Otherwise, slf4j-api prints an error message.
>
> Actually it's already the case.
> You're getting the message as a hint that tells you that you should really
> have made an explicit decision about the logging backend. That's because for
> the vast majority of cases, NOP logging is not what you want but SLF4J can't
> reasonably tell which backend is the right one to use.

It does say which is the right, default backend to use -- the NOP
logging.

>
> Heh. Indeed.
> I'd like to add this:
>
> 0) Include slf4j-nop in the class path of the main application.
>
> No insanity at all here.


Yes, this is what I have done. I will wait for Ceki to answer if he is
willing to provide a gentler mechanism for pacifying these error
messages, otherwise, this is the way to go.

Many thanks for your time!

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Robert Elliot
In reply to this post by Steven Schlansker
> On 29 Apr 2016, at 00:11, Steven Schlansker <[hidden email]> wrote:
>
> Could you simply declare an "optional" dependency on your implementation of choice?
>
> This will be present when the JAR is invoked as an application, but will not
> participate in the transitive dependencies inherited when used as a library?
>
>

Just tried that - it works fine, so I’ve learnt something new. Good solution!

I’d previously thought that “optional” meant on the compile classpath but not the runtime classpath, but I guess it means on the artefact’s own runtime classpath but not a transitive dependency. So it does exactly what you want if you want your artefact to be both a process and a library. Perfect.
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Ceki Gulcu
In reply to this post by Robert Elliot
My comments are inline.

On 4/29/2016 0:58, Robert Elliot wrote:
 > >
 > > As I have said, this distinction is artificial.
 >
 > It isn’t, in my opinion. The distinction between a process and a
 > library is fundamental. A process must, of its nature, have resolved
 > all its dependencies to concrete implementations. A library should, of
 > its nature, couple as lightly as possible to implementations of APIs
 > it depends on in order to free the hands of the process depending on
 > that library.
 >
 > It is of course easy to create an artefact that can be both be run as
 > a process and depended on as a library, but that conflates two
 > separate concerns and doing so is inherently problematic.

Robert, I agree with you. The distinction of library vs. application
is essential to the problem at hand. However, it seems that this view
is not shared by all. The core question is whether SLF4J needs to
accomodate this different point of view. At this stage, my inclination
is to recognize that some developers conflate librarries and
applications but otherwise to politely ignore their pov.

 > Unless your dependency mechanism allows for defining different
 > dependencies for an artefact when it is running as a process or acting
 > as a library for a different process (and Maven’s transitive
 > dependency system, which has become the de facto standard, does not)
 > there is no perfect solution for this. In the case of SLF4J there are
 > the following options:
 >
 > 1) Add a dependency on slf4j-nop to the artefact. This will badly
 > affect anyone who depends on your artefact as a library to their
 > process, they will find themselves with multiple SLF4J implementations
 > on the classpath, which will at a minimum print an error and 50% of
 > the time will ‘win’ and remove all their logging output and require
 > them to work out how to exclude slf4j-nop to get it back. As Maven in
 > XML has no (non-hacky) means of global dependency exclusion this may
 > be a significant headache for them.
 >
 > 2) Silently do a nop in SLF4J if no implementation is present. This
 > will give no hint to the unaware user as to why they are getting no
 > logging feedback from their process and what they should do to fix it.
 >
 > 3) Exit the process aggressively (via an exception) if no logging
 > implementation is present
 >
 > 4) Separate the artefact into two artefacts - one a library containing
 > 99% of the logic and depending on slf4j-api alone, and the other a
 > main method that depends on the library and slf4j-nop, and document
 > which the user should use depending on whether they want a library or
 > a process.
 >
 > 5) Print some description as to how to provide an SLF4J implementation
 > and otherwise allow the process to carry on
 >
 > There are other approaches, and possibly better ones, to logging than
 > SLF4J - I’m far from convinced that the static procedural approach
 > where the implementation is looked up and used without the caller
 > having control is a good one. But we are where we are, and libraries
 > routinely statically depend on slf4j, so 5) seems to me the least bad.

SLF4J's approach of binding with an implementation by directly
invoking the org.slf4j.impl.StaticLoggerBinder.getSingleton() method
from within LoggerFactory is primitive and very unsophisticated. Other
approaches to this problem, e.g. OSGi, address many of the
shortcomings of the direct invocation approach. However, OSGi is very
hard to master and only a small minority of developers understand
it. In contrast, the SLF4J approach can be understood by most
programmers on their first day of programming in Java.

SLF4J's static binding approach is a direct reaction to the dynamic
binding approach (via classloader inspection) as adopted by Jakarta
Common Logging. The classloader approach is more convenient in many
cases but may become extremely complicated to debug when things go
wrong, see [1].

When SLF4J came out in 2004, JCL had 100% share of the "logging
abstraction" market. Things have changed considerably since. Rightly
or wrongly, I attribute much of SLF4J's success to static binding
although other factors surely played a role as well.

Jigsaw (new in Java 9) purportedly provides a solution to the jar hell
problem. I wonder how SLF4J could be modified to cater for Jigsaw
modules.

--
Ceki

[1] http://articles.qos.ch/classloader.html

_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
Reply | Threaded
Open this post in threaded view
|

Re: Fail Silently on NOP implementation

Phillip Lord
Ceki Gulcu <[hidden email]> writes:

> My comments are inline.
>
> On 4/29/2016 0:58, Robert Elliot wrote:
>> >
>> > As I have said, this distinction is artificial.
>>
>> It isn’t, in my opinion. The distinction between a process and a
>> library is fundamental. A process must, of its nature, have resolved
>> all its dependencies to concrete implementations. A library should, of
>> its nature, couple as lightly as possible to implementations of APIs
>> it depends on in order to free the hands of the process depending on
>> that library.
>>
>> It is of course easy to create an artefact that can be both be run as
>> a process and depended on as a library, but that conflates two
>> separate concerns and doing so is inherently problematic.
>
> Robert, I agree with you. The distinction of library vs. application
> is essential to the problem at hand.


I think that things have got a little side-tracked by this discussion
really. The problem at hand is whether a library should *by default*
print to standard out/err even in the absence of an error condition.

I think it should not.

I do acknowledge the bootstrap difficulty this causes for SLF4J, but
there are solutions. The issue of library vs. application only comes
into question when we discuss the problem with your solution (i.e bind
to nop).

Phil
_______________________________________________
slf4j-user mailing list
[hidden email]
http://mailman.qos.ch/mailman/listinfo/slf4j-user
12