Django在格式化程序中记录自定义属性

umuewwlo  于 2022-12-01  发布在  Go
关注(0)|答案(4)|浏览(167)

Django如何使用logging来记录格式化程序中的自定义属性呢?例如,我想记录登录的用户名。
settings.py脚本中,LOGGING变量定义如下:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        },
    },
    'formatters' : {
        'info_format' : {
            'format' : '%(asctime)s %(levelname)s - %(message)s',
        },
    }
}

我希望使用类似以下的格式:

'format' : '%(asctime).19s %(levelname)s - %(username)s: %(message)s'

其中username是当前登录的用户。也可以在这里添加任何其他类型的会话变量。
这里的一个解决方法是在logger方法上使用extra参数,它接收一个字典,其中的键作为我想在格式字符串上使用的字符串:

logger.info(message, extra={'username' : request.user.username})

另一个(丑陋的)解决方法是构建消息属性,以包含日志格式化程序所具有的默认属性之外的内容。

message = request.user.username + " - " + message
logger.info(message)

但是,有没有一种方法可以设置带有特定属性的格式字符串,并让Django自动将它们提供给日志API?例如,如果%(username)s,request.user.username,或者其他任何属性...

zsohkypk

zsohkypk1#

可以使用筛选器添加自定义属性。例如:

def add_my_custom_attribute(record):
    record.myAttribute = 'myValue'
    record.username = record.request.user.username 
    return True

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        ...
        'add_my_custom_attribute': {
            '()': 'django.utils.log.CallbackFilter',
            'callback': add_my_custom_attribute,
        }
    },
    'handlers': {
        ...
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'filters': ['add_my_custom_attribute'],
            'formatter': 'django.server',
        },            
    },
    ...
}

通过安装过滤器,您可以处理每条日志记录,并决定是否应将其从记录器传递到处理程序。
过滤器获取日志记录,其中包含日志的所有详细信息(即:时间、重要级别、请求、状态代码)。
格式化程序使用记录得属性将其格式化为字符串消息.如果将自定义属性添加到该记录,格式化程序也可以使用这些属性.

jm81lzqq

jm81lzqq2#

关键字extra并不是一个解决方法,这是编写自定义格式化程序最有说服力的方法,除非你要编写一个自定义日志。

format: '%(asctime).19s %(levelname)s - %(username)s: %(message)s'
logging.basicConfig(format=format)
logger.info(message, extra={'username' : request.user.username})

文档中的一些注解(**kwars代表Django logger):
额外传入的字典中的键不应与日志记录系统使用的键冲突。
如果缺少格式化程序所需的字符串,则不会记录该消息。
此功能旨在用于特殊情况,但并不总是如此。

kiayqfof

kiayqfof3#

对于这个问题,我将提供许多可能的完整答案之一:
Django如何使用logging来记录格式化程序中的自定义属性呢?例如,我想记录登录的用户名。
其他的答案涉及到通过python的日志实用程序添加额外的上下文信息的方法。使用过滤器将额外的信息附加到日志记录的方法是理想的,并且在文档中有最好的描述:
https://docs.python.org/3/howto/logging-cookbook.html#using-filters-to-impart-contextual-information
这仍然没有告诉我们 * 如何以通用的方式从请求中获取用户 *。下面的库可以做到这一点:
https://github.com/ninemoreminutes/django-crum
因此,将两者结合起来,你就会对所提出的问题有一个完整的答案。

import logging
from crum import get_current_user

class ContextFilter(logging.Filter):
    """
    This is a filter injects the Django user
    """

    def filter(self, record):

        record.user = get_current_user()
        return True

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='User: %(user)-8s %(message)s')
    a1 = logging.getLogger('a.b.c')

    f = ContextFilter()
    a1.addFilter(f)
    a1.debug('A debug message')

这需要在Django请求-响应周期内正确安装CRUM库。

nxagd54h

nxagd54h4#

我在寻找一个在Django请求日志中显示用户名的解决方案时遇到了这个老问题。
napuzba的响应帮助很大,但它没有马上工作,因为用户并不总是存在于请求对象中。它导致了Django www.example.com中的这段代码settings.py:

def add_username(record):
    """
    Adds request user username to the log
    :param record:
    :return:
    """
    try:
        record.username = record.request.user.username
    except AttributeError:
        record.username = ""
    return True
 

LOGGING = {
    ...
    "formatters": {
        "verbose": {
            "format": "[%(asctime)s] %(levelname)s [%(name)s:%(module)s] [%(username)s] %(message)s",
            "datefmt": "%d.%m.%Y %H:%M:%S",
        },
    },
    "filters": {
        "add_username": {
            "()": "django.utils.log.CallbackFilter",
            "callback": add_username,
        }
    },
    "handlers": {        
        "console": {
            "level": "DEBUG",
            "class": "logging.StreamHandler",
            "formatter": "verbose",
            "filters": ["add_username"],
        },
    }
}

相关问题