当前位置: 首页 > article >正文

浅谈spring 后端项目配置logback日志

日志

Java boy 后端项目日志一般用 logback or Log4j & Log4j2,spring 默认集成logback,本文主要以logback 展开例子说明。
对于日志系统有什么样的需求?
1、本地环境需要打印Console日志。
2、测试环境最好实时打印日志。
3、生产环境打印日志不要阻塞系统(日志阻塞导致很多故障,特别是流量大的场景,小流量可以忽略)
4、可以实时修改,有些日志不关注,需要隔离一下。
5、分离日志…ERROR  ALL  not care…
… 等等信息。

日志需求分析

“小小”《环境》

现实开发场景中,很多都需要有环境的概念,redis 预发和生产 prefix key 不同.
test 环境和生产环境的调用的接口不同…  env=test env=prod 等等配置标识。

但是这些都不是非常的规范,在Spring Boot中,spring.profiles.active是一个非常重要的配置属性,它用于指定当前激活的配置文件(profiles)。通过这个属性,你可以控制应用程序在不同环境下的行为,例如开发、测试和生产环境。 SpringBoot激活profiles你知道几种方式?

  • application.properties
spring.profiles.active=dev
  • 系统参数
export SPRING_PROFILES_ACTIVE=dev
  • 命令行参数
java -jar your-application.jar --spring.profiles.active=prod

通过配置中心注入系统环境或者属性进行配置(放在公共配置,多应用统一使用),或者统一运维的部署脚本中指定,通过标准化的路径实现环境标准化,无需自定义。

环境隔离日志配置

这个是 logback-spring.xml 里面的配置
非生产、非预发、非测试 非开发环境打印console

springProfile 灵活的配置,可以让开发处理多环境的配置信息非常easy

 <springProfile name="!prod,!pre">
        <root level="INFO">
            <appender-ref ref="APPLICATION"/>
            <appender-ref ref="FILE_ERROR"/>
            <!--本地环境打印console 日志-->
            <springProfile name="!test,!dev">
                <appender-ref ref="CONSOLE"/>
            </springProfile>
        </root>
    </springProfile>

日志阻塞

之前见过很多系统由于日志阻塞导致系统功能受影响,响应耗时增加,这样的例子非常多。常见的场景的处理方式是配置为异步日志。 logback之 AsyncAppender 的原理、源码及避坑建议
在普通的日志RollingFileAppender 基础上包装一个异步日志 ,如下配置。

<appender name="APPLICATION" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>${PATTERN}</pattern>
        </encoder>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 路径 -->
            <fileNamePattern>logs/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
</appender>
<appender name="ASYNC_APPLICATION" class="ch.qos.logback.classic.AsyncAppender">
            <neverBlock>true</neverBlock>
            <queueSize>5120</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <includeCallerData>true</includeCallerData>
            <appender-ref ref="APPLICATION"/>
</appender>

异步日志,由于打印日志是异步的,导致测试环境跟踪的时候查看日志非实时写文件的,用起来非常恼火,特别是调试的时候,测试环境是否可以非异步的?
通过上面介绍的spring环境隔离即可完成,如下配置。

   <!--    prod 和 pre 进行异步日志-->
    <springProfile name="prod,pre">
        <appender name="ASYNC_APPLICATION" class="ch.qos.logback.classic.AsyncAppender">
            <neverBlock>true</neverBlock>
            <queueSize>5120</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <includeCallerData>true</includeCallerData>
            <appender-ref ref="APPLICATION"/>
        </appender>
        <root level="INFO">
            <appender-ref ref="ASYNC_APPLICATION"/>
        </root>
    </springProfile>
  
     <!--test 环境和本地 不进行异步日志-->
    <springProfile name="!prod,!pre">
        <root level="INFO">
            <appender-ref ref="APPLICATION"/>
            <!--本地环境打印console 日志-->
            <springProfile name="!test,!dev">
                <appender-ref ref="CONSOLE"/>
            </springProfile>
        </root>
    </springProfile>

怎么判断异步日志是否配置OK? debug ?arthas 也行?
查看一下异步日志的实例是否存在

[arthas@34932]$ vmtool -x  1 --action getInstances --className ch.qos.logback.classic.AsyncAppender  --limit 5
@AsyncAppender[][
    @AsyncAppender[ch.qos.logback.classic.AsyncAppender[ASYNC_LOG_FILE_OKHTTP]],
    @AsyncAppender[ch.qos.logback.classic.AsyncAppender[ASYNC_LOG_FILE_MIDDLEWARE]],
    @AsyncAppender[ch.qos.logback.classic.AsyncAppender[ASYNC_ERROR]],
    @AsyncAppender[ch.qos.logback.classic.AsyncAppender[ASYNC_APPLICATION]],
]

logback 配置文件不推荐放在配置中心

配置文件和源码放在一起,通过环境变量区分不同环境的处理方式比较好,方便修改
某些场景需要隐藏某些日志,放在配置中心非常不方便,修改起来也非常麻烦,修改错误了也不知道,只有发布的时候才能感知。
eg: kafka的日志不要放在all 日志里面,需要在线日志系统订阅关键的业务日志信息,减少费用。

<logger name="org.apache.kafka" level="INFO" additivity="false">
        <appender-ref ref="LOG_FILE_MIDDLEWARE"/>
</logger>

eg: 我要禁用日志 ,这种想法可能跟随者业务需求进行变化。

 <logger name="org.redisson.connection.DNSMonitor" level="OFF"/>

分离日志

  • additivity=“false”  不加入总日志信息
  • error 日志分离
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application_error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${PATTERN}</pattern>
        </encoder>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 路径 -->
            <fileNamePattern>logs/application_error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
</appender>

总结

日志系统平常开发过程中经常遇到,日志打印刷屏、日志太多、日志治理等发生在日常的开发过程中,养成一个好的习惯,好的日志更快速的排查到问题。
线上环境error日志重点关注,前提是error日志要少,如果一个error一天几百个G,会有人看?

附上完整日志配置

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
  
    <property name="PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}]  %X{method} %-5level [%thread] [%logger:%line] :%m %n"/>
  
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 采用Spring boot中默认的控制台彩色日志输出模板 -->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
  
    <appender name="APPLICATION" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>${PATTERN}</pattern>
        </encoder>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 路径 -->
            <fileNamePattern>logs/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
    </appender>
  
  
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application_error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${PATTERN}</pattern>
        </encoder>
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 路径 -->
            <fileNamePattern>logs/application_error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>3</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
  
    <appender name="LOG_FILE_OKHTTP" class="ch.qos.logback.core.rolling.RollingFileAppender" additivity="false">
        <file>logs/application_okhttp.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>logs/application_okhttp.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>2</maxHistory>
            <totalSizeCap>2GB</totalSizeCap>
        </rollingPolicy>
        <!-- 格式化输出 -->
        <encoder>
            <pattern>${PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
  
    <appender name="LOG_FILE_MIDDLEWARE" class="ch.qos.logback.core.rolling.RollingFileAppender" additivity="false">
        <immediateFlush>false</immediateFlush>
        <file>logs/application_middleware_client.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>logs/application_middleware_client.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>1GB</maxFileSize>
            <maxHistory>2</maxHistory>
            <totalSizeCap>2GB</totalSizeCap>
        </rollingPolicy>
        <!-- 格式化输出 -->
        <encoder>
            <pattern>${PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
  
  
    <logger name="okhttp3.OkHttpClient" level="INFO" additivity="false">
        <appender-ref ref="LOG_FILE_OKHTTP"/>
    </logger>
  
    <logger name="org.apache.kafka" level="INFO" additivity="false">
        <appender-ref ref="LOG_FILE_MIDDLEWARE"/>
    </logger>
    <logger name="org.apache.zookeeper" level="INFO" additivity="false">
        <appender-ref ref="LOG_FILE_MIDDLEWARE"/>
    </logger>
    <logger name="org.apache.curator" level="INFO" additivity="false">
        <appender-ref ref="LOG_FILE_MIDDLEWARE"/>
    </logger>
  
    <!--    prod 和 pre 进行异步日志-->
    <springProfile name="prod,pre">
        <appender name="ASYNC_APPLICATION" class="ch.qos.logback.classic.AsyncAppender">
            <neverBlock>true</neverBlock>
            <queueSize>5120</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <includeCallerData>true</includeCallerData>
            <appender-ref ref="APPLICATION"/>
        </appender>
        <appender name="ASYNC_ERROR" class="ch.qos.logback.classic.AsyncAppender">
            <neverBlock>true</neverBlock>
            <queueSize>5120</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <includeCallerData>true</includeCallerData>
            <appender-ref ref="FILE_ERROR"/>
        </appender>
        <appender name="ASYNC_LOG_FILE_MIDDLEWARE" class="ch.qos.logback.classic.AsyncAppender">
            <neverBlock>true</neverBlock>
            <queueSize>1024</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <includeCallerData>false</includeCallerData>
            <appender-ref ref="LOG_FILE_MIDDLEWARE"/>
        </appender>
        <appender name="ASYNC_LOG_FILE_OKHTTP" class="ch.qos.logback.classic.AsyncAppender">
            <queueSize>1024</queueSize>
            <discardingThreshold>20</discardingThreshold>
            <neverBlock>true</neverBlock>
            <includeCallerData>false</includeCallerData>
            <appender-ref ref="LOG_FILE_OKHTTP"/>
        </appender>
        <root level="INFO">
            <appender-ref ref="ASYNC_APPLICATION"/>
            <appender-ref ref="ASYNC_ERROR"/>
        </root>
    </springProfile>
  
    <!--test 环境和本地 不进行异步日志-->
    <springProfile name="!prod,!pre">
        <root level="INFO">
            <appender-ref ref="APPLICATION"/>
            <appender-ref ref="FILE_ERROR"/>
            <!--本地环境打印console 日志-->
            <springProfile name="!test,!dev">
                <appender-ref ref="CONSOLE"/>
            </springProfile>
        </root>
    </springProfile>
  
    <!-- 日志通过系统环境变量配置spring active: export SPRING_PROFILES_ACTIVE=dev
     https://blog.csdn.net/weixin_42033269/article/details/102805546 -->
  
</configuration>

http://www.kler.cn/news/316730.html

相关文章:

  • 无人机之4G模块的主要功能和优势
  • 华为HarmonyOS地图服务 1 -- 如何实现地图呈现?
  • Flask高级特性实战
  • 字符串反转
  • 【kafka-04】kafka线上问题以及高效原理
  • HarmonyOS鸿蒙开发实战(5.0)网格元素拖动交换案例实践
  • Go语言并发编程之sync包详解
  • 前后端分离,使用MOCK进行数据模拟开发,让前端攻城师独立于后端进行开发
  • 【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
  • Kotlin高阶函数func
  • 计算机毕业设计 美妆神域网站的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 一对一视频通话软件Call-Me
  • 某采招网爬虫数据采集逆向
  • 医学数据分析实训 项目四 回归分析--预测帕金森病病情的严重程度
  • I.MX6U裸机-C语言版LED灯实验
  • ld-linux-x86-64.so.2
  • git 操作远程别名
  • tcpdump使用方法
  • 24. Revit API: 几何对象(五)- (Sur)Face
  • [Linux]Vi和Vim编辑器
  • 修改Git配置信息:用户名
  • linux第三课(linux中安装nginx与redis及SpringBoot集成redis)
  • 颍川陈氏——平民崛起的典范
  • 【AcWing】基础算法
  • Django 数据库配置以及字段设置详解
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——14.AVL树
  • C++(学习)2024.9.20
  • 【Kubernetes】常见面试题汇总(二十五)
  • 基于安全风险预测的自动驾驶自适应巡航控制优化
  • 智能BI项目第一期