日志需平衡可观测性与开销,按环境分层控制级别;用结构化占位符延迟格式化;敏感字段必须过滤,上下文通过loggeradapter注入;高频场景启用采样与异步写入。

日志不是越多越好,也不是越少越安全;关键是在可观测性与运行开销之间找到平衡点。粒度太粗,问题无从定位;粒度太细,又拖慢响应、撑爆磁盘。设计时要围绕“谁要看、什么时候看、看什么”来决策。
按场景分层控制日志输出
不同环境对日志的需求差异极大,不能一套配置打天下:
- 开发阶段:启用 DEBUG 级别,记录函数入参、中间状态、SQL 查询、HTTP 请求/响应体(脱敏后)
- 测试/预发环境:INFO 为主,WARNING 及以上必留,可额外开启关键路径的 DEBUG(如支付流程)
-
生产环境:默认 INFO,ERROR/CRTICAL 全量捕获;DEBUG 仅对特定模块动态开启(如
logging.getLogger("myapp.payment").setLevel(logging.DEBUG))
用结构化占位符代替字符串拼接
写日志时别急着格式化,延迟解析能省下不少 CPU:
- ✅ 推荐:
logger.info("User %s accessed %s in %d ms", user_id, path, duration) - ❌ 避免:
logger.info(f"User {user_id} accessed {path} in {duration} ms")或logger.info("User " + str(user_id) + ...)
前者只在日志实际被输出时才执行变量转换和字符串拼接;后者无论级别是否匹配,都会提前构造完整字符串,浪费资源。
立即学习“Python免费学习笔记(深入)”;
敏感字段必须过滤,上下文信息按需注入
日志里不该出现密码、token、身份证号等——这不是风格问题,是合规红线:
- 用
Filter类统一拦截含敏感关键词的日志(如"password"、"auth_token"),替换成"***" - 需要 trace_id、request_id、user_id 等上下文时,优先用
LoggerAdapter注入,而不是每次调用都手动传参 - 避免在日志消息中硬编码业务逻辑(如
if debug: logger.debug(...)),应交由 logging 系统自身按 level 控制
异步写入与采样机制降低性能冲击
高频服务(如 API 网关、实时风控)需主动限流日志行为:
- 对非关键路径的 INFO 日志做概率采样(如每 100 条记 1 条),用
Filter实现 - 高吞吐场景可引入
QueueHandler + QueueListener模式,把日志写入转为后台线程处理 - 避免在 hot path(如循环体、核心算法内)打 DEBUG 日志;必要时改用计数器或聚合统计代替逐条记录











