介绍:

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}

127.0.0.1

local6

514

${FILE_LOG_PATTERN}

java MDC_log4j MDC实现日志追踪相关推荐

  1. 简单记录使用org.slf4j.MDC进行日志追踪

    日志追踪 依赖 配置文件 代码 controller service 控制台打印 源码追踪 依赖 这里使用的是log4j2 <parent><groupId>org.sprin ...

  2. java ndc_通过slf4j/log4j的MDC/NDC 实现日志追踪

    在分布式系统或者较为复杂的系统中,我们希望可以看到一个客户请求的处理过程所涉及到的所有子系统\模块的处理日志. 由于slf4j/log4j基本是日志记录的标准组件,所以slf4j/log4j成为了我的 ...

  3. 循序渐进看Java web日志跟踪(1)-Tomcat 日志追踪与配置

    日志,是软件运行过程中,对各类操作中重要信息的记录. 日志跟踪,不管对于怎么样的项目来说,都是非常重要的一部分,它关系到项目后期的维护和排错,起着举足轻重的作用.项目开发过程中,对日志的记录规则,也将 ...

  4. MDC实现日志链路追踪

    开发过程中难免遇到需要查看日志来找出问题出在哪一环节的情况,而在实际情况中服务之间互相调用所产生的日志冗长且复杂,若是再加上同一时间别的请求所产生的日志,想要精准定位自己想要查看的日志就比较麻烦.为解 ...

  5. 探索java世界中的日志奥秘

    java日志简单介绍 对于一个应用程序来说日志记录是必不可少的一部分.线上问题追踪,基于日志的业务逻辑统计分析等都离不日志.JAVA领域存在多种日志框架,目前常用的日志框架包括Log4j,Log4j ...

  6. 【Spring Cloud Alibaba 温故而知新】(五)SpringCloud Sleuth + Zipkin:分布式日志追踪

    目录 8.1.1 SpringCloud Sleuth 是什么 SpringCloud Sleuth 必知必会 SpringCloud Sleuth 实现的功能是:它会自动为当前应用构建起各通信通道的 ...

  7. 使用MDC增强日志记录

    文章目录 (一)日志框架 1. 日志框架介绍和选择 2. 原理介绍 3. SpringBoot日志框架 (二)使用MDC增强日志记录 1. 介绍 2. 普通示例 3. 在Log4j中使用MDC 4. ...

  8. java 可视化系统操作日志_技术文 | 日志框架使用技巧分享

    原标题:技术文 | 日志框架使用技巧分享 日志的意义 对于一个应用程序来说日志记录是具有重要意义的. 日志通常用于线上问题追踪,协助定位业务问题或程序问题,以及基于日志的业务逻辑统计分析等. java ...

  9. Dubbo分布式日志追踪

    很多互联网公司都用的dubbo分布式框架进行微服务的开发,一个大系统往往会被拆分成很多不同的子系统,并且子系统还会部署多台机器,当其中一个系统出问题了,查看日志十分麻烦 所以我们需要一个固定的流程ID ...

最新文章

  1. C# BackgroundWorker 详解
  2. C#如何判断线程池中所有的线程是否已经完成(转)
  3. Angular 中的依赖注入link
  4. java暂停的方法_Java使用join方法暂停当前线程
  5. 【Linux部署】Linux环境 .rar 格式文件处理工具安装使用(一波两折避坑指北)
  6. 图灵原版计算机科学系列,图灵原版计算科学系列
  7. 53pagecontext对象
  8. wxwidget编译安装_wxWidgets的安装编译、相关配置、问题分析处理
  9. python中装饰器修复技术_python3之装饰器修复技术@wraps
  10. Andriod下音频的相关操作
  11. mybatis 动态SQL-where标签
  12. ASP.NET对HTML元素进行权限控制(二)
  13. Intel HD Graphics
  14. 四象限原则+番茄时间管理法
  15. icon好看的图标-素材库
  16. 懒人精灵 一 获取淘宝北京时间接口
  17. ddd软件设计两个人的工作
  18. Xcode 13.4.1如何显示文件拓展名
  19. 【教程】笔记本装Win10+Deepin双系统|详细
  20. Mac电池显示需要维修

热门文章

  1. 谷歌浏览器翻译插件 Linkclump:一次性打开多个链接
  2. linux shell 提示符消失 终端提示符显示-bash-4.1# 解决方法
  3. UNIX中的restrict
  4. ruby gem 本地安装方法
  5. 测试自己像什么动物软件叫什么,【测试】你最像哪种动物?
  6. scrapy 中不同页面的拼接_scrapy官方文档提供的常见使用问题
  7. 学生计算机屏幕坏了怎么办,如果计算机显示器的屏幕坏了怎么办?
  8. java模拟银行存取_JAVA基础案例 模拟银行存取款业务
  9. linux svn磁盘空间满,Linux svn checkout时候总报设备上没有空间
  10. angular路由传递参数_@medux 路由篇