简体   繁体   中英

Directing JUL logging to SLF4J does not work

I am using a third party library ( Sphinx ) which uses java.util.logging. I have been trying several approaches to route its logs to slf4j. The logging library I wish to use is Log4j2, which is configured like this:

Configuration:
  properties:
    property:
    - name: logPath
      value: logs
    - name: logName
      value: flux
    - name: rootLevel
      value: info
    - name: useConsole
      value: ALLOW
  Appenders:
    Console:
      name: Console
      target: SYSTEM_OUT
      ThresholdFilter:
        level: ${sys:rootLevel}
        onMatch: ${sys:useConsole}
      PatternLayout:
        pattern: "%d{yyyy.MM.dd G HH:mm:ss,SSS z} %-5p [%t] %C{2} (%F:%L) - %m%n"
    RollingRandomAccessFile:
      name: File
      fileName: "${sys:logPath}/${sys:logName}.log"
      filePattern: "${sys:logPath}/${sys:logName}.%d{yyyy-MM-dd}.log"
      PatternLayout:
        pattern: "%d{yyyy.MM.dd G HH:mm:ss,SSS z} %-5p [%t] %C{2} (%F:%L) - %m%n"
      Policies:
        TimeBasedTriggeringPolicy:
          interval: 1
  Loggers:
    Root:
      level: ${sys:rootLevel}
      AppenderRef:
        - ref: File
        - ref: Console

I applied without success all the solutions I could find on this and other forums. Among others:

I added this maven dependency to my POM:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jul-to-slf4j</artifactId>
        <version>1.7.20</version>
    </dependency>

I also tried with calling this in a static block:

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

And tried setting the system property:

System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");

In my last attempt I passed the VM argument:

-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager

and got the exception below:

Could not load Logmanager "org.apache.logging.log4j.jul.LogManager"
java.lang.ClassNotFoundException: org.apache.logging.log4j.jul.LogManager
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.util.logging.LogManager$1.run(LogManager.java:195)
at java.util.logging.LogManager$1.run(LogManager.java:181)
at java.security.AccessController.doPrivileged(Native Method)
at java.util.logging.LogManager.<clinit>(LogManager.java:181)
at org.chatbot.stt.SttEngineDemo.<clinit>(SttEngineDemo.java:25)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)

Am I doing something wrong? What else can I try?

Update:

I also tried redirecting jul to log4j2, bypassing slf4j, hence changing my original strategy (thanks for the suggestion @rgoers). In order to do this, I added the dependency below:

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-jul</artifactId>
        <version>2.5</version>
    </dependency>

and also set the System property java.util.logging.manager to: org.apache.logging.log4j.jul.LogManager

Then the sphinx logs are gone. I know they are not routed to my log4j2 logger since most of the Sphinx logs have the level INFO and they should be processed by log4j2. So still not correct.

If you want to route the messages to Log4j 2 why not just use Log4j 2's bridge? log4j-jul-2.5.jar

We have a solution here working and the difference I noticed is: logger.setUseParentHandler(false) and logger.addHandler(new org.slf4j.bridge.SLF4JBridgeHandler());

I make sure I don't have any other handler and then attach the SLF4JBridgeHandler to the Logger instance.

import java.io.File;
import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

class Helper {

    public static Logger get(String name) {
        Logger logger = Logger.getLogger(name);
        logger.setUseParentHandlers(false);
        configureLogger(logger);
        return logger;
    }

    private static void configureLogger(Logger logger) {
        try {
            // Remove Console Handler
            Handler[] handlers = logger.getHandlers();
            for (int i = handlers.length - 1; i >= 0; --i) {
                logger.removeHandler(handlers[i]);
            }
            // Add handler for SLF4J
            logger.addHandler(new org.slf4j.bridge.SLF4JBridgeHandler());
        } catch (Throwable ex) {
            logger.log(Level.SEVERE, "configureLogger", ex);
        }
    }

}

I have a JEE-Webapp, an wanted to log servlet-filter. The underlying Tomcat 8.5 has already initialized the JUL at startup. So I needed to override the Tomcat-initialization. This code worked for me.

    SLF4JBridgeHandler.removeHandlersForRootLogger();

    LogManager manager = LogManager.getLogManager();
    Enumeration<String> loggernames = LogManager.getLogManager().getLoggerNames();
    while(loggernames.hasMoreElements()) {
        String loggername = loggernames.nextElement();
        Logger logger = manager.getLogger(loggername);

        Handler[] handlers = logger.getHandlers();
        for (int i = handlers.length - 1; i >= 0; --i) {
            logger.removeHandler(handlers[i]);
            logger.setUseParentHandlers(true);
        }
    }

    SLF4JBridgeHandler.install();
    // Decision what to log is on slf4j-Side. So we delegate every log-request.
    Logger.getLogger("").setLevel(Level.FINEST);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM