简体   繁体   English

动态重新加载log4j.properties以在tomcat中运行的grails应用程序

[英]Dynamically reload log4j.properties for grails application running in tomcat

I have a grails application, deployed to tomcat, that is using log4j. 我有一个grails应用程序,已部署到tomcat,使用的是log4j。 I would like to be able to update /webapps/WEB-INF/classes/log4j.properties in tomcat, and then have the application dynamically pickup the changes without requiring a restart. 我希望能够在tomcat中更新/webapps/WEB-INF/classes/log4j.properties,然后让应用程序动态地获取更改而无需重新启动。 I haven't had any luck finding a good way to do this. 我还没有运气找到这样做的好方法。 What I have figured out is: 我发现的是:

I can retrieve a file as a stream: 我可以将文件作为流检索:

Thread.currentThread().getContextClassLoader().getResourceAsStream("log4j.properties")

Unfortunately this is the class loaded during startup, and I'm not sure if/how I can force it to update from the actual file. 不幸的是,这是启动期间加载的类,我不确定是否/如何强制其从实际文件中更新。 If that worked I could read each property and use: 如果可行,我可以阅读每个属性并使用:

Logger.rootLogger.loggerRepository.getLogger(<key>).level = <new log level>

I've seen things about LogManager.resetConfiguration() but that doesn't seem to help either. 我已经看到了有关LogManager.resetConfiguration()但这似乎也无济于事。

Also, this is how I setup log4j in resources.groovy 另外,这就是我在resources.groovy设置log4j的方式

beans = {
    // Setting up external configuration for log4j
    log4jConfigurer(org.springframework.beans.factory.config.MethodInvokingFactoryBean) {
        targetClass = "org.springframework.util.Log4jConfigurer"
        targetMethod = "initLogging"
        arguments = ["classpath:log4j.properties"]
    }
}

I'm not interested in using the configureAndWatch approach as I've read about its vulnerabilities. 当我了解它的漏洞时,我对使用configureAndWatch方法不感兴趣。

I see that there are XML and JSON properties you can use for log4j, and I'm just using a plain *.properties file, and I'm not sure if that is part of the problem. 我看到有可以用于log4j的XML和JSON属性,而我只是使用一个普通的* .properties文件,我不确定这是否是问题的一部分。

Any tips would be greatly appreciated, thanks in advance! 任何提示将不胜感激,在此先感谢!

The following is what I did to get around this issue, it required setUseCaches(false), to make sure that cached versions of a file (from the classloader) were not used. 以下是解决此问题的方法,它需要setUseCaches(false),以确保未使用文件的缓存版本(来自类加载器)。

def fileInputStream = null
// The method below is used to ensure that the file is read from disk every time, rather than using the previously loaded file from the ClassLoader
def classLoader = Thread.currentThread().getContextClassLoader()
def resource = classLoader.getResource("log4j.properties")
def connection = resource.openConnection()
connection.setUseCaches(false)
// Warning: do not read or log the fileInputStream, because it will close the connection
fileInputStream = (FileInputStream)connection.getInputStream().in
// Use the Properties object to prevent errors on comments (#)
def props = new Properties()
props.load(fileInputStream)
def config = new ConfigSlurper().parse(props)

Then I can reference logger properties using: 然后,我可以使用以下方式引用记录器属性:

config.log4j.logger.each {
    Logger.rootLogger.loggerRepository.getLogger(it.key).level = Level.toLevel(it.value)
}

You can also make checks to see what the existing log levels are and provide output to state which logging has actually changed. 您还可以进行检查以查看现有的日志级别是什么,并提供输出以表明实际更改了哪些日志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM