在Django中在哪里调用logging.setLoggerClass()

2 投票
2 回答
1318 浏览
提问于 2025-04-16 19:44

我正在使用Django 1.3,并且用的是标准的Python日志记录。我已经设置好让它把错误记录到一个文件里:

'loggers': {
    'django': {
        'handlers': ['logfile'],
        'level': 'ERROR',
        'propagate': False,
    },

我还想把当前登录的Django用户的用户名也记录下来。为此,我定义了自己的格式化器,格式中包含了“%(username)s”,并创建了一个自己的日志类(叫做RequestLogger),这个类会填充额外的username属性。现在只剩下一个步骤,就是调用:

logging.setLoggerClass(RequestLogger)

问题是:我应该在哪里调用这个?我试着把它放在__init__.py(项目级别)和settings.py里。这两种方法在Django开发服务器上都能正常工作,但在使用WSGI运行Apache时,我在Apache的错误日志中看到这样的错误:

[error] Traceback (most recent call last):
[error]   File "/usr/lib/python2.7/logging/__init__.py", line 842, in emit
[error]     msg = self.format(record)
[error]   File "/usr/lib/python2.7/logging/__init__.py", line 719, in format
[error]     return fmt.format(record)
[error]   File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
[error]     s = self._fmt % record.__dict__
[error] KeyError: 'username'
[error] Logged from file base.py, line 209

这似乎意味着在WSGI中,Django的日志记录器在我调用logging.setLoggerClass()之前就已经初始化了。(这个调用确实被执行了,因为我自己的日志记录工作正常,并且包含了用户名)。

2 个回答

3

Vinay Sajip 提出的使用过滤器的解决方案完全避免了这个问题,所以我接受了他的回答。关于如何使用字典配置过滤器的文档有点不足,所以我在这里放一个例子:

LOGGING = {
    ...
    'filters': {
        'add_django_request': {
            '()': 'logger.AddDjangoRequestFilter',
        },
    },
    'handlers': {
        'myhandler': {
            ...
            'filters': ['add_django_request'],
        },
    },

如果有人在想,这个方法也适用于自定义的 Logger 类,只要在 .wsgi 文件中调用 setLoggerClass,并且在 import django.core.handlers.wsgi 这一行之前(对于 Apache 来说),还有在 manage.py 文件中(对于 Django 开发服务器)。不过,过滤器的解决方案更好。

4

与其使用一个自定义的日志记录类,不如在你的处理程序上使用一个过滤器来实现这个功能。你可以看看这篇文章,还有文档中的这一部分

撰写回答