1.概念
JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j....等等很多,一般我们使用SLF4j作为日志的抽象层,Logback或者Log4j2作为实现类,log4j自身由于效率问题被淘汰,Logback与log4j与SLF4j是同一个人写的,springboot默认使用SLF4j+Logback
2.SLF4j
官网 https://www.slf4j.org/
依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
基本使用
@Test
public void testLog4J(){
Logger logger=LoggerFactory.getLogger(MvcDemoApplicationTests.class);
logger.warn("警告");//保存日志级别warn,还有info,error,fatal,debug,与level级别一致
}
3. SLF4j统一日志的原理
即使是别的框架也统一使用slf4j进行输出
原理:先要排除别的日志的依赖,然后使用相应的SLF4j的jar替换掉原来的jar,然后倒入相应的实现或者适配包以及实现,原理图如下

相应的SLF4j的jar有下图可知是采用偷梁换柱的方式修改了相应的日志类

排除日志包的依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency>
4. spring与springboot的日志记录
SpringBoot能自动适配所有的日志(原因是假如了相应的适配包),底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可;
logback-spring.xml:添加-spring后,日志框架就不直接加载日志的配置项,而是由SpringBoot解析加载,可以使用SpringBoot的高级Profile功能,假如没有-spring,那么由logback会直接加载
spring使用自动适配所有的日志时需要的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐logging</artifactId> </dependency>
添加上述依赖后的依赖关系图

springboot的Logback文件的配置(spring-boot-1.5.17.RELEASE.jar下)

假如需要对日志配置文件进行修改见Logback
5. Logback
Logback与Log4J对比
相对Logback 执行更快,更充分的测试,原生实现了 SLF4J API(有上述可知Log4J 还需要有一个中间转换层),内容更丰富的文档,支持 XML 或者 Groovy 方式配置,配置文件自动热加载,从 IO 错误中优雅恢复,自动删除日志归档,自动压缩日志成为归档文件,支持 Prudent 模式,使多个 JVM 进程能记录同一个日志文件,支持配置文件中加入条件判断来适应不同的环境,更强大的过滤器,支持 SiftingAppender(可筛选 Appender),异常栈信息带有包信息。
Logback的日志级别
TRACE < DEBUG < INFO < WARN < ERROR
Logback配置说明
<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当该属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 scanPeriod:设置监测配置文件是否修改的时间间隔,如果没有给出时间单位,默认单位是毫秒,默认的时间间隔为1分钟,当scan为true时,此属性生效 debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- 定义日志的根目录 --> <property name="LOG_HOME" value="/app/log" /> <!-- 定义日志文件名称 --> <property name="appName" value="SkyTest"></property>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出, ch.qos.logback.core.FileAppender 输出到文件 ch.qos.logback.core.rolling.RollingFileAppender回滚 -->
<!----------------------------------------------------------------------------------> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--编码--> <Encoding>UTF-8</Encoding> <!-- 日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </layout> </appender> <!----------------------------------------------------------------------------------> <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录WARN级别的日志 ,不常用-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<Encoding>UTF-8</Encoding>
<!-- 指定日志文件的名称,<property> 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过<property>定义的值会被插入到logger上下文中。 定义变量后,可以使“${}”来使用变量。 --> <file>${LOG_HOME}/${appName}.log</file>
<!-- rollingPolicy回滚策略: TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动 --> <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern> <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动, 且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是, 那些为了归档而创建的目录也会被删除。 --> <MaxHistory>365</MaxHistory>
<!-- 当日志文件超过maxFileSize指定的大小时,根据上面提到的%i进行日志文件滚动,注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,
必须配置timeBasedFileNamingAndTriggeringPolicy --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy>
<!-- 日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern> </layout>
</appender>
<!----------------------------------------------------------------------------------> <!-- logger主要用于存放日志对象,也可以定义日志类型、级别 name:表示匹配的logger类型前缀,也就是包的前半部分 level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR additivity:是否向上级loger传递打印信息。默认是true。<loger>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。 --> <!-- hibernate logger --> <logger name="org.hibernate" level="error" />
<!-- Spring framework logger --> <logger name="org.springframework" level="error" additivity="false"></logger> <logger name="com.creditease" level="info" additivity="true"> <appender-ref ref="appLogAppender" /> </logger> <!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,有匹配的logger则为logger,没有则为默认的root --> <root level="info"> <appender-ref ref="stdout" /><!--stdouty与appender的name保持一致--> <appender-ref ref="appLogAppender" /> </root> <!-- show parameters for hibernate sql 专为 Hibernate 定制 --> <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" /> <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" /> <logger name="org.hibernate.SQL" level="DEBUG" /> <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" /> <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" /> <!--日志异步到数据库 --> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <!--日志异步到数据库 --> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <!--连接池 --> <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource"> <driverClass>com.mysql.jdbc.Driver</driverClass> <url>jdbc:mysql://127.0.0.1:3306/databaseName</url> <user>root</user> <password>root</password> </dataSource> </connectionSource> </appender> </configuration>
<!-- <encoder>:对日志进行格式化。//都有 <target>:字符串 System.out 或者 System.err ,默认 System.out //控制台 <file>:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 //文件,回滚日志 <append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。//文件,回滚日志 <prudent>:如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。//文件,回滚日志 <rollingPolicy>:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 //回滚日志 <triggeringPolicy >: 告知 RollingFileAppender 合适激活滚动 //回滚日志 -->
logback-spring.xml:添加-spring后,日志框架就不直接加载日志的配置项,而是由SpringBoot解析加载,可以使用SpringBoot的高级Profile功能,假如没有-spring,那么由logback会直接加载
6.log4j的配置(LOG4J.xml放在类路径下会自动加载)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<!--STDOUT表示输出 org.apache.log4j.ConsoleAppender 表示输出的类,这里表示输出到控制台-->
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<!--表达式输出的字符集-->
<param name="Encoding" value="UTF-8"/>
<!--org.apache.log4j.PatternLayout 对象和与之相关的格式化的日志记录信息转换模式,这里表示表达式-->
<layout class="org.apache.log4j.PatternLayout">
<!--ConversionPattern格式 -->
<param name="ConversionPattern" value="%-5p %d{yyyy/MM/dd HH:mm:ss,SSS} %m %c (%F:%L)
"/>
</layout>
</appender>
<!--org.apache.log4j.ConsoleAppender(控制台)-->
<!--org.apache.log4j.FileAppender(文件)-->
<!--org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)-->
<!--org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)-->
<!--org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)-->
<appender name="file" class="org.apache.log4j.FileAppender">
<!--表达式输出的字符集-->
<param name="Encoding" value="UTF-8"/>
<!--Threshold=debug:指定日志消息的输出最低层次。-->
<param name="Threshold" value="debug"/>
<!--append:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容-->
<param name="append" value="true"/>
<!--File指定消息输出到mylog.txt文件。-->
<param name="File" value="D:/logs/log4j.log"/>
<!--ImmediateFlush:默认值是true,意谓着所有的消息都会被立即输出。-->
<param name="ImmediateFlush" value="true"/>
<!--org.apache.log4j.PatternLayout 对象和与之相关的格式化的日志记录信息转换模式,这里表示表达式-->
<layout class="org.apache.log4j.PatternLayout">
<!--ConversionPattern格式
%c: 输出日志信息所属的类目,通常就是所在类的全名
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy/MM/dd HH:mm:ss,SSS},
输出类似:2018/10/06 14:16:41,429
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
"-"号指定左对齐。
%m: 输出代码中指定的消息,产生的日志具体信息
换行
%r: 输出自应用启动到输出该log信息耗费的毫秒数
-->
<param name="ConversionPattern" value="%-5p %d{yyyy/MM/dd HH:mm:ss,SSS} %m %c (%F:%L)
"/>
</layout>
</appender>
<!-- <appender name="rolling" class="org.apache.log4j.FileAppender">
其他参数
在name="file"的基础上增加了如下两个参数
MaxFileSize=200KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
MaxBackupIndex=5:指定可以产生的滚动文件的最大数。
</appender>-->
<!--
properties与xml的配置类似,只是在properties中用的是点,而在xml中是节点
# 应用于socket
log4j.appender.socket=org.apache.log4j.RollingFileAppender
log4j.appender.socket.RemoteHost=localhost
log4j.appender.socket.Port=5001
log4j.appender.socket.LocationInfo=true
# Set up for Log Factor 5
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) –> [%t] %l: %m %x %n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.Threshold=FATAL
log4j.appender.mail.BufferSize=10
log4j.appender.mail.From = xxx@mail.com
log4j.appender.mail.SMTPHost=mail.com
log4j.appender.mail.Subject=Log4J Message
log4j.appender.mail.To= xxx@mail.com
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) –> [%t] %l: %m %x %n
# 应用于数据库
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test
log4j.appender.database.driver=com.mysql.jdbc.Driver
log4j.appender.database.user=root
log4j.appender.database.password=
log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) –> [%t] %l: %m %x %n')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) –> [%t] %l: %m %x %n
-->
<!--指定包名下的输出级别-->
<logger name="cn.mybaties.dao">
<level value="debug"/>
</logger>
<!--STDOUT的所有的输出级别 fatal(致命错误) > error (错误) > warn (警告) > info(普通信
息) > debug(调试信息) 如下为相应的name添加级别-->
<root>
<level value="warn"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="file"/>
</root>
</log4j:configuration>