[英]Log4j2: Dynamic creation of log files for multiple logs
我目前正在创建一个可以包含模块(将它们视为插件)的系统,其中每个模块都可以有自己的专用日志。
我想使用 log4j2 项目进行日志记录,但我似乎在使用文件附加程序时遇到了一些问题。
主项目(模块加载器和整个事情的“核心”)应该有自己的日志文件,而模块应该有自己的(如mod_XXXXXXXX.log
)。
通过阅读有关 appenders 的文档,我发现了FileAppender
类,我打算使用它。 直到我发现我不能简单地将附加程序添加到由LogManager.getLog()
创建的默认记录器中。
LogManager 返回的记录器与Logger
接口是不同的记录器。
即使搜索也没有给我任何接近的解决方案,我发现的只是 xml 配置中的预定义文件日志——这不是我想要的。
感谢您的阅读; 即使是最轻微的线索也是受欢迎的:)
如果您确实需要动态确定日志文件,请查看Log4J2 RoutingAppender 。 一个较长的示例在常见问题解答中,这些 stackoverflow 问题可能很有趣: Log4j2 的 RoutingAppender 的通配符模式和如何使用 log4j2(xml 中的 MDC)在不同的文件中写入不同的日志?
请注意,您需要在 RoutingAppender 用来决定将日志事件路由到哪个附加程序的ThreadContext
映射中设置值。 这意味着每次您的代码进入不同的插件时,您都需要在 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>
我假设您希望您的模块管理代码定义记录器配置,对吗? 如果是这样,您可能需要查看手册的这一部分,该部分讨论了扩展 LoggerConfig,它根据您的要求是我认为您正在寻找的。
http://logging.apache.org/log4j/2.x/manual/extending.html
值得一提的是,我之前曾参与过基于大型插件的系统(使用 OSGi),而且老实说,我们还没有走这条路。 从单个日志文件中 grep 您感兴趣的类或包通常更容易。
尽管 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
。
***** Creating Dynamic Multiple Log Files using RoutingAppender and
RollingFileAppender based on MDC *****
1) In the below file I am creating the three files dynamically
a) specialspecial.log
b) rollingtest.log
c) Queue.Name.log
Note: we can create as many as you want just need change the keyname
like ThreadContext.remove("keyname"); //removing previous key
ThreadContext.put("keyname","fileNameWithPath") //adding new file
log.info("Message"); //now onwards log the messages into above file
2) I have added the IdlePurgePolicy( 1min) - if the log events are not coming for 1 min then
it released all resources attached with the appender and deletes the dormant appender
and after deleting the appender if again log event is coming then it
will create the new appender and log the messages into our desired file
I have created my own and tested working fine in debug mode
---------------------------------------------------------------------------------------
log4j2.properties
status=debug
name=PropertiesConfig
filter.threshold.type=ThresholdFilter
filter.threshold.level=debug
appenders=routing
appender.routing.type=Routing
appender.routing.name=Routing
appender.routing.purge.type=IdlePurgePolicy
appender.routing.purge.timeToLive=1
appender.routing.purge.timeUnit=minutes
appender.routing.routes.type=Routes
appender.routing.routes.pattern=$${ctx:keyname}
appender.routing.routes.route.type=Route
appender.routing.routes.route.rolling.type=RollingFile
appender.routing.routes.route.rolling.name=RollingFile
appender.routing.routes.route.rolling.fileName=${ctx:keyname}.log
appender.routing.routes.route.rolling.filePattern=${ctx:keyname}-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.routing.routes.route.rolling.layout.type=PatternLayout
appender.routing.routes.route.rolling.layout.pattern=%m%n
appender.routing.routes.route.rolling.policies.type=Policies
#appender.routing.routes.route.rolling.policies.time.type=TimeBasedTriggeringPolicy
#appender.routing.routes.route.rolling.policies.time.interval=2
#appender.routing.routes.route.rolling.policies.time.modulate=true
appender.routing.routes.route.rolling.policies.size.type=SizeBasedTriggeringPolicy
appender.routing.routes.route.rolling.policies.size.size=1KB
appender.routing.routes.route.rolling.strategy.type=DefaultRolloverStrategy
appender.routing.routes.route.rolling.strategy.max=5
appender.routing.routes.route2.type=Route
appender.routing.routes.route2.key=P:/TestLogging/specialspecial
#appender.routing.routes.route.ref=Routes
appender.routing.routes.route2.rolling.type=RollingFile
appender.routing.routes.route2.rolling.name=RollingFile
appender.routing.routes.route2.rolling.fileName=${ctx:keyname}.log
appender.routing.routes.route2.rolling.filePattern=${ctx:keyname}-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.routing.routes.route2.rolling.layout.type=PatternLayout
appender.routing.routes.route2.rolling.layout.pattern=%d %p %C{1.} [%t] %m%n
appender.routing.routes.route2.rolling.policies.type=Policies
#appender.routing.routes.route2.rolling.policies.time.type=TimeBasedTriggeringPolicy
#appender.routing.routes.route2.rolling.policies.time.interval=2
#appender.routing.routes.route2.rolling.policies.time.modulate=true
appender.routing.routes.route2.rolling.policies.size.type=SizeBasedTriggeringPolicy
appender.routing.routes.route2.rolling.policies.size.size=1KB
appender.routing.routes.route2.rolling.strategy.type=DefaultRolloverStrategy
appender.routing.routes.route2.rolling.strategy.max = 5
loggers=routing
logger.routing.level=debug
logger.routing.name=com.infy.demo
logger.routing.additivity=false
logger.routing.appenderRef.routing.ref=Routing
rootLogger.level=debug
------------------------------------------------------------------------------------------------------------------
TestLog4j2Logging.class
package com.infy.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
public class TestLog4j2Logging {
private static final Logger log = LogManager.getLogger(TestLog4j2Logging.class);
public TestLog4j2Logging() {
logInfo("Logging has been initalized");
}
static {
ThreadContext.put("keyname","P:/TestLogging/TestLog4j2Logging");
Configurator.initialize(null, "./properties/log4j2.properties");
}
public void logTestLog4j2LoggingMesg()
{
String[] arr = {"Msg1111111111111","Msg222222222222222","Msg3333333333333","Msg44444444444"};
for (String string : arr) {
logInfo(string);
logError(string);
log.debug(string);
}
}
public void logMqMsg() throws Exception
{
String[] mqArr = {"MQ111111111111111111","MQ222222222222222222222222","MQ3333333333333333333333"};
for (String string : mqArr) {
log.info(string);
}
}
public void logSpecialKeyRouteMsgAppender()
{
String[] mqArr = {"Special111111111111111111","Special222222222222222222222222","Special3333333333333333333333"};
for (String string : mqArr) {
log.info(string);
}
}
public static void main(String[] args) throws Exception
{
TestLog4j2Logging testLog4j2Logging = new TestLog4j2Logging();
System.out.println("=================file TestLog4j2Logging.log creating and logging the messages==============================================");
//Logging the messages for the this class level Logging
testLog4j2Logging.logTestLog4j2LoggingMesg();
System.out.println("=================file Queue.Name.log creating and logging the messages c==============================================");
//Logging the messages for the MQ Logging file Queue.Name
ThreadContext.remove("keyname");
ThreadContext.put("keyname", "P:/TestLogging/Queue.Name");
testLog4j2Logging.logMqMsg();
ThreadContext.remove("keyname");
ThreadContext.put("keyname", "P:/TestLogging/TestLog4j2Logging");
System.out.println("=================file TestLog4j2Logging logging the messages==============================================");
//Logging the messages for special key in the log4j.properties file
ThreadContext.remove("keyname");
ThreadContext.put("keyname", "P:/TestLogging/specialspecial");
testLog4j2Logging.logSpecialKeyRouteMsgAppender();
ThreadContext.remove("keyname");
ThreadContext.put("keyname", "P:/TestLogging/TestLog4j2Logging");
Thread.sleep(61000);
logInfo("Logging is Complted sucessfully");
System.out.println("Messages are getting Logged");
}
private static String getCurrentDateAndTime() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return dtf.format(LocalDateTime.now());
}
private static void logInfo(String msg) {
log.info("{} INFO {} - {}",getCurrentDateAndTime(),TestLog4j2Logging.class.getName(),msg);
}
private static void logError(String msg) {
log.info("{} ERROR {} - {}",getCurrentDateAndTime(),TestLog4j2Logging.class.getName(),msg);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.