Springboot 日志处理(非常详细)

日志存入数据库(AOP

1.引入aop依赖

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

2.创建自定义注解类(用于在Controller层使用注解标注哪个方法需要增加日志)

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

3.编写LogAspect增强类与增强方法(我们使用环绕增强around

@Aspect
@Component
public class LogAspect {
//切入点,指定当使用Log注解时进入环绕增强
@Pointcut("@annotation(com.hz.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("获取所有用户集合")
@GetMapping("/getSfUserList")
public List<SfUser> getSfUserList() {
List<SfUser> sfUserList = sfUserService.getSfUserList(1);
System.out.println(sfUserList.size());
return sfUserList;
}

5.开始写入数据库

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;

6.创建实体类

/**
* 日志记录实体类
*/
public class SysLog {
private Long id;
private String username;
private String operation;
private Integer time;
private String method;
private String params;
private String ip;
private Date createTime;
.....get...set...
}

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

@Repository
public class SysLogDaoImpl implements SysLogDao {
@Autowired
@Qualifier("mysqlJdbcTemplateOne") //使用第一个数据源
private JdbcTemplate jdbcTemplate;
//保存信息到日志表
@Override
public void saveSysLog(SysLog syslog) {
String sql = "insert into sys_log(USERNAME,OPERATION,TIME,METHOD,PARAMS,IP)";
jdbcTemplate.update(sql,new Object[]
{syslog.getUsername(),syslog.getOperation(),syslog.getTime(),syslog.getMethod(),
syslog.getParams(),syslog.getIp()});
}
}

8.修改LogAspect增强类与增强方法

@Aspect
@Component
public class LogAspect {
@Autowired
private SysLogDao sysLogDao;
@Pointcut("@annotation(com.hz.log.Log)")
public void pointcut() {}
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) {
try {
long beginTime = System.currentTimeMillis();//开始执行时间
Object result = point.proceed();//执行方法
// 执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//实例化日志类
SysLog sysLog = new SysLog();
sysLog.setUsername("wzy");//模拟一个用户名 实际可以从session中获取
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);
}
// 保存系统日志
sysLogDao.saveSysLog(sysLog);
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
注意:
IP的获取需要工具类,网上可以自行查找
获取参数与获取方法名的方式都可以从网站查询

9.运行测试@Log

日志控制台打印与写入文件(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.WhitespaceThrowableProx
yConverter" />
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrow
ableProxyConverter" />
<!-- 彩色日志格式 -->
<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-ddHH}.%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-MMdd}.%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-MMdd}.%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

3.编写controller测试

Logger log = Logger.getLogger(SfUserController.class);
log.info("要输出的内容");//输出信息
等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息,如果配置
为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示

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

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

相关文章

5. langgraph中的react agent使用 (从零构建一个react agent)

1. 定义 Agent 状态 首先&#xff0c;我们需要定义 Agent 的状态&#xff0c;这包括 Agent 所持有的消息。 from typing import (Annotated,Sequence,TypedDict, ) from langchain_core.messages import BaseMessage from langgraph.graph.message import add_messagesclass …

源码解析-Spring Eureka(更新ing)

源码解析-Spring Eureka 文章目录 源码解析-Spring Eureka前言一、从Spring.factory和注解开始二、重要的一步EurekaServerInitializerConfiguration三、初始化了什么&#xff1f;自动保护 四, 重新回到EurekaServerAutoConfiguration关于unavailable-replicas 前言 无 一、从…

STL序列式容器之list

相较于vector的连续性空间&#xff0c;list相对比较复杂&#xff1b;list内部使用了双向环形链表的方式对数据进行存储&#xff1b;list在增加元素时&#xff0c;采用了精准的方式分配一片空间对数据及附加指针等信息进行存储&#xff1b; list节点定义如下 template<clas…

Science Robotics 封面论文:视触觉传感器的手内操作

现在&#xff0c;随便丢给机械手一个陌生物体&#xff0c;它都可以像人类一样轻松拿捏了。除了苹果&#xff0c;罐头、乐高积木、大象玩偶、骰子&#xff0c;都不在话下&#xff1a; 这就是来自Meta FAIR团队最新的NeuralFeels技术&#xff0c;通过融合触觉和视觉&#xff0c;机…

python语言基础-5 进阶语法-5.2 装饰器-5.2.2 简单装饰器

声明&#xff1a;本内容非盈利性质&#xff0c;也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站&#xff0c;会尽量附上原文链接&#xff0c;并鼓励大家看原文。侵删。 5.2.2 简单装饰器 装饰器的形式就是一个闭包&#xff0c;下面是一个简单的定义并使用…

定时器简介

TIM(Timer定时器)简介 在第一部分,我们主要讲的是定时器基本定时的功能&#xff0c;也就是定一个时间&#xff0c;然后让定时器每隔这个时间产生一个中断&#xff0c;来实现每隔一个固定时间执行一段程序的目的&#xff0c;比如你要做个时钟、秒表&#xff0c;或者使用一些程序…

【电子设计】按键LED控制与FreeRTOS

1. 安装Keilv5 打开野火资料,寻找软件包 解压后得到的信息 百度网盘 请输入提取码 提取码:gfpp 安装526或者533版本都可以 下载需要的 F1、F4、F7、H7 名字的 DFP pack 芯片包 安装完 keil 后直接双击安装 注册操作,解压注册文件夹后根据里面的图示步骤操作 打开说明 STM…

阅读2020-2023年《国外军用无人机装备技术发展综述》笔记_技术趋势

目录 文献基本信息 序言 1 发展概况 2 重点技术发展 2.1 人工智能技术 2.1.1 应用深化 2.1.2 作战效能提升 2.2 航空技术 2.2.1螺旋桨设计创新 2.2.2 发射回收技术进步 2.3 其他相关技术 2.3.1 远程控制技术探 2.3.2 云地控制平台应用 3 装备系统进展 3.1 无人作…

redis类型介绍

1. 字符串&#xff08;String&#xff09;&#xff1a; • 简介&#xff1a;最基础的数据类型&#xff0c;可以存储任何形式的字符串&#xff0c;包括文本数据和数字数据。 • 常用操作&#xff1a;SET、GET、INCR、DECR等。 2. 列表&#xff08;List&#xff09;&#xff1a; …

免费送源码:Java+Springboot+MySQL Springboot多租户博客网站的设计 计算机毕业设计原创定制

Springboot多租户博客网站的设计 摘 要 博客网站是当今网络的热点&#xff0c;博客技术的出现使得每个人可以零成本、零维护地创建自己的网络媒体&#xff0c;Blog站点所形成的网状结构促成了不同于以往社区的Blog文化&#xff0c;Blog技术缔造了“博客”文化。本文课题研究的“…

家政服务小程序,家政行业数字化发展下的优势

今年以来&#xff0c;家政市场需求持续增长&#xff0c;市场规模达到了万亿级别&#xff0c;家政服务行业成为了热门行业之一&#xff01; 家政服务种类目前逐渐呈现了多样化&#xff0c;月嫂、保姆、做饭保洁、收纳、维修等家政种类不断出现&#xff0c;满足了居民日益增长的…

炼码LintCode--数据库题库(级别:简单;数量:55道)--刷题笔记_02

目录 炼码LintCode--数据库题库&#xff08;级别&#xff1a;简单&#xff1b;数量&#xff1a;55道&#xff09;--刷题笔记_023618 耗时前三的任务&#xff08;日期差&#xff09;题&#xff1a;sql&#xff1a;解释&#xff1a;DATEDIFF 天数差order by 别名TIMESTAMPDIFF 月…

正则表达式那些事儿

目录 1.正则表达式中的模糊匹配符1.1点"."1.2星号"*"1.3问号"?"1.4 d 当处理文本需要匹配特定的字符串的时候&#xff0c;我们需要使用正则表达式。 1.正则表达式中的模糊匹配符 有很多字符是正则表达式中的特殊用途字符&#xff0c;不能直接用…

如何使用正则表达式验证域名

下面是一篇关于如何使用正则表达式验证域名的教程。 如何使用正则表达式验证域名 简介 域名是互联网上网站的地址&#xff0c;每个域名由多个标签&#xff08;label&#xff09;组成&#xff0c;标签之间用点 . 分隔。域名规则有很多细节&#xff0c;但基本要求是&#xff1a…

猫狗识别之BUG汇总

一、github登不上去问题 下载watt toolkit 下载地址&#xff1a;https://steampp.net/ 可以下载后加速&#xff0c;访问github 二、猫狗总体参考核心 B哥的博客 https://github.com/bubbliiiing/classification-keras?tabreadme-ov-file 三、CSDN很多会员才能阅读问题 根据…

Failed to create a temp file - Jenkins 无法创建任务

近日&#xff0c;突然发现任务集群的jenkins异常退出了&#xff0c;没有任何的迹象。后来排查到jenkins的job的日志后&#xff0c;找到了以下错误日志。 Started by user unknown or anonymous Running as SYSTEM Building in workspace /Users/xxxxx/work/jenkins2/jenkins_h…

【C++】list 与 string 基础与实现字符串操作

【C】使用 list 与 string 实现基础字符串操作 文章目录 一、字符串的基础操作1.1 - startsWith1.2 - endsWith1.3 - trim1.4 - indexOf1.5 - replaceAll 二、list 基础操作2.1 - 遍历2.1.1 - 使用迭代器访问2.1.2 - 使用基于范围的 for 循环遍历2.1.3 - 使用标准算法库遍历 2.…

CI/CD认识

CI/CD 是 Continuous Integration&#xff08;持续集成&#xff09; 和 Continuous Delivery/Deployment&#xff08;持续交付/部署&#xff09; 的缩写&#xff0c;是一种软件开发和运维实践&#xff0c;旨在通过自动化和持续迭代来提高开发效率、代码质量以及交付速度。 CI&…

Git主干分支master开发优缺点

优缺点 主干开发&#xff1a;是指开发人员直接向主干&#xff08;习惯上主干分支通常为&#xff1a;main或master&#xff09;提交/推送代码。通常开发团队的成员1天至少一次地将代码提交到主干分支&#xff0c;在到达发布条件时&#xff0c;从主干拉出发布分支通常为&#xf…

药典新篇:Spring Boot助力中药实验管理

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中药实验管理系统的相关信息成为必然。开发…