日志规范

1.基本原则

  • 不影响系统正常运行
  • 不允许出现安全问题
  • 日志可供开发人员定位问题的真正原因
  • 日志可供监控系统自动监控与分析

2.日志级别

  • ERROR:影响系统正常运行,影响业务正常运行,明确需要人工干预。比如:数据库不可用,关键业务流程中断等等
  • WARN:发生这个级别问题时,处理过程可以继续,但必须对这个问题给予额外关注。这个问题又可以细分成两种情况:一种是存在严重的问题但有应急措施(比如数据库不可用,使用Cache);第二种是潜在问题及建议(ATTENTION),比如生产环境的应用运行在Development模式下、管理控制台没有密码保护等。系统可以允许这种错误的存在,但必须及时做跟踪检查
  • INFO:重要的业务处理已经结束。在实际环境中,系统管理员或者高级用户要能理解INFO输出的信息并能很快的了解应用正在做什么。比如,一个和处理机票预订的系统,对每一张票要有且只有一条INFO信息描述 “[Who] booked ticket from [Where] to [Where]”。另外一种对INFO信息的定义是:记录显著改变应用状态的每一个action,比如:数据库更新、外部系统请求
  • DEBUG:用于开发人员使用。将在TRACE章节中一起说明这个级别该输出什么信息。
  • TRACE:非常具体的信息,只能用于开发调试使用。部署到生产环境后,这个级别的信息只能保持很短的时间。这些信息只能临时存在,并将最终被关闭。要区分DEBUG和TRACE会比较困难,对一个在开发及测试完成后将被删除的LOG输出,可能会比较适合定义为TRACE级别。

3.日志对性能的影响

  • 如何创建Logger实例:对于可以预见的多数情况下单例运行的class,可以不添加static前缀;对于可能是多例居多,尤其是需要频繁创建的class,我们要求要添加static前缀
  • 判断日志级别:对于可以预见的会频繁产生的日志输出,比如for、while循环,定期执行的job等,建议先使用if对日志级别进行判断后再输出。对于日志输出内容需要复杂的序列化,或输出的某些信息获取成本较高时,需要对日志级别进行判断。比如日志中需要输出用户名,而用户名需要在日志输出时从数据库获取,此时就需要先判断一下日志级别,看看是否有必要获取这些信息。
  • 优先使用参数,减少字符串拼接:使用参数的方式输出日志信息,有助于在性能和代码简洁之间取得平衡。当日志级别限制输出该日志时,参数内容将不会融合到最终输出中,减少了字符串的拼接,从而提升执行效率。

4.什么时候应该打印日志

  • 系统初始化:系统初始化时会依赖一些关键配置,根据参数不同会提供不一样的服务。将系统的启动参数记录INFO日志,打印出参数以及启动完成态服务表述。
  • 业务流程与预期不符:项目代码中结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确,数据处理问题导致返回码不在合理范围内等等
  • 系统核心的关键动作:系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录INFO级别日志,比如电商系统用户从登录到下单的整个流程;微服务各服务节点交互;核心数据表增删改等等。
  • 系统异常:这类捕获的异常是系统告知开发人员需要加以关注的,是质量非常高的报错。应当适当记录日志,根据实际结合业务的情况使用warn或者error级别。

5.建议

  • 使用参数化信息的方式:
    1
    logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);
  • 使用[]进行参数变量隔离,如有参数变量,应该写成如下写法:
    1
    2
    //可读性更好,对于排查问题更有帮助。
    logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);
  • 禁用System.out.println 不要直接使用System.out或System.err 输出日志,也不允许使用 STDOUT、STDERR 作为Logger名字
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //错误
    System.out.print( "do something. . .");
    System.err.print("do something. . .");
    //错误
    STDOUT.info( "do something. . .");
    STDERR.info( "do something. . . ");
    //正确
    logger.info( "do something. . . ");
    logger.error( "do something.. .");
  • 对于else 是非正常的情况,需要根据情况选择打印warn 或 error 日志。对于只有 if 没有 else 的地方,如果 else 的路径是不可能的,应当加上 else 语句,并打印 error 日志。
    1
    2
    3
    4
    5
    if(true){
    //do something
    }else {
    logger.error("It is impossible. . .");
    }
  • 不打无意义的日志,不记录对于排查故障毫无意义的日志信息,日志信息一定要带有业务信息
    1
    2
    3
    4
    //错误
    logger.error( "Consume message failed !! ! ");
    //正确
    logger.error("Consume message failed, msgId=, ", id);
  • 不推荐字符串拼接,如果信息本身需要计算或合并的,打印前要对isxxxEnable()方法进行判断。这是因为在WARN级别时,即使INFO信息不打印,也会执行字符串拼接,造成资源浪费。实际上,不推荐使用字符串拼接的方式打印日志,可读性和可维护性都比较差。建议使用占位符
1
2
3
4
5
6
7
8
//错误
if (logger.isInfoEnabled()){
logger.info( "Push message success,id=" + id + ",msg=" +msg);
}
//错误
logger.warn("Push message failed,id=" + id + ",msg=" + msg + " ,reason="+ response.getReason());
//正确
logger.warn("Push message failed,id={},msg={},reason={}",id,msg,response.getReason());
  • 循环体内不要打印info日志
    1
    2
    3
    4
    5
    6
    for (Message message : messages) {
    if ( response.isSuccess()){
    //错误
    logger.info("Message sends successfully,msgId={}", message.getId());
    }
    }
  • 打印日志的代码任何情况下都不允许失败,一定要确保不会因为Log语句的问题而抛出异常造成中断。如下,如果request为null,就会抛空指针异常
    1
    logger.error( "execute failed,id:{}",request.getId());
  • 重要方法入口建议记录方法调用、入参、返回值,对于排查问题会有很大帮助。注解应该可实现,后续调研
    1
    2
    3
    4
    5
    6
    public Response consume(Message msg) {
    logger.debug("Prepare to consume a message,msgId={}, content={}" , msg.getId(), msg.getContent());
    Response response = messageService.send(msg);
    logger.debug("Consume result:{},status code:{}", response.isSuccess(), response.getCode());
    return response;
    }
  • 异常情况,catch中的异常记录必须打印堆栈信息,不要用e.printStackTrace()
    1
    2
    3
    4
    5
    6
    7
    8
    try {
    //do something
    }catch (Exception e){
    //正确
    logger.error( "something wrong", e);
    //错误
    e.printStackTrace();
    }
  • 不要记录日志后又抛出异常。抛出去的异常,一般外层会处理。如果不处理,那为什么还要抛出去?另外一个原则是,无论是否发生异常,都不要在不同地方重复记录针对同一事件的日志消息
1
2
3
4
5
6
try {
//do something
}catch (Exception e){
logger.error( "something wrong", e);
throw e;
}
  • 输出Exceptions的全部Throwable信息。否则会丢失最重要的堆栈信息。
    1
    2
    3
    4
    5
    6
    7
    8
    try {
    //do something
    } catch (Exception e){
    //错误
    logger.error( "Invoke causes a exception:{}", e.getMessage());
    //正确
    logger.error( "Invoke causes a exception:{}", e);
    }
  • 组件间交互接口上,建议增加日志输出,以方便异常情况下的排查

5.统一logback配置

  • logback.xml—->engine
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    <configuration scan="true" scanPeriod="10 seconds" debug="false">
    <!-- 日志最大的历史 -->
    <property name="MAX_HISTORY" value="30"/>
    <!-- 组件名称 -->
    <property name="MODULE_NAME" value="engine"/>
    <!-- 日志文件目录 -->
    <property name="DIR" value="logs"/>
    <!-- 日志文件大小上限 -->
    <property name="MAX_FILE_SIZE" value="100MB"/>

    <!-- 开启JMX管理日志 -->
    <jmxConfigurator />
    <!-- 输出到控制台 -->
    <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
    <!-- 输出格式 -->
    <pattern>
    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{traceId} - %msg%n
    </pattern>
    </encoder>
    </appender>

    <!-- error级别单独记录 -->
    <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}-error.log</file>
    <!-- 以day为单位自动回滚 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}-error/${MODULE_NAME}-error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!-- error级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>
    </appender>

    <!-- warn级别单独记录 -->
    <appender name="warnAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}-warn.log</file>
    <!-- 以day为单位自动回滚 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}-warn/${MODULE_NAME}-warn-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!-- error级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>WARN</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>
    </appender>

    <!-- debug级别单独记录 -->
    <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}-debug.log</file>
    <!-- 以day为单位自动回滚 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}-debug/${MODULE_NAME}-debug-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!-- error级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>DEBUG</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>
    </appender>

    <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}/${MODULE_NAME}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>INFO</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>-->
    </appender>

    <appender name="asyncSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="STDOUT" />
    </appender>

    <appender name="asyncErrorAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="errorAppender" />
    </appender>
    <appender name="asyncWarnAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="warnAppender" />
    </appender>
    <appender name="asyncInfoAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="infoAppender" />
    </appender>
    <appender name="asyncDebugAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="debugAppender" />
    </appender>

    <!-- 事件构建相关 -->
    <logger name="cn.com.bsfit.engine.core.retem" level="INFO" />
    <!-- 特征加载相关 -->
    <logger name="cn.com.bsfit.engine.core.load" level="INFO" />
    <!-- 规则执行相关 -->
    <logger name="cn.com.bsfit.engine.core.exec" level="INFO" />
    <!-- 模型执行相关 -->
    <logger name="cn.com.bsfit.engine.core.model" level="INFO" />
    <!-- 事件下发相关 -->
    <logger name="cn.com.bsfit.engine.core.mgr" level="INFO" />
    <!-- rest接口可以打印接收到的原始报文日志 -->
    <logger name="cn.com.bsfit.engine.core.web" level="INFO" />
    <!-- 流立方客户端查询相关 -->
    <logger name="cn.com.bsfit.sc.client.command" level="INFO" />

    <!-- 根,所有logger的祖先 -->
    <root level="INFO">
    <appender-ref ref="asyncSTDOUT" />
    <appender-ref ref="asyncErrorAppender" />
    <appender-ref ref="asyncWarnAppender" />
    <appender-ref ref="asyncInfoAppender" />
    <appender-ref ref="asyncDebugAppender" />
    </root>
    </configuration>
  • logback.xml—->mgr
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    <configuration>
    <!-- 日志最大的历史 -->
    <property name="MAX_HISTORY" value="30"/>
    <!-- 组件名称 -->
    <property name="MODULE_NAME" value="mgr"/>
    <!-- 日志文件目录 -->
    <property name="DIR" value="logs"/>
    <!-- 日志文件大小上限 -->
    <property name="MAX_FILE_SIZE" value="100MB"/>

    <!-- 开启JMX管理日志 -->
    <jmxConfigurator />
    <!-- 输出到控制台 -->
    <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
    <!-- 输出格式 -->
    <pattern>
    %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{traceId} - %msg%n
    </pattern>
    </encoder>
    </appender>

    <!-- error级别单独记录 -->
    <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}-error.log</file>
    <!-- 以day为单位自动回滚 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}-error/${MODULE_NAME}-error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!-- error级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>
    </appender>

    <!-- warn级别单独记录 -->
    <appender name="warnAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}-warn.log</file>
    <!-- 以day为单位自动回滚 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}-warn/${MODULE_NAME}-warn-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!-- error级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>WARN</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>
    </appender>

    <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${DIR}/${MODULE_NAME}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${DIR}/${MODULE_NAME}/${MODULE_NAME}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxHistory>${MAX_HISTORY}</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    <!-- or whenever the file size reaches 100MB -->
    <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} %X{traceId} - %msg%n</pattern>
    </encoder>
    <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>INFO</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
    </filter>-->
    </appender>

    <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="STDOUT" />
    </appender>

    <appender name="ASYNCerrorAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="errorAppender" />
    </appender>
    <appender name="ASYNCwarnAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="warnAppender" />
    </appender>
    <appender name="ASYNCinfoAppender" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 -->
    <discardingThreshold>0</discardingThreshold>
    <queueSize>512</queueSize>
    <appender-ref ref="infoAppender" />
    </appender>
    <!-- <logger name="com.netflix" level="INFO"/>-->
    <!-- <logger name="cn.com.bsfit.frms.engine" level="INFO"/>-->
    <!-- <logger name="cn.com.bsfit.frms.pay.engine.loader.mob" level="INFO"/> -->
    <!-- 根,所有logger的祖先 -->
    <root level="INFO">
    <appender-ref ref="ASYNCSTDOUT" />
    <appender-ref ref="ASYNCerrorAppender" />
    <appender-ref ref="ASYNCwarnAppender" />
    <appender-ref ref="ASYNCinfoAppender" />
    </root>
    </configuration>

日志规范
https://vegetablest.github.io/2021/02/19/日志规范/
作者
af su
发布于
2021年2月19日
许可协议