Redirect Jersey JUL logging to Log4j2
Asked Answered
A

2

3

I need to redirect Jersey request/response log to my log4j2.

I have Jersey logging enabled by using this code on my ApplicationJAXRS extends Application:

@Override
public Set<Class<?>> getClasses() {
    return new HashSet<Class<?>>() {{
        add(LoggingFilter.class);
    }};
    }

It seems that Jersey uses JUL (Java Logging) internally and the default output is STDOUT. At this moment I can see the STDOUT on Eclipse Console.

The Log4j2 documentation have a section about JDK Logging Adapter. It says

To use the JDK Logging Adapter, you must set the system property java.util.logging.manager to org.apache.logging.log4j.jul.LogManager

This must be done either through the command line (i.e., using the -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager argument) or by using System.setProperty() before any calls are made to LogManager or Logger.

To call the System.setProperty(*) before any Logger call I've tried to put it on a @PostConstruct in my Aplication class.

@PostConstruct
    public void init() {
        System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
    }

I could get it to log on my logging files.

This is my log4j2.xml:

    <Appenders>
        <RollingFile name="RollingFile" fileName="${log-path}/${name}.log" 
            filePattern="${log-path}/${date:yyyy-MM}/${name}-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout>
                <Pattern>%d{dd-MM-yy HH:mm:ss,SSS} %-5p [%t] (%F:%L) - %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
            <DefaultRolloverStrategy max="10" />
        </RollingFile>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" level="debug"/>
            <AppenderRef ref="RollingFile" level="debug"/>
        </Root>
    </Loggers>
</Configuration>
Allure answered 20/3, 2015 at 19:45 Comment(0)
P
2

I would imagine that you have to set the system property at launch. Add code to your init method to see if setting the system property worked.

@PostConstruct
public void init() {
    String cn = "org.apache.logging.log4j.jul.LogManager";
    System.setProperty("java.util.logging.manager", cn);
    LogManager lm = LogManager.getLogManager();
    if (!cn.equals(lm.getClass().getName())) {
       try {
           ClassLoader.getSystemClassLoader().loadClass(cn);
       } catch (ClassNotFoundException cnfe) {
          throw new IllegalStateException("Jars not in system class path.", cnfe);
       }
       throw new IllegalStateException("Found " + lm.getClass().getName() + " set as launch param instead.");
    }
}
Percept answered 20/3, 2015 at 20:23 Comment(9)
java.lang.IllegalStateException: java.util.logging.LogManager was throwed.Rutilant
That means that setting the system property in 'init' doesn't work because loggers have been created.Percept
Tried to add the -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager on init params of Tomcat. It throws java.lang.ClassNotFoundException: org.apache.logging.log4j.jul.LogManagerRutilant
Log4j must not be on the system class path.Percept
log4j-api-2.2.jar, log4j-core-2.2 and log4j-jul-2.2 are on TOMCAT/lib and in the application classpath.Rutilant
Configured the tomcat classpath and it worket, but in my case I can't modify the server, so I need a application solution. Thank you anyway!Rutilant
@Allure Where you able to solve this problem? Can you share your findings?Scruple
@GAkshay unfortunately I made no progress.Rutilant
@GAkshay this link might have the answer you are looking for (without touching the server's configuration). It's not the accepted answer, but another one (just a heads-up).Autoicous
H
2

This actually works for the Jersey case though you still need to set the System property java.util.logging.manager=org.apache.logging.log4j.jul.LogManager

Instantiate your logger as normal for log4j2 for your general application logging. Then, explicitly instantiate a java.util.logging.Logger using org.apache.logging.log4j.jul.LogManager. This second Logger instance is then used to register a new LoggingFilter as can be seen here, using Jersey 2 Client for this example (verbose naming for clarity):

org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(this.getClass().getName());

java.util.logging.Logger jerseyLogger = org.apache.logging.log4j.jul.LogManager.getLogManager().getLogger(this.getClass().getName());

jerseyLogger.setLevel(java.util.logging.Level.SEVERE); //OPTIONAL

Client client = ClientBuilder.newClient();
client.register(new LoggingFilter(jerseyLogger, false));

logger.info("App logging uses the normal logger");

Now, calls to logger work as expected and all of Jersey's jul logging output is directed back into log4j2 appenders as expected.

Haler answered 21/10, 2015 at 6:33 Comment(1)
LoggingFilter is deprecated from 2.23 and replaced by LoggingFeature :)Courtneycourtrai

© 2022 - 2024 — McMap. All rights reserved.