SpringBoot之日志处理(logback和AOP记录操作日志)

发布于:2025-09-11 ⋅ 阅读:(17) ⋅ 点赞:(0)

项目准备

数据库

CREATE TABLE `smbms_user`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `userCode` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL DEFAULT NULL COMMENT '用户编码',
  `userName` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL DEFAULT NULL COMMENT '用户名称',
  `userPassword` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL DEFAULT '0000000' COMMENT '用户密码',
  `gender` int NULL DEFAULT NULL COMMENT '性别(1:女、 2:男)',
  `birthday` datetime NULL DEFAULT NULL COMMENT '出生日期',
  `phone` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL DEFAULT NULL COMMENT '手机',
  `address` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL DEFAULT NULL COMMENT '地址',
  `userRole` bigint NULL DEFAULT NULL COMMENT '用户角色(取自角色表-角色id)',
  `createdBy` bigint NULL DEFAULT NULL COMMENT '创建者(userId)',
  `creationDate` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `modifyBy` bigint NULL DEFAULT NULL COMMENT '更新者(userId)',
  `modifyDate` datetime NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 129 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_unicode_ci ROW_FORMAT = Dynamic;

INSERT INTO `smbms_user` VALUES (1, 'admin', '系统管理员', '1234567', 1, '1983-10-10 00:00:00', '13688889999', '北京市海淀区成府路207号', 1, 1, '2013-03-21 16:52:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (2, 'liming', '李明', '0000000', 2, '1983-12-10 00:00:00', '13688884457', '北京市东城区前门东大街9号', 3, 1, '2014-12-31 19:52:09', NULL, '2025-09-04 15:57:03');
INSERT INTO `smbms_user` VALUES (5, 'hanlubiao', '韩路彪', '0000000', 2, '1984-06-05 00:00:00', '18567542321', '北京市朝阳区北辰中心12号', 2, 1, '2014-12-31 19:52:09', NULL, NULL);
INSERT INTO `smbms_user` VALUES (6, 'zhanghua', '张华1', '0000000', 1, '1983-06-15 00:00:00', '13544561111', '北京市海淀区学院路61号', 3, 1, '2013-02-11 10:51:17', NULL, '2025-08-19 16:45:43');
INSERT INTO `smbms_user` VALUES (7, 'wangyang', '王洋', '0000000', 2, '1982-12-31 00:00:00', '13444561124', '北京市海淀区西二旗辉煌国际16层', 3, 1, '2014-06-11 19:09:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (8, 'zhaoyan', '赵燕', '0000000', 1, '1986-03-07 00:00:00', '18098764545', '北京市海淀区回龙观小区10号楼', 3, 1, '2016-04-21 13:54:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (10, 'sunlei', '孙磊', '0000000', 2, '1981-01-04 00:00:00', '13387676765', '北京市朝阳区管庄新月小区12楼', 3, 1, '2015-05-06 10:52:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (11, 'sunxing', '孙兴', '0000000', 2, '1978-03-12 00:00:00', '13367890900', '北京市朝阳区建国门南大街10号', 3, 1, '2016-11-09 16:51:17', NULL, NULL);
INSERT INTO `smbms_user` VALUES (12, 'zhangchen', '张晨', '0000000', 1, '1986-03-28 00:00:00', '18098765434', '朝阳区管庄路口北柏林爱乐三期13号楼', 3, 1, '2016-08-09 05:52:37', 1, '2016-04-14 14:15:36');
INSERT INTO `smbms_user` VALUES (13, 'dengchao', '邓超', '0000000', 2, '1981-11-04 00:00:00', '13689674534', '北京市海淀区北航家属院10号楼', 3, 1, '2016-07-11 08:02:47', NULL, NULL);
INSERT INTO `smbms_user` VALUES (14, 'yangguo', '杨过', '0000000', 2, '1980-01-01 00:00:00', '13388886623', '北京市朝阳区北苑家园茉莉园20号楼', 3, 1, '2015-02-01 03:52:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (15, 'zhaomin', '赵敏1', '0000000', 1, '1992-01-01 00:00:00', '18099897657', '北京市昌平区天通苑3区12号楼', 2, 1, '2015-09-12 12:02:12', NULL, NULL);
INSERT INTO `smbms_user` VALUES (103, '1', '1', '1', 1, '2025-07-17 16:34:35', '1', '1', 1, 1, '2025-07-17 16:34:35', 1, '2025-07-17 16:34:35');
INSERT INTO `smbms_user` VALUES (112, '80', '惠静怡', 'BSu9Y5mIKEZ2C8H', NULL, NULL, NULL, NULL, 1, NULL, '2025-09-03 11:09:07', NULL, NULL);
INSERT INTO `smbms_user` VALUES (113, '山东', '是的是的', '0000000', 2, '2025-09-07 08:00:00', '15457854567', '山东', 2, NULL, '2025-09-03 11:12:28', NULL, '2025-09-04 15:07:54');
INSERT INTO `smbms_user` VALUES (114, '你好', '山东', '0000000', 2, '2025-09-09 08:00:00', '15456874569', '山东', 1, NULL, '2025-09-03 11:18:27', NULL, '2025-09-03 11:30:45');
INSERT INTO `smbms_user` VALUES (115, '山东', '山东', '0000000', 2, '2025-09-01 08:00:00', '14575674578', ' 但是', 1, NULL, '2025-09-03 11:19:43', NULL, NULL);
INSERT INTO `smbms_user` VALUES (116, '山东', '山东', '0000000', 2, '2025-09-09 08:00:00', '18466559854', '山东', 1, NULL, '2025-09-03 11:21:01', NULL, NULL);
INSERT INTO `smbms_user` VALUES (117, '山东', '山东', '0000000', 2, '2025-09-01 08:00:00', '14567854569', '45', 1, NULL, '2025-09-03 11:22:15', NULL, NULL);
INSERT INTO `smbms_user` VALUES (119, NULL, '李四', '0000000', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL);
INSERT INTO `smbms_user` VALUES (120, NULL, '李四', '0000000', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL);

新建项目并选择模块安装

创建一个空的 Spring Boot 工程
文件–>新建项目
在这里插入图片描述

选择模块

  1. SpringBoot版本选择2.7.6
  2. DeveloperTools中选择Lombok
  3. Web中选择SpringWeb
  4. SQL中选择MySQLDriver
    在这里插入图片描述

添加依赖

<!-- mybatis-plus依赖 -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.5.1</version>
	<!--sql性能分析插件使用版本-->
	<!-- <version>3.1.2</version> -->
</dependency>

添加application.yml

我们删除application.properties
在resources文件下新建application.yml.
application.yml 中配置文件中添加mysql 数据库相关配置:

server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root
# mybatis-plus 相关配置
mybatis-plus:
  type-aliases-package: com.hsh.pojo #类型别名所在的包
  #控制台打印sql语句
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: false #关闭驼峰映射

注意你要写你的数据库端口号账号密码你要简化的包名 这些一定要看一下。

删除demos.web包

在这里插入图片描述

编写pojo层

user

com/hsh/pojo/user

package com.hsh.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("smbms_user")
public class User {
    private Long id;// 主键ID
    private String userCode;// 用户编码
    private String userName;// 用户名称
    private String userPassword;// 用户密码
    private Integer gender;// 性别(1:女、 2:男)
    private LocalDateTime birthday;//  出生日期
    private String phone;//  手机
    private String address;//  地址
    private Long userRole;// 用户角色(取自角色表-角色id)
    private Long createdBy;// 创建者(userId)
    private LocalDateTime creationDate;// 创建时间
    private Long modifyBy; // 更新者(userId)
    private LocalDateTime modifyDate; // 更新时间
}

dto/ResultJson

package com.hsh.pojo.tdo;
import java.io.Serializable;

@Data
public class ResultJSON<T> implements Serializable {
    private Integer code;
    private String msg;
    private T data;
    public ResultJSON(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;

    }

    /**
     * 操作成功或者失败
     * @param c 受影响行数
     * @return 当前传入的受影响行数>0则返回成功,否则返回失败
     */
    public static  ResultJSON successORerror(int c){
        return c>0?new ResultJSON(200,"操作成功",c)
                :new ResultJSON(400,"操作失败",c);
    }

    public static ResultJSON success(){
        return new ResultJSON(200,"操作成功",null);
    }
    public static ResultJSON success(String msg){
        return new ResultJSON(200,msg,null);
    }
    public static <T> ResultJSON success(T data){
        return new ResultJSON(200,"操作成功",data);
    }
    public static ResultJSON success(Integer code,String msg){
        return new ResultJSON(code,msg,null);
    }
    public static <T> ResultJSON success(String msg,T data){
        return new ResultJSON(200,msg,data);
    }
    public static <T> ResultJSON success(Integer code,String msg,T data){
        return new ResultJSON(code,msg,data);
    }

    public static ResultJSON error(){
        return new ResultJSON(500,"操作失败",null);
    }
    public static ResultJSON error(String msg){
        return new ResultJSON(500,msg,null);
    }
    public static ResultJSON error(Integer code,String msg){
        return new ResultJSON(code,msg,null);
    }
 
}

编写mapper层

UserMapper

package com.hsh.mapper;

public interface UserMapper extends BaseMapper<User> {

}

编写service层

UserService

// 接口
package com.hsh.service;
public interface UserService {
    ResultJSON<User> getUserById(Long id);
    ResultJSON<User> editUser(User user);
    ResultJSON<User> deleteUser(Long id);
    ResultJSON<User> addUser(User user);
}

// 实现类
package com.hsh.service.impl;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public ResultJSON<User> getUserById(Long id) {
        User user = userMapper.selectById(id);
        return ResultJSON.success(user);
    }
    @Override
    public ResultJSON<User> editUser(User user) {
        int i = userMapper.updateById(user);
        return ResultJSON.successORerror(i);
    }
    @Override
    public ResultJSON<User> deleteUser(Long id) {
        int i = userMapper.deleteById(id);
        return ResultJSON.successORerror(i);
    }
    @Override
    public ResultJSON<User> addUser(User user) {
        int i = userMapper.insert(user);
        return ResultJSON.successORerror(i);
    }
}

编写controller层

UserContoller

package com.hsh.controller;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getUserById")
    public ResultJSON getUserById(Long id){
        return ResultJSON.success(userService.getUserById(id));
    }
    @RequestMapping("/addUser")
    public ResultJSON addUser(@RequestBody User user){
        return userService.addUser(user);
    }
    @RequestMapping("/deleteUser")
    public ResultJSON deleteUser(Long id){
        return userService.deleteUser(id);
    }
    @RequestMapping("/editUser")
    public ResultJSON editUser(@RequestBody User user){
        return userService.editUser(user);
    }
}

编写配置类

MybatisPlusConfig

package com.hsh.config;

@Configuration
@MapperScan("com.hsh.mapper")
public class MybatisPlusConfig {

}

编写测试类

package com.hsh;

import com.hsh.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MybatisPlus01ApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        System.out.println(userMapper.selectById(1));
    }
}

在这里插入图片描述

概述

日志处理分两种

  1. 异常日志:当程序报异常进行记录。
    • 使用技术:log4j,logback,slf4j,
  2. 操作日志:当用户进行修改,更新,删除,操作时需要记录。查询不需要记录。
    • 使用技术:AOP。使用AOP需要自定义注解进行使用。当我在方法上写这个自定义注解,我就去捕获这方法进行操作日志记录。

我们这些日志如何存贮呢?

  1. 数据库:当数据库满了需要手动备份然后清空数据库。(若依框架就是使用的这一套)
  2. Redis:虽然redis能持久化,但是一次要拿很多数据,只能用stream流过滤,当数据过大会出问题。
  3. 记事本:数据量过大会卡顿。
  4. 搜索引擎:solr(单体式项目),ES(分布式项目)。

记录操作日志

我们使用数据库存储,因为若依使用的就是这一套。
我们的记录日志操作是对某些方法进行操作,所以aop就可以对某些方法进行操作。

使用AOP对日志注解增强

引入aop依赖

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

编写@Log注解

com/hsh文件夹下新建aop文件夹,并在com/hsh/aop下新建Log类

package com.hsh.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// @Target 用来说明该注解可以被声明在那些元素之前
// ElementType.METHOD说明该注解只能被声明在一个类的方法前
@Target(ElementType.METHOD)
// @Retention 用来说明注解的声明周期
// RetentionPolicy.RUNTIME注解保留在程序运行期间,
// 此时可以通过反射获得定义在某个类上的所有注解。
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {// @interface 注解类,自定义注解
    String value() default "";
}

编写LogAspect增强类与增强方法

编写LogAspect增强类与增强方法(我们使用环绕增强around)
com/hsh文件夹下新建aop文件夹,并在com/hsh/aop下新建LogAspect类

package com.hsh.aop;

@Aspect
@Component
public class LogAspect {
    //切入点,指定当使用Log注解时进入环绕增强
    @Pointcut("@annotation(com.hsh.aop.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;
    }
}

在controller进行测试

package com.hsh.controller;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    
		// 加入@Log注解测试
    @RequestMapping("/getUserById")
    @Log("获取所有用户集合")
    public ResultJSON getUserById(Long id){
        return ResultJSON.success(userService.getUserById(id));
    }
}

浏览器输入http://localhost:8080/user/getUserById?id=1

在这里插入图片描述查看idea控制台说明对注解的增强生效。
在这里插入图片描述

使用操作日志

创建数据库sys_log记录操作

创建日志记录表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;

创建实体类

package com.hsh.pojo;
@TableName("sys_log")
@Data
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;
}

创建操作方法的实现

编写DAO层接口与实现,向表中插入数据

package com.hsh.mapper;

public interface SysLogMapper extends BaseMapper<SysLog> {
    
}

创建获取request的工具类

com/hsh文件夹下新建utils文件夹,并在com/hsh/utils下新建HttpContextUtils 类

package com.hsh.utils;

public class HttpContextUtils {
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }
}

创建获取用户IP的工具类

com/hsh/utils下新建IPUtils 类

package com.hsh.utils;

public class IPUtils {
    public static String getIpAddr(HttpServletRequest request){
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;

    }
}

修改LogAspect增强类与增强方法

package com.hsh.aop;

import com.hsh.mapper.SysLogMapper;
import com.hsh.pojo.SysLog;
import com.hsh.utils.HttpContextUtils;
import com.hsh.utils.IPUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
public class LogAspect {
    @Autowired
    private SysLogMapper sysLogMapper;
    //切入点,指定当使用Log注解时进入环绕增强
    @Pointcut("@annotation(com.hsh.aop.Log)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) {
        try {
            //实例化日志类
            SysLog sysLog = new SysLog();
            sysLog.setUsername("xrkhy");//模拟一个用户名 实际可以从session中获取
            //开始执行时间
            long beginTime = System.currentTimeMillis();
            //执行方法
            Object result = point.proceed();
            // 执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            //执行时长(毫秒)
            sysLog.setTime((int) time);
            // 获取request
            HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
            // 设置IP地址
            sysLog.setIp(IPUtils.getIpAddr(request));
            // 通过反射获取方法名
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            // 获取操作名称
            Log logAnnotation = method.getAnnotation(Log.class);
            if (logAnnotation != null) {
                // 注解上的描述
                sysLog.setOperation(logAnnotation.value());
            }
            // 请求的方法名
            String className = point.getTarget().getClass().getName();
            String methodName = signature.getName();
            sysLog.setMethod(className + "." + 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];
                }
                sysLog.setParams(params);
            }

            // 保存系统日志
            sysLogMapper.insert(sysLog);

            return result;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;

    }
}

在service的增删改上面添加@Log注解

package com.hsh.controller;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getUserById")
    public ResultJSON getUserById(Long id){
        return ResultJSON.success(userService.getUserById(id));
    }

    @RequestMapping("/addUser")
    @Log("添加用户")
    public ResultJSON addUser(User user){
        return userService.addUser(user);
    }
    @RequestMapping("/deleteUser")
    @Log("删除用户")
    public ResultJSON deleteUser(Long id){
        return userService.deleteUser(id);
    }
    @RequestMapping("/editUser")
    @Log("修改用户")
    public ResultJSON editUser(User user){
        return userService.editUser(user);
    }
}

测试

打开接口测试工具
apifox或者postman进行测试。
在这里插入图片描述
检查sys_log数据库。
在这里插入图片描述

记录异常日志

1. 创建logback-spring.xml

创建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.properties文件

下面两种读取方式二选一

#读取配置文件
logging.config=classpath:logback-spring.xml

yml配置

#读取配置文件
logging:
  config: classpath:logback-spring.xml

3. 编写controller测试

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getUserById")
    @Log("获取指定用户集合")
    public ResultJSON getUserById(Long id){
        log.info("获取指定用户集合");//输出信息
        return ResultJSON.success(userService.getUserById(id));
    }
}

等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息,如果配置为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示


网站公告

今日签到

点亮在社区的每一天
去签到