Spring Boot日志处理
文章目录
- Spring Boot日志处理
- 1. 日志存入数据库(AOP)
- 2. 日志控制台打印与写入文件(logback)
Spring Boot日志处理
1. 日志存入数据库(AOP)
-
引入aop依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.6.14</version> </dependency>
-
创建自定义注解类(用于在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 ""; }
-
编写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; } }
-
创建controller进行测试
@Log(value = "轮播图列表") @GetMapping("/findList") public MessageJson<Carousel> findList(){ List<Carousel> carousels = carouselService.list(); return carousels!=null?MessageJson.success(carousels):MessageJson.error(); }
-
开始写入数据库
创建日志记录表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; } }
-
运行测试
@Log
2. 日志控制台打印与写入文件(logback)
-
创建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"> <!–格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符–> <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>
-
配置application.yml文件
logging: config: classpath:logback-spring.xml
-
编写controller测试
@slf4j