Django 中如何优雅的记录日志(1),大佬手把手教你如何仿写出大厂的APP

self.logger.addHandler(fh)

创建一个StreamHandler,用于输出到控制台

ch = logging.StreamHandler()

ch.setLevel(logging.DEBUG)

ch.setFormatter(self.formatter)

self.logger.addHandler(ch)

if level == ‘info’:

self.logger.info(message)

elif level == ‘debug’:

self.logger.debug(message)

elif level == ‘warning’:

self.logger.warning(message)

elif level == ‘error’:

self.logger.error(message)

这两行代码是为了避免日志输出重复问题

self.logger.removeHandler(ch)

self.logger.removeHandler(fh)

关闭打开的文件

fh.close()

def debug(self, message):

self.__console(‘debug’, message)

def info(self, message):

self.__console(‘info’, message)

def warning(self, message):

self.__console(‘warning’, message)

def error(self, message):

self.__console(‘error’, message)

这是我在项目中还在用的一段代码,生成的文件按天进行切分。

当时写这段代码,有个问题折腾了我很久,就是显示代码报错行数的问题。当 formatter 配置 %(lineno)d 时,每次并不是显示实际的报错行,而是显示日志类中的代码行,但这样显示就失去意义了,所以也就没有配置,用了 %(name)s 来展示实际的调用文件。

其实,如果只是为了排错方便,记录一些日志,这个类基本可以满足要求。但如果要记录访问系统的所有请求日志,那就无能为力了,因为不可能手动在每个接口代码加日志,也没必要。

这个时候,很自然就能想到 Django 中间件了。

Django 中间件

中间件日志代码一共分三个部分,分别是:Filters 代码,middleware 代码,settings 配置,如下:

local = threading.local()

class RequestLogFilter(logging.Filter):

“”"

日志过滤器

“”"

def filter(self, record):

record.sip = getattr(local, ‘sip’, ‘none’)

record.dip = getattr(local, ‘dip’, ‘none’)

record.body = getattr(local, ‘body’, ‘none’)

record.path = getattr(local, ‘path’, ‘none’)

record.method = getattr(local, ‘method’, ‘none’)

record.username = getattr(local, ‘username’, ‘none’)

record.status_code = getattr(local, ‘status_code’, ‘none’)

record.reason_phrase = getattr(local, ‘reason_phrase’, ‘none’)

return True

class RequestLogMiddleware(MiddlewareMixin):

“”"

将request的信息记录在当前的请求线程上。

“”"

def init(self, get_response=None):

self.get_response = get_response

self.apiLogger = logging.getLogger(‘web.log’)

def call(self, request):

try:

body = json.loads(request.body)

except Exception:

body = dict()

if request.method == ‘GET’:

body.update(dict(request.GET))

else:

body.update(dict(request.POST))

local.body = body

local.path = request.path

local.method = request.method

local.username = request.user

local.sip = request.META.get(‘REMOTE_ADDR’, ‘’)

local.dip = socket.gethostbyname(socket.gethostname())

response = self.get_response(request)

local.status_code = response.status_code

local.reason_phrase = response.reason_phrase

self.apiLogger.info(‘system-auto’)

return response

settings.py 文件配置:

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’,

自定义中间件添加在最后

‘lib.log_middleware.RequestLogMiddleware’

]

LOGGING = {

版本

‘version’: 1,

是否禁止默认配置的记录器

‘disable_existing_loggers’: False,

‘formatters’: {

‘standard’: {

‘format’: ‘{“time”: “%(asctime)s”, “level”: “%(levelname)s”, “method”: “%(method)s”, “username”: “%(username)s”, “sip”: “%(sip)s”, “dip”: “%(dip)s”, “path”: “%(path)s”, “status_code”: “%(status_code)s”, “reason_phrase”: “%(reason_phrase)s”, “func”: “%(module)s.%(funcName)s:%(lineno)d”, “message”: “%(message)s”}’,

‘datefmt’: ‘%Y-%m-%d %H:%M:%S’

}

},

过滤器

‘filters’: {

‘request_info’: {‘()’: ‘lib.log_middleware.RequestLogFilter’},

},

‘handlers’: {

标准输出

‘console’: {

‘level’: ‘ERROR’,

‘class’: ‘logging.StreamHandler’,

‘formatter’: ‘standard’

},

自定义 handlers,输出到文件

‘restful_api’: {

‘level’: ‘DEBUG’,

时间滚动切分

‘class’: ‘logging.handlers.TimedRotatingFileHandler’,

‘filename’: os.path.join(LOGS_DIR, ‘web-log.log’),

‘formatter’: ‘standard’,

调用过滤器

‘filters’: [‘request_info’],

每天凌晨切分

‘when’: ‘MIDNIGHT’,

保存 30 天

‘backupCount’: 30,

},

},

‘loggers’: {

‘django’: {

‘handlers’: [‘console’],

‘level’: ‘ERROR’,

‘propagate’: False

},

‘web.log’: {

‘handlers’: [‘restful_api’],

‘level’: ‘INFO’,

此记录器处理过的消息就不再让 django 记录器再次处理了

‘propagate’: False

},

}

}

通过这种方式,只要过 Django 的请求就都会有日志,不管是 web 还是 Django admin。具体记录哪些字段可以根据项目需要进行获取和配置。

有一点需要注意的是,通过 request.user 来获取用户名只适用于 session 的认证方式,因为 session 认证之后会将用户名赋值给 request.user,所以才能取得到。

假设用 jwt 方式认证,request.user 是没有值的。想要获取用户名可以有两种方式:一是在日志中间件中解析 jwt cookie 获取用户名,但这种方式并不好,更好的方法是重写 jwt 认证,将用户名赋值给 request.user,这样就可以在其他任何地方调用 request.user 来取值了。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
img

n/img_convert/6c361282296f86381401c05e862fe4e9.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
[外链图片转存中…(img-LDRcdDgh-1711929043693)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值