創建過濾器
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.UUID;
/**
* @Author GUOSHAOHUA093
* @Description 添加日誌追蹤id
* @Date 2019-7-17 14:09
**/
@Component
@PropertySource(value = {"medicalbase.properties"},encoding="utf-8")
@WebFilter(urlPatterns = "/*", filterName = "logMdcFilter")
public class LogMdcFilter implements Filter {
@Value("${medical.log.trace.id}")
private String traceId;
private static String UNIQUE_ID;
@Override
public void init(FilterConfig filterConfig) {
UNIQUE_ID = traceId;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean bInsertMDC = insertMDC();
try {
chain.doFilter(request, response);
} finally {
if (bInsertMDC) {
MDC.remove(UNIQUE_ID);
}
}
}
@Override
public void destroy() {
}
public static boolean insertMDC() {
if (MDC.get(UNIQUE_ID) == null) {
UUID uuid = UUID.randomUUID();
String uniqueId = uuid.toString().replace("-", "");
MDC.put(UNIQUE_ID, uniqueId);
}
return true;
}
public static String getMDC() {
return MDC.get(UNIQUE_ID);
}
public static String getUNIQUE_ID() {
return UNIQUE_ID;
}
}
配置文件 medicalbase.properties
#日誌唯一id
medical.log.trace.id=traceId
線程池定義
@Bean("asyncExecutor")
public ThreadPoolTaskExecutor getAsyncExecutor() {//實現AsyncConfigurer接口並重寫getAsyncExecutor方法,並返回一個ThreadPoolTaskExecutor,這樣我們就獲得了一個基於線程池TaskExecutor
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutorMedical();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.setAwaitTerminationSeconds(60 * 15);// 等待時間 (默認爲0,此時立即停止),並沒等待xx秒後強制停止
// taskExecutor.setThreadNamePrefix("paAsync-");// 線程名稱前綴
taskExecutor.initialize();
return taskExecutor;
}
工具類
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.Map;
import java.util.concurrent.*;
/**
* @Author GUOSHAOHUA093
* @Description 線程mdc工具類
* @Date 2019-7-18 15:47
**/
public class ThreadMdcUtil {
public static void setTraceIdIfAbsent() {
LogMdcFilter.insertMDC();
}
public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
return () -> {
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
setTraceIdIfAbsent();
try {
return callable.call();
} finally {
MDC.clear();
}
};
}
public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
return () -> {
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
setTraceIdIfAbsent();
try {
runnable.run();
} finally {
MDC.clear();
}
};
}
public static class ThreadPoolTaskExecutorMdcWrapper extends ThreadPoolTaskExecutor {
@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public void execute(Runnable task, long startTimeout) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), startTimeout);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
return super.submitListenable(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
public static class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor {
public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), result);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
public static class ForkJoinPoolMdcWrapper extends ForkJoinPool {
public ForkJoinPoolMdcWrapper() {
super();
}
public ForkJoinPoolMdcWrapper(int parallelism) {
super(parallelism);
}
public ForkJoinPoolMdcWrapper(int parallelism, ForkJoinWorkerThreadFactory factory,
Thread.UncaughtExceptionHandler handler, boolean asyncMode) {
super(parallelism, factory, handler, asyncMode);
}
@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public <T> ForkJoinTask<T> submit(Runnable task, T result) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), result);
}
@Override
public <T> ForkJoinTask<T> submit(Callable<T> task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
}
/**
* @ClassName ThreadPoolTaskExecutorMedical
* @Destription 線程重寫類
* @AUTHOR GUOSHAOHUA093
* @Date 2019-7-25 10:55
*
* @VERSION 1.0
**/
public class ThreadPoolTaskExecutorMedical extends ThreadPoolTaskExecutor {
@Override
public <T> Future<T> submit(Callable<T> task) {
// 傳入線程池之前先複製當前線程的MDC
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
日誌打印格式
<Pattern>%d{yyyy-MM-dd HH:mm:ss} job [%thread] [%X{traceId}] %level %logger{35} - %msg%n</Pattern>
對於分佈式系統日誌的追蹤可以改進全局的 traceId 生成規則,但是我這個擔心性能問題,其實取號系統發號速度是非常快的,這個後續會給出方案。