栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

详解Spring Boot下使用logback 记录多个文件日志

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解Spring Boot下使用logback 记录多个文件日志

背景

这两天遇到一个比较有意思的日志问题.

近期对我之前的python代码进行java的重构, 一方面是因为java使用的医疗库非常健全稳定, 可以商用. 另一方面是因为java速度快, 这个库的实现的效率也高, 性能是Python版本的好几倍.

但是作为这个项目的唯一作者, 我的癖好也成为这个项目的风格. 这个项目会给很多部署工程师使用. 当然项目的可用性和性能作为第一考虑的因素, 但是作为一个懒人, 对使用软件时候的复杂部署过程和混乱调试信息深恶痛绝. 所以我在项目中使用了高度可配置/易用和多文件日志.

说道多文件日志, 它的优点是每个日志只容纳自身的逻辑, 所以对于一般的入门开发者或者是初级运维工程师查看起来非常方便.

初步尝试

因为spring boot的配置一般来讲是application.properties, 但是同时开发者可以使用yml格式的配置, 二者相比, yml文件更为简洁. 熟读python之禅的我当然是简洁胜于冗余选择了yml.

发现spring-boot可以通过application.yml配置日志. 高兴的配置一番之后发现没法配置多个logger, 弃用! 改用logback-spring.xml(为什么不用logback.xml? 因为-spring这种文件可以获取到spring配置中的变量.下面再说)

第一次实现

我有好几个服务需要打日志. 一般来讲我的日志风格是 *.log 保存 INFO以上级别日志. *.err.log保存ERROR以上级别日志. 我如果每个文件日志都使用一个Appender的话, 配置文件太长了. 而且很难看, 不是我的风格.

Google了一下, 发现了这种方案:



  # 下面这一行的意思是使用application.yml中的global.log-dir变量
  
  
  # 这个是一个可以定义变量的Appender
  
    # 使用 LoggerNamebasedDiscriminator 这个类根据当前Logger获取变量
    
      general
    
    
      # 根据变量loggerName名字生成根据日期滚动的Appender
      
 
   ${LOG_DIR}/${loggerName}.log
 
 
   
     ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.log.gz
   
   15
 

 
   INFO
 

 
   %d{HH:mm:ss.SSS} %-5level - %msg%n
   
 
      

      
 ${LOG_DIR}/${loggerName}.err.log
 
   
     ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.err.log.gz
   
   15
 

 
   ERROR
 

 
   %d{HH:mm:ss.SSS} %-5level - %msg%n
   
 
      
    
  
  

  
  
    
  
  

下的是对应的 LoggerNamebasedDiscriminator 类

package com.utils.loggers;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.sift.AbstractDiscriminator;

public class LoggerNamebasedDiscriminator extends AbstractDiscriminator {
  private static final String KEY = "loggerName";
  private String defaultValue;

  public String getDefaultValue() {
    return defaultValue;
  }

  public void setDefaultValue(String defaultValue) {
    this.defaultValue = defaultValue;
  }
  # 这就是之所以xml里面可以引用loggerName变量的原因
  public String getKey() {
    return KEY;
  }

  public void setKey() {
    throw new UnsupportedOperationException("Key not settable. Using " + KEY);
  }

  public String getDiscriminatingValue(ILoggingEvent e) {
    String loggerName = e.getLoggerName();

    if (loggerName == null)
      return defaultValue;
    else {
      String[] split = loggerName.split("\.");
      return split[split.length - 1];
    }
  }
}

最开始我的日志里面没有报错信息, 正常的生成INFO日志. 但是后来发现事情好像不是想象的那样

问题出现

后来我把程序改成多线程. 发现所有涉及到多线程的服务日志里面都没信息了. Google半天, 发现几个令我震惊的真相:

  • 真相1: 所有滚动Appender都不支持异步追加 (其实也不是, 但是那种方式需要写死日志文件名, 不推荐, 不讲)
  • 真相2: SiftingAppender 内部最多嵌套一个Appender. 所以理论上我的ERROR的日志里面应该永远不会有内容.

问题解决

对于之前的两个问题, 分而治之.

不支持异步

再次谷歌(到这里读者基本上发现了我搬砖的本质), 发现有个Appender名字叫AsyncAppender, 这玩意是一个其他Appender的Wrapper. 说白了, 就是你打日志的命令是异步的, 放到队列里面, 而它真正的打日志的动作是一个单独的同步线程. 这就牛逼了, 使用这玩意收集我所有日志, 然后再转发给SiftingAppender 进行分发即可.

SiftingAppender 内部最多嵌套一个Appender

这个好办, 把INFO的Appender和ERROR的Appender拆开放到两个SiftingAppender里面就行了, 不过这样的话, 前面提到的的AsyncAppender 也要写两个.

最后, logback-spring.xml文件如下



  

  
  
    
    
    
      
 ${LOG_DIR}/${loggerName}.log
 
   
     ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.log
   
   15
 

 
   INFO
 

 
   %d{HH:mm:ss.SSS} %-5level - %msg%n
   
 
      
    
  
  
    
    
    
      
 ${LOG_DIR}/${loggerName}.err.log
 
   
     ${LOG_DIR}/${loggerName}.%d{yyyy-MM-dd}.err.log
   
   15
   50MB
 

 
   ERROR
 

 
   %d{HH:mm:ss.SSS} %-5level - %msg%n
   
 
      
    
  

  
  
    
    0
    
    512
    
    
  

  
  
    
    0
    
    512
    
    
  
  

  

  
    
  
  

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/140148.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号