# logger.py
import logging
import socket
import threading
import uuid
from logging.config import dictConfig
local = threading.local()
# 定义一个类,用于实现自定义的过滤器功能
class RequestFilter(logging.Filter):
def filter(self, record):
get_req_id()
request_id = getattr(local, "request_id", None) # 获取当前线程的请求ID
ip = getattr(local, "ip", None) # 获取当前线程的IP
record.request_id = request_id # 将请求ID添加到日志记录对象的extra属性中
record.ip = ip # 将IP添加到日志记录对象的extra属性中
return True # 返回True表示该日志记录可以被处理
def generate_uid():
uid = str(uuid.uuid4())[-8:]
th_name = threading.currentThread().name
_uid = f'{th_name}_{uid}'
# _uid = str(uuid.uuid4())
return _uid.replace('-', '_').lower()
def get_req_id():
if hasattr(local, 'request_id'):
return local.request_id
else:
# local.request_id = str(uuid.uuid4()).replace('-', '_') # 随机生成一个请求ID,并存储在本地变量中, 替换下划线方便复制
local.request_id = generate_uid() # 随机生成一个请求ID,并存储在本地变量中
local.ip = socket.gethostbyname(socket.gethostname()) # 获取本机IP地址,并存储在本地变量中
return local.request_id
LOGGING_CONFIG = {
'version': 1, # 版本号,必须为1
'disable_existing_loggers': False, # 是否禁用已存在的logger对象
'filters': { # 过滤器对象,用于对日志记录进行过滤操作
'request_filter': { # 名称为request_filter 的过滤器
'()': RequestFilter # 使用自定义的RequestFilter 类来创建过滤器对象
}
},
'formatters': { # 格式化器对象,用于定义日志的格式
'console_fmt': { # 名称为info的格式化器
'format': '[{asctime}] [{request_id}] [{module}.{funcName}:{lineno}] [{levelname:^8s}] {message}',
'style': '{',
},
'info': { # 名称为info的格式化器
'format': '[{asctime}] [{ip}] [{request_id}] [{module}.{funcName}:{lineno}] [{levelname:^8s}] [{message}]',
'style': '{',
},
'error': { # 名称为error的格式化器
'format': '[{asctime}] [{ip}] [{request_id}] [{module}.{funcName}:{lineno}] [{levelname:^8s}] [{message}]',
'style': '{',
}
},
'handlers': { # 处理器对象,用于将日志记录发送到不同的目的地
'info_rotating_file_handler': { # 名称为info_rotating_file_handler的处理器,使用RotatingFileHandler类创建
'level': "INFO", # 处理INFO及以上级别的日志记录(根据参数level决定)
'formatter': 'info', # 使用info格式化器来格式化日志记录
'class': 'logging.handlers.TimedRotatingFileHandler', # 使用TimedRotatingFileHandler类来创建处理器对象
'filename': "flask.log", # 将日志记录写入path指定的文件中(根据参数path决定)
'when': 'midnight', # 在每天凌晨进行日志切割
'backupCount': 10, # 保留最近10天的日志备份文件
'filters': ['request_filter'], # 使用request_filter过滤器来过滤日志记录
# 'filemode': 'a'
},
'error_file_handler': { # 名称为error_file_handler的处理器,使用FileHandler类创建
'level': 'ERROR', # 处理ERROR及以上级别的日志记录(根据参数level决定)
'formatter': 'error', # 使用error格式化器来格式化日志记录
'class': 'logging.FileHandler', # 使用FileHandler类来创建处理器对象
'filename': 'flask.log', # 将日志记录写入path指定的文件中,并加上.err后缀(根据参数path决定)
'filters': ['request_filter'], # 使用request_filter过滤器来过滤日志记录
# 'mode': 'a'
},
"console_handler": { # 名称为console_handler的处理器,使用StreamHandler类创建
"level": "DEBUG", # 处理DEBUG及以上级别的日志记录
"formatter": "console_fmt", # 使用info格式化器来格式化日志记录
"class": "logging.StreamHandler", # 使用StreamHandler类来创建处理器对象
"stream": "ext://sys.stdout", # 将日志记录输出到标准输出流中
'filters': ['request_filter'] #
},
'wsgi': { # 名称为info_rotating_file_handler的处理器,使用RotatingFileHandler类创建
'level': "DEBUG", # 处理INFO及以上级别的日志记录(根据参数level决定)
'formatter': 'info', # 使用info格式化器来格式化日志记录
'class': 'logging.handlers.TimedRotatingFileHandler', # 使用TimedRotatingFileHandler类来创建处理器对象
'filename': "wsgi.log", # 将日志记录写入path指定的文件中(根据参数path决定)
'when': 'midnight', # 在每天凌晨进行日志切割
'backupCount': 10, # 保留最近10天的日志备份文件
'filters': ['request_filter'], # 使用request_filter过滤器来过滤日志记录
# 'filemode': 'a'
},
# 'wsgi': {
# 'class': 'logging.FileHandler', # 使用FileHandler类来创建处理器对象
# "level": "DEBUG", # 处理DEBUG及以上级别的日志记录
# # 'stream': 'ext://flask.logging.wsgi_errors_stream',
# 'formatter': 'info',
# 'filename': 'wsgi.log',
# 'filters': ['request_filter'] #
# },
},
'loggers': { # 日志收集器对象,用于管理不同的logger对象
# "root": { # 名称为name指定的logger对象(根据参数name决定)
# 'handlers': ['info_rotating_file_handler', 'error_file_handler', 'console_handler', 'wsgi'],
# # 使用两个处理器来处理该logger对象的日志记录
# 'level': "DEBUG", # 设置该logger对象的级别(根据参数level决定)
# 'propagate': False # 设置该logger对象是否向上级传递,默认为False,表示不传递
# },
'sqlalchemy.engine': { # 支持对sqlalchemy日志收集
'level': "DEBUG",
'handlers': ['info_rotating_file_handler', 'error_file_handler', 'console_handler'],
}
},
"root": { # 名称为name指定的logger对象(根据参数name决定)
'handlers': ['info_rotating_file_handler', 'error_file_handler', 'console_handler', 'wsgi'],
# 'handlers': ['info_rotating_file_handler', 'error_file_handler', 'console_handler'],
# 使用两个处理器来处理该logger对象的日志记录
'level': "DEBUG", # 设置该logger对象的级别(根据参数level决定)
'propagate': False # 设置该logger对象是否向上级传递,默认为False,表示不传递
},
}
dictConfig(LOGGING_CONFIG) # 根据字典配置信息,配置logger对象
log = logging.getLogger()
if __name__ == '__main__':
def log_test():
log.info('hello world')
import time
def worker(num):
log.info('Worker %d started' % num)
time.sleep(1)
log.info('Worker %d finished' % num)
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
t.start()
log.info('done')
log_test()
标签:info,logging,level,Python,request,handler,日志,id,模板
From: https://www.cnblogs.com/l806760/p/17492918.html