美文网首页Java游戏服务器开发
既然使用Logback,应该对它多些了解(三)

既然使用Logback,应该对它多些了解(三)

作者: 王广帅 | 来源:发表于2020-05-12 14:46 被阅读0次

    1. AsyncAppender 异步记录日志

    AsyncAppender仅仅是做为一个日志分发器存在,因此,它必须绑定到其它的Appender上面。
    AsyncAppender会将日志缓存在一个BlockingQueue之中,然后启动一个线程从队列中取日志输出。默认情况下,缓存队列的长度是256。如果缓存占了队列的80%的时候,AsyncAppender就会丢弃trace,debug,info级别的日志。如果不想丢掉日志,可以配置AsyncAppender的discardingThreshold为0。

    因为缓存的存在,在应用退出的时候,需要等待将缓存的日志写到日志文件中,否则就有可能日志丢失。可以使用下面的代码关闭日志:

            LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
            context.stop();
    

    在写入日志的时候,会有一个超时时间,默认是1000ms,如果这个时间太短,可以通过AsyncAppender的maxFlushTime配置这个超时时间。
    另外也可以在logback的配置文件中添加jvm的关闭时的回调钩子:

    <configuration debug="true">
       <!-- in the absence of the class attribute, assume 
       ch.qos.logback.core.hook.DefaultShutdownHook 
    在旧的版本中,可能是:ch.qos.logback.core.hook.DelayingShutdownHook-->
     <shutdownHook/>
      .... 
    </configuration>
    

    这样,当jvm通过命令exit退出的时候,logback会自动关闭所有的appender,关把缓存在队列中的日志输出到日志文件里面。需要注意的一点是,如果在jvm中添加多个回调钩子,它们是并行执行的,没有顺序性。如果在logback中配置了shutdownHook,有可能提前关闭了日志,其它钩子如果有日志打印就不会输出了,不可以配置logback的关闭钩子的延迟执行时间,

        <shutdownHook class="ch.qos.logback.core.hook.DefaultShutdownHook">
            <delay>5000</delay>
        </shutdownHook>
    

    下面是一个异步日志的输出配置方式:

    <configuration>
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>myapp.log</file>
        <encoder>
          <pattern>%logger{35} - %msg%n</pattern>
        </encoder>
      </appender>
    
      <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE" />
      </appender>
    
      <root level="DEBUG">
        <appender-ref ref="ASYNC" />
      </root>
    </configuration>
    

    2. 自定义Appender

    通过继承AppenderBase可以自定义自己的Appender。它只需要实现一个方法:append(Object eventObject)。下面是一个例子,用来限制日志的输出数据,当日志数量达到限制之后就不再输出了:

    package chapters.appenders;
    
    import java.io.IOException;
    
    import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.AppenderBase;
    
    
    public class CountingConsoleAppender extends AppenderBase<ILoggingEvent> {
      static int DEFAULT_LIMIT = 10;
      int counter = 0;
      int limit = DEFAULT_LIMIT;
      
      PatternLayoutEncoder encoder;
      
      public void setLimit(int limit) {
        this.limit = limit;
      }
    
      public int getLimit() {
        return limit;
      }
      
      @Override
      public void start() {
        if (this.encoder == null) {
          addError("No encoder set for the appender named ["+ name +"].");
          return;
        }
        
        try {
          encoder.init(System.out);
        } catch (IOException e) {
        }
        super.start();
      }
    
      public void append(ILoggingEvent event) {
        if (counter >= limit) {//达到限制了,不再输出日志
          return;
        }
        // output the events as formatted by our layout
        try {
          this.encoder.doEncode(event);
        } catch (IOException e) {
        }
    
        // prepare for next event
        counter++;
      }
    
      public PatternLayoutEncoder getEncoder() {
        return encoder;
      }
    
      public void setEncoder(PatternLayoutEncoder encoder) {
        this.encoder = encoder;
      }
    }
    

    在类中的成员变量,只要有getter/setter方法,就可以像配置其它Appender一样,在logback配置文件中配置。
    start()方法一般用来初始化。

    3. Encoder

    Encoder负责将日志事件转化为byte[]并写入到OutputStream之中。因此,Encoder决定了何时写入OutputSteam,以及写入什么。
    目前最常用的Encoder是PatternLayoutEncoder,它取代了以前版本的Layout。

    4. 日志过滤组件-Filters

    logback有两种不同类型的filters,一个是Regular filters,一个是turbo filters。最常用的是Regular Filters。

    Regular Filters 有一个decide方法,它的参数是ILogingEvent,多个filter是按顺序执行的,decide方法返回一个枚举类型:DENY,NETURAL,ACCEPT。如果返回的是DENY,日志事件就会被立刻丢弃,并且不会再执行剩下的Filters,如果返回的是NETURAL,日志事件会被传到下一个filter,如果返回的是ACCEPT,日志将会被处理,并且不会再执行剩下的filters。
    Filters可以配置到Appender之中,可以配置多个,你可以在filter中添加任意的条件。

    4.1 自定义Filter

    自定义的Filter需要继承实现Filter,如下所示:

    package chapters.filters;
    
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.filter.Filter;
    import ch.qos.logback.core.spi.FilterReply;
    
    public class SampleFilter extends Filter<ILoggingEvent> {
    
      @Override
      public FilterReply decide(ILoggingEvent event) {    
        if (event.getMessage().contains("sample")) {
          return FilterReply.ACCEPT;
        } else {
          return FilterReply.NEUTRAL;
        }
      }
    }
    

    然后可以这样配置:

    View as .groovy
    <configuration>
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    
        <filter class="chapters.filters.SampleFilter" />
    
        <encoder>
          <pattern>
            %-4relative [%thread] %-5level %logger - %msg%n
          </pattern>
        </encoder>
      </appender>
            
      <root>
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>
    

    4.2 LevelFilter

    LevelFitler是根据日志的级别进行判断的,配置如下:

    View as .groovy
    <configuration>
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <level>INFO</level>
          <onMatch>ACCEPT</onMatch>
          <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
          <pattern>
            %-4relative [%thread] %-5level %logger{30} - %msg%n
          </pattern>
        </encoder>
      </appender>
      <root level="DEBUG">
        <appender-ref ref="CONSOLE" />
      </root>
    </configuration>
    

    这表示,如果日志是INFO级别,就会被接收处理,如果不是,就拒绝并丢弃。

    4.3 ThresholdFilter

    这个Filter需要设置一个临界值,大于等于这个临界值会被接收,小于这个临界值被拒绝。

    View as .groovy
    <configuration>
      <appender name="CONSOLE"
        class="ch.qos.logback.core.ConsoleAppender">
        <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
          <level>INFO</level>
        </filter>
        <encoder>
          <pattern>
            %-4relative [%thread] %-5level %logger{30} - %msg%n
          </pattern>
        </encoder>
      </appender>
      <root level="DEBUG">
        <appender-ref ref="CONSOLE" />
      </root>
    </configuration>
    

    像trace,debug小于info级别的日志会被拒绝,而info,warn,error会被接收处理。


    公众号.png

    相关文章

      网友评论

        本文标题:既然使用Logback,应该对它多些了解(三)

        本文链接:https://www.haomeiwen.com/subject/pycmnhtx.html