不管运行程序的平台是 docker 还是 k8s, 采集日志有两种方案:
- 方案一:采集程序的标准输出
- 方案二:程序把日志写文件中,然后采集日志文件
在先来分析一下方案一和二的好坏
方案一的坏处就是:『多行日志采集』
不管是用『行首正则表达式』还是『json化』都不是优雅的解决方案
『行首正则表达式』,不是所有模块的日志都有固定格式,当然,想要强制一致也有办法;『json化』:没有格式化的 json 是人类不可读的,『json化』方便了程序,但是恶心了程序员的眼睛
所以,pass
方案二:没有缺点
我怎么用的:程序,即打印日志到标准输出,又写入日志文件
- 打印日志到标准输出: 这是给人看到,可以直接使用 docker logs、docker-compose logs、kubectl logs 直接看,方便
- 写入日志文件:使用 loguru 的 serialize='json' 将单条日志写入日志文件
所以这些日志输出方案,及满足了程序员直接查看日志,也方便程序的采集。
那具体如何实现呢?直接上代码
from loguru import logger
from mark import BASE_DIR
import settings
import os
import json
from loguru._handler import Handler
from loguru._recattrs import RecordException
log_path = BASE_DIR/'logs'
if not os.path.exists(log_path):
os.makedirs(log_path)
def _serialize_record(text: str, record: dict):
exception: RecordException = record["exception"]
if exception is not None:
exception = {
"type": None if exception.type is None else exception.type.__name__,
"value": exception.value,
"traceback": bool(exception.traceback),
}
serializable = {
"text": text,
"record": {
"extra": record["extra"],
},
}
return json.dumps(serializable, default=str, ensure_ascii=False) + "\n"
Handler._serialize_record = staticmethod(_serialize_record)
logger.add(
log_path/'run.log',
serialize='json',
rotation='100 MB',
retention=1
)
最重要的就是下面这段,我们添加一个日志处理器,用于将日志写到文件中
第一个参数指定,写哪里
第二个参数指定,用什么格式写,这里用 json,因为这样可以避免『打印堆栈错误会多行』的问题
第三、四个参数指定,表示日志轮换规则,写慢 100 MB,就备份一下,然后从 0MB 重新开始,总共有 1 份
logger.add(
log_path/'run.log',
serialize='json',
rotation='100 MB',
retention=1
)
loguru 使用 serialize='json' 默认输出的字段太多了,所以我们使用猴子补丁,替换 _serialize_record
函数,去掉不需要的字段,节约日志存储成本
参考文章:
loguru 如何轮换日志
loguru serialize 减少字段
如何使用 loguru 接管程序的所有日志输出
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。