日志模块设计
日志模块设计
模块说明
此模块使用的是责任链模式和简单工厂,注册即可用,主要用来监控所有的请求和日常项目中的日志打印。
系统日志中记录了请求的头,参数响应,请求的信息等,每个请求都有唯一ID;手动日志中记录了请求方法ip地址,有唯一ID可以关联系统日志查询
模块记录参数和响应只记录JSON格式的,其他的不做记录
日志的查询模块可以单独写,模块可能损耗性能的地方在于响应序列化和反序列化,生成uuid,以及pipline的处理。
如果pipline性能瓶颈可以将pipline都关闭,然后写一个队列pipline把数据放MQ使用worker处理
日志目录
.
├── README.md
├── __init__.py
├── custom_logger.py
├── logpiplines
│ ├── __init__.py
│ ├── logs
│ │ ├── manual_65844_log.log
│ │ └── system_65844_log.log
│ ├── sql_pipline.py
│ └── std_out_pipline.py
├── middleware_reg.py
└── persistence.py
目前还没有错误日志采集
日志模块用法
- 模块引入之后,先在app中注册中间件
from app.logcollection import CustomMiddleware # 注意包路径
app.add_middleware(CustomMiddleware)
- 使用的时候在logpiplines文件夹下创建python文件,像下面所说实现Handler类即可自动引入调用。 默认已经使用loguru实现的是系统日志和手动日志打印控制台以及单个文件(logs文件夹,也可以手动指定LOGFILEPATH 应该是WORKDIR的相对路径,注意),以及注释起来的,让手动日志分模块写入
在模块中使用from app.logcollection import logger
调用logger对象的方法即可打印手动日志 - 日志分两类:
- 系统日志
logobj = {"level": "INFO", # 固定INFO
"logtype": "Inbound" or "Outbound",
"request_id": uuid4:str,
"url": 字符串,
"req_path":请求路径,
"client_ipport": "127.0.0.1:80", # 请求者ip端口
"http_method": 此次请求的方法,
"logtime": datetime.now(),
"timeconsume": 请求耗时 Inbound为None,
"response_data":response_data, # 响应数据 Inbound为None
"path_params":path_params, # 路径参数
"query_params":query_params, # 关键字参数
"request_body":body_json # 携带的请求体,默认就{}
}
- 手动日志
logobj = {"level": CustomLogger中规定["DEBUG","INFO","WARNING","ERROR","CRITICAL"],
"logtype": "Manual",
"logtime": datetime.now() ,
"message": 字符串,
"extra_data": 任意字典,
"request_id": uuid4:str,
"url": 字符串,
"req_path":请求路径,
"client_ipport": "127.0.0.1:80", # 请求者ip端口
"http_method": 此次请求的方法
}
对应Handler分两个,一类是ManualLogHandler,SystemLogHandler,继承了哪个Handler就会加入责任链处理对应type的日志
from ..persistence import log_persister, ManualLogHandler, SystemLogHandler
@log_persister # 用这个装饰器装饰
class InfoHandler(ManualLogHandler): # 继承Handler类
def __init__(self):
super().__init__(-1) # 指定pipline的处理优先级,不定义此方法默认都是-1随机,越大越早处理
def process(self, message): # 必须实现的实现处理函数
print(f"日志对象为: {message}")
- 如果在PIPLINE中使用loguru全局的sink是共享的,一定要注意,也就是如果你原先有loguru在处理,可能导致写入乱七八糟的日志
- 日志模块的uuid功能是使用ContextVar实现,这个模块只在py3.7以上内置,并且在一些上下文被切换掉的情况下不能用
- 在多线程环境中运行异步代码,如果你使用多线程库(例如,concurrent.futures.ThreadPoolExecutor)在一个独立的线程中运行代码,这段代码是无法访问在主线程(处理 HTTP 请求的线程)中设置的 ContextVar 变量的。
- 使用外部系统的回调,比如MQ的时候
- 在不同的事件循环或不同的 Task 中,如果你创建一个与请求处理完全解耦的新任务(例如,使用 asyncio.create_task()),那么这个任务就不会自动继承当前请求的 ContextVar 变量。
- 理论上来说可以在async和非asyncAPI中混着用,但是一般async方法是用来执行后台任务的,时间过长ID会被其他的请求重置,所以使用logger的get_request_var获得变量手动方法传递到handler处理
模块开发者
- jack
and his miku
Loading...