【发布时间】:2025-12-05 00:40:01
【问题描述】:
我正在尝试使用 log4j 从基于 servlet 的 java 应用程序中进行一些日志记录。我想记录额外的信息,如用户 ID 等。有没有办法将局部变量放在线程中?并且在记录时,是否可以获取当前线程,并获取设置的局部变量?
【问题讨论】:
-
你可以通过你的 log4j 配置,然后我会告诉你如何添加线程名称
我正在尝试使用 log4j 从基于 servlet 的 java 应用程序中进行一些日志记录。我想记录额外的信息,如用户 ID 等。有没有办法将局部变量放在线程中?并且在记录时,是否可以获取当前线程,并获取设置的局部变量?
【问题讨论】:
Log4J MDC 方法
这是使用 MDC 的方法
public class MdcExample implements Runnable {
private static final Logger logger = Logger.getLogger(MdcExample.class);
public static void main(final String[] args) {
final MdcExample threadLocalExample = new MdcExample();
final Thread thread1 = new Thread(threadLocalExample);
final Thread thread2 = new Thread(threadLocalExample);
final Thread thread3 = new Thread(threadLocalExample);
thread1.start(); thread2.start(); thread3.start();
}
@Override
public void run() {
while (true) {
MDC.put("random", "" + Math.random());
try {
logger.info("My log message, prefixed with MDC");
TimeUnit.SECONDS.sleep(1);
}
catch (final InterruptedException e) {
}
}
}
}
Log4J 设置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %X{random}:- %m%n" />
</layout>
</appender>
<!-- Root Logger -->
<root>
<priority value="info" />
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</log4j:configuration>
线程本地方法(如果您的业务逻辑需要)
如果您想将值(如用户)本地存储到线程,请使用ThreadLocal:
import java.util.concurrent.TimeUnit;
public class ThreadLocalExample implements Runnable {
ThreadLocal<Double> myRandom = new ThreadLocal<>();
public static void main(final String[] args) {
final ThreadLocalExample threadLocalExample = new ThreadLocalExample();
final Thread thread1 = new Thread(threadLocalExample);
final Thread thread2 = new Thread(threadLocalExample);
final Thread thread3 = new Thread(threadLocalExample);
thread1.start(); thread2.start(); thread3.start();
}
@Override
public void run() {
this.myRandom.set(Math.random());
while (true) {
System.out.println(Thread.currentThread().getId() + " " + this.myRandom.get());
try {
TimeUnit.SECONDS.sleep(1);
}
catch (final InterruptedException e) {
}
}
}
}
http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html
将线程 ID 添加到 log4j 输出
关于您的 log4j 问题,您可以使用 t-Placeholder 作为线程名称:
这是一个可以使用的示例 Appender:
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%5p %d{ISO8601} [%t][%x] %c - %m%n" />
</layout>
</appender>
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
【讨论】:
ThreadLocal 是要走的路。 ThreadLocal 提供了保存变量的功能,这些变量不在线程之间共享,并且在线程的整个生命周期中都可用。
ThreadLocal 就其本质而言,此功能可帮助您摆脱同步块。
【讨论】:
您应该为此使用MDC。您可以存储命名属性,然后直接以日志格式引用它们。示例见What is the difference between Log4j's NDC and MDC facilities?。
【讨论】: