一 日志概述
- 日志是用于记录系统运行状态、用户操作和重大事件的工具。
1.日志的用途
- 系统监控
监控现在几乎是一个成熟系统的标配, 我们可以通过日志记录这个系统的运行状态, 每⼀个方法的响应时间, 响应状态等, 对数据进行分析, 设置不同的规则, 超过阈值时进行报警. 比如统计日志中关键字的数量,并在关键字数量达到一定条件时报警,这也是日志的常见需求之⼀- 数据采集
数据采集是⼀个比较大的范围, 采集的数据可以作用在很多方面, 比如数据统计, 推荐排序等
- 数据统计: 统计页面的浏览量(PV), 访客量(UV), 点击量等, 根据这些数据进行数据分析, 优化公司运营策略
- 推荐排序: 目前推荐排序应用在各个领域, 我们经常接触的各行各业很多也都涉及推荐排序, 比如购物, 广告, 新闻等领域. 数据采集是推荐排序工作中必须做的一环, 系统通过日志记录用户的浏览历史, 停留时长等, 算法人员通过分析这些数据, 训练模型, 给用户做推荐.
- 日志审计
随着互联网的发展,众多企业的关键业务越来越多的运行于网络之上. 网络安全越来越受到大家的关注, 系统安全也成为了项目中的⼀个重要环节, 安全审计也是系统中非常重要的部分. 国家的政策法规、行业标准等都明确对日志审计提出了要求. 通过系统日志分析,可以判断一些非法攻击, 非法调用,以及系统处理过程中的安全隐患.
2.日志的类型
- 诊断日志:记录请求入口出口、外部服务调用、资源消耗操作等,有助于技术团队理解和解决具体问题。
- 统计日志:涉及用户访问统计和计费信息,对分析产品使用模式和进行计费非常重要。
- 审计日志:记录管理操作和安全事件,对维护系统的安全性和合规性至关重要。
- 操作日志:记录系统操作员的操作轨迹,为后续审计和问题追踪提供依据。
- 安全日志:专注于记录登录信息、权限变更等安全相关事件。
二.打印日志
@RequestMapping("/logger")
@RestController
public class LoggerController {
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/test")
public String test() {
logger.info("------------打印日志---------------");
return "success";
}
}
1.SLF4J
- 即简单日志门面(Simple Logging Facade for Java),是一个抽象层,使得用户可以在不修改代码的情况下切换底层的日志系统。这极大地方便了开发人员在不同的日志系统间进行选择和迁移, 允许用户在部署其应用程序时插入所希望的日志系统。它自身不直接实现日志功能,而是提供了一个通用的API,通过这个API可以接入多种不同的日志框架
- SLF4J的主要特点
- 门面模式的应用:SLF4J是门面模式的典型应用,它本身不包含业务逻辑,而是定义了一组接口并将客户端请求委派给相应的日志实现框架处理。
- 灵活的日志系统切换:通过更换相应的适配器,可以在不同日志系统如Log4j, java.util.logging等之间自由切换,而无需修改应用程序代码。
2.门面模式(外观模式)
- 门面模式(Facade Pattern)又称为外观模式, 提供了一个统一的接口, 用来访问子系统中的一群接口.
- 门面模式主要包含2种角色:
- 外观角色(Facade): 也称门面角色,系统对外的统一接口.
- ⼦系统角色(SubSystem): 可以同时有⼀个或多个 SubSystem. 每个 SubSytem 都不是一个单独的类,而是⼀个类的集合. SubSystem 并不知道 Facade 的存在, 对于 SubSystem 而言, Facade 只是另一个客户端而已(即 Facade 对 SubSystem 透明)
举个例子比如去医院看病,可能要去挂号, 门诊, 化验, 取药, 让患者或患者家属觉得很复杂, 如果有提供接待人员, 只让接待人员来处理, 就很方便.
- 门面模式的优点:
- 减少了系统的相互依赖. 实现了客户端与子系统的耦合关系, 这使得子系统的变化不会影响到调用它的客户端;
- 提高了灵活性, 简化了客户端对子系统的使用难度, 客户端无需关心子系统的具体实现方式, 而只需要和门面对象交互即可.
- 提高了安全性. 可以灵活设定访问权限, 不在门面对象中开通方法, 就无法访问.
三.日志格式详细说明
-
- 时间日期:精确到毫秒
-
- 日志级别:ERROR, WARN, INFO, DEBUG 或TRACE
-
- 进程ID
-
- 线程名
-
- Logger名(通常使⽤源代码的类名)
-
- 日志内容
日志级别
日志的级别从高到低依次为: FATAL、ERROR、WARN、INFO、DEBUG、TRACE
- FATAL: 致命信息,表示需要立即被处理的系统级错误.
- ERROR: 错误信息, 级别较高的错误日志信息, 但仍然不影响系统的继续运行.
- WARN: 警告信息, 不影响使用, 但需要注意的问题
- INFO: 普通信息, 用于记录应用程序正常运行时的一些信息, 例如系统启动完成、请求处理完成等.
- DEBUG: 调试信息, 需要调试时候的关键信息打印.
- TRACE: 追踪信息, 比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG级别替代)
注
==日志级别通常和测试人员的Bug级别没有关系.==日志级别是开发人员设置的, 用来给开发人员看的. 日志级别的正确设置, 也与开发人员的工作经验有关. 如果开发人员把error级别的日志设置成了info, 就很有可能会影响开发人员对项目运行情况的判断. 出现error级别的日志信息较多时, 可能也没有任何问题. 测试的bug级别更多是依据现象和影响范围来判断
@RequestMapping("/logger")
@RestController
public class LoggerController {
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/level")
public String level() {
logger.error("-----------error级别的日志------------");
logger.warn("-----------warn级别的日志------------");
logger.info("-----------info级别的日志------------");
logger.debug("-----------debug级别的日志------------");
logger.trace("-----------trace级别的日志------------");
return "success";
}
}
结果发现, 只打印了info, warn和error级别的日志
这与日志级别的配置有关, 日志的输出级别默认是 info级别, 所以只会打印大于等于此级别的日志, 也就是info, warn和error.
四.日志配置
- 日志的配置只需要在application.yml或者application.properties里面设置相应的配置即可.
1.配置日志的输出级别
properties日志设置,设置日志级别为debug
logging.level.root: debug
yml日志设置,设置日志级别为debug
logging:
level:
root: debug
2.配置日志的持久化存储
- 以上的日志都是输出在控制台上的, 然而在线上环境中, 我们需要把日志保存下来, 以便出现问题之后追溯问题. 把日志保存下来就叫持久化.
- 日志持久化有两种方式:
-
- 配置日志文件名
-
- 配置日志的存储目录
- 配置日志的存储目录
-
- 配置日志文件的路径和文件名:
properties日志设置
logging.file.name: logger/springboot.log
yml日志设置
logging:
file:
name: logger/springboot.log
- 配置日志文件的保存路径
properties日志设置
logging.file.path: logger
yml日志设置
logging:
file:
path: logger
注意:
- logging.file.name 和 logging.file.path 两个都配置的情况下, 只生效其⼀, 以logging.file.name 为准.
- logging.file.name既能设置路径也能设置名称, logging.file.path只能设置路径默认的文件路径名为spring.log
3.配置日志文件分割
- 如果我们的日志都放在一个文件中, 随着项目的运行, 日志文件会越来越大, 需要对日志文件进行分割.
- 当然, 日志框架也帮我们考虑到了这一点, 所以如果不进行配置, 就走自动配置,默认日志文件超过10M就进分割.
更多详细配置可以去官网查看:
https://springdoc.cn/spring-boot/application-properties.html#application-properties.core.logging.logback.rollingpolicy.file-name-pattern
配置日志文件分割:Properties配置
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB
配置日志文件分割:yml配置
logging:
logback:
rollingpolicy:
max-file-size: 1KB
file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
3.配置日志格式
-
控制台日志格式:
- 配置项:
logging.pattern.console
- 默认值:
%clr(%d{KaTeX parse error: Unexpected character: '' at position 33: …ATTERN:-yyyy-MM̲dd'T'HH:mm:ss.S…{LOG_LEVEL_PATTERN:-%5p}) %clr( P I D : − ) m a g e n t a f a i n t {PID:- }){magenta} %clr(---){faint} %clr([%15.15t]) {faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n PID:−)magentafaint{LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
- 配置项:
-
日志文件的日志格式:
- 配置项:
logging.pattern.file
- 默认值:%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MMdd’T’HH:mm:ss.SSSXXX}} ${LOG_LEVEL_PATTERN:-%5p} P I D : − − − − [ {PID:- }--- [%t] %-40.40logger{39}:%m%n PID:−−−−[{LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
- 配置项:
-
配置项说明:
-
%clr(表达式){颜色} 设置输入日志的颜色 默认支持blue cyan faint green magenta red yellow这几种颜色.
-
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd’T’HH:mm:ss.SSSXXX}} 日期和时间–精确到毫秒.
%d{} ⽇期
${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd’T’HH:mm:ss.SSSXXX} 非空表达式, 获取
系统属性 LOG_DATEFORMAT_PATTERN , 若属性 LOG_DATEFORMAT_PATTERN 不存在,则使
用 -yyyy-MM-dd HH:mm:ss.SSSXXX 格式, 系统属性可以
System.getProperty(“LOG_DATEFORMAT_PATTERN”) 获取 -
%5p 显示日志级别ERROR,MARN,INFO,DEBUG,TRACE.
-
%t 线程名. %c 类的全限定名. %M method. %L 为行号. %thread 线程名称. %m 或者%msg 显示输出消息. %n 换行符
-
%5 若字符长度小于5,则右边用空格填充. %-5 若字符长度小于5,则左边用空格填充. %.15 若字符长度超过15,截去多余字符. %15.15 若字符长度小于15,则右边用空格填充. 若字符长度超过15,截取多余字符
-
日志格式Properties配置
logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %C %M %L [%thread] %m%n'
日志格式yml配置
logging:
pattern:
console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %C %M %L [%thread] %m%n'
五.更简单的日志输出.
- 每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加⼀遍, lombok给我们提供了一种更简单的方式
- 添加 lombok 框架支持
- 使用 @slf4j 注解输出日志
Lombok依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
使用注解:
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {
public void log(){
log.info("--------------要输出⽇志的内容----------------");
}
}