4

一些Log4j配置器有一个configureAndWatch()方法,它启动一个线程来监视用于配置的文件(XML文件或properties文件)并在文件更改时触发重新配置。

但是,如果您依赖Log4j 默认初始化过程,您将永远没有机会调用configureAndWatch(). 您甚至不知道用于配置的文件(它甚至可能不是文件。)

是否有一种获得configureAndWatch()样式行为的好方法,允许动态更改日志配置,同时仍使用默认初始化过程?我假设您的配置 URL 最终解析为可以观看的文件,因为另一台服务器上的 URL 可能不是您希望每60 秒提取一次的内容。

(我看到这个方法在Java EEconfigureAndWatch()环境中是不安全的, 因为是单独的线程,我看到一些应用服务器有自己的机制来查看配置文件,但是我现在正在处理的程序没有运行在Java EE中。)log4j

4

3 回答 3

9

我之前已经放弃了答案中的所有内容,现在重新开始,因为我更好地理解了你想要什么。

以下段落描述了 log4j 用来确定 log4j 配置文件名的真实顺序。此代码尝试遵循这些规则。

http://logging.apache.org/log4j/1.2/manual.html#defaultInit

它确定要使用的 log4j 配置文件,然后使用它找到的文件设置 PropertyConfigurator。这仅在文件位于文件系统上时才有效。如果文件在 jar 中或在远程 HTTP URL 上,它将不起作用。

    String prop = System.getProperty("log4j.configuration");
    if (prop == null) prop = "log4j.properties";
    URL log4jConfig = Loader.getResource(prop);
    if (log4jConfig.getProtocol().equalsIgnoreCase("file")) {
        PropertyConfigurator.configureAndWatch(log4jConfig.getFile().substring(1), 10000);
    }
    else {
        // cannot monitor if file changed because URL is not a file
    }
于 2012-08-30T15:26:25.327 回答
2

但是,如果您依赖 Log4j默认初始化过程,您将永远没有机会调用 configureAndWatch()。您甚至不知道用于配置的文件(它甚至可能不是文件。)

您已经发布了一些我已经在[1][2]中回答的相关问题,所以这个答案是建立在其他人的解释之上的。同样,我正在使用 AspectJ:

示例应用程序类:

import org.apache.log4j.Logger;

public class Log4jDemo {
    private static Logger logger = Logger.getLogger("scrum-master.de");

    public static void main(String[] args) throws InterruptedException {
        while (true) {
            logger.info("Log message");
            Thread.sleep(2000);
        }
    }
}

方面捕获默认 URL 并将其移交给configureAndWatch

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.aspectj.lang.SoftException;

public aspect Log4jAspect {
    after(URL defaultURL) returning :
        within(LogManager) &&
        cflow(staticinitialization(LogManager)) &&
        call(* OptionConverter.selectAndConfigure(URL, ..)) &&
        args(defaultURL, ..)
    {
        try {
            PropertyConfigurator.configureAndWatch(new File(defaultURL.toURI()).getAbsolutePath(), 2000);
        } catch (URISyntaxException e) {
            throw new SoftException(e);
        }
    }
}

我使用 Eclipse 对其进行了测试,在log4j.properties-Dlog4j.configDebug=true中将输出通道从System.log(Eclipse 控制台中的黑色)更改为System.err(红色,此处不可见),并且效果很好。在日志输出中,您还可以看到检测到文件更改后重新配置的调试信息:

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@f4a24a.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@f4a24a class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@f4a24a.
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:20,944  INFO de:10 - Log message
17:48:22,944  INFO de:10 - Log message
17:48:24,944  INFO de:10 - Log message
17:48:26,944  INFO de:10 - Log message
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:28,944  INFO de:10 - Log message
17:48:30,944  INFO de:10 - Log message
17:48:32,944  INFO de:10 - Log message
17:48:34,944  INFO de:10 - Log message
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.err].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
17:48:36,944  INFO de:10 - Log message
17:48:38,944  INFO de:10 - Log message
于 2012-08-31T15:49:46.670 回答
0

在使用默认记录器和附加程序之前,我已经这样做了。您将不得不编写一个单独的处理程序来观察属性文件的修改。当发生更改时,只需重置您的记录器并重新添加附加器设置:

/**
 * Setup log4j appender.
 */
public static void setupLog4jAppender(Class appender) {
    getLogger();

    String rootLogger=(String)props.get("log4j.rootLogger");
    rootLogger+=",appname";
    getProps().setProperty("log4j.rootLogger", rootLogger);

    getProps().put("log4j.appender.appname", appender.getName());  // Our custom appender
    getProps().put("log4j.appender.appname.layout", "org.apache.log4j.PatternLayout"); 
    //See: http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html
    getProps().put("log4j.appender.appname.layout.ConversionPattern", "%d{ABSOLUTE} %5p %c{1}:%L - %m%n");

    LogManager.resetConfiguration();
    PropertyConfigurator.configure(getProps());
}
于 2012-08-30T15:59:01.037 回答