之前遇到过在分布式环境中不方便查找日志的问题,虽然现在的很多云服务环境都提供这种功能,但是在自己搭建的分布式环境中可以考虑应急的这样做,先记录下,以便下次快速使用

注意:MDC-traceId在分布式环境中使用步骤(下面的3456四个类在分布式用到的工程中都需要添加,可以考虑添加到第三方工程中统一在pom中引入)  

1、 引入log4j的同时需要注意去除冲突包

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><!-- 排除自带的logback依赖 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>

2、resources 文件夹下添加[log4j.xml]配置文件

<appender name="trace" class="org.apache.log4j.DailyRollingFileAppender"><param name="File" value="D://logs//trace.log"/><param name="DatePattern" value="'.'yyyy-MM-dd"/><param name="threshold" value="info"/><param name="append" value="true"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] - [%X{traceId}] %-6p%c:%L - %m%n"/></layout>
</appender><root><level value="info"/><appender-ref ref="trace"/>
</root>

        3、添加[MDCUtils]自定义工具类

public class MDCUtils {/*** [获取 traceId]* @return java.lang.String**/public static String mdc(){RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);String traceId;String traceIdKey = "traceId";if (request.getHeader(traceIdKey) == null) {traceId = UUID.randomUUID().toString();} else {traceId = request.getHeader(traceIdKey);}return traceId;}}

        4、添加拦截器[LogInterceptor]为每一个请求头添加[traceId]

public class LogInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String traceIdKey = "traceId";String traceId = MDCUtils.mdc();request.setAttribute(traceIdKey, traceId);MDC.clear();MDC.put(traceIdKey, traceId);return true;}
}

        5、注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LogInterceptor()).addPathPatterns("/test/*");}
}

        6、在每次调用外部接口的httpclient地方添加请求头[traceId]

public class HttpClientHelper {public static String sendGet(String url, LinkedHashMap<String, Object> paramMap, Map<String, Object> headMap) {// 获取连接客户端工具CloseableHttpClient httpClient = HttpClients.createDefault();String entityStr = null;CloseableHttpResponse response = null;try {/** 由于GET请求的参数都是拼装在URL地址后方,所以我们要构建一个URL,带参数*/URIBuilder uriBuilder = new URIBuilder(url);// 第一种添加参数的形式/* uriBuilder.addParameter("name", "root");uriBuilder.addParameter("password", "123456");*/// 第二种添加参数的形式// 加载参数if (!CollectionUtils.isEmpty(paramMap)) {List<NameValuePair> paramertersList = new LinkedList<>();Set<String> keys = paramMap.keySet();for (String s : keys) {String key = String.valueOf(s);String value = ObjectUtils.isEmpty(paramMap.get(key)) ? null : paramMap.get(key).toString();if (ObjectUtils.isNotEmpty((value))) {BasicNameValuePair param1 = new BasicNameValuePair(key, value);paramertersList.add(param1);}}uriBuilder.setParameters(paramertersList);}// 根据带参数的URI对象构建GET请求对象HttpGet httpGet = new HttpGet(uriBuilder.build());if (headMap != null) {for (Map.Entry<String, Object> entry : headMap.entrySet()) {if (entry.getValue() != null) {httpGet.addHeader(entry.getKey(), entry.getValue().toString());}}}String traceId = MDC.get("traceId");httpGet.addHeader("traceId", traceId);httpGet.addHeader("Accept", "*/*");httpGet.addHeader("Connection", "Keep-Alive");// 浏览器表示httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)");// 传输的类型httpGet.addHeader("Content-Type", "application/x-www-form-urlencoded");// 执行请求response = httpClient.execute(httpGet);// 获得响应的实体对象HttpEntity entity = response.getEntity();// 使用Apache提供的工具类进行转换成字符串entityStr = EntityUtils.toString(entity, "UTF-8");} catch (ClientProtocolException e) {System.err.println("Http协议出现问题");e.printStackTrace();} catch (ParseException e) {System.err.println("解析错误");e.printStackTrace();} catch (URISyntaxException e) {System.err.println("URI解析异常");e.printStackTrace();} catch (IOException e) {System.err.println("IO异常");e.printStackTrace();} finally {// 释放连接if (null != response) {try {response.close();httpClient.close();} catch (IOException e) {System.err.println("释放连接出错");e.printStackTrace();}}}return entityStr;}public static String sendPost(String url, LinkedHashMap<String, Object> paramMap, Map<String, Object> headMap) {// 获取连接客户端工具CloseableHttpClient httpClient = HttpClients.createDefault();String entityStr = null;CloseableHttpResponse response = null;try {// 创建POST请求对象HttpPost httpPost = new HttpPost(url);UrlEncodedFormEntity entityParam = null;/** 添加请求参数*/// 创建请求参数if (!CollectionUtils.isEmpty(paramMap)) {List<NameValuePair> paramertersList = new LinkedList<>();Set<String> keys = paramMap.keySet();for (String s : keys) {String key = String.valueOf(s);String value = ObjectUtils.isEmpty(paramMap.get(key)) ? null : paramMap.get(key).toString();if (ObjectUtils.isNotEmpty(value)) {BasicNameValuePair param1 = new BasicNameValuePair(key, value);paramertersList.add(param1);}}// 使用URL实体转换工具entityParam = new UrlEncodedFormEntity(paramertersList, "UTF-8");}httpPost.setEntity(entityParam);if (headMap != null) {for (Map.Entry<String, Object> entry : headMap.entrySet()) {if (entry.getValue() != null) {httpPost.addHeader(entry.getKey(), entry.getValue().toString());}}}String traceId = MDC.get("traceId");httpPost.addHeader("traceId", traceId);httpPost.addHeader("Accept", "*/*");httpPost.addHeader("Connection", "Keep-Alive");httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)");// 传输的类型httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");// 执行请求response = httpClient.execute(httpPost);// 获得响应的实体对象HttpEntity entity = response.getEntity();// 使用Apache提供的工具类进行转换成字符串entityStr = EntityUtils.toString(entity, "UTF-8");// 此处获取所有的响应头信息并进行打印System.out.println(Arrays.toString(response.getAllHeaders()));} catch (ClientProtocolException e) {System.err.println("Http协议出现问题");e.printStackTrace();} catch (ParseException e) {System.err.println("解析错误");e.printStackTrace();} catch (IOException e) {System.err.println("IO异常");e.printStackTrace();} finally {// 释放连接if (null != response) {try {response.close();httpClient.close();} catch (IOException e) {System.err.println("释放连接出错");e.printStackTrace();}}}return entityStr;}}

        7、请求实例: 1-调用-2

1:
2021-07-21 11:14:30.168 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc.controller.TestController:27  - 测试 test1
2021-07-21 11:14:30.169 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc.controller.TestService:18  - =====TestService.test1
2021-07-21 11:14:30.169 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc.controller.TestService:22  - =====TestService.test3
2021-07-21 11:14:30.169 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc.controller.TestService:26  - =====TestService.test3
2021-07-21 11:14:30.771 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc.controller.TestController:35  - ===s===aaaaa2:
2021-07-21 11:14:30.746 - [283ba7ba-8910-48e3-8864-cd8de7af07cb] INFO  com.example.demolog4jmdc2.controller.TestController:26  - 测试 test1-traceId:283ba7ba-8910-48e3-8864-cd8de7af07cb

到此分布式链路追踪—traceId生成与使用(MDC)介绍完成。

分布式链路追踪—traceId生成与使用(MDC)相关推荐

  1. 原来10张图就可以搞懂分布式链路追踪系统原理

    分布式系统为什么需要链路追踪? 随着互联网业务快速扩展,软件架构也日益变得复杂,为了适应海量用户高并发请求,系统中越来越多的组件开始走向分布式化,如单体架构拆分为微服务.服务内缓存变为分布式缓存.服务 ...

  2. 分布式链路追踪框架的基本实现原理

    目录 分布式追踪 分布式系统 分布式追踪 分布式追踪有什么用呢 什么是分布式追踪 Dapper 分布式追踪系统的实现 跟踪树和 span Jaeger 和 OpenTracing OpenTracin ...

  3. 分布式链路追踪系统深入理解

    背景 对于普通系统或者服务来说,一般通过打日志来进行埋点,然后再通过elk进行定位及分析问题,更有甚者直接远程服务器,使用各种linux命令单手操作查看日志,说到这,我也没摆脱这种困境.那么随着业务越 ...

  4. 分布式链路追踪SkyWalking进阶实战之RPC上报和WebHook通知(三)

    目录 1.自定义SkyWalking链路追踪配置 1.1 什么是TraceId 1.2 使用的背景 1.3 编码 2.SkyWalking-RocketBot性能剖析 3.SkyWalking链路追踪 ...

  5. 分布式链路追踪深入了解

    分布式链路追踪系统 背景 对于普通系统或者服务来说,一般通过打日志来进行埋点,然后再通过elk进行定位及分析问题,更有甚者直接远程服务器,使用各种linux命令单手操作查看日志,说到这,我也没摆脱这种 ...

  6. 怎么理解分布式链路追踪技术?

    ▲ 点击上方"分布式实验室"关注公众号 回复"1"抽取纸质技术书 - 1 - 为什么需要链路追踪 在学习分布式链路追踪之前,我们需要先理解这项技术产生的背景,以 ...

  7. 如何理解分布式链路追踪技术

    什么是链路追踪?微服务引发了怎样的问题? 在深入了解分布式链路追踪技术之前,我们需要先理解这项技术产生的背景,以及它能够帮我们解决哪些棘手的问题. 提到分布式链路追踪,我们要先提到微服务.相信很多人都 ...

  8. 分布式链路追踪之SkyWalking

    一 链路追踪简介   在微服务架构中,一次请求往往涉及到多个模块,多个中间件,多台机器的相互协作才能完成.这一系列调用请求中,有些是串行的,有些是并行的,那么如何确定这个请求背后调用了哪些应用,哪些模 ...

  9. 分布式链路追踪之Spring Cloud Sleuth夺命连环9问?

    点击上方☝码猿技术专栏 轻松关注,设为星标! 及时获取有趣有料的技术 大家好,我是不才陈某~ 这是<Spring Cloud 进阶>第九篇文章,往期文章如下: 五十五张图告诉你微服务的灵魂 ...

最新文章

  1. win10防火墙删除的文件在哪里_Win10系统关闭Windows Defender
  2. python yield 简单用法_python中 yield 的用法 (简单、清晰)
  3. P5355-[Ynoi2017]由乃的玉米田【莫队,bitset,根号分治】
  4. 消息称百度网盘青春版降速23倍:从52MB/s降至2.2MB/s
  5. 非域环境下安装并配置Project Server 2007(二)
  6. 5A通过PMP考试分享
  7. 多个PDF怎么免费合并成一个PDF
  8. Spring配置解析之Component-scan解析
  9. MODBUS-RTU协议主机和从机代码STM32 包含2个程序代码,主机和从机
  10. 【Git学习】解决GitLab内存消耗大的问题
  11. 在Docker容器中使用iptables时的最小权限的开启方法
  12. 计算机网络上传慢,电脑上传速度慢的正确处理方法
  13. 前端轮播插件banner
  14. 数学界的扫地僧们(转载)
  15. Revit 2014 发布, Revit 2014 API新功能
  16. 【学习cmake】cmake如何使用链接库 (link_directories, LINK_LIBRARIES, target_link_libraries,FIND_PACKAGE)实践篇2
  17. 哈佛大学凌晨4点半的景象 .
  18. 智慧魔珠金字塔(类似俄罗斯方块)的所有情况 python
  19. python sklearn PCA 实例-主成分分析
  20. 如何正确理解企业文化

热门文章

  1. MAC OS 配置ATOM 编写python
  2. 三角测量计算点的三维坐标
  3. 计算机防ping取消,如何防止别人ping自己局域网电脑
  4. 动态左侧二级下拉菜单 基于bootstrap js
  5. docker里面什么emule比较好_求万由系统DOCKER电驴的设置方式
  6. JS中上树是什么意思?
  7. 腾讯+阿里+百度Java高频面试题(涵盖了年薪20W80W的高频面试题)
  8. MATLAB绘制加噪和去噪图像
  9. python批量创建账号密码
  10. linux瘦身软件下载,艾美瘦身app下载-艾美瘦身健身手机版v1.5.7-Linux公社