spring boot 之 结合aop整合日志

AOP

该切面仅用于请求日志记录,若有其他需求,在此基础上扩展即可,不多逼逼,直接上代码。

引入切面依赖

<!-- 切面 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

日志切面类

import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
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 javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;@Slf4j
@Aspect
@Component
public class RequestAop {private static final String START_TIME = "request-start";// 按需修改需要扫描的controller层@Pointcut("execution(* com.example.controller..*.*(..))")public void pointCut() {//该方法仅用于扫描controller包下类中的方法,而不做任何特殊的处理。}@Before("pointCut()")public void doBefore(JoinPoint joinPoint) {HttpServletRequest request =((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();Long start = System.currentTimeMillis();request.setAttribute(START_TIME, start);}@Around("pointCut()")@SneakyThrowspublic Object doAround(ProceedingJoinPoint joinPoint) {Object result = joinPoint.proceed();try {// 获取方法名称String method = joinPoint.getSignature().getName();// 获取类名称String className = joinPoint.getSignature().getDeclaringTypeName();// 获取请求HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();// 请求路径String requestUrl = request.getRequestURL().toString();// 获取请求参数进行打印Signature signature = joinPoint.getSignature();// 参数名数组String[] parameterNames = ((MethodSignature) signature).getParameterNames();// 构造参数组集合List<Object> argList = new ArrayList<>();for (Object arg : joinPoint.getArgs()) {// request/response无法使用toJSONif (arg instanceof HttpServletRequest) {argList.add("request");} else if (arg instanceof HttpServletResponse) {argList.add("response");} else {argList.add(JSON.toJSON(arg));}}log.info("类名:[{}] 方法名:[{}] 请求URL:[{}] 请求参数:{} -> {} 请求结果:{}", className, method, requestUrl, JSON.toJSON(parameterNames), JSON.toJSON(argList), JSON.toJSON(result));} catch (Exception e) {log.error("切面类参数获取失败: {}", e.getMessage());}return result;}@After("pointCut()")public void doAfter(JoinPoint joinPoint) {HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();Long start = (Long) request.getAttribute(START_TIME);Long end = System.currentTimeMillis();// 耗时long costTime = end - start;// 方法名String method = joinPoint.getSignature().getName();log.info("方法名:[{}] 请求耗时:[{}ms]", method, costTime);}
}

日志

级别

日志级别(Log Levels)是指日志消息的优先级或者重要程度,它用于对日志的不同类型和重要程度进行分类和过滤。
不同的日志框架可能使用不同的命名和数量的日志级别,但基本概念是相似的。以下是常见的几个标准日志级别:

1,TRACE(追踪):最低级别的日志,包含详细的调试信息,用于追踪代码的执行流程,如方法的输入参数、内部状态等。
2,DEBUG(调试):用于输出调试信息,在开发和调试阶段使用,帮助排查问题和跟踪代码执行情况以及验证程序的行为。
3,INFO(信息):提供程序运行过程中的重要信息,用于向用户提供一些关键的操作状态和进度,如程序启动关闭、配置项变更等。
4,WARN(警告):表示潜在的问题或异常情况,不会阻止程序继续执行,但可能会影响程序的正常运行,需要开发人员注意。
5,ERROR(错误):表示错误情况,通常表示某个功能或步骤无法正常完成,但程序仍然可以继续运行,需要开发人员关注和解决。
6,FATAL(致命):最高级别的日志,表示最严重的错误,表示程序无法继续运行,会导致应用程序的中断或崩溃,如系统崩溃。

特别说明:以上日志级别由上往下依次增强,而日志级别越高,控制台打印出的日志信息就越少,但打印出的日志信息越重要。

引入lombok依赖

引入lombok后,在需要记录日志的类上添加@Slf4j注解即可。

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.32</version><scope>provided</scope>
</dependency>

日志配置文件

resources下新建目录logslogs下新建logback-spring.xml文件。
仅配置了常用的infoerror级别,其余按需配置即可。

<?xml version="1.0" encoding="utf-8"?>
<configuration><!-- 引入默认得配置文件 --><include resource="org/springframework/boot/logging/logback/defaults.xml"/><!-- 模块名标识日志名称 --><springProperty scope="context" name="springAppName" source="spring.application.name"/><!-- info日志单文件大小限制 --><springProperty scope="context" name="logback.fileInfoLog.maxFileSize" source="logback.fileInfoLog.maxFileSize" defaultValue="1024MB" /><!-- info日志最大保留时长单位天 --><springProperty scope="context" name="logback.fileInfoLog.maxHistory" source="logback.fileInfoLog.maxHistory" defaultValue="30" /><!-- info日志文件总大小,超过该大小,旧得即将删除 --><springProperty scope="context" name="logback.fileInfoLog.totalSizeCap" source="logback.fileInfoLog.totalSizeCap" defaultValue="10GB" /><!-- error日志单文件大小限制 --><springProperty scope="context" name="logback.fileErrorLog.maxFileSize" source="logback.fileErrorLog.maxFileSize" defaultValue="1024MB" /><!-- error日志最大保留时长单位天 --><springProperty scope="context" name="logback.fileErrorLog.maxHistory" source="logback.fileErrorLog.maxHistory" defaultValue="30" /><!-- error日志文件总大小,超过该大小,旧得即将删除 --><springProperty scope="context" name="logback.fileErrorLog.totalSizeCap" source="logback.fileErrorLog.totalSizeCap" defaultValue="10GB" /><!-- 日志目录 --><springProperty scope="context" name="logback.rootDir" source="logback.rootDir" defaultValue="logs"/><!-- 控制台输出得日志格式 --><property name="CONSOLE_LOG_PATTERN"value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/><!-- 日志文件输出得日志格式 --><property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %t [%c:%L]-%m%n"/><!-- 控制台输出 --><appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>${CONSOLE_LOG_PATTERN}</pattern></layout></appender><!-- info日志得设定 --><appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch><onMismatch>ACCEPT</onMismatch></filter><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder><file>${logback.rootDir}/${springAppName}.log</file><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" ><!--路径--><fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern><maxFileSize>${logback.fileInfoLog.maxFileSize}</maxFileSize><maxHistory>${logback.fileInfoLog.maxHistory}</maxHistory><totalSizeCap>${logback.fileInfoLog.totalSizeCap}</totalSizeCap><cleanHistoryOnStart>true</cleanHistoryOnStart></rollingPolicy></appender><!-- 错误日志 --><appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder><file>${logback.rootDir}/${springAppName}-error.log</file><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" ><!--路径--><fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-error-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern><maxFileSize>${logback.fileErrorLog.maxFileSize}</maxFileSize><maxHistory>${logback.fileErrorLog.maxHistory}</maxHistory><totalSizeCap>${logback.fileErrorLog.totalSizeCap}</totalSizeCap><cleanHistoryOnStart>true</cleanHistoryOnStart></rollingPolicy></appender><appender name="ASYNC_consoleLog" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="consoleLog"/></appender><appender name="ASYNC_fileInfoLog" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="fileInfoLog"/></appender><appender name="ASYNC_fileErrorLog" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="fileErrorLog"/></appender><root level="info"><appender-ref ref="ASYNC_consoleLog" /><appender-ref ref="ASYNC_fileInfoLog" /><appender-ref ref="ASYNC_fileErrorLog" /></root></configuration>

application.yml配置

# spring.application.name 必须配置
# 因为上述日志配置文件指定了项目启动后输出的日志文件命名,即为该配置
spring:application:name: LogApplicationlogging:
# 指定自定义的配置文件config: classpath:logs/logback-spring.xml
# 指定输出的日志级别
# trace < debug < info < warn < error
# 例如:指定输出级别为info,则trace和debug均不会输出level:root: info #该方式指定的是整个项目的日志输出级别# com.example.controller: debug #也可以指定具体某个包下的日志输出级别

结果展示

在这里插入图片描述
以上述配置为例,项目启动后会在项目下生成logs目录,该目录下会有两个日志文件:LogApplication.logLogApplication-error.log,项目中所有log.error()日志都会输出到LogApplication-error.log,其余日志则输出到LogApplication.log.

拓展

将指定的类产生的日志输出到指定的文件中。
示例:RequestAop切面中产生的是所有的请求记录,将该类的日志放入指定的文件。

logback-spring.xml新增配置,未添加请求日志文件的大小限制、存放时间等配置,若有需求,按infoerror配置仿写即可。

    <!-- 接口请求日志 --><appender name="requestLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch><onMismatch>ACCEPT</onMismatch></filter><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder><!--此处配置输出文件名称为 应用名-request.log --><file>${logback.rootDir}/${springAppName}-request.log</file><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" ><!--路径--><fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-request-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern><maxFileSize>${logback.fileInfoLog.maxFileSize}</maxFileSize><maxHistory>${logback.fileInfoLog.maxHistory}</maxHistory><totalSizeCap>${logback.fileInfoLog.totalSizeCap}</totalSizeCap><cleanHistoryOnStart>true</cleanHistoryOnStart></rollingPolicy></appender><appender name="ASYNC_requestLog" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="requestLog"/></appender><!--将切面类所在包的位置配置上--><logger name="com.example.aop.RequestAop" additivity="false" level="INFO"><appender-ref ref="ASYNC_requestLog"/></logger>

在这里插入图片描述
以上述配置为例,项目启动后会在项目下生成logs目录,该目录下会有三个日志文件:LogApplication.logLogApplication-error.logLogApplication-request.log,项目中所有log.error()日志都会输出到LogApplication-error.logRequestAop切面类的日志会输出到LogApplication-request.log,其余日志则输出到LogApplication.log.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/17264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】set与map

目录 一、键值对 二、set 1. set的模板参数列表 2. set的构造 3. set的迭代器 4. set的容量 5. set的修改 6. set的查找 三、map 1. map的模板参数列表 2. map的构造 3. map的迭代器 4. map的容量 5. map的修改 6. map的查找 一、键值对 用来表示具有一一对应关…

SARscape5.7已经支持3米陆探一号(LT-1)数据处理

SARsacpe5.6.2.1版本已经开始支持LT-1的数据处理&#xff0c;由于当时只获取了12米的条带模式2&#xff08;STRIP2&#xff09;例子数据&#xff0c;对3米条带模式1&#xff08;STRIP1&#xff09;数据的InSAR处理轨道误差挺大&#xff0c;可能会造成干涉图异常。 SARsacpe5.7最…

三十篇:动脉脉搏:企业业务处理系统的生命力

动脉脉搏&#xff1a;企业业务处理系统的生命力 1. 引言 在数字经济的浪潮下&#xff0c;企业之间的竞争已不仅仅是产品和服务的竞争&#xff0c;更是信息处理能力的竞争。业务处理系统&#xff08;Transaction Processing System, TPS&#xff09;是企业信息系统架构的基础&a…

Python3 笔记:Python之禅

打开Python Shell&#xff0c;输入import this&#xff0c;按回车键运行程序。 Beautiful is better than ugly. 优雅胜于丑陋。 Explicit is better than implicit. 明确胜于含糊。 Simple is better than complex. 简单胜于复杂。

图形学初识--纹理采样和Wrap方式

文章目录 前言正文1、为什么需要纹理采样&#xff1f;2、什么是纹理采样&#xff1f;3、如何进行纹理采样&#xff1f;&#xff08;1&#xff09;假设绘制区域为矩形&#xff08;2&#xff09;假设绘制区域为三角形 4、什么是纹理的Wrap方式&#xff1f;5、有哪些纹理的Wrap方式…

洪师傅代驾系统开发 支持公众号H5小程序APP 后端Java源码

代驾流程图 业务流程图 管理端设置 1、首页装修 2、师傅奖励配置 师傅注册后,可享受后台设置的新师傅可得的额外奖励; 例:A注册了师傅,新人奖励可享受3天,第一天的第一笔订单完成后可得正常佣金佣金*奖励比例 完成第二笔/第三笔后依次可得正常佣金佣金*奖励比例 完成的第四…

牛客NC166 连续子数组的最大和(二)【中等 前缀和数组+动态规划 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/11662ff51a714bbd8de809a89c481e21 思路 前缀和数组动态规划Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规…

小短片创作-优化场景并输出短片(二)

1、什么是潮湿感 什么是潮湿感&#xff1a;基础颜色变化粗糙度变化表面渗入性 1.基础颜色变化&#xff1a;潮湿的地方颜色会变深 2.粗糙度变化&#xff1a;镜面粗糙度为0&#xff0c;潮湿的地方粗糙度会变低 3.表面渗入性&#xff1a;主要看材质是否防水 2、调整场景材质增…

小抄 20240526

1 一些人焦虑的原因&#xff0c;可能是他也知道自己做的事无意义&#xff0c;但是又停不下来&#xff0c;于是一直在做无用功&#xff0c;空耗精神力量。 可以试着去做一些热爱的、有价值的事情&#xff0c;焦虑就会慢慢消失。 2 人们看历史的时候&#xff0c;很容易把自己代…

士大夫v产生的

一、前言 乱码七糟 [lun qī bā zāo]&#xff0c;我时常怀疑这个成语是来形容程序猿的&#xff01; 无论承接什么样的需求&#xff0c;是不是身边总有那么几个人代码写的烂&#xff0c;但是却时常有测试小姐姐过来聊天(_求改bug_)、有产品小伙伴送吃的(_求写需求_)、有业务小…

Java 写入 influxdb

利用Python随机生成一个1000行的csv文件 import csv import random from datetime import datetime, timedelta from random import randint, choice# 定义监控对象列表和指标名称列表 monitor_objects [Server1, Server2, Server3, DB1] metric_names [CPUUsage, MemoryUsa…

网络编程 —— Http进度条

第一种下载带进度的方法 string url "https://nodejs.org/dist/v20.10.0/node-v20.10.0-x64.msi"; 1使用getASync获取服务器响应数据 参数1请求的路径&#xff0c; 参数2 HttpCompletionOption.ResponseHeadersRead 请求完成时候等待请求带什么程度才…

耐高温输送带的优势

耐高温输送带&#xff1a;工业运输的革命性升级&#xff0c;助力生产线高效稳定运行 在现代化工业生产的浪潮中&#xff0c;耐高温输送带以其独特的优势&#xff0c;正逐渐成为工业运输领域的得力助手。它不仅能够有效提升生产效率&#xff0c;更能确保生产线的安全稳定运行&a…

算法随想录第二十天打卡|654.最大二叉树 , 617.合并二叉树 ,700.二叉搜索树中的搜索 , 98.验证二叉搜索树

654.最大二叉树 又是构造二叉树&#xff0c;昨天大家刚刚做完 中序后序确定二叉树&#xff0c;今天做这个 应该会容易一些&#xff0c; 先看视频&#xff0c;好好体会一下 为什么构造二叉树都是 前序遍历 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;又是构…

「动态规划」打家劫舍

力扣原题链接&#xff0c;点击跳转。 有一个小偷&#xff0c;要偷东西。假设有n个房间&#xff0c;每个房间都有现金&#xff0c;下标为i的房间内的现金数是nums[i]。不能同时偷相邻的2个房间&#xff0c;其中第一个房间和最后一个房间是相邻的。那么这个小偷最多能偷到多少现…

YOLOv8+PyQt5鸟类检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

资源包含可视化的鸟类检测系统&#xff0c;基于最新的YOLOv8训练的鸟类检测模型&#xff0c;和基于PyQt5制作的可视化鸟类检测系统&#xff0c;包含登陆页面、注册页面和检测页面&#xff0c;该系统可自动检测和识别图片或视频当中出现的各种鸟类&#xff0c;以及自动开启摄像头…

Linux汉化Jupyter Notebook

要在Linux系统中使Jupyter Notebook汉化&#xff0c;可以通过安装jupyterlab-language-pack-zh-CN扩展来实现。以下是具体步骤和示例代码&#xff1a; 打开终端。 执行以下命令以安装Jupyter Notebook的中文语言包&#xff1a; pip install jupyterlab-language-pack-zh-CN …

【CSharp】将ushort数组保存为1通道位深16bit的Tiff图片

【CSharp】将ushort数组保存为1通道位深16bit的Tiff图片 1.背景2.接口 1.背景 System.Drawing.Common 是一个用于图像处理和图形操作的库&#xff0c;它是 System.Drawing 命名空间的一部分。由于 .NET Core 和 .NET 5 的跨平台特性&#xff0c;许多以前内置于 .NET Framework…

基于Fluent和深度学习算法驱动的流体力学计算与应用

“基于Fluent和深度学习算法驱动的流体力学计算与应用”专题大纲 目录 主要内容 机器学习与流体力学入门 一、流体力学基础理论与编程实战1、流体力学的发展概述 2、不可压缩流体力学的基本方程 3、湍流理论与湍流模型简介 4、傅里叶变换和流体的尺度分析 5、伪谱法求解不可压…

Vue小程序项目知识积累(二)

1.wx.reLaunch(Object object) 关闭所有页面&#xff0c;打开到应用内的某个页面。 wx.reLaunch({url:/pages/positons/index}) 参数说明&#xff1a; 属性类型默认值必填说明urlstring是需要跳转的应用内页面路径 (代码包路径)&#xff0c;路径后可以带参数。参数与路径之…