log4j/Logback/SLF4j
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) \n"/> </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: 输出代码中指定的消息,产生的日志具体信息 \n 换行 %r: 输出自应用启动到输出该log信息耗费的毫秒数 --> <param name="ConversionPattern" value="%-5p %d{yyyy/MM/dd HH:mm:ss,SSS} %m %c (%F:%L) \n"/> </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>