Log4j2:动态创建多个日志的日志文件

时间:2013-09-27 13:30:38

标签: java logging log4j log4j2

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

我想使用log4j2项目进行日志记录,但我似乎对文件追加器有些麻烦。

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

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

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

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

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

3 个答案:

答案 0 :(得分:9)

如果您确实需要动态确定日志文件,请查看Log4J2 RoutingAppender。更长的例子是FAQ,这些stackoverflow问题可能会引起关注: Wildcard pattern for RoutingAppender of Log4j2How to write different logs in different files with log4j2 (MDC in xml)?

请注意,您需要在ThreadContext映射中设置RoutingAppender用于决定将日志事件路由到哪个appender的值。这意味着每次代码进入不同的插件时,您需要在ThreadContext映射中放置一些值。

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

<?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>

答案 1 :(得分:0)

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

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

为了它的价值,我之前(使用OSGi)参与了大型基于插件的系统,我们老老实实没有采取这种方式。从单个日志文件中获取您感兴趣的类或包通常更容易。

答案 2 :(得分:0)

尽管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