4 道练习题·预计 70 分钟·做对一题解锁下一段
各位写代码的时候,是不是几乎都干过这种事——
代码跑出问题了,怎么办?随手在可疑位置插一行 print('xxx'),再跑一次,看输出在哪儿断掉。然后再插一行 print('yyy'),再跑。最后整个文件里散落着十几个 print('111')、print('here')、print(user),bug 修好之后,要么忘了删,要么删了又怕下次再调试时还得重新插。
本地玩玩还能凑合,可一旦把代码部署到服务器,问题就来了——
「线上挂了,咋回事?」打开服务器一看,啥都没有。print 默认是写到标准输出的,要是程序被 systemd 或者 Docker 拉起来,输出可能根本没人接,或者全混在一起,谁也分不清是哪个时间、哪个模块、哪条业务挂的。
「让我加点日志吧。」于是各位开始改代码,把 print 换成 print(time.strftime('%H:%M:%S'), 'xxx'),再加一段把它写到文件里的逻辑——写完发现,自己在重新发明日志库。
Python 标准库里早就备好了答案,就叫 logging。一行不长的代码,就能让输出自带「时间戳 + 级别 + 模块名 + 进程信息」,还能同时写到控制台、文件、远程服务器,并且可以一键切换「调试时啥都打、上线后只打 ERROR」。
这一章咱们就从最简单的 logging.info('hi') 开始,一路讲到生产环境会怎么用。学完之后,各位应该能:
print 调试getLogger(__name__) 给每个模块一个独立的 loggerRotatingFileHandler 防止日志文件无限膨胀dictConfig + yaml 在生产环境集中管理日志配置logger.exception() 在 except 里自动带上完整的 traceback走起。
各位先来感受一下 logging 是怎么个用法。最简单的写法只有两行:
import logging
logging.info("两点水开始打卡了")跑一下,奇怪的事情来了——啥都没输出。
这是新手第一次用 logging 几乎都会踩的坑。原因是:logging 默认的级别是 WARNING,比它低的 INFO 和 DEBUG 直接被丢掉了。
各位把上面那行换成 logging.warning('水哥忘了打卡') 再跑:
import logging
logging.warning("两点水忘了打卡")终于看到输出:
WARNING:root:两点水忘了打卡注意这一行的格式:级别 + logger 名字 + 内容,三段式。root 是默认 logger 的名字,后面会讲怎么换。
那 INFO 怎么打出来呢?最简单的办法是先调一行 basicConfig:
import logging
logging.basicConfig(level=logging.INFO)
logging.info("两点水开始打卡了")这次看到了:
INFO:root:两点水开始打卡了basicConfig(level=logging.INFO) 这一行做的事情是「把 root logger 的级别调成 INFO」。一调下来,INFO 及以上(也就是 INFO、WARNING、ERROR、CRITICAL)都会被打出来。
各位这里可能有疑问——「那 DEBUG 怎么打?」很简单,level=logging.DEBUG。DEBUG 是最低级别,调到这里,所有日志都会出来。
「为什么 logging 要默认 WARNING?」官方的解释是:logging 库是给「库的作者」准备的,库要是默认就打一堆 INFO,会污染最终用户的输出。所以默认只打「值得用户注意」的 WARNING 及以上。这个设计哲学理解一下,对后面看库的源码很有帮助。
用 logging.basicConfig 把日志级别调到 INFO,再用 logging.info 打印 '第一条日志'。
注意:starterCode 已经把 logging 配置成输出到 stdout 并使用 format='%(levelname)s:%(message)s' 简化格式,你只需写最后一行 logging.info(...)。
输出应该是:
INFO:第一条日志推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai