开发者必知的日志记录最佳实践

  对程序来说,良好的日志风格能够极大的降低排错的成本,增强程序的健壮性与可运维性,但大多数开发同学并没有将日志的重要性提的和代码本身一样高,本文讨论我个人记录日志的一些最佳实践

基本原则

将日志作为程序的第二个UI

  软件的第一UI当然是使用方或API调用方,而日志作为第二UI,用于开发、运维、合作方进行线上应用状态的检测与问题排查。日志的质量是代码质量的一部分。
 

写日志时,考虑看日志的人无法访问代码

  通常来说,看日志的角色不仅仅是开发代码的人员,包括线上值班人员、售后人员、其他合作方系统的人员,可能都需要依赖日志排查问题。今天的IT系统日志更容易收集后中心化,使得不同角色可以更容易访问日志。对于API,尤其是涉及其他多个子系统调用的复杂API,良好的日志可以为调用方、线上值班提供丰富的问题排查依据,在代码中打印日志时要考虑无法访问代码的角色。
 
 

日志的主要用户是Human,次要用户是机器,所以可读性很重要

  可读性包含的内容很多,下面会解释一些原则,但最基本的原则是缩进、空格等需要让阅读者易于阅读。同时日志格式也保证易于模式化解析(简单的字符串匹配,而不是复杂的正则)
 

考虑日志的目的是什么

  日志的目的不仅仅是线上Debug,也可以是记录性能或是收集后做数据分析,考虑日志在系统的目的,写日志时具备一定针对性。
 

最佳实践

 

为日志添加上下文

  非常General的日志是非常糟糕的,不仅无助于定位问题,更容易造成混淆。比如下面这个日志:
 
2021-11-30 16:44:52,725 [WARN] Connection failed!
 
无法定位是哪段代码,连接什么失败,也不知道失败的参数是什么,更好的日志格式如下:
 
类似问题还比如:
 
//don't do that
java.lang.IndexOutOfBoundsException//do that
IndexOutOfBoundsException: index 25 is greater than list size 20.
 
 
对于日志,尽量避免太general的日志,记得我们的原则,知道我们的第二个UI的目标受众是谁,看日志的人大多数可能无法访问代码。

端到端的日志&并发线程日志问题

每个请求都需要有一个唯一标识符与之对应,通常是一个GUID,主要用于两个用途
1.在不同系统或微服务间唯一标识一个请求
2.同一个应用内不同并发线程唯一标识一个请求
 
比如我们可以通过下面一个GUID追踪的一个请求完整的过程
 
 
 
careyson@CareySonMac log % grep "C97E2488-170A-4D01-8B90-BE562FD78342" xxx.log
2021-11-30 16:44:52,725 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] XXX Start
2021-11-30 16:44:53,009 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] Begin Instance Rule Check [source version=, target version=]
2021-11-30 16:44:53,010 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] rule check passed. [source version=, target version=]
2021-11-30 16:44:53,011 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] Starting check  config
2021-11-30 16:44:53,078 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] Check  config Complete
2021-11-30 16:44:53,079 [WARN] ModifyDBInstanceVersionImpl(46) - [C97E2488-170A-4D01-8B90-BE562FD78342,yunji-dbsingle2,ModifyDBInstanceVersion] Starting get Source Custins info
.....

变量值与常量值分开

将变量值与常量值分开可以使得日志更容易阅读,无论在代码还是日志本身的搜索也会变的简单,如果用工具抽取参数值也变的简单,下面是一个示例:
 
 
如果URL是一个很长的串,那么阅读的体验将会非常糟糕。
 

区分Warn与Error

日志按照严重性同样也会分级,业界标准使用最多的还是Info、Warn与Error。Info通常没什么说的,程序符合预期正常工作,在过程中记录相关信息,就是Info,Warn和Error值得提一下。
Warn意味着程序正常工作,但存在一些问题,这种问题通常在我们预期之内。
Error意味着程序异常,且这种异常不在我们预期内。
 
下面是一个程序中调用其他服务的简单例子:
 
 
 

如果可能,出错时附上KB或错误代号

写程序的人通常对程序所代表的业务有一定了解,但其他日志用户可能并没有背景知识以及业务限制,在有限的日志中通常很难说清楚,如果有对应KB或帮助文档,以及错误代号,可以附在日志中,帮助日志用户快速了解背景。比如下面这个例子:
 
 

避免记录敏感信息

  日志并不会像数据库那样有高安全等级,也就是访问日志的安全权限通常远远低于其他应用,且今天的日志更多是上传后中心化,更无法控制日志的扩散范围,因此对于敏感信息请不要记录,包括密码信息、Security Token信息、敏感身份信息等。
 

使用英文记录日志

  英文记录不仅仅是标准化和易于阅读的问题,而是今天的IT系统,日志可能经过多个系统中心化,这些系统只要有一个不支持UTF格式,就可能导致乱码,使用英文可以尽量避免这些麻烦。
 

小结

  对于程序来说,代码质量除了代码本身,还包括日志。将日志当做程序的第二UI认真对待,不仅能使得我们的程序调试与开发成本大幅下降,还能使得程序的运维排错更加简洁,Bug更早发现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/894958.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI 辅助教学案例 02

收集整理并记录现有的比较火爆的国产 AI 在教育教学中的使用案例,以期和各位同仁、莘莘学子共同进步。前情概要 2025开年之初,人工智能呈现井喷式发展,非常火爆,尤其是 DeepSeek 的发展一骑绝尘,为适应形式所需,将使用过的案例做个记录,便有后续备查。若想小试牛刀,请点…

线性回归--最小二乘法+梯度下降算法+sklearn库

线性回归一元: (1)手工最小二乘法import numpy as np a=np.loadtxt("homespace_price",delimiter=,,dtype=float) homespace=a[:,0] price=a[:,1] x_avg=np.average(homespace) y_avg=np.average(price) xfang_avg=np.average(homespace*homespace) xy_avg=np.ave…

震惊!AI编程正在淘汰这5类人,你在其中吗?

大家好,我是狂师。 今天在知乎上看到一个关于讨论:“人工智能大爆发,AI编程工具对程序员到底是颠覆还是辅助?’”问题,觉得蛮有意思。的确,AI编程的出现,引发了人们对于程序员职业未来的广泛讨论,有人担忧它可能会颠覆程序员的职业, 今天分享一些个人观点。先说结论:…

viewport meta 标记

在移动端网页开发中,viewport meta 标记是优化显示效果的关键。它定义了浏览器可视区域的宽度和缩放比例,常用于适配不同设备屏幕。 默认情况下,移动浏览器会将网页放入一个虚拟的 viewport(如 980px),然后缩放到设备屏幕(如 375px),导致内容显得很小。例如,一个宽度…

如何用Forest方便快捷地在SpringBoot项目中对接DeepSeek

​一. 环境要求JDK 8 / 17SpringBoot 2.x / 3.xForest 1.6.4+Fastjson2依赖配置 除了 SpringBoot 和 Lombok 等基础框架之外,再加上 Forest 和 Fastjson2 的依赖<!-- Forest框架 --> <dependency><groupId>com.dtflys.forest</groupId><artifactId…

5. MySQL 存储引擎(详解说明)

5. MySQL 存储引擎(详解说明) @目录5. MySQL 存储引擎(详解说明)1. 查看存储引擎2. 设置系统默认的存储引擎3. 设置表的存储引擎3.1 创建表时指定存储引擎3.2 修改表的存储引擎4. 引擎介绍4.1 InnoDB 引擎:具备外键支持功能的事务存储引擎4.2 MyISAM 引擎:主要的非事务处…

130道基础OJ编程题之: 68~77

130道基础OJ编程题之: 68~77 @目录130道基础OJ编程题之: 68~7768:BC72 平均身高69:BC74 HTTP状态码70:BC75 数字三角形71:BC76 公务员面试72:BC77 有序序列插入一个数73:BC78 筛选法求素数74: BC79 图像相似度75: BC80 登录验证76: BC85 包含数字9的数77:BC86 奇偶统计最后:68…

如何选择既能支持稳定传输 又适配信创环境的文件传输系统?

在日常工作开展中,财政局作为政府单位中负责财政收支、预算管理和财务监督的重要部门,在文件传输方面存在多种场景及需求。财政局会存在与其他政府部门间协作,向上级财政部门传输文件以及财政局各部门间传输预算报告、财务报告等场景,需要实现快速、准确的流转。财政局一般…

本地新建js公用库组件并打包发布到npm仓库详细说明

有时候,我们想在本地开发一个公用js函数组件库,并上传到npm仓库供开发者使用,本文就详细介绍了从新建本地项目到发布至npm仓库的整过过程,供大家学习!1、注册账号 首先我们去npm官网注册一个账号,注册成功后请牢记账号和密码。 需要注意的是,现在npm登录好像启用了双因素…

51CTO:《DeepSeek入门宝典(全4册)》 - 官方完整版 - PDF免费下载

由51CTO智能研究院、51CTO传媒、51CTO学堂联合倾力打造了这份《DeepSeek入门宝典》,这份DeepSeek宝典共分为四册:《技术解析篇》、《开发实战篇》、《个人使用篇》、《行业应用篇》,长达80余页。它涵盖了技术解析、开发实战、个人使用以及行业应用等多个维度,是帮助每一位通…

Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

在众多开源项目中,高颜值、功能强大且部署简单的项目往往更能俘获开发者的心。然而,实际部署 Web 应用时,面对数据库、缓存、消息队列等复杂的依赖关系,常常令人头疼。Docker 的开源为我们普及了容器化技术,能够快速打包和部署 Web 应用,让一切变得轻松简单。但当你从开发…

到底是谁还没搞清楚 OMS 和 WMS的区别?

聊到 OMS(订单管理系统) 和 WMS(仓库管理系统),很多人第一反应是:“不就是订单和仓库嘛?谁还分不清?” 但等到真正操作的时候,很多企业就开始搞混了:“WMS 不是也能管库存吗?为什么还要 OMS?” “OMS 负责订单,那 WMS 发货的时候为啥还要管订单?” “库存到底是 …