对logging 模块的调整应用
目标需求:
1、在正常的logging 中打印中默认增加其他信息
2、在django后台打印中,增加对应的信息内容
实现:
1、调整logging 模块的 Formatter 或 Filter 的模块,让在正常打印的内容中增加一些其他前置函数中的 信息
import threading
import logging
# 这边使用的是 threading.local() 存放线程中的数据
local = threading.local()
# 配置 filter 或 formatter
# 在filter 的 record 中增加字段
class changeLoggingFilter(logging.Filter):
def filter(self, record):
record.new_info = getattr(local, 'new_info', 'none')
record.new_info2 = getattr(local, 'new_info2', 'none')
record.new_info3 = getattr(local, 'new_info3', 'none')
return True
# 在formatter 中 判断是否有这 几个新参数
class changeLoggingFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
if not hasattr(record, 'new_info'):
record.new_info = getattr(local, 'new_info', 'none')
if not hasattr(record, 'new_info2'):
record.new_info2 = getattr(local, 'new_info2', 'none')
if not hasattr(record, 'new_info3'):
record.new_info3 = getattr(local, 'new_info3', 'none')
return super().format(record)
# 使用 先把调整的 filter 或 fotmatter 放入logging 模块中
# 1、使用formatter 的方式调整打印数据信息
def change_formatter():
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = changeLoggingFormatter(fmt='%(asctime)s [%(levelname)s] [new_info=%(new_info)s] [new_info2=%(new_info2)s] [new_info3=%(new_info3)s] %(message)s', datefmt=None)
if logger.handlers:
logger.handlers[0].setFormatter(formatter)
else:
sh = logging.StreamHandler()
sh.setFormatter(formatter)
logger.addHandler(sh)
# 2、调整 filter 的方式调整打印输出的信息
def change_filter():
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
f = changeLoggingFilter()
logger.addFilter(f)
formatter = logging.Formatter('%(asctime)s [%(levelname)s] [new_info=%(new_info)s] [new_info2=%(new_info2)s] [new_info3=%(new_info3)s] %(message)s')
if logger.handlers:
logger.handlers[0].setFormatter(formatter)
else:
sh = logging.StreamHandler()
sh.setFormatter(formatter)
logger.addHandler(sh)
def check_logging_start():
new_info = '1111111111'
new_info2 = '2222222222'
new_info3 = '3333333333'
local.new_info = new_info
local.new_info2 = new_info2
local.new_info3 = new_info3
logging.debug('this debug message~~')
logging.info('this info message~~')
logging.warning('this warn message~~')
logging.error('this error message~~')
if __name__ == '__main__':
change_formatter()
# change_filter()
check_logging_start()
2、在django中增加logging 和控制台输出的请求打印日志
说明:django 中可以使用 中间件 来提前对logging 模块做处理,测试使用的threading.local(),在 settings 中使用LOGGING 中导入filter 的方式,显示使用的不是同一个线程存储空间,就在中间件中直接调整
# 中间件的调用
# 一、Django默认的中间件:在django项目的settings模块中,有一个 MIDDLEWARE 变量,其中每一个元素就是一个中间件
# 1.在项目名或者应用名下创建一个任意名称的文件夹,如:mymiddlewear,
# 2.在该文件夹内创建一个任意名称的py文件,如:mymiddle
# 3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin),在这个类里面就可以自定义五个方法了,这五个方法并不是全部都需要书写,用几个写几个
process_request(self,request) # 请求相关
process_response(self, request, response) # 响应相关
process_view(self, request, callback, callback_args, callback_kwargs) # 路由层到视图层中间
process_template_response(self,request,response) # 视图层到模板层中间
process_exception(self, request, exception) # 视图函数出现异常
# 4.需要将类的路径以字符串的形式注册到配置文件中才能生效;在应用下创建的,注册路径时有提示,项目下创建的则没有提示
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'mymiddlewear.mymiddle.M1', # 你自己写的中间件的路径
]
# 二、在创建的中间件mymiddle py文件中调整logging 模块,在中间件 M1 类中
import datetime
import logging
import time
import traceback
import threading
from django.utils.deprecation import MiddlewareMixin
import uuid
local = threading.local()
# logging.raiseExceptions = False # 这个打开后,所有的 loggin 模块自带的 异常都不会打印
class change_formatter(logging.Formatter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def format(self, record):
if not hasattr(record, 'request_id'):
record.request_id = getattr(local, 'request_id', 'none')
return super().format(record)
# # 从local 中获取threading 中的信息
# class change_filter(logging.Filter):
# def filter(self, record):
# record.request_id = getattr(local, 'request_id', 'none')
# return True
# 这边使用的 是 调整formatter 的类来替换 django 中使用的所有formatter 格式
class M1(MiddlewareMixin):
def __init__(self, get_response=None):
super().__init__(get_response)
# 对两个打印信息做调整
# 使用 调整formatter 的方式来替换所有的打印
logger_server = logging.getLogger('django.server') # django 的默认响应log 信息
logger = logging.getLogger() # django中其他 使用的 logging 模块初始化
# 替换 django 默认打印的 formatter
django_formatter = change_formatter(fmt='%(server_time)s [request-id=%(request_id)s] %(message)s', datefmt=None)
logger_server.handlers[0].setFormatter(django_formatter)
# 替换 django 中 使用的 所有 logging 模块的 打印的formatter 的前置信息
formatter = change_formatter(fmt='%(asctime)s [%(levelname)s] [request-id=%(request_id)s] %(message)s', datefmt=None)
logger.handlers[0].setFormatter(formatter)
# 使用filter 的方式调换(这个方式有弊端,当框架中有其他新初始化的logging 模块时,也需要导入这个类进去,才不会报 keyerror 的异常)
# logger_server = logging.getLogger('django.server') # django 的默认响应log 信息
# logger = logging.getLogger() # django中其他 使用的 logging 模块初始化
# f = UserRunningProgramFilter() # 初始化 filter 里面增加 request_id 信息
# logger_server.addFilter(f)
# logger.addFilter(f)
# formatter = logging.Formatter('%(asctime)s [%(levelname)s] [request-id=%(request_id)s] %(message)s')
# django_formatter = logging.Formatter('%(server_time)s [request-id=%(request_id)s] %(message)s')
# logger_server.handlers[0].setFormatter(django_formatter)
# logger.handlers[0].setFormatter(formatter)
# or
# sh = logging.StreamHandler()
# sh.setFormatter(formatter)
# logger.addHandler(sh)
def process_request(self, request):
self.request_id = str(uuid.uuid4())
local.request_id = self.request_id
def process_response(self, request, response):
response.headers['request-id'] = self.request_id