Skip to content

Don't log to stderr when slf4j.provider is used. #361

@garretwilson

Description

@garretwilson

I didn't realize SLF4J-450 was already implemented, so I was excited to look into this. Thanks for the work on this, @ceki and @KengoTODA.

In the source code I see:

    static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) {
        String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY);
        if (null == explicitlySpecified || explicitlySpecified.isEmpty()) {
            return null;
        }
        try {
            String message = String.format("Attempting to load provider \"%s\" specified via \"%s\" system property", explicitlySpecified, PROVIDER_PROPERTY_KEY);
            Util.report(message);
…

Unfortunately this logs a message to stderr every time we use the slf4j.provider property. I don't quite understand the point of that. Logging something to stderr outside of the normal SLF4J logging system should only be done as a last resort, if there is some unexpected error. For example, if no logger implementation is present, SLF4J indicates, "No SLF4J providers were found.". The point here is that the user should be warned if they inadvertently don't include a logging implementation. (I'm not sure I fully agree with that decision, but I certain understand the motivation.)

But there is nothing inadvertent about the slf4j.provider. If you include it, you know you're specifically requesting a logging provider. You don't need SLF4J to remind you of that. If SLF4J uses a provider it finds on the classpath, SLF4J doesn't send a message to stderr notifying the user of which provider they chose. I don't see the difference here—if any thing, there is less of a reason to log information, because nothing happened "by default"—there was an explicit configuration.

Let's say that I want all my unit tests to ignore all logging output of the libraries they use, so that I won't have to have a logging implementation in test scope at all. (See SLF4J-592.) By default SLF4J does a a NOP, so I could just leave it at that, except that all my unit tests will have this:

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

SLF4J-450 should fix that! Now I can do this in JUnit:

@BeforeAll
static void disableLogging() {
  System.setProperty("slf4j.provider", NOP_FallbackServiceProvider.class.getName());
}

Now I get the following, which defeats the purpose of what I was trying to do. 🤦‍♂️

SLF4J: Attempting to load provider "org.slf4j.helpers.NOP_FallbackServiceProvider" specified via "slf4j.provider" system property

I can do an ugly hack to get rid of the message:

@BeforeAll
static void disableLogging() {
  System.setProperty("slf4j.provider", NOP_FallbackServiceProvider.class.getName());
  final PrintStream originalSystemErr = System.err;
  try {
    System.setErr(new PrintStream(OutputStream.nullOutputStream()));
    LoggerFactory.getILoggerFactory();
  } finally {
    System.setErr(originalSystemErr);
  }
}

That suppresses the message. But if I'm going to do that, there's no point in using slf4j.provider at all, because SLF4J would default to the NOP provider anyway.

Please remove messages to stderr when slf4j.provider is used. Or just let me know that you're OK with this change, and I can file a pull request.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions