首页 > 其他分享 >springboot的链路日志

springboot的链路日志

时间:2024-05-11 16:58:20浏览次数:11  
标签:RequestIdUtils void request uuid UUID 链路 日志 public springboot

  1.背景

  在开发银行项目的时候有一个生成项目链路日志的需求。所谓的链路日志就是一个请求会经过多个项目的接口调用,它把这个请求内调用到的所有请求通过全局id串起来,通过全局id可以把所有涉及到的系统日志都快速的定位出来,方便线上出现问题时去排查问题。

  2.实现

  查阅了一些资料后发现大致有两种方案去实现。第一种就是使用MDC( log4j 和 logback 提供的一种方便在线多线程条件下记录日志的功能,可以看成是一个与当前线程绑定的 ThreadLocal)。大致的逻辑就是在项目中声明一个过滤器,然后在dofilter方法里面使用MDC去塞一个requestId,requestId可以是从网关那边的header中传递过来,也可以是自己生成的一个uuid,然后在logback-spring.xml中配置相对应的key值。示例如下

@WebFilter(urlPatterns = {"/*"},filterName = "requestFilter")
@Slf4j
public class RequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("filter init");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        MDC.put("REQUEST_ID", this.getRequestId());
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        RequestIdUtils.removeRequestId();
        MDC.clear();
    }
    /**
     * 获取RequestId
     * 优先从header头获取,如果没有则自己生成
     *
     * @return RequestId
     */
    private String getRequestId() {
        // 因为如果有网关,则一般会从网关传递过来,所以优先从header头获取
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null && StringUtils.hasText(attributes.getRequest().getHeader("x-request-id"))) {
            HttpServletRequest request = attributes.getRequest();
            String requestId = request.getHeader("x-request-id");
            UUID uuid = UUID.fromString(requestId);
            RequestIdUtils.generateRequestId(uuid);
            return requestId;
        }
        UUID existUUID = RequestIdUtils.getRequestId();
        if (existUUID != null) {
            return existUUID.toString();
        }
        RequestIdUtils.generateRequestId();
        return RequestIdUtils.getRequestId().toString();
    }
}
public class RequestIdUtils {
    private static final ThreadLocal<UUID> requestIdHolder = new ThreadLocal<>();

    private RequestIdUtils() {

    }

    public static void generateRequestId() {
        requestIdHolder.set(UUID.randomUUID());
    }

    public static void generateRequestId(UUID uuid) {
        requestIdHolder.set(uuid);
    }

    public static UUID getRequestId() {
        return requestIdHolder.get();
    }

    public static void removeRequestId() {
        requestIdHolder.remove();
    }
}

因为我在filter里面put的key是REQUEST_ID,故logback-spring.xml里的核心配置如下:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss} [%X{REQUEST_ID}]-[%thread] %-5level %logger - %msg%n
            </Pattern>
        </layout>
    </appender>

最终的效果如下:

 

后面觉得第一种太繁琐了就使用了第二种方案,第二种就是使用sleuth依赖去实现,引入依赖之后在logback-spring.xml中配置下tarceId跟spanId就可以了。这里的spanId是基本工作单元,发送一个远程调度任务 就会产生一个Span,Span是一个64位ID唯一标识的。tarceId就是一系列Span组成的一个树状结构。tarceId 也用一个 64 位的 id 唯一标识,trace 中的所有 span 都共享该 tarceId

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

这里有一个点要注意下,当时排查了很久。traceId跟spanId是sleuth的3.X以上版本配置;3.X以下版本要配置X-B3-TraceId跟X-B3-SpanId

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId:-},%X{spanId:-}] [%thread] %-5level %logger - %msg%n
            </Pattern>
        </layout>
 </appender>

效果如下

 

标签:RequestIdUtils,void,request,uuid,UUID,链路,日志,public,springboot
From: https://www.cnblogs.com/shitechnology/p/18186775

相关文章

  • EasyLogger - 一款超轻量级、高性能的 C/C++ 日志库
    1、EasyLogger-一款超轻量级、高性能的C/C++日志库EasyLogger是一款超轻量级(ROM<1.6K,RAM<0.3K)、高性能的C/C++日志库,非常适合对资源敏感的软件项目,例如:IoT产品、可穿戴设备、智能家居等等。相比log4c、zlog这些知名的C/C++日志库,EasyLogger的功能更加简单,提供......
  • springboot使用log4j监控日志发送邮件
    实现log4j发送邮件功能大致流程:1、开启邮箱SMTP服务,获取SMTP登录密码2、引入javax.mail、javax.activation依赖3、配置log4j文件,指定邮件发送方和接收方以及发送方账号密码等4、重写SMTPAppender(不重写也能实现邮件发送功能)开启邮箱SMTP服务这里以qq邮......
  • springboot项目服务器访问速度慢-可能的解决方法
    springboot项目部署在服务器后,访问很慢或无法访问问题使用宝塔界面,尝试将打包后的jar包部署在服务器上运行时,发现访问速度不是很快,或者是直接访问不到。访问不到对应端口的springboot服务80端口也无法访问首次访问加载慢的解决方法修改jre文件找到安装的jre目......
  • 非常完整的开源无刷电机驱动项目+仅1300行代码的C语言异步网络库+简单到傻瓜都会用的
    1、VESC-非常完整的开源无刷电机驱动项目ESC是ElectricSpeedController的缩写,也就是电子调速控制器,简称电调;项目作者是BenjaminVedder,所以叫VESC,就是本杰明电调。这个项目主要分为几个部分,VESC固件,物料清单,VESC硬件,VESC工具软件,是一个非常完整的软硬件项目,并且配套的软......
  • Springboot Data Jdbc中Contains和Containing的用法
    Contains和Containing的用法privateStringtitle;privateList<String>tags;//查询标题包含指定字符串的书籍List<Book>findByTitleContains(Stringtitle);//查询包含指定标签的书籍List<Book>findByTagsContaining(Stringtag);--查询标题包含"Spring"的书......
  • 死磕nginx系列-nginx日志配置
    nginxaccess日志配置access_log日志配置access_log用来定义日志级别,日志位置。语法如下:日志级别: debug>info>notice>warn>error>crit>alert>emerg语法格式: access_logpath[format[buffer=size][gzip[=level]][flush=time][if=condition]];......
  • SpringBoot整合Mybatis时mapper文件和xml文件的位置
    xml文件放在resources下看下我的项目目录2.由于放在resurces下就无法扫描到xml文件,所以就需要在配置文件配置--mapper文件位置mybatis.mapper-locations=classpath:mapper/*.xml或mybatis.mapper-locations=classpath:/mapper/*.xmlxml和mapper文件放在一起我的项目......
  • Springboot单机多副本运行,解决端口冲突
    一、代码方式(修改配置类)@BeanpublicWebServerFactoryCustomizer<ConfigurableWebServerFactory>MyCustomizer(){returnnewWebServerFactoryCustomizer<ConfigurableWebServerFactory>(){@Overridepublicvoidcustomize(ConfigurableWebSer......
  • 日志的实现
    在mybatis-config.xml中可以配置日志的实现STDOUT_LOGGING标准日志的实现,比较简单<settings><settingname="logImpl"value="STDOUT_LOGGING"/></settings>LOG4J常用,可以进行一些自定义的配置导入log4j的包<dependency><groupId>lo......
  • springboot+vue快速部署前后台项目,无需服务器
    问题前言我们都知道,现在的主流开发大多数为,前后端分离,目前流行的框架,大多数是springboot+elementui这些框架,这无疑是给开发部署项目带来了便利,我们后台开发无需关心前端如何部署的,前端同样也无需关系后台如何部署,只需要确认能够访问即可。存在有如下问题:当由于条件有限,我......