IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python logging 添加上下文信息 -> 正文阅读

[Python知识库]python logging 添加上下文信息

官方文档中有两种方式,适配器(Adapter)和过滤器(filter)。具体地址在文末。

第一种,使用适配器。

使用LoggerAdapter 类,重写它的process方法,将上下文信息添加到日志的输出中。我理解就是,专为logger自定义输出日志而写的类,接收logger和extra。在process方法里,按照自己的想法把message信息格式化。并返回message和kw。

?博客1的例子非常详细,同时也指出了当时我按照例子写后发现不妥的地方。就是loggerAdapter已经不是原来的logger,尽管同样可以error,info。但是在不同的地方去获取logger时,取到的还是原来的。这和我预想的不一致,如果原来的代码已经大量使用,这时就不适合在改动了。

from logging import LoggerAdapter
import logging


logger = logging.getLogger(__name__)


class SesssionLoggerAdapter(LoggerAdapter):

    def process(self, msg, kwargs):
        if 'session' not in self.extra or self.extra['session'] is None:
            return msg, kwargs
        session = self.extra['session']
        if hasattr(session, 'request_id'):
            msg += ', request_id({})'.format(session.request_id)
        if 'extra' not in kwargs:
            kwargs["extra"] = self.extra
        else:
            kwargs['extra'].update(self.extra)
        return super().process(msg, kwargs)


class Session():
    def __init__(self):
        super().__init__()

    @property
    def request_id(self):
        return self._request_id

    @request_id.setter
    def request_id(self, request_id):
        self._request_id = request_id


session = Session()
logger.warning('abc')
# 这里尽管覆盖了原logger,但是只在这里覆盖,其它地方获取logger = logging.getLogger(__name__)结果并没有用。
logger = SesssionLoggerAdapter(logger, {'session': session})
session.request_id = '0'
logger.warning('hello world')
session.request_id = '1'
logger.warning('hello world')

https://segmentfault.com/a/1190000022506342

第二种,就是使用过滤器。

按道理,看名字,过滤器不应该修改message内容信息的,只能说,用filter过滤器这个词不太合适。还是看官方文档。继承logging.Filter类,重写filter方法,然后给logger添加自己重写的过滤器即可。在重写的过滤器里重新组织message。不过官方文档给的例子,写的太复杂了,最后一行,我还以为必须要每个log时要手动改。

import logging
from random import choice

class ContextFilter(logging.Filter):
    """
    This is a filter which injects contextual information into the log.

    Rather than use actual contextual information, we just use random
    data in this demo.
    """

    USERS = ['jim', 'fred', 'sheila']
    IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1']

    def filter(self, record):

        record.ip = choice(ContextFilter.IPS)
        record.user = choice(ContextFilter.USERS)
        return True

if __name__ == '__main__':
    levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s')
    a1 = logging.getLogger('a.b.c')
    a2 = logging.getLogger('d.e.f')

    f = ContextFilter()
    a1.addFilter(f)
    a2.addFilter(f)
    a1.debug('A debug message')
    a1.info('An info message with %s', 'some parameters')
    for x in range(10):
        lvl = choice(levels)
        lvlname = logging.getLevelName(lvl)
        a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')

官方文档下filter下的例子就很简单,就是在filter里重新组织message,最后返回true就行。这里就和上面的适配器不一样了,这里修改的就是原本的logger,这样,原本的代码就不用动。官网是使用dict来配置logger的,我们不管怎么配置,拿到logger后添加filter即可,如下直接添加filter的代码片段。

import logging
import logging.config
import sys

class MyFilter(logging.Filter):
    def __init__(self, param=None):
        self.param = param

    def filter(self, record):
        if self.param is None:
            allow = True
        else:
            allow = self.param not in record.msg
        if allow:
            record.msg = 'changed: ' + record.msg
        return allow

LOGGING = {
    'version': 1,
    'filters': {
        'myfilter': {
            '()': MyFilter,
            'param': 'noshow',
        }
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'filters': ['myfilter']
        }
    },
    'root': {
        'level': 'DEBUG',
        'handlers': ['console']
    },
}

if __name__ == '__main__':
    logging.config.dictConfig(LOGGING)
    logging.debug('hello')
    logging.debug('hello - noshow')

直接添加filter的代码片段:

import logging

logger = logging.getLogger("arview")


class MyFilter(logging.Filter):
    def __init__(self, param=None):
        self.param = param

    def filter(self, record):
        if self.param is None:
            allow = True
        else:
            allow = self.param not in record.msg
        if allow:
            request_id = "-"
            if hasattr(request, "requestId"):
                request_id = getattr(request, "requestId")
            record.msg = ',request_id({}),'.format(request_id) + record.msg
        return allow

user_id_filter = MyFilter()
logger.addFilter(user_id_filter)

当然还有一种方法,在每次log时传入extra,但是大部分情况下,不适合这种方式,还是希望每次log时自动加入上下文信息。具体可见博客2。

参考资料:

官方文档:

日志操作手册 — Python 3.7.13 文档

博客1:

https://segmentfault.com/a/1190000022506342

博客2:

Python 日志输出中添加上下文信息 - 月缺一格 - 博客园

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-05-15 11:33:57  更:2022-05-15 11:34:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 13:40:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码