Java项目日志记录方案

一、概述


1、采用slf4j作为日志API,采用logback作为日志输出工具,用slf4j桥接方式替换掉log4j和commons-logging。

2、采用trace(追踪)、debug(调试)、info(信息)、warn(警告)、error(错误)、fatal(致命)共6种日志级别。

3、采用dev(开发环境)、test(测试环境)、production(生产环境)等不同的日志配置,根据环境变量自动识别。

4、特殊的记录,需要大批量写入日志文件,应该采用异步线程写文件。


二、日志级别定义

    采用trace(追踪)、debug(调试)、info(信息)、warn(警告)、error(错误)、fatal(致命)共6种日志级别。


日志级别使用原则:

1、fatal(致命错误)使用原则

fatal为系统级别的异常,发生fatal错误,代表服务器整个或者核心功能已经无法工作了!!

1)在服务器启动时就应该检查,如果存在致命错误,直接抛异常,让服务器不要启动起来(启动了也无法正常工作,不如不启动)。

2)如果在服务器启动之后,发生了致命的错误,则记录fatal级别的错误日志,最好是同时触发相关的修复和告警工作(比如,给开发和维护人员发送告警邮件)。


2、error(错误)使用原则

error为功能或者逻辑级别的严重异常,发生error级别的异常,代表功能或者重要逻辑遇到问题、无法正常工作


3、warn(警告)使用原则

warn用在某些逻辑非常规,发生了一些小故障但是没有大的影响或者重要数据被修改,或者某些操作需要引起重视


4、info(信息)使用原则

info用于记录一些有用的、关键的信息,一般这些信息出现得不频繁只是在初始化的地方或者重要操作的地方才记录


5、debug(调试)使用原则

debug用于记录一些调试信息,为了方便查看程序的执行过程和相关数据、了解程序的动态


6、trace(跟踪)使用原则

trace用于记录一些更详细的调试信息,这些信息无需每次调试时都打印出来,只在需要更详细的调试信息时才开启。


7、项目稳定运行时的日志量

1)正常情况下,trace日志至少是debug日志的100倍,

trace级别的日志量  debug级别的日志量  >  100  1,

也就是说trace日志非常多,debug日志相对较少。


2)debug级别的日志量  info级别的日志量 > 1000  1,

也就是说正常情况下,info日志很少,只在部分重要位置会输出 info日志。


3)error日志和warn日志,正常情况下,几乎为0,当出现异常时,error日志和warn日志量 也在可控范围,不会超过debug级别的最大日志量。


三、日志输出(Appender)分类


分为5个一般类: 

    FILE_EXCEPTION (异常日志,包括ERROR和WARN)

    FILE_APP (应用日志,包括当前应用package下面的日志和DEBUG级别以上的其他日志)

    FILE_INFO (普通信息日志)

    FILE_DEBUG (调试日志)

    FILE_TRACE(追踪日志)

    SYSOUT(控制台输出,可以包括以上所有日志)

扩展类: 包括异步输出的日志,或者特殊业务日志。


举例说明:

假如 

当前应用的 Main Package 为 cn.zollty.lightning

ROOT_LEVEL为 trace,应用日志 LEVEL 为 debug

有以下日志打印:

1
2
3
4
5
6
7
8
9
10
11
12
13
Logger loggerA = LoggerFactory.getLogger(cn.zollty.lightning.Tests. class );
loggerA.trace( "--------" );
loggerA.debug( "--------" );
loggerA.info( "--------" );
loggerA.warn( "--------" );
loggerA.error( "--------" );
 
Logger loggerB = LoggerFactory.getLogger(org.apache.kafka.Consumer. class );
loggerB.trace( "--------" );
loggerB.debug( "--------" );
loggerB.info( "--------" );
loggerB.warn( "--------" );
loggerB.error( "--------" );

那么,异常日志(FILE_EXCEPTION)输出的为:

loggerA.warn("--------");

loggerA.error("--------");

loggerB.warn("--------");

loggerB.error("--------");

控制台(SYSOUT)输出日志的为;

loggerA.debug("--------");

loggerA.info("--------");

loggerA.warn("--------");

loggerA.error("--------");

loggerB.trace("--------");

loggerB.debug("--------");

loggerB.info("--------");

loggerB.warn("--------");

loggerB.error("--------");

应用日志(FILE_APP)输出的为:

loggerA.debug("--------");

loggerA.info("--------");

loggerA.warn("--------");

loggerA.error("--------");

loggerB.info("--------");

loggerB.warn("--------");

loggerB.error("--------");


2、历史日志文件

异常日志(error和warn)最多保存 9000 M(生产,测试)

app日志最多保存 9000 M (生产,测试)

trace日志最多保存 1000 M (仅供测试用,一般不用)

debug、info日志最多保存 5000 M(一般不用,用app日志就够了)


四、各环境默认日志定义


开发环境

1)默认日志级别定义为:

    app包为TRACE级别。日志的ROOT Level为DEBUG级别。

2)

启用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。


测试环境

1)默认日志级别定义为:

    app包为DEBUG级别。日志的ROOT Level为DEBUG级别。

2)

禁用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。


生产环境

1)默认日志级别定义为:

    app包为DEBUG级别。日志的ROOT Level为INFO级别。

2)

禁用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。


五、根据环境自动选择日志配置(借助Logback


关键点1:使用logback的环境变量定义和读取功能

例如下面的各种环境变量定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
< property  name = "DEPLOY_ENV"  value = "${deploy.env:-dev}"  />
 
< property  name = "LOG_HOME"  value = "${catalina.base:-.}/logs"  />
 
< property  name = "LOG_MAX_SIZE"  value = "100MB"  />
< property  name = "LOG_COMMON_PATTERN"  value = "%d{HH:mm:ss.SSS} [%thread] [%level] %logger - %msg%n"  />
< property  name = "LOG_DEV_PATTERN"  value = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{48}:%line - %msg%n"  />
 
< property  name = "ROOT_LEVEL"  value = "${log.root.level:-DEBUG}"  />
 
< property  name = "APP_LEVEL"  value = "${log.app.level:-TRACE}"  />
< property  name = "APP_PACKAGE"  value = "cn.zollty.lightning"  />

其中 ${deploy.env:-dev} 代表的意思是,如果环境变量中没有 deploy.env,则使用默认值dev。


一个小技巧:可以自定义类似下面这个类,在logback初始化之前,先设置变量的值:

1
< statusListener  class = "cn.zollty.commons.logbackext.InitConfigOnConsoleStatusListener"  />

这个类继承自ch.qos.logback.core.status.OnConsoleStatusListener。


关键点2:使用logback的 if-then 条件语法

1
2
3
4
5
6
7
8
9
10
11
12
< root  level = "${ROOT_LEVEL}" >
  
   < appender-ref  ref = "FILE_EXCEPTION" />
  
   < appender-ref  ref = "FILE_APP" />
 
   < if  condition = 'p("DEPLOY_ENV").contains("dev")' >
     < then >
     < appender-ref  ref = "STDOUT"  />
     then >
   if >
root >


参考配置:

logback.xml:

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
xml  version = "1.0"  encoding = "UTF-8" ?>
< configuration  scan = "true"  scanPeriod = "60 seconds"  debug = "false" >
 
   < statusListener  class = "cn.zollty.commons.logbackext.InitConfigOnConsoleStatusListener"  />
 
  
   < property  name = "DEPLOY_ENV"  value = "${deploy.env:-dev}"  />
 
  
   < property  name = "LOG_HOME"  value = "${catalina.base:-.}/logs"  />
   
  
   < property  name = "LOG_MAX_SIZE"  value = "100MB"  />
  
   < property  name = "LOG_COMMON_PATTERN"  value = "%d{HH:mm:ss.SSS} [%thread] [%level] %logger - %msg%n"  />
   < property  name = "LOG_DEV_PATTERN"  value = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{48}:%line - %msg%n"  />
 
  
   < property  name = "ROOT_LEVEL"  value = "${log.root.level:-DEBUG}"  />
 
  
   < property  name = "APP_LEVEL"  value = "${log.app.level:-TRACE}"  />
  
   < property  name = "APP_PACKAGE"  value = "cn.zollty.lightning"  />
   
   < include  resource = "includedConfig.xml" />
   
   < appender  name = "STDOUT"  class = "ch.qos.logback.core.ConsoleAppender" >
     < encoder >
       < pattern >${LOG_DEV_PATTERN} pattern >
     encoder >
   appender >
   
   < appender  name = "FILTER-DATA"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < file >${LOG_HOME}/filter.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
       < fileNamePattern >${LOG_HOME}/filter/filter-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >90 maxHistory >
       < TimeBasedFileNamingAndTriggeringPolicy  class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
         < MaxFileSize >100MB MaxFileSize >
       TimeBasedFileNamingAndTriggeringPolicy >
     rollingPolicy >
     < encoder >
       < pattern >${LOG_COMMON_PATTERN} pattern >
     encoder >
   appender >
   
   < appender  name = "ASYNC1"  class = "ch.qos.logback.classic.AsyncAppender" >
     < appender-ref  ref = "FILTER-DATA"  />
   appender >
   
   < include  resource = "special_log_level.xml" />
 
   < logger  name = "${APP_PACKAGE}"  level = "${APP_LEVEL}"  />
   
   < logger  name = "FILTER-LOGGER"  level = "${APP_LEVEL}"  additivity = "false" >
     < appender-ref  ref = "ASYNC1"  />
   logger >
 
   < root  level = "${ROOT_LEVEL}" >
    
     < appender-ref  ref = "FILE_EXCEPTION" />
    
     < appender-ref  ref = "FILE_APP" />
     
    
    
    
     
     < if  condition = 'p("DEPLOY_ENV").contains("dev")' >
       < then >
         < appender-ref  ref = "STDOUT"  />
       then >
     if >
     
   root >
 
configuration >

includedConfig.xml

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
xml  version = "1.0"  encoding = "UTF-8"  ?>
 
< included >
 
  
   < appender  name = "FILE_EXCEPTION"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < filter  class = "ch.qos.logback.classic.filter.ThresholdFilter" >
       < level >WARN level >
     filter >
     < file >${LOG_HOME}/error.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
      
       < fileNamePattern >${LOG_HOME}/error/error-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >90 maxHistory >
       < TimeBasedFileNamingAndTriggeringPolicy  class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
        
         < MaxFileSize >${LOG_MAX_SIZE} MaxFileSize >
       TimeBasedFileNamingAndTriggeringPolicy >
     rollingPolicy >
     < encoder >
       < pattern >${LOG_COMMON_PATTERN} pattern >
     encoder >
   appender >
 
  
   < appender  name = "FILE_INFO"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < filter  class = "ch.qos.logback.classic.filter.ThresholdFilter" >
       < level >INFO level >
     filter >
     < file >${LOG_HOME}/info.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
       < fileNamePattern >${LOG_HOME}/info/info-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >50 maxHistory >
       < TimeBasedFileNamingAndTriggeringPolicy  class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
         < MaxFileSize >${LOG_MAX_SIZE} MaxFileSize >
       TimeBasedFileNamingAndTriggeringPolicy >
     rollingPolicy >
     < encoder >
       < pattern >${LOG_COMMON_PATTERN} pattern >
     encoder >
   appender >
 
  
   < appender  name = "FILE_DEBUG"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < filter  class = "ch.qos.logback.classic.filter.ThresholdFilter" >
       < level >DEBUG level >
     filter >
     < file >${LOG_HOME}/debug.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
       < fileNamePattern >${LOG_HOME}/debug/debug-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >50 maxHistory >
       < TimeBasedFileNamingAndTriggeringPolicy  class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
         < MaxFileSize >${LOG_MAX_SIZE} MaxFileSize >
       TimeBasedFileNamingAndTriggeringPolicy >
     rollingPolicy >
     < encoder >
       < pattern >${LOG_COMMON_PATTERN} pattern >
     encoder >
   appender >
 
  
   < appender  name = "FILE_TRACE"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < file >${LOG_HOME}/trace.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
       < fileNamePattern >${LOG_HOME}/trace/trace-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >10 maxHistory >
       < TimeBasedFileNamingAndTriggeringPolicy  class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" >
         < MaxFileSize >${LOG_MAX_SIZE} MaxFileSize >
       TimeBasedFileNamingAndTriggeringPolicy >
     rollingPolicy >
     < encoder >
       < pattern >${LOG_COMMON_PATTERN} pattern >
     encoder >
   appender >
   
  
   < appender  name = "FILE_APP"  class = "ch.qos.logback.core.rolling.RollingFileAppender" >
     < filter  class = "cn.zollty.lightning.common.PackageOrThresholdFilter" >
       < level >INFO level >
       < prefix >${APP_PACKAGE} prefix >
     filter >
     < file >${LOG_HOME}/app.log file >
     < rollingPolicy  class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" >
       < fileNamePattern >${LOG_HOME}/app/app-%d{yyyy-MM-dd}-%i.log.zip fileNamePattern >
       < maxHistory >90 maxHistory >
      <

你可能感兴趣的:(系统架构和设计)