2

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.

Sergio
  • 8,532
  • 11
  • 52
  • 94
  • Possibly related: https://stackoverflow.com/questions/56975903/why-does-using-the-org-apache-juli-classloaderlogmanager-logging-manager-affect – doc Jul 24 '19 at 13:49

3 Answers3

3

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

rgoers
  • 8,696
  • 1
  • 22
  • 24
  • it kind of helped though I still see an error message. Please see my updated question. – Sergio Apr 01 '16 at 06:35
  • Your VM parameter is somehow specified incorrectly. Look at the error message - it contains the "D", the key and the =. If you use System.setProperty you need to make sure it is set before anything uses jul. – rgoers Apr 01 '16 at 12:33
  • I am passing the parameter following the syntax -Dkey=value, as shown here: http://stackoverflow.com/questions/862391/how-to-pass-the-d-system-properties-while-testing-on-eclipse – Sergio Apr 01 '16 at 15:13
1

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);
        }
    }

}
Valdek Santana
  • 337
  • 1
  • 8
0

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);
Oliver
  • 11
  • 2