【问题标题】:Log4j2: Dynamic creation of log files for multiple logsLog4j2:为多个日志动态创建日志文件
【发布时间】:2013-09-27 13:30:37
【问题描述】:

我目前正在创建一个可以包含模块(将它们视为插件)的系统,其中每个模块都可以有自己的专用日志。

我想使用 log4j2 项目进行日志记录,但文件附加程序似乎有些问题。

主项目(模块加载器和整个项目的“核心”)应该有自己的日志文件,而模块应该有自己的日志文件(如mod_XXXXXXXX.log)。

通过阅读有关 appenders 的文档,我发现了 FileAppender 类,我打算使用它。直到我发现我不能简单地将 appender 添加到 LogManager.getLog() 创建的默认记录器中。

LogManager 返回的记录器与Logger 接口不同。

即使搜索也没有给我任何接近的解决方案,我发现的只是 xml 配置中的预定义文件日志——这不是我想要的。

感谢您的阅读;即使是最轻微的线索也是受欢迎的:)

【问题讨论】:

    标签: java logging log4j log4j2


    【解决方案1】:

    如果你真的需要动态确定日志文件,看看 Log4J2 RoutingAppenderFAQ 中有一个更长的示例,这些 stackoverflow 问题可能很有趣: Wildcard pattern for RoutingAppender of Log4j2How to write different logs in different files with log4j2 (MDC in xml)?

    请注意,您需要在 ThreadContext 映射中设置值,RoutingAppender 使用该映射来决定将日志事件路由到哪个附加程序。这意味着每次您的代码进入不同的插件时,您都需要在 ThreadContext 映射中添加一些值。

    但是,您真的需要它如此动态吗?如果你事先知道你有什么插件,你可以为每个插件声明一个记录器(使用插件的包名是一种常用的方法),并将每个这样的记录器映射到一个单独的附加程序。

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn" name="MyApp" packages="">
      <Appenders>
        <File name="MyFile" fileName="logs/app.log">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
        </File>
        <File name="plugin1" fileName="logs/plugin1.log">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
        </File>
        <File name="plugin2" fileName="logs/plugin2.log">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
          </PatternLayout>
        </File>
      </Appenders>
      <Loggers>
        <Logger name="com.mycomp.project.plugin1" level="debug">
          <AppenderRef ref="plugin1" level="debug" />
        </Logger>
        <Logger name="com.mycomp.project.plugin2" level="debug">
          <AppenderRef ref="plugin2" level="debug" />
        </Logger>
        <Root level="trace">
          <AppenderRef ref="MyFile" level="trace" />
        </Root>
      </Loggers>
    </Configuration>
    

    【讨论】:

    • 是否必须将包名称赋予记录器的属性名称。如果这些类在不同的包中怎么办。需要帮助,因为我需要特定流程的日志。 stackoverflow.com/questions/43586574/…
    • 不是强制性的,但很多人这样做,因为它允许您为包中的所有内容配置日志级别,这可能是有用的。
    • 添加 additivity="false" 到记录器插件 1 和插件 2 仍然日志被写入 app.log。我在这里错过了什么?
    • 发现错误。注意:我已经分别用 plug1 和 plug2 替换了包名。正在做 Logger adminLog = LogManager.getLogger("plug1"+Example.class);而不是 Logger adminLog = LogManager.getLogger("plug1");现在需要弄清楚如何在日志中打印类名。任何帮助表示赞赏。
    【解决方案2】:

    我假设您希望您的模块管理代码定义记录器配置,对吗?如果是这样,您可能需要查看手册的这一部分,该部分讨论了扩展 LoggerConfig,它基于您的要求是我认为您正在寻找的内容。

    http://logging.apache.org/log4j/2.x/manual/extending.html

    不管怎样,我之前曾参与过大型基于插件的系统(使用 OSGi),但老实说,我们没有走这条路。从单个日志文件中 grep 您感兴趣的类或包通常更容易。

    【讨论】:

      【解决方案3】:

      尽管 Remko Popma 的回答可能是进行日志记录的最有效方法,但我构建了一个可以自行创建日志文件的小类。

      我想我会使用公认答案的解决方案,所以这是我为解决 XML 文件问题而编写的代码:

      import gnu.trove.map.hash.THashMap;
      import org.apache.logging.log4j.Level;
      import org.apache.logging.log4j.core.Logger;
      import org.apache.logging.log4j.core.LoggerContext;
      import org.apache.logging.log4j.core.appender.FileAppender;
      import org.apache.logging.log4j.core.async.AsyncLoggerContext;
      import org.apache.logging.log4j.core.layout.PatternLayout;
      import org.apache.logging.log4j.message.FormattedMessageFactory;
      import org.apache.logging.log4j.message.MessageFactory;
      
      import java.io.File;
      import java.io.IOException;
      import java.util.Map;
      
      /**
       * Represents a manager for custom log files stored inside a log folder.
       */
      public class LoggingManager {
          /** The default log file extension */
          public static final String FILE_EXTENSION = "log";
      
          /** The global context used for all loggers */
          private final LoggerContext context;
      
          /** The global message factory used for all loggers */
          private final MessageFactory msgFactory;
      
          /** A map of all created logs */
          private final Map<String, Logger> logCache;
      
          /** The folder containing the log files */
          private final File logFolder;
      
      
          public LoggingManager(String name, File logFolder) throws IOException {
              this.logFolder = logFolder;
      
              if(!logFolder.exists()) {
                  if(!logFolder.mkdirs()) {
                      throw new IOException("Could not create log folder");
                  }
              }
      
              this.logCache = new THashMap<String, Logger>();
      
              // Create logger context
              this.context = new AsyncLoggerContext(name);
      
              // Create formatted message factory
              this.msgFactory = new FormattedMessageFactory();
          }
      
          public Logger getLogger(String name) {
              Logger logger = logCache.get(name);
      
              // Create a new one
              if(logger == null) {
                  logger = new SimpleLogger(name);
      
                  FileAppender appender = FileAppender.createAppender(
                          new File(logFolder, name + "." + FILE_EXTENSION).getAbsolutePath(),
                          "true",
                          "false",
                          "file_appender-" + name,
                          "true",
                          "false",
                          "true",
                          PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, null, null, "UTF-8", "true"),
                          null,
                          "false",
                          null,
                          null
                  );
      
                  appender.start();
                  logger.getContext().getConfiguration().getLoggerConfig("root").addAppender(appender, Level.ALL, null);
      
                  // Add to log cache
                  logCache.put(name, logger);
              }
      
              // Return the logger
              return logger;
          }
      
          private class SimpleLogger extends Logger {
      
              public SimpleLogger(String name) {
                  super(context, name, msgFactory);
      
                  // Set to all levels
                  this.setLevel(Level.ALL);
              }
      
          }
      
      }
      

      如果您不使用trove,您可以根据需要将其替换为普通的java HashMap

      【讨论】:

      • 这是否回答了这个问题>?动态创建日志文件?
      猜你喜欢
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-10
      • 1970-01-01
      相关资源
      最近更新 更多