Spring Boot日志处理

文章目录

  • Spring Boot日志处理
    • 1. 日志存入数据库(AOP)
    • 2. 日志控制台打印与写入文件(logback)

Spring Boot日志处理

1. 日志存入数据库(AOP)

  1. 引入aop依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
        <version>2.6.14</version>
    </dependency>
    
  2. 创建自定义注解类(用于在Controller层使用注解标注哪个方法需要增加日志)

    @interface 注解类,自定义注解

    @Target 用来说明该注解可以被声明在那些元素之前

    ElementType.METHOD说明该注解只能被声明在一个类的方法前

    @Retention 用来说明该注解类的生命周期。

    RetentionPolicy.RUNTIME注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解

    /**
     * @ClassName Log
     * @Description 自定义日志注解类
     * @Author Administrator
     * @Date 2024/12/23 9:38
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Log {
        // 日志描述
        String value() default "";
    }
    
    
  3. 编写LogAspect增强类与增强方法(我们使用环绕增强around)

    /**
     * @ClassName LogAspect
     * @Description 日志增强类与增强方法
     * @Author Administrator
     * @Date 2024/12/23 9:41
     */
    public class LogAspect {
        //切入点,指定当使用Log注解时进入环绕增强
        @Pointcut("@annotation(com.hz.goods.web.log.Log)")
        public void pointcut() {}
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint point) {
            try {
                System.out.println("执行环绕增强..............开始");
                Object result = point.proceed();//执行方法
                System.out.println("结束..........");
                return result;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
    }
    
  4. 创建controller进行测试

    @Log(value = "轮播图列表")
    @GetMapping("/findList")
    public MessageJson<Carousel> findList(){
        List<Carousel> carousels = carouselService.list();
        return carousels!=null?MessageJson.success(carousels):MessageJson.error();
    }
    
  5. 开始写入数据库

    创建日志记录表sys_log

    DROP TABLE IF EXISTS `sys_log`;
    CREATE TABLE `sys_log` (
    `ID` bigint(20) NOT NULL AUTO_INCREMENT,
    `USERNAME` varchar(50) DEFAULT NULL COMMENT '用户名',
    `OPERATION` varchar(50) DEFAULT NULL COMMENT '用户操作',
    `TIME` int(11) DEFAULT NULL COMMENT '响应时间',
    `METHOD` varchar(200) DEFAULT NULL COMMENT '请求方法',
    `PARAMS` varchar(500) DEFAULT NULL COMMENT '请求参数',
    `IP` varchar(64) DEFAULT NULL COMMENT 'IP地址',
    `CREATE_TIME` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    创建实体类

    @Data
    @TableName("sys_log")
    public class SysLog {
    @TableId(value = "id",type = IdType.AUTO)
    private Long id;
    private String username;
    private String operation;
    private Integer time;
    private String method;
    private String params;
    private String ip;
    private Date createTime;
    }
    

    编写Mapper层接口

    public interface SysLogMapper extends BaseMapper<SysLog> {
    }
    

    导入工具类HttpContextUtils、IPUtils

    修改LogAspect增强类与增强方法

    @Aspect
    @Component
    public class LogAspect {
    @Autowired
    private SysLogMapper sysLogMapper;
    //切入点,指定当使用Log注解时进入环绕增强
    @Pointcut("@annotation(com.hz.goods.web.log.Log)")
    public void pointcut() {}
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) {
      try {
          SysLog sys = new SysLog();
          sys.setUsername("4072");//设置用户名
          Long start = System.currentTimeMillis();//开始时间
          Long end = System.currentTimeMillis();//结束时间
          Object result = point.proceed();//调用目标方法
          Long time = end - start;//执行时间
          sys.setTime(time.intValue());//设置执行时间
          //获取请求对象
          HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
          //获取IP地址
          sys.setIp(IPUtils.getIpAddr(request));
          //获取注解描述
          MethodSignature signature = (MethodSignature) point.getSignature();
          Method method = signature.getMethod();
          Log logAnnotation = method.getAnnotation(Log.class);
          if (logAnnotation != null) {
              sys.setOperation(logAnnotation.value());//设置操作描述
          }
          //获得请求方法名
          String methodName = point.getTarget().getClass().getName() + "." + point.getSignature().getName();
          sys.setMethod(methodName);//设置请求方法名
          // 请求的方法参数值
          Object[] args = point.getArgs();
          // 请求的方法参数名称
          LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
          String[] paramNames = u.getParameterNames(method);
          if (args != null && paramNames != null) {
              String params = "";
              for (int i = 0; i < args.length; i++) {
                  params += "," + paramNames[i] + ": " + args[i];
              }
              sys.setParams(params);
          }
          // 保存日志
          sysLogMapper.insert(sys);
          return result;
      } catch (Throwable throwable) {
          throwable.printStackTrace();
      }
      return null;
    }
    }
    
  6. 运行测试@Log

2. 日志控制台打印与写入文件(logback)

  1. 创建logback-spring.xml文件放入resource下,并复制内容到该文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <property name="LOG_CONTEXT_NAME" value="log"/>
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
        <property name="LOG_HOME" value="D:/logs" />
        <!-- 定义日志上下文的名称 -->
        <contextName>${LOG_CONTEXT_NAME}</contextName>
        <!-- 控制台输出 -->
        <!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
          <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            &lt;!&ndash;格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符&ndash;&gt;
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n</pattern>
            <charset>utf-8</charset>
          </encoder>
          <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
          </filter>
        </appender>-->
    
    
        <!-- 彩色日志依赖的渲染类 -->
        <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
        <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
        <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
        <!-- 彩色日志格式 -->
        <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%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}}"/>
    
        <!--1. 输出到控制台-->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>INFO</level>
            </filter>
            <encoder>
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
                <!-- 设置字符集 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <!--info日志统一输出到这里-->
        <appender name="file.info" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <Prudent>true</Prudent>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名,按小时生成-->
                <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/info/info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <!-- 除按日志记录之外,还配置了日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始, -->
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符-->
                <pattern> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录info级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>INFO</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
    
        <!--错误日志统一输出到这里-->
        <appender name="file.error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <Prudent>true</Prudent>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名,按天生成-->
                <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/error/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <!-- 除按日志记录之外,还配置了日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始, -->
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符-->
                <pattern> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录error级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
        <!--warn日志统一输出到这里-->
        <appender name="file.warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <Prudent>true</Prudent>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/warn/warn.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <!-- 除按日志记录之外,还配置了日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始, -->
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符-->
                <pattern> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录warn级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>WARN</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
        <!--  日志输出级别 -->
        <root level="DEBUG">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="file.error" />
            <appender-ref ref="file.info" />
            <appender-ref ref="file.warn" />
        </root>
    
    </configuration>
    
  2. 配置application.yml文件

    logging:
      config: classpath:logback-spring.xml
    
  3. 编写controller测试@slf4j

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#编写的金鱼趣味小应用 - 开源研究系列文章

今天逛网&#xff0c;在GitHub中文网上发现一个源码&#xff0c;里面有这个金鱼小应用&#xff0c;于是就下载下来&#xff0c;根据自己的C#架构模板进行了更改&#xff0c;最终形成了这个例子。 1、 项目目录&#xff1b; 2、 源码介绍&#xff1b; 1) 初始化&#xff1b; 将样…

通过无障碍服务(AccessibilityService)实现Android设备全局水印显示

一、无障碍功能简介 首先我们先来了解下无障碍功能的官方介绍&#xff1a; 无障碍服务仅应用于帮助残障用户使用 Android 设备和应用。它们在后台运行&#xff0c;并在触发 AccessibilityEvents 时接收系统的回调。此类事件表示用户界面中的某些状态转换&#xff0c;例如焦点已…

【Blackbox Exporter】prober.Handler源码详细分析

http.HandleFunc(path.Join(*routePrefix, "/probe"), func(w http.ResponseWriter, r *http.Request) {sc.Lock()conf : sc.Csc.Unlock()prober.Handler(w, r, conf, logger, rh, *timeoutOffset, nil, moduleUnknownCounter, allowedLevel)})我们了解到blackbox_ex…

SpringMVC核心、两种视图解析方法、过滤器拦截器 “ / “ 的意义

SpringMVC的执行流程 1. Spring MVC 的视图解析机制 Spring MVC 的核心职责之一是将数据绑定到视图并呈现给用户。它通过 视图解析器&#xff08;View Resolver&#xff09; 来将逻辑视图名称解析为具体的视图文件&#xff08;如 HTML、JSP&#xff09;。 核心流程 Controlle…

基于动力学的MPC控制器设计盲点解析

文章目录 Apollo MPC控制器的设计架构误差模型和离散化预测模型推导目标函数和约束设计优化求解优化OSQP求解器参考文献 Apollo MPC控制器的设计架构 误差模型和离散化 状态变量和控制变量 1、Apollo MPC控制器中状态变量主要有如下6个 matrix_state_ Matrix::Zero(basic_stat…

DC-DC 降压转换器设计提示和技巧

基本 DC-DC 降压转换器电路 在开始之前&#xff0c;我们先回顾一下DC-DC降压转换器的电路&#xff1a; 为了帮助您&#xff0c;我开发了降压设计中“什么影响什么”的矩阵&#xff1a; 主要的权衡是电感&#xff08;与 k 因子成反比&#xff0c;即峰峰值与平均电感电流之比&a…

Unity3D仿星露谷物语开发9之创建农场Scene

1、目标 绘制农场的场景。通过不同Sorting Layer控制物体的显示优先级&#xff0c;绘制Tilemap地图&#xff0c;添加Tilemap Collider碰撞器&#xff0c;同时添加Composite Collider碰撞器优化性能。 ps&#xff1a;绘制Tilemap的技巧&#xff1a;通过"Shift [" 可…

Linux 定时任务:轻松创建与精准执行

Linux 定时任务&#xff1a;轻松创建与精准执行 在 Linux 系统的运维与自动化管理领域&#xff0c;定时任务扮演着举足轻重的角色。它能够让系统在预设的时间点或周期性时段&#xff0c;自动执行特定的脚本、命令&#xff0c;极大地减轻了管理员的工作负担&#xff0c;提升工作…

Linux驱动开发:深入理解I2C时序(二)

在Linux驱动开发中,I2C时序的理解和正确处理是保证I2C设备正常工作和通信的关键。I2C协议的时序特性决定了数据的有效传输和设备间的协作。因此,掌握I2C的时序细节,以及如何在Linux内核中进行时序处理,能够让开发者更好地处理设备通信问题。 本文将继续深入探讨I2C通信协议…

国产编辑器EverEdit - 常用资源汇总

1 国产编辑器EverEdit-常用资源汇总 EverEdit是一款国产文本编辑器&#xff0c;历经超过15年的更新和维护&#xff0c;拥有不输业界顶级商业文本编辑器(EmEditor、UltraEdit)的实力&#xff0c;甚至在某些方面的功能更强(当然&#xff0c;各有千秋)&#xff0c;开发者对文本编辑…

解决uniapp H5页面限制输入框只能输数字问题

工作记录 最最近在做 uniapp 开发的移动端 H5 页面&#xff0c;有个需求是金额输入框只能输入数字&#xff0c;不能输入小数点和其他字符&#xff0c;经过各种尝试&#xff0c;发现其他字符可以通过正则过滤掉&#xff0c;但是输入小数点的话&#xff0c;因为没有触发 input 和…

面试准备备备备

职业技能 放到简历的黄金位置&#xff08;HR刷选简历的重要参考&#xff09; 基本准则&#xff1a;写在简历上的必须能聊&#xff0c;不然就别写 参考公式&#xff1a;职业技能 必要技术 其他技术 针对性的引导面试官&#xff08;让他问一些你想让他问的&#xff09; 寻找合…

npm install --global windows-build-tools --save 失败

注意以下点 为啥下载windows-build-tools&#xff0c;是因为node-sass4.14.1 一直下载不成功&#xff0c;提示python2 没有安装&#xff0c;最终要安装这个&#xff0c;但是安装这个又失败&#xff0c;主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …

Jenkins 中自动化部署 Spring Boot 项目

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的全栈工程师 欢迎分享 / 收藏 / 赞 / 在看…

【DSP/matlab】fftshift 是什么意思?在信号处理中有什么作用?

文章目录 前言一、定义什么是 fftshift&#xff1f;fftshift 在信号处理中的作用&#xff1a; 前言 dsp_paper 一、定义 fftshift 是一个在信号处理和数字信号处理中常用的函数&#xff0c;特别是在使用快速傅里叶变换&#xff08;FFT&#xff09;时。这个函数的主要作用是将…

【PCIe 总线及设备入门学习专栏 4.2 -- PCI 总线的三种传输模式 】

文章目录 OverviewProgrammed I/O&#xff08;PIO&#xff09;Direct Memory Access (DMA)Peer-to-Peer 本文转自&#xff1a;https://blog.chinaaet.com/justlxy/p/5100053095 Overview 本文来简单地介绍一下PCI Spec规定的三种数据传输模型&#xff1a;Programmed I/O&…

SpringBoot_第二天

SpringBoot_第二天 学习目标 Mybatis整合&数据访问 使用SpringBoot开发企业项目时&#xff0c;持久层数据访问是前端页面数据展示的基础&#xff0c;SpringBoot支持市面上常见的关系库产品(Oracle,Mysql,SqlServer,DB2等)对应的相关持久层框架&#xff0c;当然除了对于关系…

分类模型评估利器-混淆矩阵

相关文章 地理时空动态模拟工具介绍&#xff08;上&#xff09; 地理时空动态模拟工具介绍&#xff08;下&#xff09;地理时空动态模拟工具的使用方法 前言 混淆矩阵&#xff08;Confusion Matrix&#xff09;是机器学习领域中用于评估分类模型性能的一种工具。它通过矩阵的…

【SpringMVC】拦截器

拦截器&#xff08;Interceptor&#xff09;是一种用于动态拦截方法调用的机制。在 Spring MVC 中&#xff0c;拦截器能够动态地拦截控制器方法的执行过程。以下是请求发送与接收的基本流程&#xff1a; 当浏览器发出请求时&#xff0c;请求首先到达 Tomcat 服务器。Tomcat 根…

el-table 实现纵向多级表头

为了实现上图效果&#xff0c;最开始打算用el-row、el-col去实现&#xff0c;但发现把表头和数据分成两大列时&#xff0c;数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样&#xff0c;为保持高度样式一致&#xff0c;就需要我们手动去获取最高格的高度之后再设置…