1、Slf4j MDC线程安全测试
类似ThreadLocal使用
@Slf4j
public class Main {
public static void main(String[] args) {
for (int i = 1 ; i <= 10 ; i++) {
Thread thread = new Thread(new WorkerThread("Thread " + i));
thread.start();
}
}
@Slf4j
static class WorkerThread implements Runnable {
private String threadName;
public WorkerThread(String threadName) {
this.threadName = threadName;
}
@Override
public void run() {
log.info("input : {}", Thread.currentThread().getName() + "->>" + threadName);
MDC.put("threadName", Thread.currentThread().getName() + "->>" + threadName);
// 模拟一些操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("error.", e);
}
log.info("output : {}", MDC.get("threadName"));
}
}
}
输出结果 :
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-3->>Thread 4
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-9->>Thread 10
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-6->>Thread 7
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-0->>Thread 1
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-7->>Thread 8
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-4->>Thread 5
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-2->>Thread 3
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-5->>Thread 6
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-1->>Thread 2
[INFO] 2024-06-17 11:28:07.066 +0800 c.j.s.s.Main$WorkerThread:[31] - input : Thread-8->>Thread 9
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-3->>Thread 4
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-5->>Thread 6
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-0->>Thread 1
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-8->>Thread 9
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-1->>Thread 2
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-4->>Thread 5
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-7->>Thread 8
[INFO] 2024-06-17 11:28:08.070 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-2->>Thread 3
[INFO] 2024-06-17 11:28:08.071 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-9->>Thread 10
[INFO] 2024-06-17 11:28:08.073 +0800 c.j.s.s.Main$WorkerThread:[42] - output : Thread-6->>Thread 7
可以当做ThreadLocal来使用,是线程安全的
2、模拟 dolphinscheduler Task日志打印
2.1、pom.xml依赖
<dependencies>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!-- SLF4J Implementation (e.g., Logback) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
</dependencies>
2.2、TaskLogFilter
@Slf4j
public class TaskLogFilter extends Filter<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
return MDC.get("taskInstanceLogFullPath") == null ? FilterReply.DENY : FilterReply.ACCEPT;
}
}
2.3、TaskLogDiscriminator
@Slf4j
public class TaskLogDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
private String key;
private String logBase;
@Override
public String getDiscriminatingValue(ILoggingEvent event) {
String taskInstanceLogPath = MDC.get("taskInstanceLogFullPath");
if (taskInstanceLogPath == null) {
log.error("The task instance log path is null, please check the logback configuration, log: {}", event);
}
return taskInstanceLogPath;
}
@Override
public void start() {
started = true;
}
@Override
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getLogBase() {
return logBase;
}
public void setLogBase(String logBase) {
this.logBase = logBase;
}
}
2.4、logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="120 seconds">
<property name="log.base" value="logs"/>
<property scope="context" name="log.base.ctx" value="${log.base}" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} %logger{10}:[%line] - %msg%n
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="TASKLOGFILE" class="ch.qos.logback.classic.sift.SiftingAppender">
<filter class="com.journey.springboot.log.TaskLogFilter"/>
<Discriminator class="com.journey.springboot.log.TaskLogDiscriminator">
<key>taskInstanceLogFullPath</key>
<logBase>${log.base}</logBase>
</Discriminator>
<sift>
<appender name="FILE-${taskInstanceLogFullPath}" class="ch.qos.logback.core.FileAppender">
<file>${taskInstanceLogFullPath}</file>
<encoder>
<pattern>
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} - %message%n
</pattern>
<charset>UTF-8</charset>
</encoder>
<append>true</append>
</appender>
</sift>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="TASKLOGFILE"/>
</root>
</configuration>
2.5、示例
@Slf4j
public class Main {
public static void main(String[] args) {
String taskFirstSubmitTime = "20140617";
Long workflowDefinitionCode = 11123333L;
int workflowDefinitionVersion = 1;
int workflowInstanceId = 1234;
int taskInstanceId = 345;
String taskInstanceLogFullPath = getTaskInstanceLogFullPath(
taskFirstSubmitTime,
workflowDefinitionCode,
workflowDefinitionVersion,
workflowInstanceId,
taskInstanceId);
MDC.put("taskInstanceLogFullPath", taskInstanceLogFullPath);
log.info("task start.");
log.info("task execute.");
log.info("task end.");
}
public static Path getTaskInstanceLogBasePath() {
return Optional.of(LoggerFactory.getILoggerFactory())
.map(e -> (AppenderAttachable<ILoggingEvent>) (e.getLogger("ROOT")))
.map(e -> (SiftingAppender) (e.getAppender("TASKLOGFILE")))
.map(e -> ((TaskLogDiscriminator) (e.getDiscriminator())))
.map(TaskLogDiscriminator::getLogBase)
.map(e -> Paths.get(e).toAbsolutePath())
.orElse(null);
}
public static String getTaskInstanceLogFullPath(String taskFirstSubmitTime,
Long workflowDefinitionCode,
int workflowDefinitionVersion,
int workflowInstanceId,
int taskInstanceId) {
final String taskLogFileName = Paths.get(
String.valueOf(workflowDefinitionCode),
String.valueOf(workflowDefinitionVersion),
String.valueOf(workflowInstanceId),
String.format("%s.log", taskInstanceId)).toString();
return getTaskInstanceLogBasePath()
.resolve(taskFirstSubmitTime)
.resolve(taskLogFileName)
.toString();
}
}
2.6、结果
如感兴趣,点赞加关注,谢谢!!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。