当你的脚本或应用出现异常时,没有日志就像在黑暗中摸索。然而很多开发者写日志时只是随手加上 print('error'),导致生产环境中根本找不到问题根源。本文将从实际问题切入,讲解如何编写结构清晰、可读性强的日志代码,帮助你在调试、审计和运维中事半功倍。
为什么需要系统化地写日志?
在脚本编写中,日志记录被视作“一个完整、健壮的脚本应该包含的工程化要素”之一(来源[2])。如果没有统一的日志规范,当系统出问题时,你可能要翻遍成千上万行杂乱输出。系统化的日志不仅能记录异常,还能用于性能分析、安全审计和业务追踪。
选择合适的日志级别
日志级别决定了一条信息的紧急程度。常见的级别有:DEBUG、INFO、WARNING、ERROR、CRITICAL。实际编码中,很多开发者只用 print(),导致无法区分不同优先级。建议遵循以下原则:
- DEBUG:开发阶段的详细调试信息,生产环境应关闭。
- INFO:正常的系统状态变化,如用户登录、任务启动。
- WARNING:潜在问题但不影响系统继续运行,如磁盘使用率超过80%。
- ERROR:功能级别错误,如数据库连接失败,仍需继续执行。
- CRITICAL:致命错误,系统将无法继续,需要立即人工介入。
例如,在 Python 中使用 logging 模块,可以轻松设置级别和格式。来源[2]强调“错误处理、日志记录、参数处理”是健壮脚本的组成部分,说明日志级别是实现这一目标的基础。
结构化日志:让机器也能读懂
传统的文本日志难以解析。结构化日志使用 JSON 或键值对格式,便于日志分析工具(如 ELK、Splunk)自动提取字段。例如:
2025-02-20 10:23:45 INFO user_login { "user_id": 123, "ip": "192.168.1.1", "action": "login" }
这种格式既保持了人类可读性,又允许程序快速过滤。在编写日志代码时,可以封装一个函数强制使用统一结构。注意,日志中应避免包含敏感信息(如密码、身份证号),防止泄露。
使用标准日志库而非 print
很多初级开发者习惯用 print() 输出日志,但这样无法控制日志级别、输出目标(文件/控制台)和格式。标准库如 Python 的 logging、Java 的 Log4j、Node.js 的 Winston 提供了强大功能:轮转文件、异步写入、过滤器等。来源[2]提到“脚本通常是在运行时被解释执行的”,意味着日志库的配置可以在运行时动态调整,适合快速开发和运维。
日志代码的常见误区
- 过度日志:在循环内部不加条件地记录 DEBUG 日志,会导致大量 I/O,影响性能。
- 日志吞没异常:只记录
except: log.error("error")而不重新抛出让上层感知。 - 不记录前置上下文:只记录“连接失败”却不记录是哪台机器、哪个端口。
- 使用字符串拼接而非格式化:
log.info("user " + name)在日志级别不匹配时仍然执行拼接,浪费性能。推荐使用log.info("user %s", name)或 f-string 配合惰性求值。
用 Markdown 编写日志规范文档
为了团队协作,建议使用 Markdown 编写日志规范文档。Markdown 是一种轻量级标记语言,易读易写,且可轻松转换为 HTML、PDF 等格式(来源[3])。你可以用在线文本编辑器(如 TextEditor.cn)快速编辑规范,利用自动保存功能避免内容丢失。规范中可以包含:日志格式示例、级别定义、敏感信息掩码规则等。
实操步骤:改造你的现有代码
- 引入标准日志库,配置日志输出到文件和控制台。
- 定义统一的日志格式,包含时间戳、级别、模块名、消息。
- 将所有
print()替换为对应级别的日志调用。 - 添加异常捕获并在日志中包含异常信息和堆栈。
- 使用结构化日志,在关键业务点记录用户 ID、请求 ID 等字段。
- 设置敏感信息过滤器(如密码、Token)防止泄露。
来源[2]指出,脚本的工程化思维包括“日志记录”,上述步骤正是将日志代码提升为工程级的最佳实践。
参考资料
延伸阅读
