以编程方式配置Log4j记录器


189

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

我想配置3个不同的命名Logger,它们可以由LoggerFactory返回,LoggerFactory将记录不同的级别并将消息推送到不同的附加程序:

  • 记录器1“ FileLogger”记录调试并附加到 DailyRollingFileAppender
  • 记录器2“ TracingLogger”记录TRACE +并附加到 JmsAppender
  • 记录器3“ ErrorLogger”记录ERROR +并追加到其他记录器 JmsAppender

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

我想通常,我会Logger在一些自举代码中的某处(如init()方法)定义这些。但是,因为我想使用slf4j-log4j,所以对于在哪里定义记录器并使它们可用于类路径感到困惑。

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

但是,如何在Java中的类路径上配置这些log4j Logger?



3
对于log4j 1.x,请使用下面针对2.x的公认答案,请参阅logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Answers:


277

您可以通过编程将Appender添加/删除到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),fizz则将从根记录器和的所有附加器处理日志记录newAppender
您无需使用配置创建Logger,而只是为系统中所有可能的类别提供处理程序。


2
谢谢大家!快速问题-我注意到您正在将追加程序添加到根Logger。是否有一个原因?
IAmYourFaja 2012年

而且,更重要的是,我需要指定从SLF4J的LoggerFactory检索哪个Logger。是否可以向SLF4J询问log4j的根记录器?
IAmYourFaja 2012年

3
@AdamTannon您可以选择任何喜欢的Logger.getLogger(...)。我之所以选择了root logger,是因为它位于所有内容的底部,并且将处理通过其他类别中的其他Appender传递的所有内容(除非另有配置)。查看记录器层次结构
2012年

@AdamTannon,您不能使用sl4j工厂获取log4j根记录器。SL4j是伐木的门面。您不会从中获得任何log4j特定的东西。
oers 2012年

2
业主-非常感谢您的宝贵意见,但这里没有列出所有问题。您是否可以修改示例以显示添加了新的Logger(而不是root记录器),一旦将其添加到系统中,其他任何要求它的类都可以使用?例如,通常由“ Logger fizz = LoggerFactory.getLogger("com.fizz");谢谢!” 访问的记录器。
IAmYourFaja 2012年

47

听起来您正在尝试从“两端”(使用者端和配置端)使用log4j。

如果要针对slf4j api进行编码,但要提前(并以编程方式)确定classpath将返回的log4j Logger的配置,则绝对必须具有某种利用惰性构造的日志记录适配。

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提供。希望这对您有所帮助!


2
搞定了!非常感谢您提供了有用的示例!@Oers-谢谢您试图引导我朝正确的方向前进-我将为您的奉献提供绿色的支票,但必须给予zharvey赏金,因为这正是我在寻找的东西。再次感谢大家!
IAmYourFaja 2012年

4

如果您已在log4j属性中定义了一个追加器,并希望以编程方式对其进行更新,请在log4j属性中设置名称并按名称获取它。

这是一个示例log4j.properties条目:

log4j.appender.stdout.Name=console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO

要更新它,请执行以下操作:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);

1

如果有人希望使用Java以编程方式配置log4j2,则此链接可能会有所帮助:(https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class

以下是配置控制台附加程序的基本代码:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

builder.setStatusLevel(Level.DEBUG);
// naming the logger configuration
builder.setConfigurationName("DefaultLogger");

// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
// add a layout like pattern, json etc
appenderBuilder.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d %p %c [%t] %m%n"));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
rootLogger.add(builder.newAppenderRef("Console"));

builder.add(appenderBuilder);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());

这将重新配置默认的rootLogger,还将创建一个新的appender

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.