作用
规范日志输出体系,在遇到生产问题时,日志可以充分描述系统的状态,能方便、快速定位问题。
各个日志文件记录的信息
image.png
注:
(1)[app]代表当前的应用标识,各个系统应该有统一的唯一标识码。
(2)应用日志([app].log)是系统持续输出日志文件,而[app].seq.log是被归档的文件;
大小
要求每输出日志文件大小建议设置在200M-300M之间,并可以通过修复配置文件按需调整。最好是在运行时可动态调整,包括级别、路径等
日志级别
日志具有几个级别,分别是INFO、DEBUG、ERROR、WARN、FATAL。
ERROR:系统可以继续运行,但最好要尽快修复的错误。这个级别输出较多,常常伴随Java异常,错误(Error)的环境不一定会造成系统的崩溃,系统可以继续服务接下来的请求。运行时错误信息,包括异常信息等。其中应当包含技术异常。技术异常包括外部接口失败、IO异常、数据库连接异常等;
WARN:系统可以正常运行,但需要引起注意的警告信息。这个级别预示较小的问题,由系统外部的因素造成的,比如用户输入了不符合条件的参数。如程序调用了一个即将作废的接口,接口的不当使用,运行状态不是期望的但仍可继续处理等;其中应当包含业务异常。业务异常标识业务中出现的异常信息,比如,用户余额不足、密码输入错误等
INFO:系统运行的主要关键时点的操作信息,一般用于记录业务日志。同时也应该有足够的信息以保证可以记录再现缺陷的路径。这个级别记录了系统日常运转中有意义的事件。有意义的事件信息,如程序启动,关闭事件,收到请求事件、统计信息、系统性能信息、接口报文输出等。
DEBUG:系统运行中的调试信息,便于开发人员进行错误分析和修正,一般用于程序日志,关心程序操作(细粒度),不太关心业务操作(粗粒度)。系统出现问题时,必须抛出异常,在处理异常时记录日志,且日志级别必须是前三个级别Fatal、Error、Warn中的一种;
日志输出
1.应用中不可直接使用其他日志输出,应该使用系统同一的日志输出API。
import com.leimingtech.logging.MonitorLogger;?
import com.leimingtech.logging.MonitorLoggerFactory;
private static MonitorLogger mlogger = MonitorLoggerFactory.getMonitorLogger(AftersaleApplyServiceImpl.class);
mlogger.info(AftersaleStatusCode.SERVICE_AFTERSALE_APPLY_SAVE_RETURN_SUCCESS_CODE,AftersaleStatusCode.SERVICE_AFTERSALE_APPLY_SAVE_RETURN_SUCCESS_MESSAGE, logMap);
2.对于 trace/debug/级别的日志输出,必须进行日志级别的开关判断。
说明:虽然在 debug(参数)的方法体内第一行代码 isDisabled(Level.DEBUG_INT)为真时(Slf4j 的常见实现Log4j 和 Logback),就直接 return,但是参数可能会进行字符串拼接运算。此外,如果debug(getName())这种参数内有 getName()方法调用,无谓浪费方法调用的开销。
正例:// 如果判断为真,那么可以输出trace 和debug 级别的日志
if (logger.isDebugEnabled()) {
logger.debug("Current ID is: {} and name is: {}", id, getName());
}
3.异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出。
4.谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志。
如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时 删除这些观察日志。
说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。
记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
5.业务关键环节必须打印日志。
6.外部接口调用必须打印日志,并统计接口调用耗时,以便统计趋势图。
7.error级别以上的日志,必须记录关键业务信息,如方法的入参,错误发生时的变 量现场,以便回溯追踪问题。
8.禁止打印密码等敏感信息。
9.可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉无所适从。如非必要请不要在此场景打出 error 级别,避免频繁报警。
说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。
10.项目中禁止出现System.out.println()打印日志,统一使用日志码方式进行打印日志打印异常日志参数时禁止使用e.printStackTrace()。
11.打印日志的代码任何情况下都不允许失败,一定要确保不会因为Log语句的问题而抛出异常造成中断。
12.循环体内尽量不打印日志。
13.service层在对应的client模块下创建statuscode包,下面创建对应的code码声明文件,controller层在controller包同级目录下创建对应的stauscode包
14.日志状态码类统一继承ServcieStatusCode.class 。
public static final IndexSyncServiceCode INDEX_SYNC_ERROR = new IndexSyncServiceCode("500101", "商品索引同步失败", new Object[0]);?
public static final IndexSyncServiceCode CREATE_INDEX_ERROR = new IndexSyncServiceCode("500102", "创建商品索引失败", new Object[0]);?
public static final IndexSyncServiceCode CREATE_DELETE_INDEX_ERROR = new IndexSyncServiceCode("500103", "删除索引失败", new Object[0]);
15.状态码定义长度必须是6位,2开头的为成功,4开头的为客户端错误,5开头的为服务端错误,第4个字符应该是非0。
16.API入参打印统一使用@LogContext注解方式。
17.捕获已知异常时需要打印,在打印的日志信息中声明创建的logMap需要加上可供排查的重要参数保留案发现场。