简介
在实际的应用中有很多需要分离日志的需求,比如为了方便监控错误日志就会把错误日志分开,有一些重要的接口需要单独做日志的也需要单独分开。logback和log4j2都能通过配置简单实现日志的分离。log4j2和logback的配置是差不多的,这里就以logback为例介绍一下如何分离日志文件。
有2个重要的抽象一个是Appender,另一个是Logger,Logger是对日志的抽象作用是输出日志,至于怎么输出有实现决定,Appender是对日志输出的位置的抽象,在logback中日志过滤器也被封装到了Appender中。过滤器被添加到Appender中,添加一个或多个过滤器后,可以用任意条件对日志进行过滤。Appender有多个过滤器时,按照配置顺序执行。当然要分离日志,还要了解下面几个概念。
FilterReply:
过滤器的响应方式,过滤器在执行一个过滤的时候会利用FilterReply枚举,这个枚举包含3个值,分别是DENY,NEUTRAL,ACCEPT。 DENY:日志将立即被抛弃不再经过其他过滤器 NEUTRAL:有序列表里的下个过滤器过接着处理日志 ACCEPT:日志会被立即处理,不再经过剩余过滤器。
LevelFilter
级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMatch 和 onMismatch接收或拒绝日志。有以下子节点:
<level>:设置过滤级别
<onMatch>:FilterReply枚举值,用于配置匹配level时的操作
<onMismatch>:FilterReply枚举值,用于配置不匹配level时的操作
ThresholdFilter
临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。 ThresholdFilter和LevelFilter差不多LevelFilter是对指定级别的进行过滤,只是针对一个级别的,而ThresholdFilter是一个阀值,针对多个级别的。可以通过多个LevelFilter来实现ThresholdFilter同样的功能。
实例
下面通过一个简单的实例来展示一下日志分离。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogStart {
private static final Logger logger = LoggerFactory.getLogger(LogStart.class);
public static void main(String[] args) {
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
ImportantLog.log();
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ImportantLog {
private static final Logger logger = LoggerFactory.getLogger(ImportantLog.class);
public static void log(){
logger.debug("debug log");
logger.info("info log");
logger.warn("warn log");
logger.error("error log");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="LOG_DIR" value="E:/logs" />
<!-- 控制台日志 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%5level] %logger{36}[%file:%line]- %msg%n</Pattern>
</encoder>
</appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/base-%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%5level] %logger{36}[%file:%line] - %msg%n</Pattern>
</encoder>
</appender>
<appender name="ERROR_WARN_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>warn</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/error-warn-%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%5level] %logger{36}[%file:%line] - %msg%n</Pattern>
</encoder>
</appender>
<appender name="INFO_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/info-%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%5level] %logger{36}[%file:%line] - %msg%n</Pattern>
</encoder>
</appender>
<appender name="IMPORTANT_LOG_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/important-%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%5level] %logger{36}[%file:%line] - %msg%n</Pattern>
</encoder>
</appender>
<logger name="org.springframework" level="ERROR"></logger>
<!-- name:包或者类名 additivity:是否向上级传递打印信息,默认false cn.freemethod.log.ImportantLog:类的全路径
可以单独设置一个appender来输出超时的日志 -->
<logger name="cn.freemethod.log.ImportantLog" level="INFO"
additivity="false">
<appender-ref ref="IMPORTANT_LOG_FILE" />
</logger>
<root level="DEBUG">
<!-- <appender-ref ref="FILE" /> -->
<appender-ref ref="CONSOLE" />
<appender-ref ref="ERROR_WARN_FILE" />
<appender-ref ref="INFO_FILE" />
</root>
</configuration>
上面的配置文件配置了4个Appender,其中CONSOLE输出到控制台的。ERROR_WARN_FILE配置了一个ThresholdFilter只输出warn和error级别的日志。INFO_FILE配置了一个LevelFilter只输出info日志。IMPORTANT_LOG_FILE是为了重要接口单独配置输出文件位置的Appender。提供给name为cn.freemethod.log.ImportantLog的Logger使用。这个Logger的additivity="false"表示这个Logger输出后就不向父级输出了。Logger默认的父级是root,也就是表示如果配置了additivity="false"就不会向root下的Appender输出了。可以把additivity="false"改为additivity="true"试一试效果。