日志模块设计

ooowl
  • 系统设计
  • 系统设计
  • 日志
About 3 min

日志模块设计

模块说明

此模块使用的是责任链模式和简单工厂,注册即可用,主要用来监控所有的请求和日常项目中的日志打印。

系统日志中记录了请求的头,参数响应,请求的信息等,每个请求都有唯一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

目前还没有错误日志采集

日志模块用法

  1. 模块引入之后,先在app中注册中间件
from app.logcollection import CustomMiddleware # 注意包路径
app.add_middleware(CustomMiddleware)
  1. 使用的时候在logpiplines文件夹下创建python文件,像下面所说实现Handler类即可自动引入调用。 默认已经使用loguru实现的是系统日志和手动日志打印控制台以及单个文件(logs文件夹,也可以手动指定LOGFILEPATH 应该是WORKDIR的相对路径,注意),以及注释起来的,让手动日志分模块写入
    在模块中使用from app.logcollection import logger 调用logger对象的方法即可打印手动日志
  2. 日志分两类:
    • 系统日志
       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}")
  1. 如果在PIPLINE中使用loguru全局的sink是共享的,一定要注意,也就是如果你原先有loguru在处理,可能导致写入乱七八糟的日志
  2. 日志模块的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...