Log4j configureAndWatch()产生了数千个线程

时间:2009-08-26 21:57:41

标签: java java-ee log4j

所以我们使用Log4j这样的J2EE应用程序

public class CustomerController 
{
    private static Logger logger = Logger.getLogger(CustomerController.class);

     public CustomerService customerservice = null;

     public CustomerController() throws Exception 
     {
           PropertyConfigurator.configureAndWatch("c:\log4j.property", 50000);

            customerservice = ServiceManagerSingleton.getCustomerServiceInstance();
     }
}

这样我们就可以改变日志级实时。非常便利。我们的大多数类都像这个控制器一样设置。我们使用单例模式,这样我们只有一个eash类的实例;一次调用每个类的PropertyConfigurator.configureAndWatch()。

问题:我们的appserver每周大约两次死亡并创建一个堆转储。使用IBM的Heap Analyzer,我们可以看到似乎有很多与Log4j相关的线程:

 808 (0%) [200] 9 org/apache/log4j/PropertyWatchdog 0x14282ad8

总共约30,000。所以这可能是突然崩溃的原因。

  1. 我们是否正确设置了这个?
  2. 重新部署EAR时,所有这些线程会发生什么?

4 个答案:

答案 0 :(得分:7)

CustomerController实例的创建频率是多少?每次请求一次?因为我相信configureAndWatch()会在每次调用时产生一个新线程。

另外,如果您不了解,J2EE环境中的the log4j docs caution against using this feature

  

因为configureAndWatch启动了一个单独的wathdog线程,并且因为无法在log4j 1.2中停止此线程,所以configureAndWatch方法在应用程序被回收的J2EE环境中使用是不安全的。

我知道你没有使用Spring,但在我看来,Spring类Log4jWebConfigurer has a better explanation关于为什么这个特性在J2EE中是危险的:

  

警告: Log4j的监视程序线程在VM关闭之前不会终止;特别是,它不会在LogManager关闭时终止。因此,建议不要在生产J2EE环境中使用配置文件刷新;监视程序线程不会在应用程序关闭时停止。

更新:查看log4j来源,每次调用configureAndWatch()确实create a new thread

答案 1 :(得分:4)

您真正需要做的是使用应用程序服务器的启动过程(它们都不同)来初始化log4j系统。因为Log4j依赖于静态变量,所以它本身并不能独立工作(它可以,但这实际上取决于应用服务器)。在大多数情况下,整个应用程序服务器的配置确实是全局的。

您需要确保只调用一次PropertyConfigurator.configureAndWatch方法。一种方法是在JNDI中放置一些东西。

这很大程度上取决于应用服务器给你的东西。例如,我们使用JBoss,并将Log4J配置为其中的一部分,您只需更改log4j.xml文件以包含您的类所需的内容。 JBoss确保它是动态完成的。

编辑:Here是Websphere创建自定义服务的说明,在其中您将创建log4J配置,并对文件进行监控。几个警告。您将不得不将log4j.jar添加到应用程序服务器本身的类路径中,以便它可用于战争或耳朵(我确信无论如何都可以使用),并且自定义服务可能不会在耳边工作。

Here是一种替代方案,可以将所有内容保留在战争或耳中,但代价是动态加载日志更改。

答案 2 :(得分:0)

你看过logback,log4j后继吗?它处理重新加载其配置in threadJMX。这两种方法都避免了因调用PropertyConfigurator.configureandWatch()或DOMConfigurator.configurator而导致的麻烦。同样有趣的是,通过配置文件启用了线程方法(不需要自定义代码)。

答案 3 :(得分:0)

所有记录器共享相同的配置文件,因此如果每个使用记录器的类都包含此初始化代码,则每个configureAndWatch()调用都可能产生一个新的观察者线程。 (恕我直言,Log4j应该知道更好,并允许每个配置文件最多一个观察者线程,但显然它没有)