记录应用系统日志主要有三个原因:记录操作轨迹、监控系统运行状况、回溯系统故障。 记录操作轨迹:可以数据化分析用户偏好,有助于优化系统业务逻辑,为用户提供个性化服务。如:通过access.log记录用户的操作频率和跳转链接,有助于分析用户后续行为。监控系统运行状况:全面有效的日志系统有助于建立完善的应用监控体系。通过应用监控体系,可以实时监控系统运行状况,及时预警,避免故障发送。系统运行状况是指服务器的运行状态,如内存、CPU等使用情况;应用运行状况,如接口RT(响应时间)、QPS等。应用错误信息,如NPE、SQL异常、数据转换失败等。回溯系统故障:完整的现场日志方便快速定位问题,并迅速处理
一、日志的记录点要求
在程序执行过程中,以下5类日志记录点必须记录日志:
本系统接受到外部请求时(本地入口);
本系统调用其他模块或系统时(调用其他);
本系统调用其他模块或系统结束时(调用结束);
本系统处理结束时(本地出口);
本系统捕捉到错误时(出错时);
初始化参数时
初始化参数在各种框架里面可以看到一些内容,而在自己开发的业务中则使用打印业务参数阅读相关内容 系统核心角色,组件关键动作 :主要是核心业务的触发动作,但是需要避免非常高频率的打印,同时对于日志进行提炼 上述日志记录点,除出错时,均应该按[INFO]级别登记
二、日志的记录内容规则
应用程序日志原则上使用UTF-8字符编码,以便于将来的日志文件分析。 不要使用系统输出记录日志,如System.out.print, printStackTrace。不能将应用日志写入生产环境基础系统的日志。(如SystemErr.log、SystemOut.log); 日志记录应及时、完整,日志应该符合安全规范,不要在日志信息里包含安全敏感信息,敏感信息主要有客户身份信息如客户账号、名称、证件号、交易核心信息如交易金额、交易备注、安全控制信息如安全认证方式、密码。
1.日志输出不允许影响系统正常运行。
2.日志输出需符合安全审计要求,不允许产生安全问题,不允许输出敏感信息,支持保密机制。
3.日志输出格式严格按照要求、合理的打印信息,如对于交易日志,必须记录,对于程序调试中非关键节点的日志交付前进行删除,无需记录
4.日志输出内容能够提供开发和运维人员快速定位到故障问题原因。
5.日志按照一定的策略支持备份,如日期、时间等。
6.最小10M,缺省情况下,每个日志文件的大小限制为100M,超过限制,则必须写入到另一个带新序号的日志文件中
7.一定要控制日志输出量,以免出现磁盘空间不足。同时要为日志设置合理的生命周期,及时清理过期日志。避免重复打印,务必在日志配置文件中设置additivity=false
三、日志的性能要求
1、输出日志记录不能过于频繁。一般情况下10毫秒内不能输出3条以上日志信息;
2、输出的日志内容不能过长。一般情况下每行日志信息原则上不能超过2K字节,一条日志输出代码产生的日志内容不能超过40行;
3、输出日志信息的函数代码不能包含复杂的CPU计算,导致产生过多的CPU。
4.不建议打印查询list,尤其没有分页的
5.控制日志输出的长度在一定范围内,比如请求参数,避免打印大量的业务日志 如日志layout中 msg配置为 %.-4096msg,输出日志长度最长为4096字节,多余的将从后面截断不打印;
6.【建议】在循环,响应式编程中谨慎log
7.【建议】批量任务,大量mq,不建议每行均打印
8.【建议】gateway等网关中log需谨慎, gateway默认线程数很少,等你打印io线程消耗性能,遇到上传文件+报文解密+打印日志的时候,并发能力下降到2位数
9.【建议】报文加/解密 前后打印log,没必要 和第三方交互时,入参、出参可能是需要加密和解密,如果报文体积较大,明文和密文都打印没有意义,算法测试成功后,个人认为加解密成功的情况下打印明文,计算失败时异常中打印原文即可
10.【建议】如果开源jar包日志需要特别注意 如shardingsphere-jdbc等,需要关闭日志 如无法关闭,可以设置独立的logger,和其他应用日志分开 mybatis,eureka心跳等日志建议分开打印,不要和业务日志混在一起 日志按用途划分,避免业务日志,框架日志,混合,业务日志也应分模块打印: https://www.jb51.net/article/247048.htm,且日志使用rolling进行分割
11.在tps有高要求的场景应该异步打印,参考:https://www.cnblogs.com/yangyongjie/p/16230247.html
四、日志的等级分类
DEBUG 细粒度的、对出错(debug)、以及系统调试时候输出的信息、事件。
INFO 在正常运行状态中,粗粒度的、关于重要流程/事件的、可用来表示系统健康度的信息、事件。在INFO级别不允许把SQL语句、报文等这些作为日志内容输出。
WARN 有潜在风险的、不会造成大危害的错误(往往由应用外部因素造成,如不正确的输入数据)
ERROR 应用发生错误(包括业务错误和技术错误),但后续流程还能够继续进行 FATAL 应用发生严重错误(技术型异常),应用服务被终止。
五、日志的目录和文件名
1.应用日志输出至/app/logs目录下;
2.应用日志文件名以.log后缀结尾;
3.应用日志中每行以[LEVEL][yyyy-MM-dd HH:mm:ss,SSS]开头;
4.把不同类型的日志分离出去,应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。logType:日志类型,如 stats/monitor/access/error 等;logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什 么类型,什么目的,也有利于归类查找。说明:推荐对日志进行分类,如将错误日志和正常 日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。
六、日志的大小
日志文件的大小应该可以通过参数控制(log4j2 可配置),如果超过限制,则必须写入到另一个带新序号的日志文件中,且不能超过本次磁盘预警值: 参考:log4j2官网:Log4j – Log4j 2 Appenders 下面是一个示例配置,它使用滚动文件追加器,其时间和大小都基于时间 触发策略,将在同一天创建最多 100 个存档 (1-100) 存储在目录中 根据当前年份和月份,并将压缩每个 使用 gzip 存档,每小时滚动一次。 在每次翻转期间,此配置将删除与“/app-.log.gz”匹配的文件 并且出生 30 天或以上, 但保留最近的 100 GB 或最近的 10 个文件,以先到者为准 logback:官网:Chapter 4: Appenders 译文:第四章:Appenders - logback 中的maxHistory处 其他注意点:https://www.cnblogs.com/ZTPX/p/14090313.html
七、日志的清理
一般情况下,日志文件按照磁盘预警值和监控组对接需求定时清理一次,移出日志目录; 对于有审计需求的日志,按照审计规定对这些文件进行归档,归档数据转入存储服务器。
八、日志打印注意事项
1.记录异常时一定要输出异常堆栈。如下:logger.error("xxx"+e.getMessage(), e)
2.日志中如果输出对象实例,要确保实例类重写了toString方法,否则只会输出对象的hashCode值。 注:logger应被定义为static,与类绑定,防止浪费资源。 使用slf4j+日志库模式时,要防止日志库冲突,一旦发生则可能会出现日志打印功能失效问题
3.不要在打印日志时造成异常
4.日志框架选型 logback、log4j2 logback:推荐,Springboot默认的日志框架 log4j2:版本大于2.15.0
5.日志格式 日志输出基本格式(有任何需求按规范添加): •pid[级别] [时间][应用名称][调用链标识][调用层级标识][业务标识] [线程名] [线程上线映射变量] [类名] [行号] [日志内容] [换行] 即:[%-5p] [%d{yyyy-MM-dd HH:mm:ss,SSS}] [%t] [%-1X{变量名}] [%C:%L] [%m] %n
6.日志级别得支持动态修改,要么actuator通过post接口动态修改日志级别,要么放到配置中心来修改
7.链路追踪 通过 AOP 切面,日志框架 MDC 等技术结合,在日志中打印traceId,而后根据traceId可检索整个请求链路的日志
1)AOP切面结合MDC方式 ①、日志配置文件中配置traceId占位符 Gherkin <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS}|%t|%-5level|%X{traceId}|%C{0}#%M:%L|%msg%n</pattern> ②、AOP切入要增强traceId的方法 ③、在增强类中往MDC中添加traceId字段,并赋值,并在finally块移除MDC中traceId字段
2)直接使用MDC方式
①、日志配置文件中配置traceId占位符,同上
②、在方法执行业务逻辑前往MDC中添加traceId字段,并赋值
③、在方法返回前移除MDC中的traceId字段
3)在线程池中没采取阿里ttl方式做mdc前线程池必须手动使用mdc打印,防止链路追踪失败
- 不要记录异常又抛出 记录之后抛出异常是非常危险的操作,因为外层可能会因为内层捕获异常之后不会再次处理,如果是自定义异常更是难以排查问题,此外这样做法会导致堆栈二次打印,非常浪费系统性能,
- 核心功能模块日志 如果是核心功能模块的日志,其实多打印一些内容是可以接受的,但是需要注意打印的日志必须要第一时间可以定位到问题所在。 监控系统集成:建议将日志和监控系统打通,将日志信息传递给监控系统,以便实时监控系统的运行状态和性能指标。
- 理想的日志中应该记录不多不少的信息 l 不要在日志中记录无用的信息,实践中常见到的无用的日志有: 1)能够放在一条日志里的东西,放在多条日志中输出; 2)预期会发生且能够被正常处理的异常,打印出一堆无用的堆栈; 3)开发人员在开发过程中为了调试方便而加入的“临时”日志 l 对于日志的使用者,能够从日志中得到所有需要的信息