如皋网站建设公司,wordpress php 链接地址,帮网站网站做推广被抓会判刑吗,椒江住房和城乡建设规划局网站在分布式环境中一般统一收集日志#xff0c;但是在并发大时不好定位问题#xff0c;大量的日志导致无法找出日志的链路关系。 可以为每一个请求分配一个traceId#xff0c;记录日志时#xff0c;记录此traceId#xff0c;从网关开始#xff0c;依次将traceId记录到请求头… 在分布式环境中一般统一收集日志但是在并发大时不好定位问题大量的日志导致无法找出日志的链路关系。 可以为每一个请求分配一个traceId记录日志时记录此traceId从网关开始依次将traceId记录到请求头中并借用log4j2的MDC功能实现traceId的打印。
1、添加traceId过滤器
其中TRACE_ID_HEADER和LOG_TRACE_ID为上下游约定好的key。
public class LogTraceIdFilter extends OncePerRequestFilter implements Constants {Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {String traceId request.getHeader(TRACE_ID_HEADER);if (StringUtils.isBlank(traceId)) {traceId UUID.randomUUID().toString();}MDC.put(LOG_TRACE_ID, traceId);log.debug(设置traceId{}, traceId);chain.doFilter(request, response);}
}2、注册traceId过滤器
AutoConfiguration
ConditionalOnClass(LogTraceIdFilter.class)
Slf4j
public class LogTraceIdAutoConfiguration {Beanpublic LogTraceIdFilter logTraceIdFilter() {return new LogTraceIdFilter();}SuppressWarnings(unchecked)Beanpublic FilterRegistrationBean traceIdFilterRegistrationBean() {log.info(-----注册LogTraceId过滤器-------);FilterRegistrationBean frb new FilterRegistrationBean();frb.setOrder(Ordered.HIGHEST_PRECEDENCE);frb.setFilter(logTraceIdFilter());frb.addUrlPatterns(/*);frb.setName(logTraceIdFilter);log.info(-----注册LogTraceId过滤器结束-------);return frb;}
}将LogTraceIdAutoConfiguration全限定名 写入resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports如果是老版的springboot写入resources/spring.factories
3、调用其他服务时传递traceId
如果需调用其他服务需要将获取到的traceId写入请求头的TRACE_ID_HEADER中例如使用openfeign可统一处理这里略。
4、log4j2的配置文件中添加打印traceId的配置 完整的配置文件文件如下
?xml version1.0 encodingUTF-8?!--Configuration 后面的 status这个用于设置 log4j2 自身内部的信息输出级别可以不设置当设置成 trace 时你会看到 log4j2 内部各种详细输出--
!--monitorIntervalLog4j2 能够自动检测修改配置 文件和重新配置本身设置间隔秒数--
configuration statuserror monitorInterval30!--日志级别以及优先级排序: OFF FATAL ERROR WARN INFO DEBUG TRACE ALL --!--变量配置--properties!-- 格式化输出%date 表示日期%thread 表示线程名%-5level级别从左显示 5 个字符宽度 %msg日志消息%n 是换行符--!-- %logger{36} 表示 Logger 名字最长 36 个字符 --!--如果在PATTERN中配置了%C、%M、%L、%l、%F需要在appender中将includeLocation设置为true会影响日志性能项目上线后根据实际情况调整--property nameLOG_PATTERN value%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%X{traceId}] %-5level [%logger{50}:%L] - %msg%n/property nameLOG_CONSOLE_PATTERN value%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}/property nameACCESS_LOG_PATTERN value%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n/!-- 定义日志存储的路径 --property nameFILE_PATH valuelogs/property nameFILE_NAME valuenewframe//propertiesAppenders!--*********************控制台日志***********************--Console nameconsoleAppender targetSYSTEM_OUT!--设置日志格式及颜色--PatternLayout pattern${LOG_PATTERN} charsetUTF-8//Console!--info级别日志--!-- 这个会打印出所有的info及以上级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩作为存档--RollingFile nameinfoFileAppenderfileName${FILE_PATH}/${FILE_NAME}/log_info.logfilePattern${FILE_PATH}/${FILE_NAME}/info/log-info-%d{yyyy-MM-dd}_%i.log.gzappendtrue!--设置日志格式--PatternLayout pattern${LOG_PATTERN} charsetUTF-8/Filters!--过滤掉warn及更高级别日志--ThresholdFilter levelwarn onMatchDENY onMismatchNEUTRAL /ThresholdFilter levelinfo onMatchACCEPT onMismatchDENY//FiltersPolicies!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数intervalinteger型指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位比如yyyy-MM-dd-HH 单位为小时yyyy-MM-dd-HH-mm 单位为分钟modulateboolean型说明是否对封存时间进行调制。若modulatetrue则封存时间将以0点为边界进行偏移计算。比如modulatetrueinterval4hours那么假设上次封存日志的时间为00:00则下次封存日志的时间为04:00之后的封存时间依次为08:0012:0016:00--TimeBasedTriggeringPolicy interval1/SizeBasedTriggeringPolicy size10MB//Policies!-- DefaultRolloverStrategy 属性如不设置则默认为最多同一文件夹下当天 7 个文件后开始覆盖--DefaultRolloverStrategy max30!-- 删除处理策略在配置的路径中搜索maxDepth 表示往下搜索的最大深度 --Delete basePath${FILE_PATH}/${FILE_NAME}/ maxDepth2!-- 文件名搜索匹配支持正则 --IfFileName glob*.log.gz/!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--!--7天--IfLastModified age7d//Delete/DefaultRolloverStrategy/RollingFile!--warn级别日志--!-- 这个会打印出所有的warn及以上级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩作为存档--RollingFile namewarnFileAppenderfileName${FILE_PATH}/${FILE_NAME}/log_warn.logfilePattern${FILE_PATH}/${FILE_NAME}/warn/log-warn-%d{yyyy-MM-dd}_%i.log.gzappendtrue!--设置日志格式--PatternLayout pattern${LOG_PATTERN} charsetUTF-8/Filters!--过滤掉error及更高级别日志--ThresholdFilter levelerror onMatchDENY onMismatchNEUTRAL /ThresholdFilter levelwarn onMatchACCEPT onMismatchDENY//FiltersPolicies!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数intervalinteger型指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位比如yyyy-MM-dd-HH 单位为小时yyyy-MM-dd-HH-mm 单位为分钟modulateboolean型说明是否对封存时间进行调制。若modulatetrue则封存时间将以0点为边界进行偏移计算。比如modulatetrueinterval4hours那么假设上次封存日志的时间为00:00则下次封存日志的时间为04:00之后的封存时间依次为08:0012:0016:00--TimeBasedTriggeringPolicy interval1/SizeBasedTriggeringPolicy size10MB//Policies!-- DefaultRolloverStrategy 属性如不设置则默认为最多同一文件夹下当天 7 个文件后开始覆盖--DefaultRolloverStrategy max30!-- 删除处理策略在配置的路径中搜索maxDepth 表示往下搜索的最大深度 --Delete basePath${FILE_PATH}/${FILE_NAME}/ maxDepth2!-- 文件名搜索匹配支持正则 --IfFileName glob*.log.gz/!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--!--7天--IfLastModified age7d//Delete/DefaultRolloverStrategy/RollingFile!--error级别日志--!-- 这个会打印出所有的error及以上级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩作为存档--RollingFile nameerrorFileAppenderfileName${FILE_PATH}/${FILE_NAME}/log_error.logfilePattern${FILE_PATH}/${FILE_NAME}/error/log-error-%d{yyyy-MM-dd}_%i.log.gzappendtrue!--设置日志格式--PatternLayout pattern${LOG_PATTERN} charsetUTF-8/FiltersThresholdFilter levelerror onMatchACCEPT onMismatchDENY//FiltersPolicies!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数intervalinteger型指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位比如yyyy-MM-dd-HH 单位为小时yyyy-MM-dd-HH-mm 单位为分钟modulateboolean型说明是否对封存时间进行调制。若modulatetrue则封存时间将以0点为边界进行偏移计算。比如modulatetrueinterval4hours那么假设上次封存日志的时间为00:00则下次封存日志的时间为04:00之后的封存时间依次为08:0012:0016:00--TimeBasedTriggeringPolicy interval1/SizeBasedTriggeringPolicy size10MB//Policies!-- DefaultRolloverStrategy 属性如不设置则默认为最多同一文件夹下当天 7 个文件后开始覆盖--DefaultRolloverStrategy max30!-- 删除处理策略在配置的路径中搜索maxDepth 表示往下搜索的最大深度 --Delete basePath${FILE_PATH}/${FILE_NAME}/ maxDepth2!-- 文件名搜索匹配支持正则 --IfFileName glob*.log.gz/!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--!--7天--IfLastModified age7d//Delete/DefaultRolloverStrategy/RollingFile!--访问日志--RollingFile nameaccessAppenderfileName${FILE_PATH}/${FILE_NAME}/log_access.logfilePattern${FILE_PATH}/${FILE_NAME}/access/log-access-%d{yyyy-MM-dd}_%i.log.gzappendtrue!--设置日志格式--PatternLayout pattern${ACCESS_LOG_PATTERN} charsetUTF-8/FiltersThresholdFilter leveldebug onMatchACCEPT onMismatchDENY//FiltersPolicies!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数intervalinteger型指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位比如yyyy-MM-dd-HH 单位为小时yyyy-MM-dd-HH-mm 单位为分钟modulateboolean型说明是否对封存时间进行调制。若modulatetrue则封存时间将以0点为边界进行偏移计算。比如modulatetrueinterval4hours那么假设上次封存日志的时间为00:00则下次封存日志的时间为04:00之后的封存时间依次为08:0012:0016:00--TimeBasedTriggeringPolicy interval1/SizeBasedTriggeringPolicy size10MB//Policies!-- DefaultRolloverStrategy 属性如不设置则默认为最多同一文件夹下当天 7 个文件后开始覆盖--DefaultRolloverStrategy max30!-- 删除处理策略在配置的路径中搜索maxDepth 表示往下搜索的最大深度 --Delete basePath${FILE_PATH}/${FILE_NAME}/ maxDepth2!-- 文件名搜索匹配支持正则 --IfFileName glob*.log.gz/!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--!--7天--IfLastModified age7d//Delete/DefaultRolloverStrategy/RollingFile!--Async nameAsync includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//Async--/AppendersLoggersAsyncLogger nameorg.apache.http levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameio.lettuce levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameio.netty levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.quartz levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.springframework levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.springdoc levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namedruid.sql levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameio.undertow levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namesun.rmi levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.sun.mail levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namejavax.management levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namede.codecentric levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.hibernate.validator levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.mybatis.spring.mapper levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.xnio levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namespringfox levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.baomidou levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameio.micrometer.core levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameValidator levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.neo4j levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.apache.zookeeper levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.apache.curator levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameoshi.util levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namenet.javacrumbs levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.atomikos levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.springframework.boot.actuate.mail.MailHealthIndicator levelerror includeLocationtrue additivityfalseAppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.flowable levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.apache.ibatis.transaction levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.iscas.base.biz.schedule levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.sun.jna.Native levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameio.swagger levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.sun.jna.NativeLibrary levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.alibaba.druid.pool.PreparedStatementPool levelinfo includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger namecom.iscas.biz.config.log.AccessLogInterceptor leveldebug includeLocationtrue additivityfalseAppenderRef refaccessAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncLogger nameorg.apache.http.impl.execchain.RetryExec levelerror includeLocationtrue additivityfalseAppenderRef referrorFileAppender//AsyncLoggerAsyncLogger nameaccessLogger leveldebug includeLocationtrue additivityfalseAppenderRef refaccessAppender/AppenderRef refconsoleAppender//AsyncLoggerAsyncRoot leveldebug includeLocationtrue additivityfalseAppenderRef refinfoFileAppender/AppenderRef refwarnFileAppender/AppenderRef referrorFileAppender/AppenderRef refconsoleAppender//AsyncRoot/Loggers
/configuration5、添加阿里巴巴transmittable依赖
为解决调用子线程后无法打印traceId的问题引用transmittable依赖 gradle:
// https://mvnrepository.com/artifact/com.alibaba/transmittable-thread-local
implementation group: com.alibaba, name: transmittable-thread-local, version: 2.14.2
maven:
!-- https://mvnrepository.com/artifact/com.alibaba/transmittable-thread-local --
dependencygroupIdcom.alibaba/groupIdartifactIdtransmittable-thread-local/artifactIdversion2.14.2/version
/dependency
6、自定义ThreadContextMap
package org.slf4j;import com.alibaba.ttl.TransmittableThreadLocal;
import org.apache.logging.log4j.spi.ThreadContextMap;import java.util.Collections;
import java.util.HashMap;
import java.util.Map;public class TtlThreadContextMap implements ThreadContextMap {private final ThreadLocalMapString, String localMap;public TtlThreadContextMap() {this.localMap new TransmittableThreadLocalMapString, String();}Overridepublic void put(final String key, final String value) {MapString, String map localMap.get();map map null ? new HashMapString, String() : new HashMapString, String(map);map.put(key, value);localMap.set(Collections.unmodifiableMap(map));}Overridepublic String get(final String key) {final MapString, String map localMap.get();return map null ? null : map.get(key);}Overridepublic void remove(final String key) {final MapString, String map localMap.get();if (map ! null) {final MapString, String copy new HashMapString, String(map);copy.remove(key);localMap.set(Collections.unmodifiableMap(copy));}}Overridepublic void clear() {localMap.remove();}Overridepublic boolean containsKey(final String key) {final MapString, String map localMap.get();return map ! null map.containsKey(key);}Overridepublic MapString, String getCopy() {final MapString, String map localMap.get();return map null ? new HashMapString, String() : new HashMapString, String(map);}Overridepublic MapString, String getImmutableMapOrNull() {return localMap.get();}Overridepublic boolean isEmpty() {final MapString, String map localMap.get();return map null || map.size() 0;}Overridepublic String toString() {final MapString, String map localMap.get();return map null ? {} : map.toString();}Overridepublic int hashCode() {final int prime 31;int result 1;final MapString, String map this.localMap.get();result prime * result ((map null) ? 0 : map.hashCode());return result;}Overridepublic boolean equals(final Object obj) {if (this obj) {return true;}if (obj null) {return false;}if (!(obj instanceof TtlThreadContextMap)) {return false;}final TtlThreadContextMap other (TtlThreadContextMap) obj;final MapString, String map this.localMap.get();final MapString, String otherMap other.getImmutableMapOrNull();if (map null) {if (otherMap ! null) {return false;}} else if (!map.equals(otherMap)) {return false;}return true;}
}
7、注册ThreadContextMap
在resources下添加log4j2.component.properties文件文件中配置自定义的ThreadContextMap
log4j2.threadContextMaporg.slf4j.TtlThreadContextMap
8、自定义MDCAdapter
注意这里包名最好使用org.slf4j否则访问MDC中的mdcAdapter属性需要使用反射。
package org.slf4j;import com.alibaba.ttl.TransmittableThreadLocal;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.status.StatusLogger;
import org.slf4j.spi.MDCAdapter;import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
import java.util.Objects;/*** author zhuquanwen* version 1.0* date 2023/2/12 11:46*/
public class TtlMDCAdapter implements MDCAdapter {private static Logger LOGGER StatusLogger.getLogger();private final ThreadLocalMapOfStacks mapOfStacks new ThreadLocalMapOfStacks();private static TtlMDCAdapter mtcMDCAdapter;static {mtcMDCAdapter new TtlMDCAdapter();MDC.mdcAdapter mtcMDCAdapter;}public static MDCAdapter getInstance() {return mtcMDCAdapter;}Overridepublic void put(final String key, final String val) {ThreadContext.put(key, val);}Overridepublic String get(final String key) {return ThreadContext.get(key);}Overridepublic void remove(final String key) {ThreadContext.remove(key);}Overridepublic void clear() {ThreadContext.clearMap();}Overridepublic MapString, String getCopyOfContextMap() {return ThreadContext.getContext();}Overridepublic void setContextMap(final MapString, String map) {ThreadContext.clearMap();ThreadContext.putAll(map);}Overridepublic void pushByKey(String key, String value) {if (key null) {ThreadContext.push(value);} else {final String oldValue mapOfStacks.peekByKey(key);if (!Objects.equals(ThreadContext.get(key), oldValue)) {LOGGER.warn(The key {} was used in both the string and stack-valued MDC., key);}mapOfStacks.pushByKey(key, value);ThreadContext.put(key, value);}}Overridepublic String popByKey(String key) {if (key null) {return ThreadContext.getDepth() 0 ? ThreadContext.pop() : null;}final String value mapOfStacks.popByKey(key);if (!Objects.equals(ThreadContext.get(key), value)) {LOGGER.warn(The key {} was used in both the string and stack-valued MDC., key);}ThreadContext.put(key, mapOfStacks.peekByKey(key));return value;}Overridepublic DequeString getCopyOfDequeByKey(String key) {if (key null) {final ThreadContext.ContextStack stack ThreadContext.getImmutableStack();final DequeString copy new ArrayDeque(stack.size());stack.forEach(copy::push);return copy;}return mapOfStacks.getCopyOfDequeByKey(key);}Overridepublic void clearDequeByKey(String key) {if (key null) {ThreadContext.clearStack();} else {mapOfStacks.clearByKey(key);ThreadContext.put(key, null);}}private static class ThreadLocalMapOfStacks {private final ThreadLocalMapString, DequeString tlMapOfStacks new TransmittableThreadLocal();public void pushByKey(String key, String value) {tlMapOfStacks.get().computeIfAbsent(key, ignored - new ArrayDeque()).push(value);}public String popByKey(String key) {final DequeString deque tlMapOfStacks.get().get(key);return deque ! null ? deque.poll() : null;}public DequeString getCopyOfDequeByKey(String key) {final DequeString deque tlMapOfStacks.get().get(key);return deque ! null ? new ArrayDeque(deque) : null;}public void clearByKey(String key) {final DequeString deque tlMapOfStacks.get().get(key);if (deque ! null) {deque.clear();}}public String peekByKey(String key) {final DequeString deque tlMapOfStacks.get().get(key);return deque ! null ? deque.peek() : null;}}
}
9、初始化MDCAdapter
public class TtlMDCAdapterInitializer implements ApplicationContextInitializerConfigurableApplicationContext {Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {//加载TtlMDCAdapter实例TtlMDCAdapter.getInstance();}
}在resources下spring.factories中注册
org.springframework.context.ApplicationContextInitializer\
com.iscas.base.biz.config.TtlMDCAdapterInitializer10、自定义线程池
package com.iscas.base.biz.schedule;import com.alibaba.ttl.TtlCallable;
import com.alibaba.ttl.TtlRunnable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;import java.util.concurrent.Callable;
import java.util.concurrent.Future;/*** author zhuquanwen* version 1.0* date 2023/2/12 12:11*/
public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {Overridepublic void execute(Runnable runnable) {Runnable ttlRunnable TtlRunnable.get(runnable);super.execute(ttlRunnable);}Overridepublic T FutureT submit(CallableT task) {Callable ttlCallable TtlCallable.get(task);return super.submit(ttlCallable);}Overridepublic Future? submit(Runnable task) {Runnable ttlRunnable TtlRunnable.get(task);return super.submit(ttlRunnable);}Overridepublic ListenableFuture? submitListenable(Runnable task) {Runnable ttlRunnable TtlRunnable.get(task);return super.submitListenable(ttlRunnable);}Overridepublic T ListenableFutureT submitListenable(CallableT task) {Callable ttlCallable TtlCallable.get(task);return super.submitListenable(ttlCallable);}
}
11、注册线程池
package com.iscas.biz.config;import com.iscas.base.biz.schedule.CustomThreadPoolTaskExecutor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/**** author zhuquanwen* version 1.0* date 2021/2/26 10:41* since jdk1.8*/
SuppressWarnings(unused)
AutoConfiguration
EnableAsync
public class AsyncConfig implements AsyncConfigurer, BizConstant {private static final int ASYNC_KEEPALIVE_SECONDS 60;private static final int ASYNC_QUEUE_CAPACITY 20000;Bean(asyncExecutor)public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor new CustomThreadPoolTaskExecutor();executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);executor.setQueueCapacity(20000);executor.setKeepAliveSeconds(ASYNC_KEEPALIVE_SECONDS);executor.setThreadNamePrefix(ASYNC_EXECUTOR_NAME_PREFIX);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}}
12、编写示例
package com.iscas.base.biz.test.controller;import com.iscas.base.biz.util.LogLevelUtils;
import com.iscas.base.biz.util.SpringUtils;
import com.iscas.templet.common.ResponseEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.logging.LogLevel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** author zhuquanwen* version 1.0* date 2023/2/11 17:51*/
RestController
RequestMapping(/test/log)
Slf4j
public class LogControllerTest {GetMappingpublic ResponseEntity t1 () {log.debug(test-debug);return ResponseEntity.ok(null);}/*** 调整日志级别* */GetMapping(/t2)public ResponseEntity t2 () {LogLevelUtils.updateLevel(com.iscas.base.biz.test.controller, LogLevel.INFO);return ResponseEntity.ok(null);}/*** 测试子线程打印traceId* */GetMapping(/t3)public ResponseEntity t3() {ThreadPoolTaskExecutor threadPoolTaskExecutor SpringUtils.getBean(asyncExecutor);threadPoolTaskExecutor.execute(() - {log.info(测试子线程打印traceId);});return ResponseEntity.ok(null);}}
日志打印如下