一、什么是日志
- 日志:就是介绍一个过程和经历的详细记录。
- 项目日志:就是项目开发过程的详细记录,一般由项目经理记录。
- 代码里的日志:就是程序员记录某个开发过程的详细情况,这是项目里每个程序员需要做的工作。
- 日志和异常处理结合得当的话,会给项目维护带来非常大的价值。
二、日志的重要性
- 日志,通常不会在需求阶段作为一个功能单独提出来,也不会在产品方案中看到它的细节。但是,这丝毫不影响它在任何一个系统中的重
要地位。 - 为了保证服务的高可用,发现问题一定要及时,解决问题一定要迅速,所以生产环境一旦出现问题,预警系统就会通过邮件、短信甚至
电话的方式实施多维轰炸模式,确保相关负责人不错过每一个可能的 bug。预警系统判断疑似 bug 大部分源于日志。当该错误日志达到一
定次数出现的时候,就会触发报警。
三、日志在项目中的作用
主要用于记录程序运行的情况,以便于程序在部署之后的排错调试等,也有利于将这些信息进行持久化(如果不将日志信息保存到文件或
数据库,则信息便会丢失)。
- 查看程序当前运行状态
- 查看程序历史运行轨迹
- 排查系统问题
- 优化系统性能
- 安全审计的基石
四、Java 日志使用的困惑
大多数的程序员都能认识到日志在项目中的重要性,可是对日志记录具体要怎么做、做到什么程度、日志记录用什么工具,会有很多困惑。
- 工具困惑:作为 Java 程序员,幸运的是,Java 拥有功能和性能都非常强大的日志库;不幸的是,日志库不止一个,JUL(
java.util.logging), JCL( Jakarta Commons Logging,Spring 框架默认使用的),Log4j, Log4j2, Logback、 SLF4j、 jboss-logging
(Hibernate 框架默认使用的) 等,这么多的日志工具到底使用什么感到困惑。 - 使用困惑:有的程序员即使知道写 Java 程序用什么日志工具,可能对日志记录具体应该怎么写,写什么东西,什么情况下要写,这些仁
者见仁智者见智的东西也会产生困惑。
五、Java 日志演化历史
- 最先出现的是 Apache 开源社区的 Log4j,这个日志确实是应用最广泛的日志工具,成为了 Java 日志的事实上的标准。
- 然而,当时 Java 的开发主体 Sun 公司认为自己才是正统,在 Jdk1.4 中增加了 JUL 日志实现,企图对抗 Log4j,但是却造成了 Java 目
前开发者记录日志局面的混乱,迄今为止仍饱受诟病。 - 想象下你的项目应用使用 Log4j,然后使用了一个第三方库,而第三方库使用了 JUL,那么,你的应用就得同时使用 Log4j 和 JUL 两个
日志工具了,然后又有需要使用另外一个第三方库,但是这个第三方库使用了 Log4j 和 JUL 之外的simplelog。这个时候你的应用里各种log
工具满天飞,这势必会使你的程序员感到崩溃。因为这些日志工具互相没有关联,替换和统一日志工具也就变成了比较 棘手的一件事情。 - 为了搞定这个日常开发中比较棘手的问题,Apache 提供了一个日志框架作为日志的抽象,名字为 JCL。JCL 对各种日志接口进行抽象,
抽象出一个接口层,对每个日志实现都进行适配,这样这些提供给别人的库都直接使用抽象层即可,确实出色地完成了兼容主流的日志实
现(Log4j、JUL、simplelog 等),较好的解决了上述问题,基本一统江湖,就连顶顶大名的 Spring 也是依赖了 JCL。 - 但是美好的日子并不长,作为元老级日志 Log4j 的作者 (Ceki Gülcü),他觉得JCL 不够优秀,所以他再度出山,搞出了一套更优雅的日
志框架 SLF4J(这个也是抽象层),即简单日志门面(Simple Logging Facade for Java),并为 SLF4J实现了一个亲儿子——logback,
确实更加优雅了。 - 最后,Ceki Gülcü 觉得还是得照顾下自己的 “大儿子”——Log4j,又把 Log4j进行了改造,就是所谓的 Log4j2,同时支持 JCL 以及
SLF4J。 - SLF4J 的出现,又使 Java 日志体系变得混乱起来。
- 下面是一张目前 Java 日志体系的示意图:
- 日志库 Log4j,JUL,logback 是互相不兼容的,没有共同的 Interface,通过适配器模式,抽象出来一个共同的接口,然后根据具体的日
志框架来实现日志。 - java common logging 和 SLF4J 都是日志的接口,供用户使用,而没有提供实现,Log4j,JUL,logback 等等才是日志的真正实现。
- 通常情况下,日志是由一个抽象层+实现层的组合来搭建的。
- Spring Boot 的日志框架:默认情况下,Spring Boot 会用 Logback 来记录日 志,并用 INFO 级别输出到控制台。
六、Logback 的介绍
- Logback 是 log4j 框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持 SLF4J。
- 官方网站: http://logback.qos.ch。
- 它当前分为下面下个模块:
- logback-core:其它两个模块的基础模块
- logback-classic:它是 log4j 的一个改良版本,同时它完整实现了 slf4j API 使你可以很方便地更换成其它日志系统如 log4j 或 JDK1.4 Logging
- logback-access:与 Servlet 容器集成提供通过 Http 来访问日志的功能
七、Spring Boot 中整合 Logback
- Spring Boot 为我们提供了很多默认的日志配置,只要将 spring-boot-starter-logging 作为依赖加入到当前应用的 classpath,则“开 箱即用”。
- 添加日志依赖(默认已经添加了,不需要添加)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
- 默认的输出格式
日志的输出项目
日期和时间:毫秒精度且易于排序。
日志级别:ERROR,WARN,INFO,DEBUG,或 TRACE。
进程标识。
一个—分离器来区分实际日志消息的开始。
线程名称:括在方括号中(可能会被截断以用于控制台输出)。
记录器名称:这通常是源类名称(通常缩写)。
日志消息。 - 彩色编码输出
-
如果您的终端支持 ANSI,则使用颜色输出来提高可读性。
-
下表描述了日志级别到颜色的映射
-
支持的颜色:blue、cyan、faint、green、magenta、red、yellow
- 日志级别
- 日志级别从低到高分为 TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为 WARN,则低于 WARN 的信息都不会输出。
- 在 Spring 中设置日志级别,方法是使用 logging.level.=。
- 文件输出
-
默认情况下,Spring Boot 只记录到控制台,不写入日志文件。如果你想写入日志文件,你需要设置 logging.file.name 或 logging.file.path 属性
-
属性设置
logging.file:设置日志文件,可以是绝对路径,也可以是相对路径。如:
logging.file=my.log。
logging.path:设置目录,会在该目录下创建 spring.log 文件,并写入日志内容,如:logging.path=D:/var/log。
注:二者不能同时使用,如若同时使用,则只有 logging.file 生效
-
日志文件在达到 10 MB 时会旋转,并且与控制台输出一样,默认情况下会 记录 ERROR-level、WARN-level 和 INFO-level 消息。可以
使用该 logging.file.max-size 属性更改大小限制。除非 logging.file.max-history 已设置该属性,否则默认情况下会保留最近 7 天的轮换日志
文件。日志档案 的总大小可以使用 logging.file.total-size-cap. 当日志档案的总大小超过 该阈值时,将删除备份。要在应用程序启动时强制
清除日志存档,请使用该 logging.file.clean-history-on-start 属性。
八、Logback 的定制化配置
logback彩色字符编码说明
支持的颜色字符编码
%black 黑色
%red 红色
%green 绿色
%yellow 黄色
%blue 蓝色
%magenta 洋红色
%cyan 青色
%white 白色
%gray 灰色
以下为对应加粗的颜色代码
%boldRed
%boldGreen
%boldYellow
%boldBlue
%boldMagenta
%boldCyan
%boldWhite
%highlight 高亮色
- 可以看到上述方式配置简单,但是能实现的功能也非常有限,如果想要更复杂的需求,就需要下面的定制化配置了。
- 由于日志服务一般都在 ApplicationContext 创建前就初始化了,它并不是通过Spring 的配置文件控制。因此通过系统属性和传统的
Spring Boot 外部配置文 件依然可以很好的支持日志控制和管理。
- Spring Boot 官方推荐优先使用带有 xx-spring.xml 的文件名作为你的日志配置(比如:logback-spring.xml),命名为 logback-
spring.xml 的日志配置文件, Spring Boot 可以为它添加一些特有的配置项。 - 创建 logback-spring.xml 文件,放在 src/main/resources 下面即可。
- 创建示例
<?xml version="1.0" encoding="UTF-8"?>
<configuration >
<!--contextName说明:每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用设置成其他名字,
用于区分不同应用程序的记录。一旦设置,不能修改,可以通过%contextName来打印日志上下文名称。-->
<contextName>logback-spring</contextName>
<!-- name的值是变量的名称,value的值是变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="log"/>
<!-- 彩色日志依赖的渲染类 -->
<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}}"/>
<!--输出日志到控制台-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<!--ThresholdFilter:临界值过滤器,打印大于等于level标签设置的级别,小的舍弃-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<!--日志输出格式-->
<layout>
<!--指定日志格式-->
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</layout>
</appender>
<!--输出日志到文件-->
<appender name="fileLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--LevelFilter:只打印level标签设置的日志级别-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<!--匹配到就允许-->
<onMatch>ACCEPT</onMatch>
<!--没有匹配到就禁止-->
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>
%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
<!--指定文件的输出位置-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>d:/${log.path}/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--日志文档保留天数-->
<maxHistory>30</maxHistory>
<!--配置日志文件不能超过100M,若超过100M,日志文件会以索引0开始,命名日志文件-->
<maxFileSize>100MB</maxFileSize>
<!--总大小-->
<totalSizeCap>2GB</totalSizeCap>
<!--appender启动的时候,归档文件将会被删除。默认的值为 false-->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileLog"/>
</root>
<!--有logger的配置,不指定级别,不指定appender-->
<!--将org.springframework.web包下的所有类的日志的打印-->
<logger name="org.springframework.web" level="debug"/>
<!--单独对某个类进行设置-->
<logger name="cn.kgc.controller.ConfigurationPropertiesController" level="debug">
<appender-ref ref="consoleLog"/>
</logger>
</configuration>
九、程序中输出自己的日志
- 方式一:手动创建 Logger 对象
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
private Logger logger = LoggerFactory.getLogger(HelloController.class);
@GetMapping("/")
public void hello() {
logger.info("读取配置信息");
}
}
- 方式二:使用@slf4j 注解
- 添加依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- 安装插件
- 实现案例
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class TestController {
@GetMapping("/")
public String index(){
log.info("记录日志使用 lombok 插件提供注解@Slf4j");
return "";
}
}