【问题标题】:Log4j configureAndWatch() spawning thousands of threadsLog4j configureAndWatch() 产生数千个线程
【发布时间】:2010-11-23 04:34:52
【问题描述】:

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

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()。

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

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

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

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

【问题讨论】:

    标签: java jakarta-ee log4j


    【解决方案1】:

    你看过 logback,log4j 的继任者吗?它处理in thread 或通过JMX 重新加载其配置。这两种方法都避免了调用 PropertyConfigurator.configureandWatch() 或 DOMConfigurator.configurator 带来的麻烦。同样有趣的是,线程内方法通过配置文件启用(无需自定义代码)。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 这是不正确的。查看 log4j 源代码,每次调用 configureAndWatch() 都会创建一个线程。
      【解决方案3】:

      CustomerController 实例多久创建一次?每个请求一次?因为我相信 configureAndWatch() 每次调用都会产生一个新线程。

      另外,如果您不知道,the log4j docs caution against using this feature 在 J2EE 环境中:

      由于 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

      【讨论】:

      • 不,它只创建一次。我想在 J2EE 中线程通常不可用是有原因的......
      【解决方案4】:

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

      您需要确保 PropertyConfigurator.configureAndWatch 方法只被调用一次。一种方法是在 JNDI 中添加一些内容。

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

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

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

      【讨论】:

      • 你用的是什么应用服务器?
      • 我看不出这将如何解决我们试图实现的实时更新。 customeService 只是一个在服务器启动时运行的类。
      • 您可以进行配置和观看,CustomService 确保它只运行一次。
      猜你喜欢
      • 2022-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      相关资源
      最近更新 更多