日志框架的使用
1、讲一个故事
张三在一个公司做开发、开发的时候 为了在一些关键信息的上需要打印关键信息(这个信息主要使用用于判断系统在运行的时候的一些状态) 于是张三这个家伙编写了无数个System.out.println()这个语句
等到项目上线前夕、项目经理觉得 打印的数据太多影响效率 于是让张三将所有的打印信息全部删除或者 注释-------于是张三埋头苦干了两天 终于将所有的 System.out.println语句全部删除完成
等到刚删除完成不久 项目经理觉得 这些信息还是挺有用的 、可以有效的 知道这个系统运行的状况 于是就给张三说 这些信息经过反复的考虑还是挺有用的 你还是把它加上吧
张三是一个勤劳的程序员 听到项目经理有需求、张三就在想一个问题、能不能写个框架来解决这个问题、既能打印我们的系统运行信息、又能将这些不需要打印的信息给屏蔽掉、于是张三就开始来写这个代码了-----开发了大约10天左右-------这个框架就开发出来了
xxxx.jar(log4j)实现--------------------主要就是打印当前的这个系统的运行信息的 还能屏蔽不需要打印的这些信息
于是这个张三就苦思冥想这个框架存在的问题在哪里呢? 于是张三就想到了这个鬼 不能完成异步打印 会阻塞主程序 打印的信息 在一个文件里头 会导致这个文件过大 不利用查看 需要将这些日志进行归档…
xxxx-good.jar
终于张三这个鬼开发的这个程序能满足当前项目的这个需求了
在这个时候 张三需要调换项目组-------开发一个新的项目--------张三就发现了一个问题-----这个系统同样的需要上一个系统中开发的xxxx-good.jar这个程序进行系统的运行状态的记录
于是张三就在想 能不能像 sun公司一样装逼 整个规范呢? 这个规范就是咋们上面开发的记录运行系统的这个系统规范 xxxxx(接口)(slf4j)规范
张三又想规范有了 总的有个实现、实现怎么办呢?
于是张三就针对这个规范开发了一个新的框架、来满足打印这个系统的运行信息
xxxx-best.jar(logback)实现
2、市场上的日志框架有哪些
log4j log4j2 logback JCL JUL JBoos-Logging slf4j
log4j logback slf4j 一个人开发的
slf4j :simple logging facade for java
JBoss-Logging 这个是定制开发的
JCL :Jakatra commons logging 这个应该是 Spring框架内部使用的日志框架
JUL :java util logging
上面这些框架中 有些 是接口(规范) 有些是实现
3、市场上日志框架的关系
日志规范
JCL JBoss-Logging slf4j
日志实现
log4j log4j2 logback JUL
我们在做开发的时候 一般情况下 都是选择一个规范 一个实现
slf4j -------------------- logback
3.1、slf4j整合其他的第三方日志框架
理解图
3.2、将其他的框架整合成符合slf4j规范的日志框架
3.2.1、将其他日志框架转换成logback实现的日志框架
JCL和SLF4J都是规范(简称接口),logback是slf4j的默认实现框架。但是JCL是Apache的规范框架。因为日志开发者log4j(作者),觉得Apache那种面向接口开发的日志框架真香,在真香定律的加持下。这个作者写了slf4j。如果项目中有jcl日志的话需要整么解决呢?
这时候就可以写一个中间包.jar。去继承jcl包的接口,在中间包里面重写里面的方法(这里就得说哈,子父类有相同的非静态函数的方法时,有限执行子类里面的方法)。然后在这些方法中调用slf4j中的方法。最后让logback来实现。
3.2.2、将其他日志框架转换成log4j实现的日志框架
因为这个作者写框架的时候,是写的log4j,然后slf4j,最后logback。所以log4j没有实现slf4j。logback才是slf4j的默认实现。因此需要一个中间代理层,去实现slf4j里面的方法。然后在中间代理层与log4j相对应的方法中调用log4j中的日志方法。
3.2.3、参考图
4、Logback的使用
4.1、导包
<!--这个包是为了 把JCL的日志转换成复合SLF4j标准的日志进行输出
SLF4j的实现 logback
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<!--这个是SLF4j的这个接口的规范-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--Spring对logback的支持包-->
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.4</version>
</dependency>
<!-- logback end -->
4.2、编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><!-- debug="true"设置调试模式 -->
<!--
<configuration scan="true" scanPeriod="60 seconds" dubug="false">
scan这个属性如果设置为true的话 配置文件如果是发生改变那么就会自动进行 重新加载
scanPeriod这个属性检测当前的这个文件修改的时间间隔 如果你没有给定时间单位的话那么默认单位是毫秒。只有scan设置为true的时候这个才生效
debug这个属性设置为true的时候 就要日志自己的内部信息、可以时时查看logback的运行状态
-->
<!--
appender:表示的是定义了一种日志的输出
这里就类似于 变量
变量要先定义 后使用
这里 就相当于定义了日志的输出 这个日志到底输出在哪里 由这个class类类决定
ConsoleAppender:的意思就是日志要输出到控制台
name:这个名字是可以随便定义的 你高兴就好 但是一般情况下 见名之意
-->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--表示的是输出日志的格式
%d{yyyy-MM-dd-HH:mm:ss.SSS}:时间引用
%level:日志的级别 trace < debug < info < warn < error
[%thread]:线程名字
%class:当前打印日志的类名
%line:打印日志的代码的行号(一般不要)
%msg:日志本身的信息
%n:换行
-->
<!--
pattern:这个表示的是定义的是日志的输出格式
-->
<pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS}======>%level======>[%thread]-%class:%line-------->>%msg%n</pattern>
</encoder>
</appender>
<!--
这个就表示的是要把 日志输出到文件(FileAppender)
FileAppender:这个表示的是将日志输出到文件
name:可以随便写
-->
<appender name="file" class="ch.qos.logback.core.FileAppender">
<!--
catalina.home:这个实际上是引用 这个地址实际上是引用的是 Tomcat的环境变量
${catalina.home} :实际上定位的是 Tomcat的根目录
${catalina.home}/logs/file.log:下面这段地址的意思是:日志打印到了Tomcat根目录下的 logs目录下
名字 叫做 file.log
-->
<file>${catalina.home}/logs/file.log</file>
<!--这个表示的是 下一次的日志是在上一次的基础上 进行追加 不是覆盖-->
<append>true</append>
<encoder>
<pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern>
<!--这个意思是:设置编码-->
<charset>UTF-8</charset>
</encoder>
<!--
prudent=true:表示的是日志的写入是线程安全的、但是线程安全会降低效率 一般默认设置为false
-->
<prudent>false</prudent>
</appender>
<!--
RollingFileAppender:表示的是 日志文件滚动输出 并且最大保留30天
滚动输出到日志 当达到一定条件的时候 就将日志记录到其他文件中去
-->
<appender name="timeFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
rollingPolicy滚动的策略
TimeBasedRollingPolicy:最常用的一个、根据时间进行滚动 当达到一定的时间的时候、就会自动开辟一个新的日志文件
FixedWindowRollingPolicy:根据固定窗口的算法重命名文件的滚动策略
TriggeringPolicy:根据当前活动文件的大小来来确定是否滚动
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--表达式中最小的滚动单位是天、所以每天生成一个日志、日志的名字就是下面这个名字-->
<!--
log/xxxx/xxxx.log
如果直接写的文件的名字 这个路径默认是定位到 tomcat/bin/
Tomcat/bin/logfile2020-7-8.log
-->
<fileNamePattern>log/logFile%d{yyyy-MM-dd}.log</fileNamePattern>
<!--表示的是生成的日志 保留30天 30天以后自动销毁-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--
日志的滚动的输出
这个Appender的主要作用就是在生成日志的时候 如果单个的日志文件 达到了5M 那么这个时候就会创建新的日志进行继续生成
-->
<appender name="fixedFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
Tomcat/bin/log/fixedFile.log :文件是放到这个路径下的
-->
<file>log/fixedFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<!--生成日志文件的文件名的格式-->
<fileNamePattern>log/fixedFile%i.log.zip</fileNamePattern>
<!--至少生成一个日志文件-->
<minIndex>1</minIndex>
<!--最大只是生成三个日志文件 如果我们的内容超过了15M 那么就会实现覆盖前面的这个日志文件-->
<maxIndex>3</maxIndex>
</rollingPolicy>
<!--表示的是添加了触发策略-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<!--单个文件的最大的值 是5M-->
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<!--生成日志的格式和编码-->
<encoder>
<pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--
这个表示的是定义了一种日志输出格式 并和过滤器进行整合
-->
<appender name="filter" class="ch.qos.logback.core.FileAppender">
<file>log/filter.log</file>
<append>true</append>
<!--
LevelFilter:的意思是添加了一个日志级别的过滤器
如果日志的级别等于配置的级别。那么则执行onMatch里面的配置
否则执行 onMismatch中的内容
-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!--
ACCEPT:当前的日志会立即被执行不经过其他的过滤器了
DENY:日志立即被抛弃、也不再经过其他的过滤器了
NEUTRAL:下一个过滤器将继续执行、如果是最后一个过滤器的话那么就会被执行
-->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!--临界值过滤器:如果你输出的日志级别 是低于下面定义的这个级别的话那么 降火被过滤掉-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n
</pattern>
<charset>UTF-8</charset>
</encoder>
<prudent>false</prudent>
</appender>
<!--
logger:定义的是输出的对象
name:一般写 包名 level:就是咋们的日志的级别
addtivity:true、日志将会继续的向他爹进行传递
表示的是给整个项目的某一个包 单独定义日志的输出
比如:
我要给 com.qf.springboot.controller 这个包 定义输出级别是 info 低于info的都不输出
并且我还要定义这些日志输出到哪些地方
file :就表示的是输出到文件
stdout:这个就表示的是还要输出到控制台
局部的
-->
<!-- <logger name="com.qf.meeting.controller" level="error" addtivity="false">
<appender-ref ref="file" />
</logger>-->
<!--全局设置了一个日志级别 如果只是在这里引用的话 其余的是不生效的 -->
<!--简单的说 就是全局所有的日志都要打印到控制台-->
<!--
给整个项目设置一个全局的日志的打印
在整个项目中 日志级别都是 info 意思是如果低于这个级别那么这个日志就将不打印
全局的
trace < debug < info < warn < error
-->
<root level="debug">
<appender-ref ref="file"></appender-ref>
<appender-ref ref="stdout" />
<appender-ref ref="timeFile" />
<appender-ref ref="fixedFile" />
<appender-ref ref="filter" />
</root>
</configuration>
4.3、使用日志框架
private Logger logger= LoggerFactory.getLogger(UserController.class);
logger.trace("我好的");
logger.debug("我好的");
logger.info("我好的");
logger.warn("我好的");
logger.error("我好的");
spirng-boot日志相关配置
编写 logback-spring.xml配置文件
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- 变量 yudao.info.base-package,基础业务包 -->
<!-- <springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/>-->
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
<property name="PATTERN_DEFAULT"
value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread ) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- 控制台 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN_DEFAULT}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件 Appender -->
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${PATTERN_DEFAULT}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志文件名 -->
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 滚动后的日志文件名 -->
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
</fileNamePattern>
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<!-- 日志文件,到达多少容量,进行滚动 -->
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
<!-- 日志文件的总大小,0 表示不限制 -->
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<!-- 日志文件的保留天数 -->
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
<queueSize>256</queueSize>
<appender-ref ref="FILE"/>
</appender>
<!-- 本地环境 -->
<springProfile name="local">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>
<!-- 其它环境 -->
<springProfile name="dev,test,stage,prod,default">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
<!-- <appender-ref ref="ASYNC"/>-->
</root>
</springProfile>
</configuration>
LOG_FILE
是在yml中配置的
# yml 日志配置级别优先 logback-spring.xml配置文件
logging:
file:
name: logs/${spring.application.name}.log # 日志文件名,全路径
level:
com.github.pagehelper: DEBUG
# org.mybatis: DEBUG
# org.mybatis.spring.SqlSessionUtils: DEBUG
# java.sql: DEBUG
# org.apache.ibatis: DEBUG