所以我们使用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。所以这可能是突然崩溃的原因。
答案 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 thread或JMX。这两种方法都避免了因调用PropertyConfigurator.configureandWatch()或DOMConfigurator.configurator而导致的麻烦。同样有趣的是,通过配置文件启用了线程方法(不需要自定义代码)。
答案 3 :(得分:0)
所有记录器共享相同的配置文件,因此如果每个使用记录器的类都包含此初始化代码,则每个configureAndWatch()调用都可能产生一个新的观察者线程。 (恕我直言,Log4j应该知道更好,并允许每个配置文件最多一个观察者线程,但显然它没有)