基于aop的日志记录

aop实现日志记录

    • 记录工具
    • 切面
    • logback配置
    • 测试

记录工具

目标:
统计rest接口请求参数,请求地址,请求IP,响应数据,响应时间。方便后续问题排查,以及性能的总体分析。

  1. 基于springboot
  2. 会使用面向切面编程
  3. 基于logback,使用slf4j

切面

package top.lel.ft.config.aop;import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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.MDC;
import org.springframework.stereotype.Component;
import top.lel.ft.common.utils.IpUtils;
import top.lel.ft.framework.BaseController;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;/*** @author echo lovely* @description web url 日志记录* @since 2022/6/14 09:22*/@Slf4j
@Aspect
@Component
public class UrlLogAspect {// 使用ThreadLocal记录第一次的请求时间, 统计接口响应时间// 也可用环绕通知统计接口响应时间final ThreadLocal<Long> tl = new ThreadLocal<>();// 作用于controller的切点@Pointcut("execution(public * top.lel.ft.controller.*.*(..))" +"|| execution(public * top.lel.ft.web.*.*(..))")public void controllerAspect() {}// 记录IP,日志,请求参数@Before(value = "controllerAspect()")public void methodBefore(JoinPoint joinPoint) {List<String> paramList = new ArrayList<>();Object[] args = joinPoint.getArgs();if (args != null) {for (Object arg : args) {if (!isOriginType(arg)) {paramList.add(JSON.toJSONString(arg));}}}String methodName = joinPoint.getSignature().getName();HttpServletRequest httpReq = BaseController.getServletReq();String ipAddress = IpUtils.getIpAddr(httpReq);// 日志增强实现MDC.put("ip", ipAddress);MDC.put("traceId", UUID.randomUUID().toString().replaceAll("-", ""));log.debug("请求路径: {}, 请求方法: {}, 请求参数: {}, 请求IP: {}", httpReq.getRequestURI(), methodName, String.join(", ", paramList), ipAddress);tl.set(System.currentTimeMillis());}@AfterReturning(pointcut = "controllerAspect()", returning = "retVal")public void afterRet(Object retVal) {log.info("响应时间: {}毫秒, 响应内容: {}", System.currentTimeMillis() - tl.get(), JSON.toJSONString(retVal));tl.remove();MDC.clear();}/*** 判断是原生servlet容器*/private boolean isOriginType(Object e) {return e instanceof HttpServletRequest || e instanceof HttpSession;}
}

logback配置

application.yaml 配置logback.logPath

<configuration><!-- 日志存放路径 --><springProperty scope="context" name="logPath" source="logback.logPath"/><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /><!-- 日志输出格式 --><!--  traceId为日志跟踪id,ip为请求ip,见切面MDC工具  --><property name="log.pattern" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) [%X{traceId}] %boldMagenta([%X{ip}] [%thread]) %highlight(%-5level) %clr(%logger{50}){pink} - %cyan(%msg%n)" /><!-- <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%X{ip}] [%thread] %-5level %logger{20} - %msg%n" />--><springProperty scope="context" name="appName" source="spring.application.name"/><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.PatternLayout"><Pattern>${log.pattern}</Pattern></layout></encoder></appender><!-- 系统日志输出 --><appender name="server" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${logPath}/${appName}_server.log</file><!-- 循环政策:基于时间创建日志文件 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志文件名格式 --><fileNamePattern>${logPath}/%d{yyyyMMdd}/${appName}_server.%i.log</fileNamePattern><!-- 日志最大的历史 60--><maxHistory>60</maxHistory><!-- 文件最大50M --><TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><MaxFileSize>50MB</MaxFileSize></TimeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.PatternLayout"><Pattern>${log.pattern}</Pattern></layout></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 过滤的级别 --><level>DEBUG</level></filter></appender><appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${logPath}/${appName}_error.log</file><!-- 循环政策:基于时间创建日志文件 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志文件名格式 --><fileNamePattern>${logPath}/%d{yyyyMMdd}/${appName}_error.%i.log</fileNamePattern><!-- 日志最大的历史 60--><maxHistory>60</maxHistory><!-- 文件最大50M --><TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><MaxFileSize>50MB</MaxFileSize></TimeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.PatternLayout"><Pattern>${log.pattern}</Pattern></layout></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 过滤的级别 --><level>ERROR</level></filter></appender><!--异常日志监控告警 todo: 实现WarningAppender, 如进行告警邮件通知.--><!--ch.qos.logback.core.UnsynchronizedAppenderBase(ILoggingEvent logEvent)--><!--<appender name="warningAppender" class="top.lel.ft.common.warning.WarningAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter></appender>--><!-- Spring日志级别控制  --><logger name="org.springframework" level="warn" /><root level="info">
<!--        <appender-ref ref="warningAppender" />--><appender-ref ref="STDOUT" /></root><root level="info"><appender-ref ref="server" /><appender-ref ref="error" /></root>
</configuration>

测试

、


or

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

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

相关文章

前端学习(1351)模板引擎

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, index.art); const html template(views, {name: 张三,age: 20 }); console.log(html); index.art <!DOCTYPE html> <html la…

前端学习(1352)模板语法

demo27.js const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, 01.art); const html template(views, {name: 张三,age: 20,content: <h1>我是歌谣</h1> }); console.log(html)…

前端学习(1353)模板语法条件判断

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, 02.art); const html template(views, {name: 张三,age: 20,/* content: <h1>我是歌谣</h1> */ }); console.log(html); 0…

MySql 缓存查询原理与缓存监控 和 索引监控

MySql缓存查询原理与缓存监控 And 索引监控 by:授客 QQ&#xff1a;1033553122 查询缓存 1.查询缓存操作原理 mysql执行查询语句之前&#xff0c;把查询语句同查询缓存中的语句进行比较&#xff0c;且是按字节比较&#xff0c;仅完全一致才被认为相同。如下&#xff0c;这两…

前端学习(1354):集合关联

const mongoose require(mongoose); mongoose.connect(mongodb://localhost/playground, { useUnifiedTopology: true }).then(() > console.log(数据库连接成功)).catch(err > console.log(err, 数据库连接失败)) const userSchema new mongoose.Schema({name: {type:…

ati jti jwt 和_一文搞懂JWT

Django REST framework JWT一、JWT简介二、JWT 组成headersignature三.使用手动生成jwt前端保存jwt一、JWT简介JWT(Json Web Token) 是一个开放标准(RFC 7519)&#xff0c;它定义了一种用于简洁&#xff0c;自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT…

前端学习(1355)模板语法循环

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, 03.art); const html template(views, {users: [{name: geyao,age: 20,sex: 男}, {name: xiao,age: 20,sex: 男}, {name: hau,age: 20,se…

c++检测ip是否匹配子网掩码_网络工程师从入门到精通通俗易懂系列 | ARP和IP这篇文章讲的相当详细了,这么基础的知识往往也是最容易遗忘的!...

网络层负责将报文从源送到目的包括TCP建立连接&#xff0c;也需要依靠网络层&#xff0c;来将这个连接请求&#xff0c;传递到对方。为设备提供逻辑地址&#xff0c;也就是IP地址主流是IPV4地址IPV4地址&#xff0c;为32位二进制数&#xff0c;长度4个字节&#xff0c;1字节等于…

前端学习(1357) :模板配置

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, 07.art); const dateFormat require(dateFormat) template.defaults.imports.dateFormat dateFormat; const html template(views, {ti…

使用Office Word 2010/2013 发布文章到博客园

使用Office Word 2010/2013 发布文章到博客园 ☆&#xff1a;参考http://www.cnblogs.com/liuxianan/archive/2013/04/13/3018732.html&#xff1b; 软件准备&#xff1a;Office Word2010/2013 初次使用&#xff0c;必要的配置&#xff1a; Office Word2010&#xff1a;代开wor…

前端学习(1355) 子模板

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path); const views path.join(__dirname, 04.art); const html template(views, {msg: 我是首页,name: geyao,age: 20 }); console.log(html); 04.art {{include./index.art}} {…

前端学习(1358) :渲染模板默认

const template require(art-template); //绝对路径 模板中显示的数据 const path require(path);const dateFormat require(dateFormat) template.defaults.imports.dateFormat dateFormat; template.defaults.root path.join(__dirname); template.defaults.extname .a…

UML九种图 之 包图和对象图

前言 对象图和包图依然是对系统的静态的描写叙述。UML九种图加上包图&#xff0c;事实上是十幅图。 包图 1.构成 2.包中的元素 类、接口、用例、构件、其他包等。&#xff08;若包被撤销&#xff0c;当中的元素被撤销&#xff09; 3.包之间的关系 泛化、细化、依赖&#xff08;…

前端学习(1359) :学生档案信息管理1

\ service.js //引入http模块 const http require(http); //创建网站服务器 const app http.createServer(); // require(./connect.js) const Student require(./user.js) app.on(request, (req, res) > {res.end(ok); }); app.listen(3000); console.log(服务器启动成…

刚学unity3d,跟着仿作了flappy bird,记下一些琐碎的心得!

1、关于场景&#xff0c;即scene。 一个正常的游戏至少要有三个场景&#xff0c;即菜单&#xff08;或者文件夹&#xff09;场景、游戏关卡场景、游戏结束场景。它们一般统一放在project文件夹下scene文件夹&#xff08;自己创建&#xff09;中&#xff0c;方便管理。1.1场景切…

不学好css模型的怎么入山门?师傅与徒弟的真实独白

目录 前言 开篇 定义 ie盒 标准盒 真实占有宽度 结局 前言 很久很久以前&#xff0c;在一个小山庄里面住着一位少年。这位少年出生之时天有异向&#xff0c;七星连珠&#xff0c;乃神人也。三岁那年他跟着师傅上山学艺&#xff0c;面临这人生的第一道关卡。这位少年我们…

看完这篇还不知道css固定和自适应可以小和尚要摆地摊了

目录 前言 开篇 左右侧采用浮动 中间采用margin-left 和 margin-right 方法。 中篇 利用绝对定位中间同样采用margin-left margin-right方法 续篇 负的margin 终篇 三列布局中间固定&#xff0c;其他两列自适应 前言 接上一篇的小徒弟继续说吧 上一篇小徒弟进入山门…

classpass 配置mysql_jmeter压测学习18-JDBC配置连接mysql数据库

前言使用jmeter压测接口的时候&#xff0c;有时候需要批量造数据&#xff0c;需使用jmeter连数据库造对应的测试数据。或者测试结束后&#xff0c;对测试的数据还原&#xff0c;删掉一些垃圾数据&#xff0c;都会用到连接数据库执行sql的操作。JDBC 连接配置添加配置元件-JDBC …

为了梦想开始历练之清除浮动篇

目录 前言 开篇 中篇 原因 解决方式 1额外标签得方法 2触发BFC overflow 3伪元素 4双伪元素 结尾 前言 师傅&#xff08;路人甲&#xff09;小徒弟&#xff08;路人乙&#xff09;,自从路人乙昨晚没有被叫去摆地摊之后。早上一起床 路人甲:徒儿&#xff0c;昨晚休…

这篇看完我得理解ES6中中常见语法

目录 前言 1let篇 1.1作用域 1.2变量提升 1.3相同作用域赋值 2const篇 3模板字符串篇 3.1传统 3.2模板字符串复制 4扩展运算符篇 4.1传统赋值 4.2扩展字符串复制 前言 ES6是前端面试中常考查得知识点&#xff0c;还请大家不断得去琢磨琢磨 let篇 <!DOCTYPE h…