聊聊日常开发中,你会选择哪款Log框架?

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本篇文章主要讲解我在工作中是使用什么日志框架,因为大家都知道:适合的才是最好的。springboot 相信大家都用过吧,是的,关于日志的选择,springboot 都帮我们做好了,它的日志门面选用的就是 SLF4J,而日志实现选用的是Logback

至于它为什么会这样选择?我觉得还是有一定的道理的。至于门面为什么选择SLF4J,不作过多赘述,还是来聊聊实现为什么选择Logback吧。

Logback 作为流行的 log4j 项目的继承者。这两个框架都是同一个人写的,性能比 log4j 要好。至于 log4j2 ,它是log4j 1.x 的升级版,参考了 logback 的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升。为什么没有选择它呢?我认为还是因为其他的一些框架没有更好的和log4j2 进行适配起来。导致现在流行的日志框架都还是选择Logback

日志的用途

日志的用途大致可以归纳成以下三种:

  • 问题追踪:通过日志不仅仅包括我们程序的一些bug,也可以在安装配置时,通过日志可以发现问题。

  • 状态监控:通过实时分析日志,可以监控系统的运行状态,做到早发现问题、早处理问题。

  • 安全审计:审计主要体现在安全上,通过对日志进行分析,可以发现是否存在非授权的操作。

日志的级别

数字越大,级别越高,框架只会输出大于等于当前日志级别的信息。

  • ERROR 40
  • WARN 30
  • INFO 20
  • DEBUG 10
  • TRACE 0

Slf4j的使用

springboot默认帮我们配置好了日志。spring-boot-starter这个依赖里面已经为我们集成好了,自己去看看。

第一种方式

private static final Logger logger = LoggerFactory.getLogger(Test.class);

logger.info();

 ...
复制代码

默认的级别上info,按上面的排名只会输出 info、warn、error级别以上的日志。

在获取logger对象时,一般都是将本类的class传递进去,在默认的格式在日志输出时会把每条日志信息所在的class名输出出来。

第二种方式

使用 Lombok

Lombok不仅仅提供了强大的@Data注解,同时支持日志相关。

@Slf4j添加在类上,我们就不用再手动的获取Logger对象了,而是直接使用log。

log.debug("dubug..."); 
log.info("info...");
log.error("error...");
复制代码

输出格式

log.info("name = " + name + " ,age = " + age);
log.info("name:{},age: {}", name, age);
复制代码

配置文件

我们可以在配置文件中修改日志的默认配置。

image-20210926113424811

logback-spring.xml

下面是我经常用到的一些配置,你们可以根据自己的需要进行一些修改,文件默认放在resources目录下。

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--设置存储路径变量-->
    <property name="LOG_HOME" value="./logs"/>

    <!--控制台输出appender-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--设置输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--设置编码-->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--打印所有日志-->
    <appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志名,指定最新的文件名,其他文件名使用FileNamePattern -->
        <File>${LOG_HOME}/log.log</File>
        <!--文件滚动模式  按照时间,每天产生一个-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名,使用gz压缩-->
            <FileNamePattern>${LOG_HOME}/log.%d{yyyy-MM-dd}.log.gz</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
            <!--按大小分割同一天的-->
            <!--            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">-->
            <!--                <maxFileSize>100MB</maxFileSize>-->
            <!--            </timeBasedFileNamingAndTriggeringPolicy>-->
        </rollingPolicy>

        <!--输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--设置编码-->
            <charset>UTF-8</charset>
        </encoder>
        <!--在root指定的级别之上再次进行过滤,输出大于等于level,可通过onMatch和onMisMatch来确定只输出某个级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!--打印Error日志-->
    <appender name="errorLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志名,指定最新的文件名,其他文件名使用FileNamePattern -->
        <File>${LOG_HOME}/error.log</File>
        <!--文件滚动模式  按照时间,每天产生一个-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名,使用gz压缩-->
            <FileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log.gz</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>

        <!--输出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--设置编码-->
            <charset>UTF-8</charset>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--设置日志级别,过滤掉info日志,只输入error日志-->
            <level>ERROR</level>
        </filter>
    </appender>


    <!--指定基础的日志输出级别-->
    <root level="INFO">
        <!--appender将会添加到这个loger-->
        <appender-ref ref="console"/>
        <appender-ref ref="logFile"/>
        <appender-ref ref="errorLogFile"/>
    </root>
</configuration>
复制代码

使用示例

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TestService
{
    
    public static void main(String[] args)
    {
        log.info("info信息");
        log.warn("warn信息");
        log.error("error信息");
    }
}
复制代码

小结

以上就是我平时在工作中用到日志框架的简单的使用。同时也提醒大家,在输出日志的时候要谨慎,由于输出log过程需要进行磁盘操作,所以log信息一定要言简意赅,不要输出一些无用的log