我目前正在创建一个可以拥有模块的系统(将它们视为插件),其中每个模块都可以拥有自己的专用日志。
我想使用log4j2项目进行日志记录,但我似乎对文件追加器有些麻烦。
主项目(模块加载器和整个事物的“核心”)应该有自己的日志文件,而模块应该有自己的(如mod_XXXXXXXX.log
)。
通过阅读有关appender的文档,我发现了FileAppender
类,我将使用它。直到我发现我不能简单地将appender添加到LogManager.getLog()
创建的默认记录器中。
LogManager返回的记录器是与Logger
接口不同的记录器。
即使搜索也没有给我任何接近的解决方案,我发现只是xml配置中的预定义文件日志 - 这不是我想要的。
感谢您的阅读;即使是最轻微的线索也是受欢迎的。)
答案 0 :(得分:9)
如果您确实需要动态确定日志文件,请查看Log4J2 RoutingAppender。更长的例子是FAQ,这些stackoverflow问题可能会引起关注: Wildcard pattern for RoutingAppender of Log4j2 和How 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
。