目录
1. 日志的作用
日志最基本的作用就是发现和定位问题, 我们平时在写程序的时候, 没有达到预期效果时, 我们都会打开控制台去查看错误原因, 这就是最基本的体现.
当然日志还有其他的作用:
1. 记录用户登录日志,方便分析用户是正常登录还是恶意破解用户.2. 记录系统的操作日志,方便数据恢复和定位操作人.3. 记录程序的执行时间,方便为以后优化程序提供数据支持.
2. 自定义日志打印
2.1 日志的基本格式
自定义日志打印的基本步骤:
- 得到日志对象
- 使用日志对象提供的方法, 打印自定义的日志内容
【代码示例】
2.2 得到日志对象
private static Logger log = LoggerFactory.getLogger(TestController.class);
1. Logger 对象和 LoggerFactory 都是来自与 org.slf4j 包下的.
2. TestController.class 表示当前日志的出处, 来自于哪个类, 对应上述格式中的执行类名.
2.3 使用日志对象提供的方法, 打印自定义的日志内容
当然, 我们使用 System.out.println() 也能输出日志, 但是它不能代替日志, 因为这样打印日志存在问题:
1. 这样打印的日志只有日志内容, 没有日志的其他信息, 例如: 日志的打印时间, 打印的日志是来自于哪个类.
2.不能实现不同环境下的行为控制.
2.4 日志框架的说明
【解析】日志的框架其实也类似前后端分离, 日志门面相当于前端, 日志实现相当于后端.
为什么一个简简单单的日志也分 "前后端" ?
>>最早其实是不分的, 最早可能就是调用一个 log4j 就实现了, 后来因为代码通用性等问题, log4j 爆出一些漏洞了, 亦或是 log4j 太老了, 没人更新了, 于是就换用了 logback 日志, 但是在换用 logback 的时候, 之前调用日志代码的部分都得去改, 这就是一个致命的问题.
>>我们的 JDBC 也是如此, 在最早没有 JDBC 的时候, 每一家数据库的厂商和 API 都是不一样的, 所以这样就导致了我的数据库代码没有移植性可言, 为了解决这个问题, 才引入了 JDBC , 给这些数据库厂商上面又封了一层, 对于用户来说, 你不用关注你操作的到底是谁, 你只需要遵守 JDBC 的写法, 你只需要在配置里声明你要连接的数据库即可. 这样就可以解决数据库的差异化了. (JVM -- Java 代码的一处编译到处运行亦是如此)
>> 所以此处的日志门面就是将底下的日志实现又封装了一层, 给用户去调用, 用户始终操作的是 SLF4J, 然后 SLF4J 会帮咱们去适配底层的实现. (Spring Boot 默认的日志实现是 logback)
3. 日志的持久化
为什么要将日志持久化?
如果不将日志持久化, 我们就只能在控制台上看日志, 控制台一关, 我们的日志就没了. 并且生产环境随时可能会出现问题, 不可能让运维人员 24 小时的盯着控制台去看, 这不现实.
日志的持久化有两种方式:
- 配置日志文件的文件名.
- 配置日志文件的保存路径.
3.1 配置日志文件的文件名
# 配置日志的保存名称
logging:
file:
name: mylog.log
启动程序, 访问 url, 我们的项目中就会多出一个 mylog.log 的文件, 如果你的项目中没有出现你命名的日志文件, 并且代码都是正确的情况下, 那可能就是 IDEA 缓存的问题, 你就可以打开你项目的文件夹, 找到底下的 target ,将其删除, 然后再运行一次程序, 访问 url 就能看见了.
打开 mylog 文件可以看到和在控制台看到一样的日志信息:
3.2 配置日志文件的保存路径
# 配置日志的保存路径
logging:
file:
path: D:\aa\
和上述操作一样, 最终会在指定路径下得到一个 spring.log 的文件.
3.3 持久化日志的特性
上述两种持久化日志的方式, 都会存在两种顾虑:
1. 如果程序运多次, 我的本地日志文件, 是产生覆盖的效果, 还是追加的效果? 如果是覆盖, 那岂不是也有丢失日志的风险?
2. 如果是追加日志, 那么随着程序的多次运行, 日志越来越大, 光查看日志就很不方便了, 它是怎么解决的?
首先, 持久化日志的两种方式的特性都是有日志追加效果:
对于日志越来越大不方便查看的问题, 它也是有相应的应对策略的: 当日志比较大的时候, 会自动分割成多个文件 (默认是 20 MB, 可设置系统参数)
4. 日志的级别
4.1 日志级别的作用
- 日志级别的作用就是用来筛选日志的, 默认日志级别是 info, 那么对于普通日志和调试日志就可以忽略了, 可以加快开发的效率.
- 日志级别可以控制不同情况下, 一个程序对日志信息的需求, 例如开发环境上需要很详细的信息, 可能需要看到 info 甚至 dubug 以下的信息, 而生产环境上为了安全和性能就会输出尽可能少的日志信息, 这时候就可以通过日志级别来控制了.
4.2 日志级别的分类
日志有 6 个级别, 级别从低到高如下图所示:
trace: 微量, 少许的意思, 级别最低.
debug:需要调试时候的关键信息打印.info:普通的打印信息 (默认日志级别).warn:警告,不影响使用,但需要注意的问题.error:错误信息,级别较高的错误日志信息.fatal:致命的,因为代码异常导致程序退出执行的事件.(不能在程序中调用它, 但是它存在)
这 6 个级别的设置, 越往下, 输出的日志就越少. 例如我们设置了 warn 级别, 那么我们就只能收到 warn, error, fatal 级别的日志了.
【代码示例】
@RestController
public class TestController {
private static Logger log = LoggerFactory.getLogger(TestController.class);
@RequestMapping("/log")
public String printLog() {
log.trace("i am trace.");
log.debug("i am debug.");
log.info("i am info.");
log.warn("i am warn.");
log.error("i am error.");
return "Hello Spring Boot~";
}
}
从执行结果来看, 当我们不设置日志级别的时候, 默认是 info, 于是控制台只打印了 warn, error 级别的日志. (fatal 级别的日志是不能通过方法打印出来的, 它没有这个方法, 只有在代码异常导致程序退出执行时才会有)
4.3 设置日志级别
基本格式:
logging:
level:
root: debug # 全局日志级别
此时云运行之前的代码:
设置成 debug 后, Spring 很多的系统日志就都打印出来了, 不方便查找我们所需要的日志, 这时候我们还可以更精细化的设置日志级别.
logging:
level:
root: warn # 设置系统日志级别
com:
example:
demo: debug # 具体到设置文件夹的日志级别
我们可以看到打印的日志信息少了很多, 只会打印我们所控制的日志级别范围内的日志信息了.
5.更加简单的打印日志
经过前面的讲解, 我们已经知道了打印日志需要两个步骤: 1. 得到日志对象; 2. 调用日志对象的方法, 打印日志.
>> 于是就会存在这样一件事情, 我们每个类中似乎都要去做第一步: 得到日志对象, 相对来说还是有点麻烦的, 那么我们可以使用 lombok 来做到更加简单的实现.
【具体步骤】
- 添加 lombok 依赖
- 使用 @SLF4J 注解替代第一步 - 得到日志对象.
5.1 添加 lombok 依赖
方式一:
- 下载 EditStarters 插件
- 在 pom.xml 中右键选择 Generate -> Edit Starters 然后进行选择 lombok 依赖.
方式二: (IDEA 2021 3.2+)
- 在 pom.xml 中右击选择 Generate -> Dependency, 然后输入 lombok 进行查找, 选择相关依赖.
5.2 使用 @SLF4J 注解实现更简单的打印日志
【代码示例】
@RestController
@Slf4j // @SLF4J 注解代替原始步骤的第一步
public class UserController {
@RequestMapping("/user")
public String hello() {
log.info("i am info."); // 内置的 log 对象
return "Hello Spring Boot~";
}
}
注意: 当我们使用 @SLF4J 注解时, 它会为我们提供一个 log 对象, 我们只能拿这个对象去调用打印日志的方法, 这是 lombok 的规定, 我们要遵守!!
>>> 为什么使用一个 @SLF4J 注解就能实现下面这条语句呢 ?
这就要去分析底层源码了>>>
5.3 lombok 原理分析
1. 打开项目文件夹所在路径, 找到以下路径下的 UserController.class 文件:
.\target\classes\com\example\demo
然后拖入到 IDEA 中观察代码:
可以发现生成的最终源码还是按照以前的方式来打印日志的, 所以 lombok 只是帮我们做了这些复杂的事情.
运行原理图:
本篇文章就到这里了, 谢谢观看!!