(二)、logback + slf4j
Appender和Layout和log4j原理相同:
-
logback实现了slf4j的一种日志框架,log4j2也实现了slf4j
- 代码中获取logger方法:
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Log4jTest.class);
logger.debug("ABC:{}{}", abc, efg);
- logback.xml
-
- logback.xml 继承了log4j.properties功能结构,只是以xml方式实现。
- 日志级别以及logger的调用关系也继承了log4j的原则
- additivity属性可以去掉父子继承关系
<?xmlversion="1.0"encoding="UTF-8"?>
<!--debug:true 日志debug调试 -->
<configurationscan="true"scanPeriod="6
seconds"debug="true">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
<propertyname="LOG_HOME"value="d:/log"/>
<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志输出编码 -->
<filterclass="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>message.contains("SQL")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss}
[%thread] %-5level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<appendername="DAILY_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 输出文件log路径及名称 -->
<file>${LOG_HOME}/myApp_daily.log</file>
<!-- 策略(按大小和时间) -->
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 超过大小或策略的文件命名方式 -->
<fileNamePattern>${LOG_HOME}/myApp_daily.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<!-- 文件最多数 -->
<maxHistory>3</maxHistory>
<!-- 文件最大值 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<!-- %d:日期格式;%thread:线程名;%-5level:级别从左显示5个字符宽度;%logger{50}:输出logger长度;%msg:日志消息;%n:换行符 -->
<pattern>%d{yyyy-MM HH:mm:ss.SSS}
[%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appendername="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/myApp_file.log</file>
<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${LOG_HOME}/myApp_file.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<layoutclass="ch.qos.logback.classic.PatternLayout">
<!-- %d:日期格式;%thread:线程名;%-5level:级别从左显示5个字符宽度;%logger{50}:输出logger长度;%msg:日志消息;%n:换行符 -->
<pattern>%d{yyyy-MM HH:mm:ss.SSS}
[%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>50 MB</maxFileSize>
</triggeringPolicy>
</appender>
<!-- 按照登录用户的userIdsheng -->
<appendername="SIFT"class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<Key>userId</Key>
<DefaultValue>unknown</DefaultValue>
</discriminator>
<sift>
<appendername="FILE-${userId}"class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>d:/log/${userId}/%d{yyyyMMdd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd
HH:mm:ss.SSS} [%thread] %-5level %logger{15}- %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
<appendername="FILE2"class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/myApp_file2.log</file>
<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${LOG_HOME}/myApp_file2.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<layoutclass="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM HH:mm:ss.SSS}
[%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>50 MB</maxFileSize>
</triggeringPolicy>
</appender>
<appendername="QUEUE"class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>10</discardingThreshold>
<queueSize>10000</queueSize>
<neverBlock>false</neverBlock>
<appender-refref="FILE2"/>
</appender>
<!--<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="SIFT"/>
</root> -->
<loggername="com.leixin.test2.LogbackAsync"level="info">
<appender-refref="QUEUE"/>
</logger>
<loggername="com.leixin.test2.LogbackCompare"level="info">
<appender-refref="FILE"/>
</logger>
<!-- <logger name="com.leixin.test2.LogbackTest" level = "DEBUG"> <appender-ref
ref="FILE"/> </logger> -->
<!-- <logger name="com.leixin.test2.LogbackA" level = "DEBUG"> <appender-ref
ref="QUEUE"/> </logger> -->
<!-- <logger name="java.util.List" level = "INFO"> <appender-ref ref="STDOUT"/>
<appender-ref ref="SIFT"/> <appender-ref ref="DAILY_FILE" /> </logger> -->
<!-- <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator>
<expression>message.contains("billing")</expression> </evaluator> <OnMismatch>ACCEPT</OnMismatch>
<OnMatch>ACCEPT</OnMatch> </filter> -->
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> -->
<!-- <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator>
<expression>message.contains("billing")</expression> </evaluator> <OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch> </filter> -->
</configuration>
-
- 实时加载:
<?xmlversion="1.0"encoding="UTF-8"?>
<configuration scan="true"scanPeriod="6
seconds">
- scan:
-
- 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
- scanPeriod:
-
- 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
-
-
设置变量:<property>
-
设置路径是使用。避免重复赋值。如下:
<propertyname="LOG_HOME"value="d:/log"/>
<FileNamePattern>${LOG_HOME}/myApp.log.%d{yyyy-MM-dd}.log</FileNamePattern>
-
-
- 用来定义变量值的标签,<property> 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。
-
-
-
- 通过<property>定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
-
例如使用<property>定义日志存放的根目录,然后在<FileNamePattern>
-
- RollingFileAppender:
-
- logback将log4j中RollingFileAppender做了调整,新的RollingFileAppender可以通过不同的Policy(策略)工作,既可以按大小,又可以按日期大小
<appendername="DAILY_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 输出文件log路径及名称 -->
<file>${LOG_HOME}/myApp_daily.log</file>
<!-- 策略(按大小和时间) -->
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 超过大小或策略的文件命名方式 -->
<fileNamePattern>${LOG_HOME}/myApp_daily.log.%d{yyyy-MM-dd}.%i</fileNamePattern>
<!-- 文件最多数 -->
<maxHistory>3</maxHistory>
<!-- 文件最大值 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<!-- %d:日期格式;%thread:线程名;%-5level:级别从左显示5个字符宽度;%logger{50}:输出logger长度;%msg:日志消息;%n:换行符 -->
<pattern>%d{yyyy-MM HH:mm:ss.SSS} [%thread]
%-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appendername="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 输出文件log路径及名称 -->
<file>${LOG_HOME}/myApp_file.log</file>
<!-- 策略(固定大小) FixedWindowRollingPolicy -->
<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<!-- 旧的日志文件命名方式 -->
<fileNamePattern>${LOG_HOME}/myApp_file.log.%i</fileNamePattern>
<!-- 最小、最大文件数量 -->
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<!-- 输出格式 -->
<layoutclass="ch.qos.logback.classic.PatternLayout">
<!-- %d:日期格式;%thread:线程名;%-5level:级别从左显示5个字符宽度;%logger{50}:输出logger长度;%msg:日志消息;%n:换行符 -->
<pattern>%d{yyyy-MM HH:mm:ss.SSS} [%thread]
%-5level %logger{50} - %msg%n</pattern>
</layout>
<!-- 日志文件超过多大触发策略 -->
<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>50MB</maxFileSize>
</triggeringPolicy>
</appender>
- encode:
-
- encoder是在原来layout的基础上又封装了一次,里面默认封装了PatternLayout
<encoder>
<pattern>%d{yyyy-MM HH:mm:ss.SSS} [%thread]
%-5level %logger{50} - %msg%n</pattern>
</encoder>
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式
如:%d{yyyy年MM月dd日 HH:mm:ss,SSS},输出类似:2012年01月05日 22:10:28,921
%level 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL,level前面的数字表示占字位
%msg 输出代码中指定的消息
%thread 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%logger 输出源记录事件的 logger 名,后面的数字要结合下页的缩写算法
%class 输出执行记录请求的调用者的全限定类名,效率低,谨慎输出
-
- logger{??}的算法:
- Filter:
-
- LevelFilter: 级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。有以下子节点:
-
-
- <level>:设置过滤级别
-
-
-
- <onMatch>:用于配置符合过滤条件的操作
-
-
-
- <onMismatch>:用于配置不符合过滤条件的操作
-
<filterclass="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
-
- EvaluatorFilter: 求值过滤器,你可以通过一个条件判断定义过滤器是否接收或拒绝日志。有以下子节点:
-
-
- <expression>:设置表达式,返回一个布尔值。
-
-
-
- <onMatch>:用于配置符合过滤条件的操作
-
-
-
- <onMismatch>:用于配置不符合过滤条件的操作
-
需要引入一个表达式支持的jar包:janino.2.7.8.jar
-
<filterclass="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>message.contains("SQL")</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
-
SiftingAppender实现日志分片:
-
-
实际应用中,可能存在这种需求:根据某些特定的表示将日志从逻辑上分成不同部分。比如根据不同的登录 用户id,将日志保存到不同的文件中去
-
logback提供了siftingAppender,可以接受java程序中的变量作为参数传递到日志的配置当中
- Java代码写法:
-
logger.error("0000000000"); // 分入默认值用户对应的日志
MDC.put("userId","zhang3");
logger.error("1111111111");//分入用户zhang3对应的日志
logger.error("2222222222" );//分入用户对应的日志
MDC.put("userId","li4");
logger.error("3333333333"); //分入用户li4对应的日志
-
- xml:
<!-- 按照碎片方式记录日志 -->
<appendername="SIFT"class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<!-- 筛选的key -->
<Key>userId</Key>
<!-- 默认文件夹名称 -->
<DefaultValue>unknown</DefaultValue>
</discriminator>
<sift>
<appendername="FILE-${userId}"class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>d:/log/${userId}/%d{yyyyMMdd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd
HH:mm:ss.SSS} [%thread] %-5level %logger{15}- %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
-
AsyncAppender异步记录日志:
-
- 工作原理:
-
- 当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入队列中,队列的另一端会从队尾取出event交给对应的appender进行后面的日志推送。
<appendername="FILE2"class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/myApp_file2.log</file>
<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${LOG_HOME}/myApp_file2.log.%i</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<layoutclass="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM
HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>50
MB</maxFileSize>
</triggeringPolicy>
</appender>
<!-- 异步输出日志:AsyncAppender -->
<appendername="QUEUE"class="ch.qos.logback.classic.AsyncAppender">
<!-- 队列剩余百分比开始清理相对不重要的日志, 默认20 -->
<!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0
-->
<discardingThreshold>10</discardingThreshold>
<!-- 队列长度, 默认为 256 -->
<queueSize>10000</queueSize>
<!-- false:阻塞;true:不阻塞 -->
<neverBlock>false</neverBlock>
<!-- 引用的输出方式 -->
<appender-refref="FILE2"/>
</appender>