java MDC_JAVA编程技巧之 MDC实现日志追踪

MDC 中包含的可以被同一线程中执行的代码所访问内容。当前线程的子线程会继承其父线程中的 MDC 的内容。记录日志时,只需要从 MDC 中获取所需的信息即可。

作用:

使用MDC来记录日志,可以规范多开发下日志格式。

一:新建线程处理类 ThreadContext

import java.io.Serializable;import java.util.HashMap;import java.util.Map;import java.util.Optional;

/**

* 线程上下文

*

* @date 2017年3月1日

* @since 1.0.0

*/public class ThreadContext {

/**

* 线程上下文变量的持有者

*/

private final static ThreadLocal> CTX_HOLDER = new ThreadLocal>();

static {

CTX_HOLDER.set(new HashMap());

}

/**

* traceID

*/

private final static String TRACE_ID_KEY = "traceId";

/**

* 会话ID

*/

private final static String SESSION_KEY = "token";

/**

* 操作用户ID

*/

private final static String VISITOR_ID_KEY = "userId";

/**

* 操作用户名

*/

private final static String VISITOR_NAME_KEY = "userName";

/**

* 客户端IP

*/

private static final String CLIENT_IP_KEY = "clientIp";

/**

* 添加内容到线程上下文中

*

* @param key

* @param value

*/

public final static void putContext(String key, Object value) {

Map ctx = CTX_HOLDER.get();

if (ctx == null) {

return;

}

ctx.put(key, value);

}

/**

* 从线程上下文中获取内容

*

* @param key

*/

@SuppressWarnings("unchecked")

public final static  T getContext(String key) {

Map ctx = CTX_HOLDER.get();

if (ctx == null) {

return null;

}

return (T) ctx.get(key);

}

/**

* 获取线程上下文

*/

public final static Map getContext() {

Map ctx = CTX_HOLDER.get();

if (ctx == null) {

return null;

}

return ctx;

}

/**

* 删除上下文中的key

*

* @param key

*/

public final static void remove(String key) {

Map ctx = CTX_HOLDER.get();

if (ctx != null) {

ctx.remove(key);

}

}

/**

* 上下文中是否包含此key

*

* @param key

* @return

*/

public final static boolean contains(String key) {

Map ctx = CTX_HOLDER.get();

if (ctx != null) {

return ctx.containsKey(key);

}

return false;

}

/**

* 清空线程上下文

*/

public final static void clean() {

CTX_HOLDER.remove();

}

/**

* 初始化线程上下文

*/

public final static void init() {

CTX_HOLDER.set(new HashMap());

}

/**

* 设置traceID数据

*/

public final static void putTraceId(String traceId) {

putContext(TRACE_ID_KEY, traceId);

}

/**

* 获取traceID数据

*/

public final static String getTraceId() {

return getContext(TRACE_ID_KEY);

}

/**

* 设置会话的用户ID

*/

public final static void putUserId(Integer userId) {

putContext(VISITOR_ID_KEY, userId);

}

/**

* 设置会话的用户ID

*/

public final static int getUserId() {

Integer val = getContext(VISITOR_ID_KEY);

return val == null ? 0 : val;

}

/**

* 设置会话的用户名

*/

public final static void putUserName(String userName) {

putContext(VISITOR_NAME_KEY, userName);

}

/**

* 获取会话的用户名称

*/

public final static String getUserName() {

return Optional.ofNullable(getContext(VISITOR_NAME_KEY))

.map(name -> String.valueOf(name))

.orElse("");

}

/**

* 取出IP

*

* @return

*/

public static final String getClientIp() {

return getContext(CLIENT_IP_KEY);

}

/**

* 设置IP

*

* @param ip

*/

public static final void putClientIp(String ip) {

putContext(CLIENT_IP_KEY, ip);

}

/**

* 设置会话ID

*

* @param token

*/

public static void putSessionId(String token) {

putContext(SESSION_KEY, token);

}

/**

* 获取会话ID

*

* @param token

*/

public static String getSessionId(String token) {

return getContext(SESSION_KEY);

}

/**

* 清空会话数据

*/

public final static void removeSessionId() {

remove(SESSION_KEY);

}

}

二:添加工具类TraceUtil

import java.util.UUID;import org.slf4j.MDC;import ThreadContext;

/**

* trace工具

*

* @date 2017年3月10日

* @since 1.0.0

*/public class TraceUtil {

public static void traceStart() {

ThreadContext.init();

String traceId = generateTraceId();

MDC.put('traceId', traceId);

ThreadContext.putTraceId(traceId);

}

public static void traceEnd() {

MDC.clear();

ThreadContext.clean();

}

/**

* 生成跟踪ID

*

* @return

*/

private static String generateTraceId() {

return UUID.randomUUID().toString();

}

}

三:添加ContextFilter,对于每个请求随机生成RequestID并放入MDC

import java.io.IOException;

import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;

import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.web.filter.OncePerRequestFilter;

import com.pingan.manpan.common.util.TraceUtil;import com.pingan.manpan.user.dto.ThreadContext;import com.pingan.manpan.web.common.surpport.IpUtils;

/**

* 上下文Filter

*

* @date 2017/3/10

* @since 1.0.0

*///@Order 标记组件的加载顺序

@Order(Ordered.HIGHEST_PRECEDENCE)public class ContextFilter extends OncePerRequestFilter {

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,

FilterChain filterChain) throws ServletException, IOException {

try {

ThreadContext.putClientIp(IpUtils.getClientIp(request));

TraceUtil.traceStart();

filterChain.doFilter(request, response);

} finally {

TraceUtil.traceEnd();

}

}

}

四:在webConfiguriation注册filter

/**

* 请求上下文,应该在最外层

*

* @return

*/

@Bean

public FilterRegistrationBean requestContextRepositoryFilterRegistrationBean() {

FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

filterRegistrationBean.setFilter(new ContextFilter());

filterRegistrationBean.addUrlPatterns("/*");

return filterRegistrationBean;

}

五:修改log4j日志配置文件,设置日志traceId

class="ch.qos.logback.core.rolling.RollingFileAppender">

${FILE_LOG_PATTERN}

${LOG_FILE}${LOG_FILE_SUFFIX}

${LOG_FILE}.%d{yyyy-MM-dd}${LOG_FILE_SUFFIX}

以上就介绍了JAVA的相关知识,希望对JAVA有兴趣的朋友有所帮助。了解更多内容,请关注职坐标编程语言JAVA频道!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值