我们在做java项目的时候通常需要通过请求日志来排查定位线上问题,在日志比较多而我们又需要查找整个请求的全部日志的时候会比较困难。所以,就需要在日志记录的时候讲同一个请求的关键日志用同一个唯一标识串联起来。这样查找的时候就会比较好查找。下面来用java aop实现请求id的日志记录。(该支持子线程继承主线程请求id)

一:首先我们需要一个日志请求链路id切面类

注意:如果不考虑多线程则(第二步和第三步可以不要)

package com.iMagine.iMagine_pro.aop;

import com.iMagine.iMagine_common.utils.UUIDUtil;
import com.iMagine.iMagine_pro.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

/**
* @author 名一
* @ClassName TraceIdAspect
* @description: 日志请求链路id切面处理
* @datetime 2024年 12月 16日 14:28
* @version: 1.0
*/
@Slf4j
@Aspect
@Component
public class TraceIdAspect {

/** 链路追踪id */
public final static String TRACE_ID = "TRACE_ID";
/** 用户 */
public final static String USER = "USER";

/**
* 链路id切点定义
*/
@Pointcut("execution(* com.iMagine.iMagine_pro.controller.*.*(..))")
public void TraceIdCut() {

}

/**
* 链路id添加
*/
@Before("TraceIdCut()")
public void cutProcessBefore() {
MDC.put(TRACE_ID, UUIDUtil.getUUID());
//以下代码为记录用户信息,方便更直观的识别日志操作人信息。若不需要可以将下面部分删除
String nickname = TokenUtil.getNicknameByToken();
if (null == nickname){
nickname = "游客访问";
}
MDC.put(USER, nickname);
}

/**
* 链路id清除
*/
@After("TraceIdCut()")
public void cutProcessAfter() {
MDC.clear();
}
}
package com.iMagine.iMagine_common.utils;

import java.util.UUID;

/**
* @author 名一
* @ClassName UUIDUtil
* @description: UUID工具类
* @datetime 2024年 04月 23日 11:49
* @version: 1.0
*/
public class UUIDUtil { /**
* 获取UUID
*
* @return
*/
public static String getUUID() {
//生产uuid并去掉uuid的短横线
return UUID.randomUUID().toString().replace("-", "");
}
}

二:创建一个处理多线程链路追踪的工具类

package com.iMagine.iMagine_common.utils;

import com.iMagine.iMagine_common.constant.SysConstant;
import org.slf4j.MDC;

import java.util.Map;

/**
* @author 名一
* @ClassName ThreadMdcUtil
* @description: 多线程链路追踪工具类
* @datetime 2024年 12月 16日 14:57
* @version: 1.0
*/
public class ThreadMdcUtil {

// 获取唯一性标识
public static String generateTraceId() {
return UUIDUtil.getUUID();
}

public static void setTraceIdIfAbsent() {
if (MDC.get(SysConstant.TRACE_ID) == null) {
MDC.put(SysConstant.TRACE_ID, generateTraceId());
}
}

/**
* 用于父线程向线程池中提交任务时,将自身MDC中的数据复制给子线程
*
* @param runnable 要执行的线程
* @param context 父线程的mdc
* @return 链路id传递后的任务
*/
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();
}
};
}
}

三:在往线程池放任务的时候做请求链路id传递

/**
* 线程池添加 [ai server 相关操作(psot)]任务
*
* @param task 添加的任务
*/
public static void addSendPostThreadToThreadPool(SendPostThread task) {
log.info("addSendPostThreadToThreadPool pool:{}, task:{}", pool, task);
try {
pool.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
} catch (Exception e) {
log.error("addSendPostThreadToThreadPool error pool:{}, task:{}, e:", pool, task, e);
}
}

四:在日志配置里将链路追踪id加入日志输出格式的配置里

<!-- 日志输出格式 (其中%X{TRACE_ID}是mdc里边链路请求id的key,user-%X{USER}是用户信息的key)-->
<property name="ENCODER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{TRACE_ID} user-%X{USER} %-5level %logger{32}-[%line] - %msg%n"/>

到此spring 项目实现带请求链路id的日志记录就完成了

spring 项目实现带请求链路id的日志记录的更多相关文章

  1. 9.Spring Boot实战之配置使用Logback进行日志记录

    转自:https://blog.csdn.net/meiliangdeng1990/article/details/54300227 Spring Boot实战之配置使用Logback进行日志记录 在 ...

  2. 通过 Spring RestTemplate 调用带请求体的 Delete 方法(Delete With Request Body)

    Spring 框架的RestTemplate 类定义了一些我们在通过 java 代码调用 Rest 服务时经常需要用到的方法,使得我们通过 java 调用 rest 服务时更加方便.简单.但是 Res ...

  3. Spring AOP的日志记录

    现在的项目是Spring+MyBatis,前段时间项目经理让我干了一个活,就是给所有的controller里的所有方法加上日志记录的代码,其实没有多少,也就300来个方法,也没有抱怨什么,一边打着瞌睡 ...

  4. Spring Boot 之日志记录

    Spring Boot 之日志记录 Spring Boot 支持集成 Java 世界主流的日志库. 如果对于 Java 日志库不熟悉,可以参考:细说 Java 主流日志工具库 关键词: log4j, ...

  5. Spring MVC中forward请求转发2种方式(带参数)

    Spring MVC中forward请求转发2种方式(带参数) http://www.51gjie.com/javaweb/956.html  

  6. Spring项目集成ShiroFilter简单实现权限管理

    Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ...

  7. Spring Cloud 系列之 Sleuth 链路追踪(一)

    随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务.互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发.可能使用不同的编程语言来实现.有可能布在了 ...

  8. go-zero 是如何追踪你的请求链路的

    go-zero 是如何追踪你的请求链路 微服务架构中,调用链可能很漫长,从 http 到 rpc ,又从 rpc 到 http .而开发者想了解每个环节的调用情况及性能,最佳方案就是 全链路跟踪. 追 ...

  9. spring boot / cloud (十六) 分布式ID生成服务

    spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...

  10. Spring项目集成ShiroFilter简单配置

    Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ...

随机推荐

  1. Redis数据库常见命令

    Redis数据库常见命令 Linux启动Redis # 启动服务 redis-server # 开启客户端 redis-cli # 关闭redis服务 shutdown #查看服务是否运行 ping ...

  2. uniapp中前端canvas合成图片使用详解

    项目开发中用到了定位打卡,保存当前位置到上传图片的功能.刚开始想着后端人员合成,前端上传经纬度.位置信息和图片就OK,没想到后端人员以使用项目中现有的组件为借口,让前端合成图片,造成前端工作量大增,再 ...

  3. 在Vue3中如何实现四种全局状态数据的统一管理?

    四种全局状态数据 在实际开发当中,会遇到四种全局状态数据:异步数据(一般来自服务端).同步数据.同步数据又分为三种:localstorage.cookie.内存.在传统的 Vue3 当中,分别采用不同 ...

  4. C#的排序方法 OrderBy

    using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.R ...

  5. 66.有没有碰到过数组响应丢失(问的是ref和reactive的用法,什么情况下用)

    由于vue3使用proxy,对于对象和数组都不能直接整个赋值.  直接赋值丢失了响应性 只有push或者根据索引遍历赋值才可以保留reactive数组的响应性  : 可以使用 toRefs 解决这个问 ...

  6. 基于.NET8 + Vue/UniApp前后端分离的快速开发框架,开箱即用!

    前言 今天大姚给大家分享一款基于.NET8 + Vue/UniApp前后端分离的快速开发框架,开箱即用:ZR.Admin.NET. 开源免费(基于MIT License开源协议).代码量少.学习简单. ...

  7. ARM 版 Kylin V10 部署 KubeSphere 3.4.0 不完全指南

    前言 知识点 定级:入门级 KubeKey 安装部署 ARM 版 KubeSphere 和 Kubernetes ARM 版麒麟 V10 安装部署 KubeSphere 和 Kubernetes 常见 ...

  8. snap和apt的区别简单了解[]

    Linux中没有tree命令的时候提示安装的时候出现了两个命令,简单看了看两者有何区别(一般用apt就可以了):   sudo snap install tree 和 sudo apt install ...

  9. 常用css列表

    常用css列表 color 设置文字的颜色,如: color:red; font-size 设置文字的大小,如:font-size:12px; font-family 设置文字的字体,如:font-f ...

  10. Java EasyExcel 导出报内存溢出如何解决

    大家好,我是 V 哥.使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时.你有遇到过这种情况吗,以下是V 哥整理的解决该问题的一些常见方法,分享给大家,欢迎一起讨论 ...