springboot日志集成:
日志实现: logback、log4j、log4j2、 JUL(java.util.longging)
日志抽象层:JCL(jakarta Commons Logging) 、 SLF4J(Simple Logging Facade for java) 、jboss-logging
也就是 抽象层选一个,实现类选一个就成了一个日志框架。
JCL(jakarta Commons Logging): 最后更新 2014年,过时。
jboss-logging:应用场景太少。
SLF4J、Log4J、Logback:出自同一个人编写,就在这里面选了。
Log4j没有Logback 的功能多。
Log4J2:apche小组重新研发的 ,有兼容性问题。
所以我们选择:
日志门面(抽象层):SLF4J
日志实现:LogBack
调用方式:
官方说明:http://www.slf4j.org/manual.html
代码调用示例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
SLF4J+Logback原理:
application(应用) 调用SLF4J(抽象层),再调用LogBack实现。
SLF4J+Log4J原理:
application(应用) 调用SLF4J(抽象层),不能直接调用Log4j实现类(原因:Log4j最初根本没想到有slf4j抽象层,所以不兼容),需要加入适配器Adaptation layer,
这个适配器相当于SLF4J调用了他的方法,然后更具他的方法去调用log4j的实现类。
**SLF4J+JUL(java.Uilt.logging)原理: **
application(应用) 调用SLF4J(抽象层),不能直接调用JUL实现类(原因:JUL是临时加入抢占市场的,并没有考虑兼容slf4j抽象层,所以不兼容),和调用log4j一样,需要加入适配器Adaptation layer,适配器再调用JUL的实现类。
SLF4J本身就有简单的实现类:
包名:slf4j-api.jar
加入slf4j-simple.jar: 只有一些简单的实现类,可以直接使用。
加入slf4j-nop.jar: 没有什么实现,但是也可以使用,直接输出到空的文件。
每一个日志的实现框架都有自己的配置文件,使用哪个日志的实现类就配置哪个实现类的配置文件。
比如:我们用了slf4j,实现类是logback,所以我们要配置log back的文件。
遗留问题:日志统一
比如: 系统太大了,使用了多个框架,spring自带的Commons logging、hibernate的jboss-logging、mybatis、XXX 等一系列日志。
太杂,而我们现在想用slf4j+logback来作为统一日志。
方法:
看官方说明(http://www.slf4j.org/legacy.html),给出了张图:
这个图第一部分的意思就是:
原理:
先去掉系统自带的框架Commons-logging,使用中间包(作用:替换原有的日志jar包)jcl-over-slf4j.jar来替换Commons-logging,jcl-over-slf4j再调用SLF4J,SLF4J再调用Logback实现类。
用idea工具在pom.xml右击鼠标,选择Diagrams–>ShowDependencies…可以清楚的看到依赖结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOo8REoE-1571111198385)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\1571039872501.png)]
springboot与日志的底层关系:
springboot-logging官方手册说明:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html
导入maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
底层依赖关系图:
spring boot 底层也用的slf4j+logback的方式进行日志记录。
spring boot 把底层的日志都替换成了slf4j
中间包:比如jcl-over-slf4j.jar 里面有org.Commons-logging的包,但它的实现却是slf4j的初始化,也就是调用的还是slf4j。
如果spring boot要引入其他框架比如说Log4J,那么一定要先排除原有的默认日志依赖logback,
spring框架用的是Commons-logging;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QA3PMiLg-1571111198387)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\1571041405599.png)]
2.0版本以前的springboot底层也是这样做的,但是在spring boot 2.0就没有排除了,应该说是没有依赖Commons-logging了能找到的也就只有log4j-to-slf4j、 jul-to-slf4以及logback-classic的jar.
但是统一方法还是一样的,如果要更换其他日志,还是得先排除。在添加自己要集成得日志jar.
springboot默认日志配置:
//logger 为日志记录器
private static final Logger log=LoggerFactory.getLogger(Test.class);
用法:
//trace 追踪
log.trace("这是一个trace日志记录");
log.debug("这是一个Debug的测试日志记录");
log.info("这是一个info日志记录");
log.warn("这是一个warn日志记录");
log.error("这是一个error日志记录");
日志级别:
由低到高分别为:trace–>debug–>info–>warn–>error
作用:可以调整日志级别的输出,比如说项目不想看到Debug和info这一类日志信息,那么我们就写成warn,那么就只会输出warn以及warn以上级别的信息。
spring boot 默认日志输出级别为Info,也就是控制台只输出info及info以上的信息。
指定级别:
logging:
level.logdemo: //logdemo 为项目的包名,该包下的所有日志都输出trace级别及以上级别的信息,没有指定的包输出级别的为springboot默认级别Info
root: trace
Logging properties:
logging.file |
logging.path |
Example | 描述(Description) |
---|---|---|---|
(没有) | (没有) | 仅控制台记录。 | |
特定档案 | (没有) | my.log |
写入指定的日志文件。名称可以是确切位置,也可以是相对于当前目录的位置。 |
(没有) | 具体目录 | /var/log |
写入spring.log 指定的目录。名称可以是确切位置,也可以是相对于当前目录的位置 |
日志文件达到10 MB时会旋转,并且与控制台输出一样,默认情况下会记录ERROR
-level,WARN
-level和INFO
-level消息。可以使用该logging.file.max-size
属性更改大小限制。除非logging.file.max-history
已设置属性,否则以前旋转的文件将无限期存档。
指定日志文件存放路径:
logging.file:
logging:
level.logdemo:
root: trace
file: E:\\IDEA_project\\logdemo\\logs\\info.log
logging.path:
logging:
level.logdemo:
root: trace
path:/spring/log
//这里"/"是Linux下的绝对路径, 表示在当前磁盘路径下创建spring文件夹 ,在spring文件夹下创建log文件夹,默认文件的是spring.log
logging.file和logging.path:二者不能同时使用,如若同时使用,则只有logging.file生效
logging:
level.logdemo:
root: INFO
# org:
# springframework:
# hibernate: ERROR
# web: DEBUG
#logging.file和logging.path二者不能同时使用,如若同时使用,则只有logging.file生效
file: E:\\IDEA_project\\logdemo\\logs\\info.log
pattern:
#在控制台输出的格式
console:
#指定文件中的输出格式:
file:
日志输出格式:
%d: 日期时间
%thread或%t: 线程名
%-5level或%5p: 级别从左显示5个字符宽
%logger{50}: logger名字最长50个字符,否在按照句点分割
%msg : 日志消息
%n: 换行
自定义日志配置:
给类路径下放上每个日志框架自己的配置文件,springboot就不会启动默认的配置了。
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
logback.xml: 直接就被日志框架识别
logback-spring.xml: 日志框架不自动识别并加载,spring boot2.0好像可以自动识别并加载,
注意:由于xml文件配置的加载要优先于application.yml,logback-spring.xml会找不到配置的文件存放地址,所以不能在yml里面配置日志存放的位置。
Logback扩展:
在使用logback-spring.xml
作为配置文件,可以使用log back的高级功能。
由于标准logback.xml
配置文件加载太早,因此不能在其中使用扩展名。您需要使用logback-spring.xml
或定义一个logging.config
属性。
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
使用logback-spring.xml作为配置文件则我们可以使用高级功能:springProfile 这个配置
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
<!-当“staging(临时或者测试环境)”配置文件处于活动状态时要启用的配置->
</springProfile>
<springProfile name = " dev | staging" >
<!-要在激活“dev(开发环境)”或“staging”配置文件时启用配置->
</ springProfile>
<springProfile name = "!production" >
<!-当“poduction(生产环境)”配置文件未激活时要启用的配置->
</ springProfile>
当然先要设置开发环境:
server:
port: 8080
servlet:
context-path: /logdemo
#logging:
# pattern:
# level.com: Info
# console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){blue} %clr(%-5level) %clr([%t]){magenta} %clr(----){faint} %clr(%-40.40logger{39}){cyan} %clr(:){blue} %m%n"
# file: "%d{yyyy-MM-dd HH:mm:ss.SSS}{faint} %-5level [%t] ---- %-40.40logger{39} : %m%n"
# file: E:\\IDEA_project\\logdemo\\logs\\info.log
spring:
profiles.:
active: dev #设置为开发环境dev,或者 是生产环境production
个人自定义完整配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="E:\\IDEA_project\\logdemo\\logs\\" />
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<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" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){blue} %clr(%-5level) %clr([%t]){magenta} %clr(----){faint} %clr(%-40.40logger{39}){cyan} %clr(:){blue} %m%n</pattern>
</encoder>
</appender>
<appender name="stdout" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}Info-%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}{faint} %-5level [%t] ---- %-40.40logger{39} : %m%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
</rollingPolicy>
</appender>-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="stdout" />
<!--<appender-ref ref="FILE" />-->
</root>
</configuration>
分级日志文件存放配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="E:\\IDEA_project\\logdemo\\logs\\" />
<springProfile name = "!dev">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%t] ---- %-40.40logger{39}: %m%n</pattern>
</encoder>
</appender>
</springProfile>
<springProfile name = "dev" >
<!--要在激活“dev(开发环境)”或“staging”配置文件时启用配置-->
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<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" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){blue} %clr(%-5level) %clr([%t]){magenta} %clr(----){faint} %clr(%-40.40logger{39}){cyan} %clr(:){blue} %m%n</pattern>
</encoder>
</appender>
</springProfile>
<!-- Console 输出设置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 不用彩色控制台输出 -->
<!-- 控制台输出 -->
<!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">-->
<!--<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
<!--<!–格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符–>-->
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>-->
<!--</encoder>-->
<!--</appender>-->
<!-- 按照每天生成日志文件 -->
<!--info-->
<appender name="DAYINFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/Info-%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--error appender-->
<appender name="DAYERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/Error-%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<!--这里设置日志级别为error-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--warning appender-->
<appender name="DAYWARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/Warning-%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<!--这里设置日志级别为error-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="DAYINFO" />
<appender-ref ref="DAYERROR" />
<appender-ref ref="DAYWARN" />
</root>
</configuration>