JUL适配器不适用于Jersey

我正在尝试使用JUL Adapter将Java Util Logging委派给Log4j2。 更准确地说,任何使用JUL生成日志的第三方库都应该委托给Log4j2。

作为一个简单的练习,我创建了一个使用库的独立应用程序(我创建此库用于测试目的,它使用JUL生成日志)来测试JUL适配器 。 当我按照此处所述更改日志管理器时,我可以看到效果。 它工作正常。

她是代码:

import org.apache.logging.log4j.LogManager; import com.ah.loggen.LogGenerator; public class TestLogging { static { System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); } private static final org.apache.logging.log4j.Logger LOG4J = LogManager.getLogger(); public static void main(String[] args) { System.out.println("Java Util Logging"); LogGenerator.generateError("This is an error message."); LogGenerator.generateInfo("This is an info message."); LogGenerator.generateWarning("This is a warning message."); System.out.println("LOG4J"); LOG4J.info("[LOG4J] This is an info message."); LOG4J.error("[LOG4J] This is an error message."); LOG4J.warn("[LOG4J] This is a warning message."); } } 

需要的依赖关系:

 dependencies { compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0' compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0' compile group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.10.0' compile files('lib/loggen.jar') testCompile 'junit:junit:4.12' } 

但是,我无法在使用Jersey的java Web应用程序上工作。 Jersey使用JUL,我正在尝试将其与Log4j2连接起来。

这是build.gradle文件:

 apply plugin: 'java' apply plugin: 'war' apply plugin: 'eclipse-wtp' apply from: 'https://raw.github.com/akhikhl/gretty/master/pluginScripts/gretty.plugin' repositories { mavenCentral() } task wrapper(type: Wrapper) { gradleVersion = '4.4.1' } dependencies { compile "javax.ws.rs:javax.ws.rs-api:2.1" compile "org.glassfish.jersey.core:jersey-server:2.22.1" compile "org.glassfish.jersey.containers:jersey-container-servlet:2.22.1" compile "org.glassfish.jersey.media:jersey-media-json-jackson:2.22.1" providedCompile "javax.servlet:javax.servlet-api:3.1.0" compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.8' compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8' compile group: 'org.apache.logging.log4j', name: 'log4j-web', version: '2.8' compile group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.8' } gretty { servletContainer = 'tomcat8' httpPort = 8081 } 

我试过这些选项:

  1. 在扩展Application的类中更改日志管理器。

     package com.ahoxha.test; import java.util.HashSet; import java.util.Set; import javax.annotation.PostConstruct; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import com.ahoxha.filters.JerseyLoggingFilter; @ApplicationPath("") public class HelloApplication extends Application { @Override public final Set<Class> getClasses() { final Set<Class> classes = new HashSet(); classes.add(Hello.class); classes.add(MessageResource.class); classes.add(JerseyLoggingFilter.class); return classes; } @PostConstruct public void init() { String cn = "org.apache.logging.log4j.jul.LogManager"; System.setProperty("java.util.logging.manager", cn); } } 
  2. 在实现ServletContextListener的类中更改日志管理器

     package com.ahoxha.context; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class ContextInitializer implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("Initializing context."); System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("Context destroyed."); } } 
  3. 除了上面的两个选项之外,我还尝试将日志管理器设置为static block (对于选项1和2)。

不幸的是,这些选项都不适用于我。 我想知道应该在哪里做。 有什么东西我不见了吗?

tomcatgretty等Web应用程序容器启动时, java.util.logging.LogManager类被初始化。 在加载时(在static block ),此类检查java.util.logging.manager系统属性的值并相应地创建Logger 。 初始化后,此类永远不会再次初始化。

因此,对于Web应用程序,通过Web应用程序代码设置此系统属性为时已晚。

一种可能的解决方案是将此系统属性值通过VM arguments传递给应用程序容器 –

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

在这种情况下,您必须在启动容器时提供log4j jar和配置文件,以便可以通过System ClassLoader加载org.apache.logging.log4j.ju‌​l.LogManager

对于tomcat,在3个jar子之后你必须加载bootstrap.jar (tomcat启动), tomcat-juli.jar (日志)以使其工作 –

 log4j-jul log4j-api log4j-core 

类似的方法也需要用于其他容器。

如果您无法或不允许更改容器的配置,这里有一个替代解决方案,对我有用。

初始化上下文时,删除JUL记录器具有的所有处理程序,然后添加您自己的自定义处理程序,您可以在其中使用首选日志记录框架。

这是一个例子:

 import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Logger; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @WebListener public class ContextInitializer implements ServletContextListener { Logger logger = Logger.getLogger(""); static final org.apache.logging.log4j.Logger log4jLogger = LogManager.getLogger(); @Override public void contextInitialized(ServletContextEvent sce) { for (Handler hanlder : logger.getHandlers()) { logger.removeHandler(hanlder); } logger.addHandler(new CustomHandler()); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("Context destroyed."); } private static class CustomHandler extends Handler { @Override public void publish(LogRecord record) { log4jLogger.log(CustomHandler.julToLog4jLevel(record.getLevel()), record.getMessage(), record.getThrown()); } /** * Converts the logging level according to [default level conversions](https://logging.apache.org/log4j/2.0/log4j-jul/index.html) */ private static Level julToLog4jLevel(java.util.logging.Level level) { if (level == java.util.logging.Level.WARNING) { return Level.WARN; } else if (level == java.util.logging.Level.SEVERE) { return Level.ERROR; } else if (level == java.util.logging.Level.INFO) { return Level.INFO; } else if (level == java.util.logging.Level.FINE) { return Level.DEBUG; } else if (level == java.util.logging.Level.FINER) { return Level.TRACE; } else if (level == java.util.logging.Level.FINEST) { return Level.ALL; } return null; } @Override public void flush() { } @Override public void close() throws SecurityException { } } } 

我相信“java.util.logging.LogManager”类初始化发生在系统属性更新之前。

因此,您可以使容器类加载器可以使用日志库,并使用环境变量或配置文件为整个容器配置此系统属性。