logback进阶

参考:

https://www.cnblogs.com/yw0219/p/9310701.html

https://www.cnblogs.com/yw0219/p/9310845.html

https://www.cnblogs.com/yw0219/p/9320846.html

https://www.cnblogs.com/yw0219/p/9361040.html

以上是logback的官方文档的翻译,值得一看。

 

在一般的服务中,我们调试的时候将日志打印到控制台console,生产环境中将日志输出到日志文件

1.对日志分级别level进行打印,一般至少分三个文件error.log,warn.log和info.log

2.每天的日志写入以当天命名的文件夹中,比如20220525,

3.日志文件指定一个阈值大小,比如10M,或者100M,超过阈值对日志文件进行切分,新日志写入新文件。

分级别、分日期、滚动写入。以上的配置对于一般的服务就足够了。

但有一种特殊的服务,比如调度系统,它会执行非常多的异构任务,这些任务的日志为了方便查看,是不应该写入一个文件中的。

需要将每个任务写入特定的文件中。那么logback能实现吗?

答案是肯定的!

首先我们贴出logback.xml配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration>
    <property name="logDir" value="logs" />
    <property name="maxHistory" value="30" />
    <property name="log.base" value="logs"/>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>



    <!-- ERROR级别日志 -->
    <appender name="ERROR"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logDir}/error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/%d{yyyyMMdd}/error.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>${maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger -
                %msg%n</pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
        <append>false</append>
        <prudent>false</prudent>
    </appender>

    <!-- WARN级别日志 -->
    <appender name="WARN"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logDir}/warn.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/%d{yyyyMMdd}/warn.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>${maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
        <append>false</append>
        <prudent>false</prudent>
    </appender>

    <!-- INFO级别日志 -->
    <appender name="INFO"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logDir}/info.log</file>
        <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>${logDir}/%d{yyyyMMdd}/info.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>${maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
        <append>false</append>
        <prudent>false</prudent>
    </appender>

    <appender name="TASKLOGFILE" class="ch.qos.logback.classic.sift.SiftingAppender">
        <filter class="cc.eslink.metadata.scheduler.log.TaskLogFilter"/>
        <Discriminator class="cc.eslink.metadata.scheduler.log.TaskLogDiscriminator">
            <key>taskAppId</key>
            <logBase>${log.base}</logBase>
        </Discriminator>
        <sift>
            <appender name="FILE-${taskAppId}" class="ch.qos.logback.core.FileAppender">
                <file>${log.base}/${taskAppId}.log</file>
                <encoder>
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern>
                    <charset class="java.nio.charset.Charset">UTF-8</charset>
                </encoder>
                <append>true</append>
            </appender>
        </sift>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="ERROR" />
        <appender-ref ref="WARN" />
        <appender-ref ref="INFO" />
        <appender-ref ref="TASKLOGFILE" />
    </root>
</configuration>

name等于ERROR、WARN、INFO的appender都是一般的配置,我们指定任务写入指定文件的配置主要在TASKLOGFILE的appender中。

为了实现行级日志的指定文件写入,我们自定义了两个配置类。分别是TaskLogFilter和TaskLogDiscriminator

//TaskLogFilter 决定哪些日志会被筛选到名为TASKLOGFILE的appender中
public class TaskLogFilter extends Filter<ILoggingEvent> {
    private Level level;

    public void setLevel(String level) {
        this.level = Level.toLevel(level);
    }

    @Override
    public FilterReply decide(ILoggingEvent event) {
        FilterReply filterReply = FilterReply.DENY;
        if ((event.getThreadName().startsWith("taskAppId")
                && event.getLoggerName().startsWith("TaskLogLogger"))
                || event.getLevel().isGreaterOrEqual(level)) {
            filterReply = FilterReply.ACCEPT;
        }
        return filterReply;
    }
}

日志的筛选我们已经完成了,下一步就是把对应任务的日志写入对应的文件中,这个实现在TaskLogDiscriminator中

//通过一系列操作,我们将groupName=group,jobName=job的调度任务的日志写入到group/job.log文件中
public class TaskLogDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
    /**
     * key
     */
    private String key;

    /**
     * log base
     */
    private String logBase;

    @Override
    public String getDiscriminatingValue(ILoggingEvent event) {
        String key = "unknown_task";
        if (event.getLoggerName().startsWith("TaskLogLogger")) {
            String threadName = event.getThreadName();

            String part1 = threadName.split("=")[1];
            String prefix = "TASK-";
            if (part1.startsWith(prefix)) {
                key = part1.substring(prefix.length()).replaceFirst("-", "/");
            }
        }
        return key;
    }

    @Override
    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getLogBase() {
        return logBase;
    }

    public void setLogBase(String logBase) {
        this.logBase = logBase;
    }
}

大功告成,感谢logback!

 

posted @ 2022-05-26 14:59  Mars.wang  阅读(62)  评论(0编辑  收藏  举报