美文网首页
java日志体系

java日志体系

作者: 一个菜鸟JAVA | 来源:发表于2021-03-28 20:20 被阅读0次

    为什么要使用日志

    刚开始接触java时都使用过System.out来调试,通过它我们能打印出一些关注的信息到控制台便于我们调试。这种方式只限于我们平常开发时简单测试,但是生产环境这样是不行的。首先这样做会有性能上的问题,其次使用这种方式会很麻烦。例如我打印的结果需要显示方法名称、线程名称、时间等等,你总不能每次都手动拼接然后打印吧;还例如我需要将它输入到不同的文件中。以上说的都是System.out所不能实现或者特别麻烦的地方

    混乱的日志体系

    上面我们总结了System.out不足之处,所以我们正式项目一般都是使用的日志。但是java中的日志体系特别乱,特别对于新手来说简直就是一脸闷逼。你肯定听过Log4j、JUL、JCL、Slf4j、Logback、Log4j2这些里面的几种,面对这么多日志相关的东西,你除此接触简直就是一脸闷逼。下面我们来简单说说这些日志工具的关系和历史。

    Log4j:Java之前官方并没有提供日志相关的工具,而Log4j就是最早提供日志功能的工具了,然后大家都开始使用这个工具,而Log4j也几乎成为Java标准的日志库了。

    JUC:log4j很流行但是并没有成为java标准的日志库,Sun公司推出了JUL(java Util Logging)。因为在之前大家已经习惯使用Log4j了,所以JUL并没有流行起来。

    JCL:上面说了已经存在Log4j和JUL,如果想从Log4j换成JUC或者从JUC换成Log4j很麻烦,需要修改所有日志调用的地方,所以Apache为了解决问题推出了JCL(Jakarta Commons Loggin)。JCL中只是定义了一套日志接口,支持在运行时动态的加载日志组件的实现。也就是说我们在代码里使用JCL的API,底层我们可以使用Log4j或者JUC实现,这样我们在切换日志实现时,不需要修改大量的代码。

    Slf4j和Logback:而之前开发Log4j的作者离开原来的公司之后,觉得之前的日志框架还不够牛逼,于是他再次出手,掏出Slfj4和Logback(Sl4j的实现)两个项目。这下java日志领域基本上就分成两个帮派了,Commons Loggin和Slf4j。而随着时间推移,Slf4j搭配Logback慢慢的抢占了Log4j的用户。

    Log4j 2:上面说了Slf4j搭配Logback慢慢的抢占了Log4j的用户,这个时候Log4j推出了Log4j 2.x与Logback对战。

    看了上面的java日志工具的发展,现在大概明白了日志工具的体系了吧。对于上面说的工具基本上可以分为两类,一类是日志接口,也就是日志门面,它们不提供实现或者提供简单的实现。而另外一类是日志实现,也就是实际上实现日志功能的工具。

    对于日志工具包门面工具主要就是Slf4j和JCL这个两个,而实际上因为效率问题,目前日志门面大家都使用的是Slf4j,而JCL逐渐的退出了舞台。

    对于日志的实现现在基本上的选择就是Log4j、Logback、Log4j 2。

    Slf4j和Logback组合使用

    这个组合应该是目前使用最广的,至少我个人使用比较多,而且在Spring Boot中也默认使用的该组合,下面就说如何使用Slf4j和Logback组合使用。

    jar包说明

    logback-core:Logback核心功能包,如果只是想用Logback使用这个包就可以了。

    logback-access:访问模块集成和Servlet容器集成,提供Http访问日志的功能。

    logback-classic:如果想与Slf4j集成就需要使用到这个包,这个包里面还依赖了Slf4j的包。

    一般情况下我们使用Slf4j与Logback只需要在工程中添加下面的依赖即可,不需要我们手动添加Slf4j包的依赖。

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    

    Logback配置说明

    如果不需要定制化的日志只需要添加相关的maven依赖就可以了,如果需要定制化需求就需要自己添加配置。Logback支持通过XML和groovy的方式来配置,但是使用较多的方式还是通过XML这种方式配置。配置时我们只需要在创建Logback.xml文件放在resource下即可。

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="60 seconds" debug="true">
        <!--设置变量-->
        <property name="APP_NAME" value="logback-demo"/>
        <!--上下文名称,设置之后不能再修改-->
        <contextName>${APP_NAME}</contextName>
        <!--配置appender-->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
            </encoder>
        </appender>
        <!--配置logger-->
        <logger name="com.buydeem.share.log.logback" level="debug" additivity="true"/>
        <!--配置root-->
        <root level="info">
            <!--引用appender-->
            <appender-ref ref="STDOUT"/>
        </root>
    </configuration>
    

    configuration

    上面就是一个最简单的logback配置文件,首先就是configuration节点的配置,其中scanscanPeriod是用来监控配置文件变化的,scan设置为true时代表会扫描配置文件的变化,而scanPeriod是用来指定扫描频率。而debug是用来打印Logback内部的日志,它会打印如何查找配置文件和实际应用的日志文件等信息。

    contextName

    设置应用的名称,该值设置之后是无法再次修改的。简单的说就是应用启动之后,再次修改该值是不生效的。

    property

    用来定义变量,在后续的配置中可是使用该变量。

    appender

    日志输出组件,主要用来输入和格式化日志,而且Logback中提供了多种appender组件,不同的组件有不同的效果。例如可以将日志输出在控制台中,还可以将日志输出到文件中。例如我们上文中使用的ch.qos.logback.core.ConsoleAppender它就是将日志输出到控制台。

    对于appender节点来说我们还可以配置其他东西,例如我们可以筛选日志的级别,让该appender中只输出某种级别的日志。利用这个设置,我们可以将不同级别的日志输出到不同的文件中。

    logger和root

    logger用来设置某一个包或者具体某一个类的日志打印级别以及指定appender。你可以理解logger和root是同一种东西,不同的在于root是logger的最上级。对于logger节点中,我们可以设置的属性有level和additivity两个属性。

    level代表该appender中输出的最低日志级别,例如上面的配置文件中我们将其设置成debug代表低于该级别的日志将不会再logger中打印出来。如果我们没有设置将应用父级的level,如果logger没有父级则会使用root中的level(root是所有level最上级)。

    additivity用来设置该logger是否向上级传递,如果设置为true,该logger下打印的日志还会传递到root中。在我们的配置中,我们并没有在logger下配置appender,但是仍然可以打印出日志。这是因为我们在root节点下配置了appender,并且我们还把logger的additivity设置成了true。如果我们将该值改为false,你可以发现日志将不会再控制台中输出了。

    配置不同级别的日志内容输出到不同的文件

    对于实际开发中我们可能需要将不同的日志输出到不同的文件,下面是一个示例配置。

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="60 seconds">
        <!--日志文件前缀,即应用名称 -->
        <property name="logfile.prefix" value="logback-demo"/>
        <!--日志路径,可写相对路径,也可写绝对路径 -->
        <property name="log.path" value="logs"/>
        <!-- 日志输出格式 -->
        <property name="log.pattern"
                  value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%15thread] %40.40logger{40} [%10method,%line] : %msg%n"/>
        <!-- 控制台输出日志 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--        设置日志输出格式-->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${log.pattern}</pattern>
                <!-- 编码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!-- 文件输出日志, 滚动(时间/文件大小)输出策略 -->
        <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 过滤器,只记录debug级别的日志 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>DEBUG</level>
                <OnMismatch>DENY</OnMismatch>
                <OnMatch>ACCEPT</OnMatch>
            </filter>
            <!-- 日志文件路径及文件名 -->
            <File>${log.path}/${logfile.prefix}-debug.log</File>
            <!-- 日志记录器的滚动策略,按日期记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 日志输出格式 -->
                <FileNamePattern>${log.path}/${logfile.prefix}-debug.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!-- 日志保留天数 -->
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <!--        设置日志输出格式-->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${log.pattern}</pattern>
                <!-- 编码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!--    info级别-->
        <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>INFO</level>
                <OnMismatch>DENY</OnMismatch>
                <OnMatch>ACCEPT</OnMatch>
            </filter>
            <File>${log.path}/${logfile.prefix}-info.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${log.path}/${logfile.prefix}-info.%d{yyyy-MM-dd}.log</FileNamePattern>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <!--        设置日志输出格式-->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${log.pattern}</pattern>
                <!-- 编码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!--    warn级别-->
        <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>WARN</level>
                <OnMismatch>DENY</OnMismatch>
                <OnMatch>ACCEPT</OnMatch>
            </filter>
            <File>${log.path}/${logfile.prefix}-warn.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${log.path}/${logfile.prefix}-warn.%d{yyyy-MM-dd}.log</FileNamePattern>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <!--        设置日志输出格式-->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${log.pattern}</pattern>
                <!-- 编码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
        <!--    error级别-->
        <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <OnMismatch>DENY</OnMismatch>
                <OnMatch>ACCEPT</OnMatch>
            </filter>
            <File>${log.path}/${logfile.prefix}-error.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${log.path}/${logfile.prefix}-error.%d{yyyy-MM-dd}.log</FileNamePattern>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <!--        设置日志输出格式-->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${log.pattern}</pattern>
                <!-- 编码 -->
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <logger name="com.buydeem.share.log.logback" level="debug" additivity="true"/>
        <!-- 日志输出 -->
        <root level="DEBUG">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="DEBUG_FILE"/>
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="WARN_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
    </configuration>
    

    相关文章

      网友评论

          本文标题:java日志体系

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