• Java日志系统


    前言

    各组件之间的关系:

    slf4j是The Simple Logging Facade for Java的简称,是一个简单日志门面抽象框架,它本身只提供了日志Facade API和一个简单的日志类实现,一般常配合Log4jLogBackjava.util.logging使用。

    Slf4j作为应用层的Log接入时,程序可以根据实际应用场景动态调整底层的日志实现框架(Log4j/LogBack/JdkLog...);

     LogBack和Log4j都是开源日记工具库,LogBack是Log4j的改良版本,比Log4j拥有更多的特性,同时也带来很大性能提升。

    LogBack官方建议配合Slf4j使用,这样可以灵活地替换底层日志框架。

    一、Slf4j

    1、Slf4j的概念

    slf4j只是一个日志标准,并不是日志系统的具体实现。理解这句话非常重要,slf4j只做两件事情:

    • 提供日志接口
    • 提供获取具体日志对象的方法

    slf4j的直接/间接实现有slf4j-simple、logback、slf4j-log4j12

    2、我们为什么要使用slf4j

    2.1、 面向接口编程/外观模式的所有好处

    2.2、 统一所有模块的日志

    3、Slf4j的实现原理

    3.1 提供Slf4j功能的组件实现了Logger接口

    3.2 提供Slf4j功能的组件里面必须要实现一个文件:org/slf4j/impl/StaticLoggerBinder.class

      Slf4j通过 ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); 这句代码获取到这个类的对象,进而获得Logger  

      //STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"

       如果有多个同名,会随机选一个

    4、Slf4j的用法

     pom:

            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.25</version>
            </dependency>

          注意:下面的这几个实现,只需要其中一个。 <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency>

    注意,如果需要用@Slf4j这种注解的方式使用日志,需要加lombak的引用,并在ide中添加lombak插件  

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.18</version>
            </dependency>
    

      

    @Slf4j
    public class AlarmUtil
    {
        public static void main(String[] args)
        {
          log.info("hahah");
        }
    }
    

      

    @Slf4j这个注解是一个源码级注解,目的是生成一个log对象,看注解的注释:

     二、logback

    LogBack是一个日志框架,它是Log4j作者Ceki的又一个日志组件。 

     1、LogBack的结构

    LogBack分为3个组件,logback-core, logback-classic 和 logback-access。

    其中logback-core提供了LogBack的核心功能,是另外两个组件的基础。

    logback-classic则实现了Slf4j的API,所以当想配合Slf4j使用时,则需要引入这个包。

    logback-access是为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。

     

    2、slf4j与logback结合使用实践

    2.1  配置pom,前文已叙

    2.2 配置logback的配置文件 :文件位置位于src/main/resources下,名字默认为logback.xml。logback也支持groovy格式的配置文件,如果你会用那更好。

    简单的配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>
      <root level="DEBUG">          
        <appender-ref ref="STDOUT" />
      </root>  
    </configuration>
    

      一个稍微复杂的配置:

    <?xml version="1.0" encoding="UTF-8"?>
    

     <!-- scan 是否定期扫描xml文件, scanPeriod是说扫描周期是30秒-->

    <configuration scan="true" scanPeriod="30 seconds" debug="false" packagingData="true">
        <!-- 项目名称 -->
        <contextName>myApp1 contextName</contextName>
        <!-- 属性 -->
        <property name="USER_HOME" value="./log"/>
    
        <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
           the key "bySecond" into the logger context. This value will be
           available to all subsequent configuration elements. -->
        <timestamp key="bySecond" datePattern="yyyyMMdd" timeReference="contextBirth"/>
        
        <!-- appender很重要,一个配置文件会有多个appender -->
        <!-- ConsoleApperder意思是从console中打印出来 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!-- 过滤器,一个appender可以有多个 -->
            <!-- 阈值过滤,就是log行为级别过滤,debug及debug以上的信息会被打印出来 -->
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>debug</level>
            </filter>
    
            <!-- encoders are assigned the type
                 ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
            <!-- encoder编码规则 -->
            <encoder>
                <!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
                <!--<pattern>%d %contextName %msg%n</pattern>-->
                <!-- pattern模式 %d时间 %thread 线程名 %level行为级别 %logger logger名称 %method 方法名称 %message 调用方法的入参消息 -->
                <pattern>%-4d [%thread] %highlight%-5level %cyan%logger.%-10method - %message%n</pattern>
            </encoder>
        </appender>
        
        <!-- FileAppender 输出到文件 -->
        <appender name="FILE" class="ch.qos.logback.core.FileAppender">
            <!-- 文件存放位置 %{xxx} 就是之前定义的属性xxx -->
            <file>${USER_HOME}/myApp1log-${bySecond}.log</file>
            
            <encoder>
                <!-- %date和%d是一个意思 %file是所在文件 %line是所在行 -->
                <pattern>%date %level [%thread] %logger{30} [%file:%line] %msg%n</pattern>
            </encoder>
        </appender>
        
        <!-- 输出到HTML格式的文件 -->
        <appender name="HTMLFILE" class="ch.qos.logback.core.FileAppender">
            <!-- 过滤器,这个过滤器是行为过滤器,直接过滤掉了除debug外所有的行为信息 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>debug</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
    
            <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <!-- HTML输出格式 可以和上边差不多 -->
                <layout class="ch.qos.logback.classic.html.HTMLLayout">
                    <pattern>%relative%thread%mdc%level%logger%msg</pattern>
                </layout>
            </encoder>
            <file>${USER_HOME}/test.html</file>
        </appender>
    
        <!-- 滚动日志文件,这个比较常用 -->
        <appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 当project等于true的时候file就不会起效果-->
            <prudent>true</prudent>
            <!--<file>${USER_HOME}/logFile.log</file>-->
            <!-- 按天新建log日志 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- daily rollover -->
                <fileNamePattern>${USER_HOME}/logFile.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
                <!-- 保留30天的历史日志 -->
                <maxHistory>30</maxHistory>
                
                <!-- 基于大小和时间,这个可以有,可以没有 -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <!-- or whenever the file size reaches 100MB -->
                    <!-- 当一个日志大小大于10KB,则换一个新的日志。日志名的%i从0开始,自动递增 -->
                    <maxFileSize>10KB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
    
            <encoder>
                <!-- %ex就是指抛出的异常,full是显示全部,如果在{}中写入数字,则表示展示多少行 -->
                <pattern>%-4date [%thread] %-5level %logger{35} - %msg%n%ex{full, DISPLAY_EX_EVAL}</pattern>
            </encoder>
        </appender>
    
        <!-- 重点来了,上边都是appender输出源。这里开始就是looger了 -->
        <!-- name意思是这个logger管的哪一片,像下面这个管的就是log/test包下的所有文件 level是只展示什么行为信息级别以上的,
      类似阈值过滤器 additivity表示是否再抛出事件,就是说如果有一个logger的name是log,如果这个属性是true,另一个logger就会在这个logger处理完后接着继续处理 --> <logger name="log.test" level="INFO" additivity="false"> <!-- 连接输出源,也就是上边那几个输出源 ,你可以随便选几个appender--> <appender-ref ref="STDOUT"/> <appender-ref ref="ROLLINGFILE"/> <appender-ref ref="HTMLFILE"/> </logger> <!-- 这个logger详细到了类 --> <logger name="log.test.Foo" level="debug" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="ROLLINGFILE"/> <appender-ref ref="HTMLFILE"/> </logger> <!-- Strictly speaking, the level attribute is not necessary since --> <!-- the level of the root level is set to DEBUG by default. --> <!-- 这就是上边logger没有管到的情况下 root默认接管所有logger --> <root level="debug"> <appender-ref ref="STDOUT"/> </root> </configuration>

      

    3.过滤器

    Logback的过滤器基于三值逻辑,允许把它们组装或成链,从而组成任意的复合过滤策略。过滤器很大程度上受到Linux的iptables启发。这里的所谓三值逻辑是说,过滤器的返回值只能是ACCEPT、DENY和NEUTRAL的其中一个。
    如果返回DENY,那么记录事件立即被抛弃,不再经过剩余过滤器;
    如果返回NEUTRAL,那么有序列表里的下一个过滤器会接着处理记录事件;
    如果返回ACCEPT,那么记录事件被立即处理,不再经过剩余过滤器。

    一个简单的过滤器

    public class SampleFilter extends Filter<ILoggingEvent> {
      @Override
      public FilterReply decide(ILoggingEvent event) {    
        if (event.getMessage().contains("let")) {
          return FilterReply.ACCEPT;
        } else {
          return FilterReply.DENY;
        }
         return FilterReply.NEUTRAL;
      }
    }
    

     除上边几种输出源之外,logback还支持输出到远程套接字服务器、 MySQL、 PostreSQL、Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等等。

    参考

    Java日志框架:slf4j作用及其实现原理

    LogBack入门实践

    logback相关说明:

    官方手册
    LogBack简易教程
    实际的xml配置
    Logback浅析
    logback 配置详解(一)

  • 相关阅读:
    pickle模块的基本使用
    python selenium 开发环境配置
    ubuntu ftp服务器搭建
    再探VIM配置
    counting elements--codility
    Time complexity--codility
    Arrays--codility
    Iterations --codility
    adobe reader DC 字体设置
    按位操作
  • 原文地址:https://www.cnblogs.com/aoyihuashao/p/10116458.html
Copyright © 2020-2023  润新知