因为basicconfig()仅在根logger未初始化时生效,第三方库(如requests)提前调用getlogger()会导致配置静默失效;生产环境须显式创建命名logger并独立配置handler,避免依赖全局状态。

为什么默认的 logging.basicConfig() 不适合生产环境
因为 basicConfig() 只能在首次调用 logging.getLogger() 前生效,一旦日志器被创建(比如第三方库提前初始化了 root logger),它就完全失效——你改了配置却看不到效果,这是最常被忽略的起点。
生产环境必须显式获取 logger 并独立配置,避免依赖全局状态。常见错误是写完 basicConfig(filename=...) 后发现日志没写入文件,其实是因为某处 import 了 requests 或 flask,它们内部已触发了 root logger 初始化。
- 永远用
logger = logging.getLogger(__name__)获取命名 logger,而不是直接调logging.info() - 配置前先检查:
logging.getLogger().handlers是否为空,不为空说明已被占用 - 禁用 root logger 的默认 handler:
logging.getLogger().handlers.clear()(谨慎执行,确认无其他模块依赖)
如何配置 RotatingFileHandler 避免磁盘被日志撑爆
用 FileHandler 直接写单个大文件等于埋雷;RotatingFileHandler 是标配,但参数选错照样出事——比如 maxBytes=1024*1024(1MB)配 backupCount=5,看似合理,实际在高并发下可能因锁竞争导致日志丢失或写入延迟。
更稳妥的做法是结合时间轮转与大小控制:
- 优先用
TimedRotatingFileHandler,按天切分:when='midnight',interval=1,backupCount=30 - 务必设置
encoding='utf-8',否则中文日志乱码(Windows 默认 cp1252) - 加
delay=True,让 handler 在首次写日志时才真正创建文件,避免启动时无权限报错阻塞进程 - 日志路径必须是绝对路径,相对路径在 daemon 模式或 systemd 下会指向根目录或不可预期位置
怎样让 traceback 完整输出且带上关键上下文
只写 logger.error("failed") 而不带 exc_info=True,等于放弃定位能力。但盲目加 exc_info=True 也可能暴露敏感数据(如数据库密码出现在 traceback 中)。
正确姿势是分层处理:
- 捕获异常后,用
logger.exception("task failed")—— 它等价于error(..., exc_info=True),且语义明确 - 若需过滤敏感字段,先用
traceback.format_exc()拿到字符串,手动清洗后再传给logger.error() - 在 record 中注入请求 ID:
logger = logging.LoggerAdapter(logger, {'request_id': 'abc123'}),配合%(request_id)s格式化,方便链路追踪 - 避免在 format 字符串里拼接变量:
logger.error(f"user {uid} failed")—— 异常时 f-string 会中断,应写成logger.error("user %s failed", uid)
为什么生产日志里经常看不到 INFO 级别以下的日志
不是代码没打,而是 logger 和 handler 的 level 是两个独立开关:logger.level 控制“是否把这条日志发出去”,handler.level 控制“收到后是否真正处理”。两者取高者生效。
典型误配:logger.setLevel(logging.DEBUG),但 handler.setLevel(logging.WARNING) → 所有 DEBUG/INFO 都被 handler 拦截了。
- 统一设为
logging.DEBUG,再靠 handler 过滤:handler 可以同时挂多个(比如一个输出 ERROR 到文件,一个输出 INFO 到 stdout) - 用
Filter实现动态过滤:例如只记录特定模块的 WARNING+,其余模块只记 ERROR+ - 别信 IDE 或本地终端颜色提示——生产环境要看真实输出,用
tail -f /var/log/app.log | grep -E "(ERROR|Traceback)"验证
./logs/app.log 会尝试写入根目录,直接 PermissionError。写死绝对路径 + 启动前 mkdir -p,比任何高级配置都管用。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











