当天日志命名:以“应用名.log”来保存
过往日志命名:以{logname}.log.{保存日期}命名;日期格式:yyyy-MM-dd
日志文件至少保存15天:便于排查某些以周为频次发生的异常
敏感操作信息联机存储6个月:网络安全相关法律的规定
记录用户敏感信息或者操作的日志为何要存储6个月,并多机备份?除了法律规定以外,也是为了保留证据记录,以防发生纠纷。该类日志最好使用什么日志级别输出?warn
日志记录规约
- 系统应依赖使用日志框架(SLF4J、JCL)的API而不是具体日志库中的。java commons-logging
CEKI GULCU,先在这里拜一下。
- 在日志输出时,字符串变量之间的拼接使用占位符的方式
- 日志打印时禁止直接用JSON工具讲对象转换成String
- 尽量用英文来描述日志错误信息
错误码规约
- 定义时要有字母也要有数字
- 要分级分类管理
- 不能直接输出给用户作为提示信息使用
- 不要与业务架构或者组织架构挂钩
- 使用者避免随意定义新的错误码
- 便于不同语言的开发者之间协作
日志库冲突问题
某个工程用log4j打印日志,但是它依赖的某个jar包用的是logback,这个时候就会发生jar包冲突的问题。下面这个spring-boot的issue比较清楚地描述了这个问题,里面也有一些解决方案,但不一定是最佳的。
异常处理与日志综合实践
-- 在Controller层统一捕获异常(其他层向上抛出)
注:各层分布式部署在多台机器时,异常日志需要每层单独记录。这样方便定位问题,查清源头,厘清责任。
-- 全局异常处理组件的定义和使用(GlobalExceptionHandler)
全局异常处理组件定义一个父类异常的处理方式,这样所有子类都会通过Spring框架用已定义的方式来处理。这篇博客有示例。
- 严格约束条件判断
API层要严格校验保证进入系统的数据是合法、合规的:基本判断约束(Null值判断);实体属性约束(满足JSR 303 基础判断)
- 客户端返回要友好:API层异常要给客户端返回状态码及其对应的错误消息
- 下层异常转译:讲Service层、Manager层异常转译成API层异常
- 错误码文档要规范:系统状态码对应的异常或错误信息以及可能发生异常的原因,要整理成便于用户查阅的文档,同步给接口调用方
-- Service层异常设计实践
- 严格约束条件判断
Service层严格约束条件判断避免脏数据:
基本判断约束(Null值判断);
实体属性约束(满足JSR 303等基础判断);
业务条件约束(需求提出的不同的业务约束)
- 抛出指定类型的异常:Service层抛出带状态码或者指定类型的异常
- 转移DAO层异常:讲DAO层的异常转译为Service层或者更高层能够理解的异常
-- DAO数据处理层异常日志实践
- 使用通用DaoException:使用继承自RuntimeException的通用DaoException封装DAO层异常并向上抛出。
- 框架层面有选择性地记录数据操作:在DAO层(框架层面)有选择地记录数据操作的有效信息,比如:每次操作的原始SQL语句及其执行时间
-- 使用MDC实现轻量级调用链路追踪
- 分布式链路追踪:将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上,每个服务节点的请求状态等等
- 链路跟踪主要功能:故障快速定位;链路性能可视化;链路分析;
这篇讲解了如何使用MDC。
https://www.baeldung.com/mdc-in-log4j-2-logbackhttps://www.baeldung.com/mdc-in-log4j-2-logback可以用log工具中的MdcAdapter来实现。MDC简单来讲就是给每个线程分配一个专有的map,可以往里面存放键值对,logger可以从map中拿到数据然后打印出来。
-- 用有限的异常类处理业务中复杂多变的无限可能
- 通用ServiceException:定义继承RuntimeException的通用ServiceException业务异常
- 结合ErrorCode:结合与业务关联的ErrorCode实现复杂多变的业务异常需求
-- 降低系统的维护难度与过度设计、冗余的手段