无法使用 log4j2 为不同的线程写入不同的日志
unable to write into different logs for different threads using log4j2
我正在尝试为每个 Thread/ThreadGroup 将日志写入不同的文件。
我的代码为每个线程创建不同的文件,但它将所有其他线程写入一个文件。
MainTest.java
public class MainTest {
public static void main(String[] args) {
ThreadGroup tg1 = new ThreadGroup("Group A");
Thread t1 = new Thread(tg1, new LoggingTest(), "t1");
t1.start();
Thread t2 = new Thread(tg1, new LoggingTest(), "t2");
t2.start();
//
Thread t3 = new Thread(new LoggingTest(),"t3");
t3.start();
}
}
LoggingTest.java
public class LoggingTest implements Runnable {
private static final Logger logger = LogManager.getLogger(LoggingTest.class);
private static final String logFilePath = "/output/logs/";
private static final String pattern = "%d{dd MMM yyyy HH:mm:ss.SSS} (%F:%L) - %m%n";
public void run() {
Thread runner = Thread.currentThread();
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
try {
URL configFile = LoggingTest.class.getResource("/log4j2.properties");
context.setConfigLocation(configFile.toURI());
}catch(Exception e) {
e.printStackTrace();
}
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
FileAppender appender = null;
try {
appender = FileAppender
.newBuilder()
.setName("Name")
.setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
.withFileName(logFilePath + runner.getName() + ".log")
.build();
} catch (Exception e) {
logger.error("error -> "+e);
}
if (appender != null) {
if ( runner.getThreadGroup().getParent() != null )
{
appender.addFilter( new ThreadGroupFilter( runner.getThreadGroup() ) );
}
else
{
appender.addFilter( new ThreadFilter( runner ) );
}
appender.start();
ctx.getRootLogger().addAppender(appender);
ctx.updateLoggers();
}
logger.info("info msg");
logger.debug("debug msg");
logger.error("error msg");
if ( appender != null ) {
ctx.getRootLogger().removeAppender(appender);
ctx.updateLoggers();
appender.stop();
}
}
}
在这里,我为线程和线程组创建了几个过滤器 类。但似乎这些无法正常工作。
ThreadGroupFilter.java
import org.apache.logging.log4j.core.Filter;
public class ThreadGroupFilter implements Filter {
private final ThreadGroup filterThreadGroup;
public ThreadGroupFilter( ThreadGroup filterThreadGroup ) {
this.filterThreadGroup = filterThreadGroup;
}
@Override
public Result filter(LogEvent event) {
if ( Thread.currentThread().getThreadGroup() != filterThreadGroup )
return Filter.Result.DENY;
return Filter.Result.NEUTRAL;
}
}
ThreadFilter.java
public class ThreadFilter implements Filter {
private final Thread filterThread;
public ThreadFilter( Thread filterThread ) {
this.filterThread = filterThread;
}
@Override
public Result filter(LogEvent event) {
if ( Thread.currentThread() != filterThread )
return Filter.Result.DENY;
return Filter.Result.NEUTRAL;
}
}
log4j2.properties
name=PropertiesConfig
property.basePath = ../logs
appenders = console
appender.console.type = Console
appender.console.name = consoleLogger
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %5p [%c] [%t] (%F:%L) - %m%n
rootLogger.level = debug
rootLogger.appenderRefs = console
rootLogger.appenderRef.stdout.ref = consoleLogger
我希望每个 Thread/ThreadGroup 有多个日志文件。但是我最终得到了每个线程的多个日志文件,并且所有线程都记录到一个文件中。
提前致谢。
您的每个线程都调用 LoggerContext#setConfigLocation
,这会导致重新配置 Log4j2。重新配置 删除 您以编程方式添加的所有附加程序。这就是为什么你最终只有一个附加程序。
请注意,您不需要编程配置每个线程都有不同的文件附加程序。您可以像 .
中那样使用 RoutingAppender
编辑:如果你真的想使用程序化配置(出于兼容性原因不鼓励这样做),你还需要为每个appender使用一个唯一的名称,否则它们将静默忽略(您使用的 Logger#addAppender
方法不是 public API 的一部分,请参见 javadoc,因此不会报告错误)。
将这段代码从 LoggingTest 移到 MainTest
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
try {
URL configFile = LoggingTest.class.getResource("/log4j2.properties");
context.setConfigLocation(configFile.toURI());
}catch(Exception e) {
e.printStackTrace();
}
并在 Appender 配置中进行了细微修改。
FileAppender appender = null;
String appenderName = (runner.getThreadGroup() != null) ? "appender_"+runner.getThreadGroup().getName() : "appender_"+runner.getName();
try {
appender = FileAppender
.newBuilder()
.setName(appenderName)
.setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
.withFileName(logFilePath + appenderName + ".log")
.build();
} catch (Exception e) {
logger.error("error -> "+e);
}
感谢解决方案Poitr P. Karwasz
我正在尝试为每个 Thread/ThreadGroup 将日志写入不同的文件。 我的代码为每个线程创建不同的文件,但它将所有其他线程写入一个文件。
MainTest.java
public class MainTest {
public static void main(String[] args) {
ThreadGroup tg1 = new ThreadGroup("Group A");
Thread t1 = new Thread(tg1, new LoggingTest(), "t1");
t1.start();
Thread t2 = new Thread(tg1, new LoggingTest(), "t2");
t2.start();
//
Thread t3 = new Thread(new LoggingTest(),"t3");
t3.start();
}
}
LoggingTest.java
public class LoggingTest implements Runnable {
private static final Logger logger = LogManager.getLogger(LoggingTest.class);
private static final String logFilePath = "/output/logs/";
private static final String pattern = "%d{dd MMM yyyy HH:mm:ss.SSS} (%F:%L) - %m%n";
public void run() {
Thread runner = Thread.currentThread();
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
try {
URL configFile = LoggingTest.class.getResource("/log4j2.properties");
context.setConfigLocation(configFile.toURI());
}catch(Exception e) {
e.printStackTrace();
}
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
FileAppender appender = null;
try {
appender = FileAppender
.newBuilder()
.setName("Name")
.setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
.withFileName(logFilePath + runner.getName() + ".log")
.build();
} catch (Exception e) {
logger.error("error -> "+e);
}
if (appender != null) {
if ( runner.getThreadGroup().getParent() != null )
{
appender.addFilter( new ThreadGroupFilter( runner.getThreadGroup() ) );
}
else
{
appender.addFilter( new ThreadFilter( runner ) );
}
appender.start();
ctx.getRootLogger().addAppender(appender);
ctx.updateLoggers();
}
logger.info("info msg");
logger.debug("debug msg");
logger.error("error msg");
if ( appender != null ) {
ctx.getRootLogger().removeAppender(appender);
ctx.updateLoggers();
appender.stop();
}
}
}
在这里,我为线程和线程组创建了几个过滤器 类。但似乎这些无法正常工作。 ThreadGroupFilter.java
import org.apache.logging.log4j.core.Filter;
public class ThreadGroupFilter implements Filter {
private final ThreadGroup filterThreadGroup;
public ThreadGroupFilter( ThreadGroup filterThreadGroup ) {
this.filterThreadGroup = filterThreadGroup;
}
@Override
public Result filter(LogEvent event) {
if ( Thread.currentThread().getThreadGroup() != filterThreadGroup )
return Filter.Result.DENY;
return Filter.Result.NEUTRAL;
}
}
ThreadFilter.java
public class ThreadFilter implements Filter {
private final Thread filterThread;
public ThreadFilter( Thread filterThread ) {
this.filterThread = filterThread;
}
@Override
public Result filter(LogEvent event) {
if ( Thread.currentThread() != filterThread )
return Filter.Result.DENY;
return Filter.Result.NEUTRAL;
}
}
log4j2.properties
name=PropertiesConfig
property.basePath = ../logs
appenders = console
appender.console.type = Console
appender.console.name = consoleLogger
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %5p [%c] [%t] (%F:%L) - %m%n
rootLogger.level = debug
rootLogger.appenderRefs = console
rootLogger.appenderRef.stdout.ref = consoleLogger
我希望每个 Thread/ThreadGroup 有多个日志文件。但是我最终得到了每个线程的多个日志文件,并且所有线程都记录到一个文件中。
提前致谢。
您的每个线程都调用 LoggerContext#setConfigLocation
,这会导致重新配置 Log4j2。重新配置 删除 您以编程方式添加的所有附加程序。这就是为什么你最终只有一个附加程序。
请注意,您不需要编程配置每个线程都有不同的文件附加程序。您可以像
RoutingAppender
编辑:如果你真的想使用程序化配置(出于兼容性原因不鼓励这样做),你还需要为每个appender使用一个唯一的名称,否则它们将静默忽略(您使用的 Logger#addAppender
方法不是 public API 的一部分,请参见 javadoc,因此不会报告错误)。
将这段代码从 LoggingTest 移到 MainTest
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
try {
URL configFile = LoggingTest.class.getResource("/log4j2.properties");
context.setConfigLocation(configFile.toURI());
}catch(Exception e) {
e.printStackTrace();
}
并在 Appender 配置中进行了细微修改。
FileAppender appender = null;
String appenderName = (runner.getThreadGroup() != null) ? "appender_"+runner.getThreadGroup().getName() : "appender_"+runner.getName();
try {
appender = FileAppender
.newBuilder()
.setName(appenderName)
.setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
.withFileName(logFilePath + appenderName + ".log")
.build();
} catch (Exception e) {
logger.error("error -> "+e);
}
感谢解决方案Poitr P. Karwasz