zoukankan      html  css  js  c++  java
  • SpringBoot | 第二十三章:日志管理之整合篇

    前言

    在本系列《第四章:日志管理》中,由于工作中日志这块都是走默认配置,也没有深入了解过,因为部署过程中直接使用了linux中的输出重定向功能,如java -jar xx.jar > app.log 2>&1 &,直接输出到某个日志文件了。所以也就没有认真关心过默认的日志格式了。系列文章出来后,也看见有网友反馈说如何进行日志的相关配置,或者配置失效问题。本着负责的原则,本文就来详细介绍下SpringBoot中日志管理相关配置问题。也是最近熟悉了下,有不足之处,还望指出!

    一点知识

    细说各日志框架整合配置前,我们先来大致了解下,最常见的日志的几个级别:ERROR, WARN, INFO, DEBUGTRACE。像其他的,比如ALLOFFFATAL之类的开发过程中应该基本上是不会涉及的。所以以下从低到高一次介绍下常见的日志级别。

    • TRACE:追踪。一般上对核心系统进行性能调试或者跟踪问题时有用,此级别很低,一般上是不开启的,开启后日志会很快就打满磁盘的。
    • DEBUG:调试。这个大家应该不陌生了。开发过程中主要是打印记录一些运行信息之类的。
    • INFO:信息。这个是最常见的了,大部分默认就是这个级别的日志。一般上记录了一些交互信息,一些请求参数等等。可方便定位问题,或者还原现场环境的时候使用。此日志相对来说是比较重要的。
    • WARN:警告。这个一般上是记录潜在的可能会引发错误的信息。比如启动时,某某配置文件不存在或者某个参数未设置之类的。
    • ERROR:错误。这个也是比较常见的,一般上是在捕获异常时输出,虽然发生了错误,但不影响系统的正常运行。但可能会导致系统出错或是宕机等。

    如果将日志设置在某个等级,则比此级别高的都能打印出来。比如,设置了INFO,那么ERROR, WARN等都能输出打印了,而DEBUGTRACE等就被忽略了。

    而为了能很好的对各日志框架的支持,开发过程中,一般上都是使用Commons Logging或者SL4J这些门面日志工具。其底层封装了统一日志的操作,屏蔽了不同日志组件之间的差异。使得我们使用或者切换某个日志框架时,只需要引入相关的依赖包就可替换完毕,而无需去修改源码。其最后日志的实际操作还是由像log4j2logback这些日志框架去实现的。

    从前面章节,我们知道。SpringBoot中,内部日志也是使用Commons Logging,同时默认配置也提供了对常用日志的支持,如:Java Util LoggingLog4J, Log4J2Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。

    关于日志的自定义配置等相关知识点,这里就不阐述了,可直接移步《Spring Boot | 第四章:日志管理》了解。本章节主要就探讨下常用的log4j2logback相关配置。

    整合log4j2

    log4j2log4j的升级版本,号称比第一版具有更高的性能,当然现在也慢慢被logback替代了。

    配置依赖

    0.移除SpringBoot默认的logback依赖包。由于我们直接引入了spring-boot-starter-web,所以直接排除了相应包。

    题外话:真正引入spring-boot-starter-logging包的是spring-boot-starter依赖,所以我们也可以直接在spring-boot-starter下排除即可。

    <!-- 排除logging -->
    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    或者

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
    1. 加入log4j2依赖。
            <!-- 引入log4j2 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-log4j2</artifactId>
            </dependency>
    

    配置文件

    按官网的说明,默认是支持XML, JSON, YAMLproperties格式。

    xml文件形式

    按SpringBoot官网的说明,我们命名一个log4j2-spring.xml文件作为默认的日志配置文件。

    自定义日志配置

    log4j2-spring.xml(本配置改造自:聊一聊log4j2配置文件log4j2.xml):

    <?xml version="1.0" encoding="UTF-8"?>
     <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
     <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
     <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
     <configuration status="WARN" monitorInterval="30">
         <!--先定义所有的appender-->
         <appenders>
         <!--这个输出控制台的配置-->
             <console name="Console" target="SYSTEM_OUT">
             <!--输出日志的格式-->
                 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             </console>
         <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
         <File name="log" fileName="log/test.log" append="false" >
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
         </File>
         <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
             <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
                          filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
                 <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->        
                 <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
                 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
                 <Policies>
                     <TimeBasedTriggeringPolicy/>
                     <SizeBasedTriggeringPolicy size="100 MB"/>
                 </Policies>
             </RollingFile>
             <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"
                          filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
                 <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
                 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
                 <Policies>
                     <TimeBasedTriggeringPolicy/>
                     <SizeBasedTriggeringPolicy size="100 MB"/>
                 </Policies>
             <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
                 <DefaultRolloverStrategy max="20"/>
             </RollingFile>
             <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"
                          filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
                 <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
                 <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
                 <Policies>
                     <TimeBasedTriggeringPolicy/>
                     <SizeBasedTriggeringPolicy size="100 MB"/>
                 </Policies>
             </RollingFile>
         </appenders>
         <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
         <loggers>
             <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
             <logger name="org.springframework" level="INFO"></logger>
             <logger name="org.mybatis" level="INFO"></logger>
             <!-- 自定义包下设置为INFO,则可以看见输出的日志不包含debug输出了 -->
             <logger name="cn.lqdev.learning" level="INFO"/>
             <root level="all">
                 <appender-ref ref="Console"/>
                 <appender-ref ref="RollingFileInfo"/>
                 <appender-ref ref="RollingFileWarn"/>
                 <appender-ref ref="RollingFileError"/>
             </root>
         </loggers>
     </configuration>
    

    我觉得这个配置步骤就是:先配置appenders,按需求进行个性化配置,如按天记录等等,然后可以使用logger个性化配置一些包的level日志等级,最后配置下rootappender

    properties文件形式

    从官网文档获悉,从2.4版本后才提供了通过配置文件的支持,这使用时要注意。详细使用语法可查看官网:Configuration with Properties,这里以官网的例子简单说明下:

    # log4j2内部自身的日志级别
    status = error
    # 配置日志信息输出到哪里:err表示作为标准错误输出,还可以是一个文件路径或者一个URL
    dest = err
    # 配置名称
    name = PropertiesConfig
    
    # 自定义属性名称,以便在之后的配置中使用,如${filename} 
    property.filename = target/rolling/rollingtest.log
     
    # 级别过滤(过滤日志记录) 
    filter.threshold.type = ThresholdFilter
    # 只记录debug级别以上的日志,大小写都可以
    filter.threshold.level = debug
    
    # 控制台类型的日志输出源 
    appender.console.type = Console
    # 名称 :唯一
    appender.console.name = STDOUT
    # 布局类型
    appender.console.layout.type = PatternLayout
    # 输出模板格式 这是springboot
    appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID:-} [%15.15t] %C{1.} [%t]: %m%n
    # 过滤级别 ThresholdFilter:低于级别的不输出
    appender.console.filter.threshold.type = ThresholdFilter
    # 记录日志的级别
    appender.console.filter.threshold.level = info
     
     # 滚动文件,会根据配置如文件大小或者时间自动生成一个新文件
    appender.rolling.type = RollingFile
    appender.rolling.name = RollingFile
    # 日志文件名称
    appender.rolling.fileName = ${filename}
    # 日志回滚的文件命名规则
    appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yyyy}-%i.log.gz
    appender.rolling.layout.type = PatternLayout
    # 输出格式
    appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
    # 滚动日志的策略,即设置何时新建日志文件输出日志
    appender.rolling.policies.type = Policies
    # 设置时间 
    appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
    # 指定多久滚动一次 单位跟着filePattern配置精度最后一位 ,这里就是2秒了
    appender.rolling.policies.time.interval = 2
    appender.rolling.policies.time.modulate = true
    # 日志文件的大小 
    appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
    # 为了测试设置小一点
    appender.rolling.policies.size.size=1kb
    
    ##  还有其他的触发条件如:CronTriggeringPolicy 按Cron表达式进行的 具体使用可自行搜索
    
    # 指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的
    appender.rolling.strategy.type = DefaultRolloverStrategy
    # 最多5个文件,其实还是看filePattern的i的值,当大于5后,就会自动覆盖了
    appender.rolling.strategy.max = 5
     
    rootLogger.level = info
    rootLogger.appenderRef.stdout.ref = STDOUT
    
    

    此处需要额外设置配置文件属性值(logging.config),本地测试时,就目录rolling会生成文件,但里面是空的。加上后就正常了:

    logging.config=classpath:log4j2.properties
    

    题外话:设置完,对properties配置规则还是不太了解。。感觉怎么配好像都可以输出,还望有网友能分享下具体的配置规则。对比完,还是觉得xml格式比较直观也容易理解。

    其他格式

    按官网说明,还可以以jsonyml格式进行配合,但需要加入相应依赖。

    格式 依赖包 文件名
    YAML com.fasterxml.jackson.core:jackson-databindcom.fasterxml.jackson.dataformat:jackson-dataformat-yaml log4j2.yamllog4j2.yml
    JSON com.fasterxml.jackson.core:jackson-databind log4j2.jsonlog4j2.jsn

    按需要添加相应依赖包即可。这里就不细说了。

    格式化符号说明

    对于格式化输出时,会看见有不同的格式化符号,起初看了也是一头雾水,下面搜索相关资料后进行简单整理归纳下。

    题外话:SpringBoot默认的log4j2配置文件在:spring-boot-1.5.15.RELEASE.jar/org/springframework/boot/logging/log4j2/log4j2.xml

    具体官网有说明:http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout

    ######### 常见参数 #########
    //
    %c{参数} 或 %logger{参数}  ##输出日志名称
    %C{参数} 或 %class{参数    ##输出类型
    %d{参数}{时区te{参数}{时区} ##输出时间,如:%d{yyyy-MM-dd HH:mm:ss, SSS}
    %F|%file                  ##输出文件名
    highlight{pattern}{style} ##高亮显示
    %l  ##输出错误的完整位置
    %L  ##输出错误行号
    %m 或 %msg 或 %message ##输出错误信息
    %M 或 %method ##输出方法名
    %n            ##输出换行符
    %level{参数1}{参数2}{参数3} ##输出日志的级别
    %t 或 %thread              ##创建logging事件的线程名
    */
    
    ######### 特殊符号 ############
    #有些特殊符号不能直接打印,需要使用实体名称或者编号
    //
    & —— &amp; 或者 &#38;
    < —— &lt;  或者 &#60;
    > —— &gt;  或者 &#62;
    “ —— &quot; 或者 &#34;
    ‘ —— &apos; 或者 &#39;
    */
    
    ######## pattern对齐修饰 ##########
    
    // 对齐修饰,可以指定信息的输出格式,如是否左对齐,是否留空格等。
    ## 编写格式为在任何pattern和%之间加入一个小数,可以是正数,也可以是负数。
    ## 整数表示右对齐,负数表示左对齐;
    ## 整数位表示输出信息的最小n个字符,如果输出信息不够n个字符,将用空格补齐;
    ## 小数位表示输出信息的最大字符数,如果超过n个字符,则只保留最后n个字符的信息
    ## (注意:保留的是后20个字符,而不是前20个字符)
    */
    
    #示例如下
    //
    
    %20 —— 右对齐,不足20个字符则在信息前面用空格补足,超过20个字符则保留原信息
    %-20 —— 左对齐,不足20个字符则在信息后面用空格补足,超过20个字符则保留原信息
    %.30 —— 如果信息超过30个字符,则只保留最后30个字符
    %20.30 —— 右对齐,不足20个字符则在信息前面用空格补足,超过30个字符则只保留最后30个字符
    %-20.30 —— 左对齐,不足20个字符则在信息后面用空格补足,超过30个字符则只保留最后30个字符
    
    

    多环境配置

    可直接通过多环境配置文件,设置logging.config的值,如
    application-test.properties

    logging.config=classpath:log4j2-test-spring.xml
    

    application-prod.properties

    logging.config=classpath:log4j2-prod-spring.xml
    

    整合logback

    logback是由log4j创始人设计的又一个开源日志组件。同时也是SpringBoot默认记录日志的框架。

    xml形式

    由于默认就是使用logback,所以只需要配置一个logback-spring.xml文件在resources目录即可,会自动识别的。

    logback-spring.xml(修改自:logback.xml详解):

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="false">
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
        <property name="LOG_HOME" value="/home" />
        <!-- 控制台输出 -->
        <appender name="STDOUT"
            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>
            </encoder>
        </appender>
        <!-- 按照每天生成日志文件 -->
        <appender name="FILE"
            class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名 -->
                <FileNamePattern>${LOG_HOME}/TestoKong.log.%d{yyyy-MM-dd}.log
                </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>
            </encoder>
            <!--日志文件最大的大小 -->
            <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <MaxFileSize>10MB</MaxFileSize>
            </triggeringPolicy>
        </appender>
    
        <!-- 自定义包下设置为INFO,则可以看见输出的日志不包含debug输出了 -->
        <logger name="cn.lqdev.learning" level="INFO" />
        
        <!-- 日志输出级别 -->
        <root level="INFO">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE" />
        </root>
    </configuration>
    

    多环境配置:springProfile

    使用扩展属性 springProfilespringPropertylogback-spring.xml 配置实现多环境配置的效果。

        <!-- 生产环境生效 -->
        <springProfile name="prod">
            <root level="error">
                <appender-ref ref="STDOUT" />
                <appender-ref ref="FILE" />
            </root>
        </springProfile>
    
    
        <!-- 测试和开发环境日志级别为INFO/并且记录日志文件 -->
        <springProfile name="dev,test">
            <!-- 日志输出级别 -->
            <root level="INFO">
                <appender-ref ref="STDOUT" />
                <appender-ref ref="FILE" />
            </root>
        </springProfile>
    

    springProfile还支持读取Spring Environment的属性值

    <!-- 读取 spring.application.name 属性来生成日志文件名
        scope:作用域
        name:在 logback-spring.xml 使用的键
        source:application.properties 文件中的键
        defaultValue:默认值
     -->
    <springProperty scope="context" name="logName" source="spring.application.name" defaultValue="myapp.log"/>
    

    之后就可以直接使用${logName}获取到变量值了。

    logback格式化符号说明

    log4j2类似,具体可去官网查看:PatternLayout

    • %m:输出代码中指定的消息
    • %p:输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
    • %r:输出自应用启动到输出该log信息耗费的毫秒数
    • %c:输出所属的类目,通常就是所在类的全名
    • %t:输出产生该日志事件的线程名
    • %n:输出一个回车换行符,Windows平台为“ ”,Unix平台为“ ”
    • %d:输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
    • %l:输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlogback.main(TestLogback.java:10)

    题外话:SpringBoot默认的logback配置文件在:spring-boot-1.5.15.RELEASE.jar/org/springframework/boot/logging/logback/defaults.xml

    参考资料

    关于详细属性配置,大家可以自行搜索下。以下是编写此文时,参考的一些网站信息。

    1. https://docs.spring.io/spring-boot/docs/1.5.15.RELEASE/reference/htmlsingle/#boot-features-logging

    2. http://logging.apache.org/log4j/2.x/manual/configuration.html

    3. https://www.cnblogs.com/wang1024/p/7786916.html

    4. http://blog.51cto.com/11931236/2058708

    5. https://www.cnblogs.com/hafiz/p/6170702.html

    6. https://logback.qos.ch/manual/

    总结

    本文主要是简单介绍了日志相关知识点,同时对于常用的log4j2logback相关配置进行了简单介绍。对于详细的配置信息,可去官网查阅下。另外,对于日志而言,不是越多越好,毕竟日志输出是会有性能损坏的。个人是建议,记录该记录的,保留事故现场的及一些错误都是需要进行日志记录的。而像一些无意义的输出,本身就是多余的。最后,不要随意打日志!打印日志时也注意不能用字符串拼接,需要使用占位符或者先判断日志级别!不要让日志拖慢了你的系统!下一章节,主要会介绍下利用AOP实现统一的访问日志管理。

    最后

    目前互联网上很多大佬都有SpringBoot系列教程,如有雷同,请多多包涵了。本文是作者在电脑前一字一句敲的,每一步都是自己实践和理解的。若文中有所错误之处,还望提出,谢谢。

    老生常谈

    • 个人QQ:499452441
    • 微信公众号:lqdevOps

    公众号

    个人博客:http://blog.lqdev.cn

    完整示例:https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-23

    原文地址:http://blog.lqdev.cn/2018/08/22/springboot/chapter-twenty-three/

  • 相关阅读:
    EJB 笔记
    设计模式
    go 笔记
    破解ssl pinning 抓APP的https数据包
    python读取、写入csv文件
    Python中用正则匹配手机号码
    苹果手机安装charles证书
    mysql在表中插入一个字段
    Python递归调用自己的函数
    mysql查询语句
  • 原文地址:https://www.cnblogs.com/okong/p/springboot-twenty-three.html
Copyright © 2011-2022 走看看