(二)、logback + slf4j

来源:互联网 发布:言论自由 知乎 编辑:程序博客网 时间:2024/05/29 00:32
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: 
    • 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scantrue时,此属性生效。默认的时间间隔为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>

部分内容在log4j1中有说明