在一个 class 配置中设置 log4j.rootLogger=OFF,将导致另一个 class 中的日志崩溃

Setting log4j.rootLogger=OFF in one class configuration, will cause log crash in another class

在一个 class 配置中设置 log4j.rootLogger=OFF,将导致另一个 class 不登录。 我有两个示例 classes:LogCrasher 和 MainLogger。这两个 classes 被配置为记录一些测试日志。每个 class 都有自己的配置文件。从 MainLogger 调用了 LogCrasher。当LogCrashers log4j配置文件中的log4j.rootLogger设置为INFO, WARN... logging没有问题,但是如果我们设置为OFF,那么MainLogger就不会再输出日志了。 如何解决这个问题,将一个 class 记录器与另一个记录器隔离开来。

MainLogger.java

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class MainLogger {
    private static String LOG_PROPS = "mainlogger.properties";
    final static Logger logger = Logger.getLogger(MainLogger.class);

    static {
        PropertyConfigurator.configureAndWatch(LOG_PROPS);
    }

    public static void main(String[] args) {
        MainLogger mainLogger = new MainLogger();
        try {
            mainLogger.doLogging();
        } catch (Throwable t) {
            logger.error(t.getMessage(), t);
        }
    }

    public void doLogging() {
        logger.info("Before calling log crasher.");
        printTestLog();

        new Thread(new Runnable() {

            @Override
            public void run() {
                LogCrasher logCrasher = new LogCrasher();
                logCrasher.printTestLog();
            }
        }).start();

        logger.info("After calling log crasher.");

        printTestLog();
    }

    private void printTestLog() {
        int counter = 0;
        while (++counter < 5) {
            logger.info("Counter: " + counter);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.info("printTestLog sleeper thread interupted: " + e.getMessage());
            }
        }
    }
}

LogCrasher.java

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class LogCrasher {
    private static String LOG_PROPS = "logcrasher.properties";
    final static Logger logger = Logger.getLogger(LogCrasher.class);

    static {
        PropertyConfigurator.configureAndWatch(LOG_PROPS);
    }

    public void printTestLog() {
        int counter = 0;
        while (++counter < 5) {
            logger.info("Counter: " + counter);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.info("printTestLog sleeper thread interupted: " + e.getMessage());
            }
        }
    }
}

logcrasher.properties

# Root logger option
log4j.rootLogger=OFF, stdout, file

# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Rirect log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=logcrasher.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

mainlogger.properties

# Root logger option
log4j.rootLogger=INFO, stdout, file

# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Rirect log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=mainlogger.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

log4 framework 使用 factory/singleton 方法...因此如果您在 1 class 中重新加载新的 config,则所有 class同样 class loader 应该看到 config 就好像它是 1 true live config.

您需要做的是在 package/class 级别封装您需要的日志记录行为,您将在调用 Logger.getLogger() 时看到效果。使用较新版本的 apache log4j,您可以使用 no args 调用 LogManger.getLogger() 以获取 current class 的记录器(使其易于在所有 class 文件中定义).

然后因为你可以有一系列不同的 loggersappenders,以及设置附加程序通过不同的记录器级联,你不应该需要超过 1 个配置文件。

希望对您有所帮助!

您不能像这样定义 2 个 log4j 属性文件。 Log4j 框架将只加载并考虑一个,它将首先在 class 路径中找到。

现在对于您的问题的解决方案部分,您不能像这样在 class 级别有单独的日志记录方案,但您可以在包级别有单独的日志记录方案。
现在考虑到你的 2 classes 在不同的包中,你可以有你的 log4j.properties 如下。
log4j.logger.com.Whosebug.meta 将应用于 com.Whosebug.meta 包中的所有 classes,log4j.logger.com.Whosebug.code 将应用于 com.Whosebug.code 包中的所有 classes。

像这样,您现在可以控制包级别的日志记录。

log4j.logger.com.Whosebug.meta=OFF, file, stdout
log4j.logger.com.Whosebug.code=DEBUG, file, stdout

# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Rirect log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=mainlogger.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n