当前位置: 移动技术网 > IT编程>开发语言>Java > springboot使用log4j2全局请求接口监控及mybatis的sql语句日志记录

springboot使用log4j2全局请求接口监控及mybatis的sql语句日志记录

2020年07月17日  | 移动技术网IT编程  | 我要评论

一、使用springboot+aop+log4j2进行全局接口请求监控

1.在pom.xml中引入aop、log4j2依赖

<!-- aop 依赖 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- 用于日志切面中,以 json 格式打印出入参 -->
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.5</version>
</dependency>

<!-- 忽略自带的日志框架. -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
   <exclusions>
	   <exclusion>
		   <groupId>org.springframework.boot</groupId>
		   <artifactId>spring-boot-starter-logging</artifactId>
	  </exclusion>
   </exclusions>
</dependency>  
   
<!-- log4j2 -->
<dependency> 
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

2.在application-dev.yml中配置log4j2-dev.xml到classpath下

application-dev.yml

logging:
  config: classpath:log4j2-dev.xml

log4j2-dev.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 -->
<!-- monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
<!-- 日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL-->
<configuration status="WARN" monitorInterval="30">
    <!--定义所有的appender -->
    <appenders>
        <!--这个输出控制台的配置 -->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式 -->
            <PatternLayout
                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}.%M@%L - %msg%n"/>
        </console>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行存档 -->
        <RollingFile name="RollingFileInfo"
                     fileName="D://logs//info.log"
                     filePattern="D://logs//$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout
                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}.%M@%L - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileError"
                     fileName="D://logs//error.log"
                     filePattern="D://logs//$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
            <Filters>
                // 设置Appender日志的上限
                <ThresholdFilter level="fatal" onMatch="DENY" onMismatch="NEUTRAL"/>
                // 设置Appender日志的底线,最终就能使该文件中只输出info日志了
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout
                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}.%M@%L - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
        </RollingFile>
        
    </appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <loggers>
        <!--把org.springframework包下的所有日志输出到info.log文件,additivity="false"表示不输出到控制台-->
        <Logger name="org.springframework" level="info" additivity="false">
            <appender-ref ref="Console"/>  <!-- 控制台输出 -->
            <appender-ref ref="RollingFileInfo" /> <!-- 输出到info.log文件 -->
        </Logger>
        <Logger name="com.pro.cssClub" level="info" additivity="false">
            <appender-ref ref="Console"/> 
            <appender-ref ref="RollingFileInfo" />
        </Logger>

        <root level="debug">
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>

</configuration>

然后在业务代码中:

private final static Logger logger = LoggerFactory.getLogger(this.class);   //即可用logger打印日志

注:需将spring-boot-starter-logging的包在spring-boot-starter中直接排除掉,从spring boot整体上进行替换
否则,Spring Boot与Log4j2集成时会出现java.lang.IllegalStateException: Logback configuration error detected

参考:https://blog.csdn.net/blueheart20/article/details/78111350

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3.配置切面编程监控接口请求
(1)首先创建自定义注解类(哪个接口需要被监控再加注解,不需要监控的不加即可)

package com.pro.cssClub.aop;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(RetentionPolicy.RUNTIME)//什么时候使用该注解,我们定义为运行时
@Target({ElementType.METHOD})//注解用于什么地方,我们定义为作用于方法上
@Documented//注解是否将包含在 JavaDoc 中
public @interface WebLog {
	/**
	 * 日志描述信息
	 */
	String description() default "";//定义一个属性,默认为空字符串
}

(2)接下来配置AOP,首先先了解下aspectj相关注解的作用

@Aspect:声明该类为一个注解类;
@Pointcut:定义一个切点,后面跟随一个表达式,表达式可以定义为切某个注解,也可以切某个 package 下的方法;

切点定义好后,就是围绕这个切点做文章了:

@Before: 在切点之前,织入相关代码;
@After: 在切点之后,织入相关代码;
@AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
@AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;
@Around: 环绕,可以在切入点前后织入代码,并且可以自由的控制何时执行切点;

在这里插入图片描述

具体代码:

package com.pro.cssClub.aop;
 
import com.google.gson.Gson;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
 
 
/**
 * 切面类
 * @author 3897
 */
@Aspect
@Component
@Profile({"dev","test"})
public class WebLogAspect {
	private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
	//换行符
	private final static String LINE_SEPARATOR = System.lineSeparator();
	
	/**
	 * 声明自定义@WebLog注解为切点
	 */
	@Pointcut("@annotation(com.pro.cssClub.aop.WebLog)")
	public void webLog(){}
	
	/**
	 * 环绕
	 */
	@Around("webLog()")
	public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
		long startTime = System.currentTimeMillis();
		Object result = proceedingJoinPoint.proceed();
		//打印出参
		logger.info("Response Args : {}",new Gson().toJson(result));
		//执行耗时
		logger.info("Time-Consuming : {} ms",System.currentTimeMillis()-startTime);
		return result;
	}
	
	/**
	 * 在切点前织入
	 */
	@Before("webLog()")
	public void doBefore(JoinPoint joinPoint) throws Throwable{
		//开始打印请求日志
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		
		//获取@WebLog注解的描述信息
		String methodDescription = getAspectLogDescription(joinPoint);
		
		//打印相关请求参数
		logger.info("=============== Start ===============");
		// 打印请求 url
        logger.info("URL            : {}", request.getRequestURL().toString());
        // 打印描述信息
        logger.info("Description    : 请求了[{}]接口", methodDescription);
        // 打印 Http method
        logger.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        logger.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        logger.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        logger.info("Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
	}
	
	/**
	 * 在切点之后织入
	 */
	@After("webLog()")
	public void doAfter() throws Throwable{
		//接口结束后换行,方便分割查看
		logger.info("=============== End ===============" + LINE_SEPARATOR);
	}
	
	/**
	 * 获取切面注解的描述
	 */
	public String getAspectLogDescription(JoinPoint joinpoint) throws Exception{
		String targetName = joinpoint.getTarget().getClass().getName();
		String methodName = joinpoint.getSignature().getName();
		Object[] arguments = joinpoint.getArgs();
		Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        StringBuilder description = new StringBuilder("");
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description.append(method.getAnnotation(WebLog.class).description());
                    break;
                }
            }
        }
        return description.toString();
	}
}

使用方法:
在这里插入图片描述

日志打印情况:

=============== Start ===============                                                            
URL            : http://10.30.2.49:8089/abnormalTile/gasMonitoList                               
Description    : 请求了[用气页面列表]接口                                                                   
HTTP Method    : GET                                                                             
Class Method   : com.goldcard.data_innovation.controller.AbnormalTileController.gasMonitoList    
IP             : 10.30.2.132                                                                     
Request Args   : ["cust_id","","0",1,10]                                                         
Response Args : {"sum":4,"list":[{"cust_id":"001","cust_name":"金卡","meter_addr":"金桥街","cust_phone
Time-Consuming : 101 ms                                                                          
=============== End ===============  

若只想在开发环境(dev)、测试环境(test)使用,而不在生产环境(prod)使用,加此注解,并配置框架的环境
在这里插入图片描述

二、springboot配置log4j2输出mybatis的sql语句日志记录

1.配置mybatis-config.xml文件

<configuration>
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="LOG4J2" />  <!-- 控制台输出STDOUT_LOGGING -->
    </settings>
</configuration>

2.在原有的log4j2-dev.xml中添加配置

(1)在 标签中添加配置sql日志输出文件

<appenders> 
<RollingFile name="RollingFileSql"
                     fileName="D://logs//sql.log"
                     filePattern="D://logs//$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log">
            <PatternLayout
                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36}.%M@%L - %msg%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
        </RollingFile>
</appenders>

(2)定义logger并t添加引入RollingFileSql

<loggers>
    <!--把com.pro.cssClub.mapper包下的所有日志输出到log文件和控制台打印-->
    <Logger name="com.pro.cssClub.mapper" level="Debug" additivity="false">
        <appender-ref ref="Console"/>
        <appender-ref ref="RollingFileSql"/>
    </Logger>
</loggers>

本文地址:https://blog.csdn.net/juner_aspasia/article/details/107356460

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网