mysql mcd date_SpringBoot查询日志:添加日志跟踪id

1.起源:

(1)业务需求:

代码的功能是写一个api接口,完成与mysql的crud操作。

后台使用SpringBoot+JdbcTemplate实现,并在controller层添加了一些请求、响应、异常处理的日志;

(2)问题产生:

由于该api接口是多方调用的,当高并发场景调用这个api时,从controller层一路下来,日志的记录将会非常混乱,所有业务日志都掺杂在一起。比如像下面这样:

08f5231c3d32?from=groupmessage

(3)一种解决方法:

当产生异常日志时,特别是高并发的情况下,作为服务端,你并不知道某条error日志报的错对应的是哪条请求,除非将请求信息打印在日志中,但是仔细想想,这就需要所有需要添加日志的类都带着请求信息,显然这太难做到了,同时日志文件也将不堪重负。

2.更好的解决方案

有没有想到过日志跟踪呢?如果不管是谁调用接口,在其每次调用的时候,代码都自动加上一个唯一的id该多好,不管这次请求是到了service层、dao层、甚至bean层,只要是调用controller里面的接口,所有这条请求的日志流都加上了这个唯一的id,这样再查找日志的时候,将会很方便。

而怎么才能在不影响已经写好业务逻辑的情况下,对日志流做统一处理呢?当然是要想到AOP了~!

具体操作如下:

(1)先配上aop的maven依赖(已经有aop就不用再加了),这里要注意spring-aop的版本对应上spring-core的版本:

org.springframework

spring-aop

4.3.10.RELEASE

org.aspectj

aspectjweaver

1.8.13

(2)再添加AOP处理类~!这里只针对controller层。(不太了解aop配置的需要补习一下基本的配置方法)

package com.tools.pincollect.common;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.slf4j.MDC;

import org.springframework.stereotype.Component;

import java.util.Arrays;

import java.util.UUID;

@Aspect

@Configuration

public class SpringAOP {

private static final Logger logger = LoggerFactory.getLogger(SpringAOP.class);

/**

* 定义切点Pointcut

* 第一个*号:表示返回类型, *号表示所有的类型

* 第二个*号:表示类名,*号表示所有的类

* 第三个*号:表示方法名,*号表示所有的方法

* 后面括弧里面表示方法的参数,两个句点表示任何参数

*/

@Pointcut("execution(* com.tools.pincollect.controller.*.*(..))")

public void executionService() {}

/**

* 方法调用之前调用

* @param joinPoint

*/

@Before(value = "executionService()")

public void doBefore(JoinPoint joinPoint){

String requestId = String.valueOf(UUID.randomUUID());

MDC.put("requestId",requestId);

logger.info("=====>@Before:请求参数为:{}",Arrays.toString(joinPoint.getArgs()));

}

/**

* 方法之后调用

* @param joinPoint

* @param returnValue 方法返回值

*/

@AfterReturning(pointcut = "executionService()",returning="returnValue")

public void doAfterReturning(JoinPoint joinPoint,Object returnValue){

logger.info("=====>@AfterReturning:响应参数为:{}",returnValue);

// 处理完请求,返回内容

MDC.clear();

}

}

(3)在项目resources目录下的logback-spring.xml中修改日志pattern(不了解的话,这里需要补充下日志配置的知识),添加[%X{requestId}],requestId就是在切面类中的MCD.put()方法中的key,如下图所示:

[ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] [%X{requestId}] %logger{96} [%line] - %msg%n

08f5231c3d32?from=groupmessage

添加了跟踪id后的日志.png

有了跟踪id,查找与定位日志是不是方便多了呢?

3.究其原理

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

MDC 可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。

具体内容请参考:

https://blog.csdn.net/sunzhenhua0608/article/details/29175283

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值