uvicorn日志清空问题
1、配置:
uvicorn + starlette
2、现象描述:
当我使用uvicorn + starlette进行Python web开发的时候,本来想把所有的日志都打印到一个文件里面,于是我写了一个启动脚本,所有的日志都输出到log.txt里面:
$ more run_s
nohup uvicorn server:app --host 0.0.0.0 --port 6786 > log.txt 2>&1 &
运行一段时间后,我发现log.txt里面的日志占了很大的磁盘空间,于是我就准备手动的清空log.txt文件,执行了下面的命令:
$ > log.txt
命令执行之后,输入ll查看一下最终结果,发现log.txt的大小确实变成了0,正准备满心欢喜的收工去喝杯小酒解解乏,基于程序员的敏感度,我进行了二次确认,就发送了一个新请求,待新请求出现后再次输入了ll命令检查日志文件,发现日志文件占用的磁盘大小又变回了为清空之前的模样,好像我们执行的清空命令毫无作用,赶紧查看一下log.txt的内容:
发现日志文件前半部分缺失内容被清空了,文件的尾部出现了我二次确认时发送的请求,神奇。
3、根因分析:
3.1、采用daphne + starlette验证
重复了上面的步骤,发现日志可以正常清空,于是排除starlette的问题,问题出现在uvicorn上
3.2、查看uvicorn的日志配置
默认情况下,uvicorn使用了logging.StreamHandler,流式写入日志,logging.StreamHandler 会记录文件写入位置,在下一次写入日志时会自动seek到上一次的位置再写新日志。由于日志已被清空,所以在上一次写入位置之前的内容全部为NUL,即0。
uvicorn按天输出访问日志配置
其实从一开始我就不应该使用默认的日志输出方式,而应该采用自定义的方式,比如一天生成一个文件,或者一小时生成一个文件,这样过期的文件直接删除,也不需要手动做清空操作。于是开始寻找解决方案。从上面的截图我们可以看到,uvicorn默认有个配置文件,仿照它来写即可。
1、日志配置文件:
uvicorn支持多种格式的配置文件,我们这里采用大家日常比较熟悉的格式:json,新建一个uvicorn_log.json:
{
"version": 1,
"disable_existing_loggers": "False",
"formatters": {
"default": {
"()": "uvicorn.logging.DefaultFormatter",
"fmt": "%(levelprefix)s %(message)s",
"use_colors": "None"
},
"access": {
"()": "uvicorn.logging.AccessFormatter",
"fmt": "%(levelprefix)s %(client_addr)s - %(request_line)s %(status_code)s"
}
},
"handlers": {
"default": {
"formatter": "default",
"class": "logging.StreamHandler",
"stream": "ext://sys.stderr"
},
"access": {
"formatter": "access",
"class": "logging.handlers.TimedRotatingFileHandler",
"filename": "./access.log",
"when": "MIDNIGHT",
"interval": 1,
"backupCount": 5,
"level": "DEBUG"
}
},
"loggers": {
"uvicorn": {
"handlers": [
"default"
],
"level": "INFO",
"propagate":0
},
"uvicorn.error": {
"handlers": [
"default"
],
"level": "INFO",
"propagate":0
},
"uvicorn.access": {
"handlers": [
"access"
],
"level": "INFO",
"propagate":0
}
}
}
注意事项:
1、"propagate":0 这个地方需要配置为0,而不是False,因为代码里面是利用 if not 判断的
2、"when": "MIDNIGHT"这个地方如果你想每天生成一个文件,需要配置为MIDNIGHT,而不是D,配置为D是每隔24小时生成一个文件
2、日志文件使用
使用--log-config uvicorn_log.json来启动uvicorn即可
$ more run_s
nohup uvicorn server:app --host 0.0.0.0 --port 6786 --log-config uvicorn_log.json > log.txt 2>&1 &
总结:
1、默认的uvicorn的日志清空存在BUG,建议不要使用
2、采用按一定的间隔来生成文件的策略更简单,让Python自己来维护日志文件的生成与清理