SpringBoot+Logback实现一个简单的链路追踪功能

最近线上排查问题时候,发现请求太多导致日志错综复杂,没办法把用户在一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简单的链路追踪,下面详细介绍下。

一、实现原理

Spring Boot默认使用LogBack日志系统,并且已经引入了相关的jar包,所以我们无需任何配置便可以使用LogBack打印日志。

MDC(Mapped Diagnostic Context,映射调试上下文)是log4j和logback提供的一种方便在多线程条件下记录日志的功能。

实现思路是在一个请求开始时,将请求相关的上下文信息(例如客户ID、客户的IP地址、sessionId、请求参数等)添加到MDC,然后配置好logback-spring.xml,则Logback组件将会在每条日志中打印出存放到MDC的信息,从而实现一个ID贯穿用户的所有操作。

二、代码实战

新建一个spring boot项目spring-boot-log,按照下面步骤操作。

新建日志拦截器

日志拦截器在请求开始获取用户的sessionId,当然也可以生成一个UUID,生成后存放到MDC中。

SessionInterceptor代码如下:

/**
 * 日志拦截器
 * @Author: Java碎碎念
 *
 */
public class SessionInterceptor extends HandlerInterceptorAdapter {
  /**
   * 会话ID
   */
  private final static String SESSION_KEY = "sessionId";

  @Override
  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
              Object arg2, ModelAndView arg3) throws Exception {
  }

  @Override
  public boolean preHandle(HttpServletRequest request,
               HttpServletResponse response, Object handler) throws Exception {

//    String token = UUID.randomUUID().toString().replaceAll("-","");
    //本例测试使用sessionId,也可以使用UUID等
    String token = request.getSession().getId();
    MDC.put(SESSION_KEY, token);
    return true;
  }

  @Override
  public void afterCompletion(HttpServletRequest arg0,
                HttpServletResponse arg1, Object arg2, Exception arg3)
      throws Exception {
    // 删除
    MDC.remove(SESSION_KEY);
  }
}

新建配置类

新建InterceptorConfig,注册刚才的日志拦截器。

InterceptorConfig代码如下:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

  @Bean
  public SessionInterceptor getSessionInterceptor() {
    return new SessionInterceptor();
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(getSessionInterceptor()).addPathPatterns("/*");
  }
}

修改logback-spring.xml

配置logback-spring.xml,获取日志拦截器添加的sessionId并打印到日志中,配置文件中获取方式如下:

%X{sessionId}

本例中打印sessionId到控制台和文件,完整配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <property name="log.base" value="./log/logback"/>
  <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern> %date [%thread] [%X{sessionId}] %-5level %logger{80} - %msg%n
      </pattern>
    </encoder>
  </appender>

  <appender name="logfile"
       class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${log.base}.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <FileNamePattern>${log.base}.%d{yyyy -MM-dd}.log.zip</FileNamePattern>
    </rollingPolicy>
    <encoder>
      <pattern> %date [%thread] [%X{sessionId}] %-5level %logger{80} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <logger name="com.sample" level="TRACE"/>
  <root>
    <level value="INFO"/>
    <appender-ref ref="stdout"/>
    <appender-ref ref="logfile"/>
  </root>
</configuration>

添加controller

新建TestLogController,打印日志。

代码如下:

@RestController
public class TestLogController {
  Logger log = LoggerFactory.getLogger(getClass());
  /**
   * 测试登录
   */
  @RequestMapping(value = "/testLogin")
  public String testLogin() {
    log.info("用户登录成功!");
    return "ok";
  }
  /**
   * 测试下单
   */
  @RequestMapping(value = "/testNewOrder")
  public String testNewOrder() {
    log.info("用户创建了订单!");
    log.info("请求完成,返回ok!");
    return "ok";
  }
  /**
   * 测试购买
   */
  @RequestMapping(value = "/testPay")
  public String testPay() {
    log.info("用户付款!");
    return "ok";
  }
}

三、测试

打开浏览器连续访问接口testLogin、testNewOrder和testPay,模拟用户登录、下单、付款操作,控制台和文件中打印的日志中已经包含了sessonId信息,打印的结果如下:

[http-nio-8888-exec-1] [CB8E7DB250A31F2BE6C05B30633B9A95] INFO  com.example.springbootlog.controller.TestLogController - 用户登录成功!
[http-nio-8888-exec-2] [CB8E7DB250A31F2BE6C05B30633B9A95] INFO  com.example.springbootlog.controller.TestLogController - 用户创建了订单!
[http-nio-8888-exec-2] [CB8E7DB250A31F2BE6C05B30633B9A95] INFO  com.example.springbootlog.controller.TestLogController - 请求完成,返回ok!
[http-nio-8888-exec-3] [CB8E7DB250A31F2BE6C05B30633B9A95] INFO  com.example.springbootlog.controller.TestLogController - 用户付款!

到此SpringBoot+Logback手写一个简单的链路追踪功能已经全部实现,有问题欢迎留言沟通哦!

完整源码地址: https://github.com/suisui2019/springboot-study

总结

以上所述是小编给大家介绍的SpringBoot+Logback实现一个简单的链路追踪功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • SpringBoot之logback-spring.xml不生效的解决方法

    一.前言 做新应用就是这样,会遇到各种问题,昨天刚解决了加载某一个类时候抛出了 class is not visible from class loader 的问题,今天就有遇到了日志文件找不到的问题,还是和二方库有关的,下面就一一道来. 二.问题产生 正常情况下在  src/main/resources 目录放下  logback-spring.xml 的配置文件(使用logback日志系统),如下图 application.properties里面设置  spring.application

  • Spring Boot 使用 logback、logstash、ELK 记录日志文件的方法

    Spring Boot 下,尝试使用 log4j 记录日志到 logstash,在src/main/resources 目录下添加 log4j.properties 文件进行自定义输出日志文件,未能成功.在 application.yml 中 配置 logging path 打印日志成功了,但是未能调试成功日志分文件记录.网上查阅资料,说是 Spring Boot 默认使用 logback 记录日志.log4j 多次尝试后无果,遂改为使用 logback 记录,最终测试成功. 1. 关于 Spr

  • SpringBoot之LogBack配置详解

    LogBack 默认集成在 Spring Boot 中,是基于 Slf4j 的日志框架.默认情况下 Spring Boot 是以 INFO 级别输出到控制台. 它的日志级别是: ALL < TRACE < DEBUG < INFO < WARN < ERROR < OFF 配置 LogBack 可以直接在 application.properties 或 application.yml 中配置,但仅支持一些简单的配置,复杂的文件输出还是需要配置在 xml 配置文件中.配

  • 详解Spring Boot 使用slf4j+logback记录日志配置

    在学校的时候使用Java进行开发,工作之后由于项目组采用.net进行开发就转到.net了.最近开始学习Java,对一些新东西进行学习.开始看SpringBoot,对遇到的问题进行记录. 学习新的东西最好从例子开始,只看文档太枯燥,但是文档还是必须要看的. spring boot主要的目的是: 为 Spring 的开发提供了更快更广泛的快速上手 使用默认方式实现快速开发 提供大多数项目所需的非功能特性,诸如:嵌入式服务器.安全.心跳检查.外部配置等 SLF4J是为各种loging APIs提供一个

  • 详解Spring Boot配置使用Logback进行日志记录的实战

    spring Boot实战之配置使用Logback进行日志记录 ,分享给大家 在这篇文章中我们将讨论在Spring Boot中使用Logback,在Spring Boot中使用Logback很简单 1.为了测试我们新建两个类 package com.xiaofangtech.sunt.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.an

  • SpringBoot+Logback实现一个简单的链路追踪功能

    最近线上排查问题时候,发现请求太多导致日志错综复杂,没办法把用户在一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简单的链路追踪,下面详细介绍下. 一.实现原理 Spring Boot默认使用LogBack日志系统,并且已经引入了相关的jar包,所以我们无需任何配置便可以使用LogBack打印日志. MDC(Mapped Diagnostic Context,映射调试上下文)是log4j和logback提供的一种方便在多线程条件下记录日志的功能. 实现思路

  • SpringBoot+Websocket实现一个简单的网页聊天功能代码

    最近做了一个SpringBoot的项目,被SpringBoot那简介的配置所迷住.刚好项目中,用到了websocket.于是,我就想着,做一个SpringBoot+websocket简单的网页聊天Demo. 效果展示: 当然,项目很简单,没什么代码,一眼就能明白 导入websocket的包. 通过使用SpringBoot导入包的时候,我们可以发现,很多包都是以 spring-boot-starter 开头的,对于我这种强迫症 ,简直是福音 <dependency> <groupId>

  • SpringBoot + FFmpeg实现一个简单的M3U8切片转码系统

    目录 想法 实现 工程 pom 配置文件 TranscodeConfig,用于控制转码的一些参数 MediaInfo,封装视频的一些基础信息 FFmpegUtils,工具类封装FFmpeg的一些操作 UploadController,执行转码操作 index.html,客户端 使用 想法 客户端上传视频到服务器,服务器对视频进行切片后,返回m3u8,封面等访问路径.可以在线的播放. 服务器可以对视频做一些简单的处理,例如裁剪,封面的截取时间. 视频转码文件夹的定义 喜羊羊与灰太狼 // 文件夹名

  • 使用原生js编写一个简单的框选功能方法

    今天我们来聊一下怎么使用原生javascript编写一个简单的框选功能. 需求描述 鼠标左键按下不放,移动鼠标出现矩形选框: 鼠标左键松开,根据上边出现的矩形选框统计选框范围内的DOM元素: 嗯...上边的功能描述看着是挺简单的,但实现起来也还是会有些地方需要斟酌思考的.比如,如果我们的框选范围不是document.body,而是某一个div里边进行框选呢?而现实开发过程中,我们会遇上的应该就是第二种情况. 点击查看完整的源码 怎么实现 二话不说,咱们动手写代码吧!因为更好的兼容性,这里就避免了

  • Vue写一个简单的倒计时按钮功能

    在项目开发里,我们经常会遇到发送验证码.点击了之后有60秒倒计时的按钮,很常见却也很简单,但是在写这个按钮的时候有个别地方还要注意下,今天写出来,如有问题欢迎指正! 完成的效果如下: 为了更快显示出效果,我把时间设成了5秒.按钮在点击之后会出现倒计时,同时按钮变为不可点击状态,样式也发生变化,鼠标悬浮上的样子也会发生变化. 接下来我们用代码来实现: <button class="button" @click="countDown"> {{content}

  • vue.js做一个简单的编辑菜谱功能

    先给大家展示下效果图,如果感觉不错,请参考实现代码 1.先获取门店下的所有菜品类型.菜品名称.菜品id(list),也就是最大数据量 this.$http.post(ceshiApi+'getCyFoodAndFoodTypeForShopId',{shopId:this.shopId},{emulateJSON:true,credentials: true}).then(function(res){ if(res.data.type=='success'){ this.foodList = r

  • 基于PHP实现一个简单的在线聊天功能

    目录 前端页面 数据库 实现思路 1.showPage() 2.newChat() 3.getChatText() 4.getChatTemp() 5.pushChat() 总结 要实现功能,首先要做前端,经过对比其他网站的在线聊天功能,发现除了基本的聊天功能以外,还要注意以下几点. 一次只能和一个人聊天,但是可以随意切换其他人. 如果用户是从"发送消息" 入口进来的,那么当前马上就切换到对应的聊天窗口,而且如果之前有过聊天记录,应该把聊天记录也展示出来. 如果是从"我的消息

  • 利用node.js+mongodb如何搭建一个简单登录注册的功能详解

    前言 最近突然对数据库和后台感兴趣了,就开始了漫长的学习之路,想想自己只是一个前端,只会java斯科瑞普,所以就开始看nodejs,看着看着突然发现mongodb和nodejs更配哦!,遂就开了我的mongodb之路.下面话不多说了,来一起看看详细的介绍吧. mongodb简介 就超简洁的说一下,mongo就是一个nosql的数据库,不使用sql的语法,当然其实也是大同小异的,增删改查还是差不多的,但是在概念上mongo还是跟mysql有相当大的区别的;比如在mongo中没有表的概念,而是一个集

  • java实现一个简单TCPSocket聊天室功能分享

    本文实例为大家分享了java实现TCPSocket聊天室功能的相关代码,供大家参考,具体内容如下 1.TCPserver.java import java.net.*; import java.io.*; import java.util.*; import java.util.concurrent.*; public class TCPserver{ private static final int SERVERPORT = 8888; private ServerSocket MyServe

  • SpringBoot 项目添加 MDC 日志链路追踪的执行流程

    目录 1. 线程池配置 2. 拦截器配置 3. 日志文件配置 4. 使用方法示例 4.1. 异步使用 4.2. 定时任务 日志链路追踪的意思就是将一个标志跨线程进行传递,在一般的小项目中也就是在你新起一个线程的时候,或者使用线程池执行任务的时候会用到,比如追踪一个用户请求的完整执行流程. 这里用到MDC和ThreadLocal,分别由下面的包提供: java.lang.ThreadLocal org.slf4j.MDC 直接上代码: 1. 线程池配置 如果你直接通过手动新建线程来执行异步任务,想

随机推荐