以编程方式配置 Log4j 记录器

2022-08-31 06:19:24

我第一次尝试使用SLF4J(带绑定)。log4j

我想配置3个不同的命名记录器,这些记录器可以由LoggerFactory返回,它将记录不同的级别并将消息推送到不同的追加器:

  • 记录器 1 “文件记录器” 记录调试并附加到DailyRollingFileAppender
  • 记录器 2 “跟踪记录程序”记录 TRACE+并追加到JmsAppender
  • 记录器3“错误记录器”记录错误+并附加到不同的JmsAppender

此外,我希望它们以编程方式配置(在Java中,而不是XML或文件)。log4j.properties

我想,通常情况下,我会在一些引导代码中的某个地方定义这些,就像一个方法一样。但是,因为我想使用 ,所以我对在哪里可以定义记录器并使其可用于类路径感到困惑。Loggerinit()slf4j-log4j

我不认为这违反了SLF4J的基本目的(作为门面),因为我使用SLF4J API的代码永远不会知道这些记录器的存在。我的代码只是对SLF4J API进行正常调用,然后将其转发到它在类路径上找到的log4j记录器。

但是我如何在类路径上配置这些log4j记录器...在爪哇?!


答案 1

您可以通过编程方式向 Log4j 添加/删除追加器:

  ConsoleAppender console = new ConsoleAppender(); //create appender
  //configure the appender
  String PATTERN = "%d [%p|%c|%C{1}] %m%n";
  console.setLayout(new PatternLayout(PATTERN)); 
  console.setThreshold(Level.FATAL);
  console.activateOptions();
  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(console);

  FileAppender fa = new FileAppender();
  fa.setName("FileLogger");
  fa.setFile("mylog.log");
  fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
  fa.setThreshold(Level.DEBUG);
  fa.setAppend(true);
  fa.activateOptions();

  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(fa);
  //repeat with all other desired appenders

我建议你把它放在一个init()的某个地方,你确信,这将在其他任何事情之前执行。然后,您可以使用以下命令删除根记录器上的所有现有追加器

 Logger.getRootLogger().getLoggerRepository().resetConfiguration();

并从添加自己的开始。当然,您需要在类路径中使用log4j才能正常工作。

备注:
您可以采取任何您喜欢的添加附加器。我只是采用了根记录器,因为它位于所有事物的底部,并且将处理通过其他类别中的其他追加器传递的所有内容(除非通过设置加性标志以其他方式配置)。Logger.getLogger(...)

如果您需要了解日志记录的工作原理以及如何确定日志的写入位置,请阅读本手册以获取有关该内容的更多信息。
总之:

  Logger fizz = LoggerFactory.getLogger("com.fizz")

将为您提供“com.fizz”类别的记录器。
对于上面的示例,这意味着使用它记录的所有内容都将引用到根记录器上的控制台和文件追加器。
如果您将追加器添加到 Logger.getLogger(“com.fizz”).addAppender(newAppender),则来自 的记录将由来自根记录器和 .
您不会使用配置创建记录器,只需为系统中所有可能的类别提供处理程序即可。fizznewAppender


答案 2

这听起来像是你试图从“两端”(消费者端和配置端)使用log4j。

如果你想针对slf4j api进行编码,但提前(和编程方式)确定类路径将返回的log4j Loggers的配置,你绝对必须有某种利用惰性构造的日志记录适应。

public class YourLoggingWrapper {
    private static boolean loggingIsInitialized = false;

    public YourLoggingWrapper() {
        // ...blah
    }

    public static void debug(String debugMsg) {
        log(LogLevel.Debug, debugMsg);
    }

    // Same for all other log levels your want to handle.
    // You mentioned TRACE and ERROR.

    private static void log(LogLevel level, String logMsg) {
        if(!loggingIsInitialized)
            initLogging();

        org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger("DebugLogger");

        switch(level) {
        case: Debug:
            logger.debug(logMsg);
            break;
        default:
            // whatever
        }
    }

    // log4j logging is lazily constructed; it gets initialized
    // the first time the invoking app calls a log method
    private static void initLogging() {
        loggingIsInitialized = true;

        org.apache.log4j.Logger debugLogger = org.apache.log4j.LoggerFactory.getLogger("DebugLogger");

        // Now all the same configuration code that @oers suggested applies...
        // configure the logger, configure and add its appenders, etc.
        debugLogger.addAppender(someConfiguredFileAppender);
    }

使用这种方法,您无需担心在何处/何时配置log4j记录器。当类路径第一次请求它们时,它们会被懒惰地构建,传递回去并通过slf4j提供。希望这有帮助!


推荐