django多线程_深入理解Django-Logging模块

Django-Logging日志

介绍并研究Logging模块的原理和Django实际生产环境中使用需要注意的点。

Logging介绍

当后端服务运行在生产环境中时,服务对外来说是一个黑盒,作为开发人员就需要做到对服务的监控和跟踪。因此logging模块就显得十分重要,logging模块允许我们的去构造一些非常有用的日志信息用于跟踪和监控。

Python的logging模块可以很好的适用于各种复杂的情况:

  • 多线程支持:Multi-threading support
  • 支持不同的日志级别:Categorization via different levels of logging
  • 灵活性并可配置:Flexibility and configurability

Logging架构

整体日志处理的流程如下,有如下几个关键的模块依次介绍:

  • Logger
  • Log Record
  • Handlers
  • Formatters
  • Filters

25140dfbe3888477c6029ca96b923f4c.png

Logger

该模块是开发者最常用到的模块. 当使用logger.info("Stock was sold at %s", price),即有如下图的情况。

e4677f3d843f88b59a2523927cec592b.png

Log records

该模块是logging用来记录所有必要信息的模块,即一条日志的信息,日志中的关键参数,调用栈信息等等,都包含在record中。可以说record对象是存储日志信息并被handler序列化至控制台或者文件中。

Handlers

该模块将log record记录并输出。Handler模块的主要作用是对日志进行分发和传播。

标准logging模块中有如下几个内建的handler

  • FileHandler:记录日志到文件中
  • StreamHandler: 记录日志到流中stdout,stderr
  • SMTPHandler: 通过Email发送日志
  • SockerHandler: 发送日志到Socket流中
  • SyslogHandler, NTEventHandler, HTTPHandler, MemoryHandler

d3d44b3cf47f6a8a768d2017059e9898.png

Formatters

该模块是将metadata-richlog record序列化到字符串。

例如:'%(asctime)s %(levelname)s %(name)s: %(message)s' 将会被构造成

“2017-07-19 15:31:13,942 INFO parent.child: Hello EuroPython.”

7dda9a9143941d7fe2c618186ca6264a.png

Filters

该模块是更细粒度控制日志的工具。开发者可以自己定义具体的filter方法,并对log record进行操作,返回True/False. Filters返回False, 则当前Logger拒绝此次日志记录。

下图是一个日志处理的全部流程:当如果设置了propagate==True则就会将日志信息继续传递给父节点的handler进行处理。即当使用了LOG=logging.getLogger(__name__), 当传入__name__的为参数时,将会建立以项目Project为基础的日志等级关系,当前日志没有命中时使用父节点的handler。

fb3726d3a38c35e2a61f13593be273f9.png

实际运用-Django

在实际的Django项目中,记录请求日志和对应的全局唯一的 request_id.
  • 自定义Filter:用来在log record中记录当前请求的request_id
  • 自定义Middlewarel:用来做Django的Middleware,并将其添加到DjangoMiddleware
  • 自定义Log格式
class RequestIDFilter(logging.Filter):

    def filter(self, record):
        record.request_id = getattr(worker_local, 'request_id')
        return True
    
class RequestIdMiddleware(MiddlewareMixin):
    def process_request(self, request):
        worker_local.request_id = request.META.get('REQUEST_ID', create_unique_id())

    def process_response(self, request, response):
        LOG.info("{} {} status: {}".format(request.method, request.path, response.status_code))
        return response
自定义 LOGGING时,注意在具体的某个 handler中定义具体的 class, formatter, class.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'request_id': {
            "()": "project.middleware.logging.RequestIDFilter",
        }
    },
    'formatters': {
        'verbose': {
            'format': '[%(levelname)s][%(asctime)s][%(module)s] [%(request_id)s] %(message)s'
        },
        'simple': {
            'format': '[%(levelname)s] %(message)s'
        }
    },

    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler'
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
            'filters': ['request_id']
        },
    },
    'loggers': {
        '': {
            'level': 'INFO',
            'handlers': ['console'],
        },
        'project': {
            'level': 'INFO',
            'handlers': ['console'],
            'propagate': False
        },

    },
}

这样就可以实现,打印日志的同时,添加了关键的request_id字段,方便跟踪和定位问题。

总结

Python的Logging模块提供了丰富的功能,能应对各种复杂场景。在生产环境中,项目具备良好的,可读性强的日志,可以方便开发人员跟踪定位问题。总之,日志是非常重要的一环,本文只是对日志模块结合自己的实践经历做简单的总结,以后还需要学习更多并实践更多。

Reference

  • guide-logging-python
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值