繁体   English   中英

Django中的Python日志记录

[英]Python logging in Django

我正在开发一个Django应用程序,我正在尝试使用Python的日志记录模块进行错误/跟踪记录。 理想情况下,我希望为站点的不同区域配置不同的记录器。 到目前为止,我已经完成了所有这些工作,但有一件事让我摸不着头脑。

我有根记录器转到sys.stderr,我已经配置了另一个记录器来写入文件。 这是在我的settings.py文件中:

sviewlog = logging.getLogger('MyApp.views.scans')
view_log_handler = logging.FileHandler('C:\\MyApp\\logs\\scan_log.log')
view_log_handler.setLevel(logging.INFO)
view_log_handler.setFormatter(logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s'))
sviewlog.addHandler(view_log_handler)

看起来很简单。 不过这是问题所在:无论我写入sviewlog还是写入日志文件两次。 根记录器只打印一次。 就像addHandler()被调用两次一样。 当我将代码放入调试器时,这正是我所看到的。 settings.py中的代码执行两次,因此创建了两个FileHandler并将其添加到同一个logger实例中。 但为什么? 我该如何解决这个问题呢?

谁能告诉我这里发生了什么? 我已经尝试将sviewlog记录器/处理程序实例化代码移动到它所使用的文件中(因为这实际上对我来说似乎是合适的地方),但我有同样的问题。 我在网上看到的大多数例子都只使用根记录器,而我更喜欢使用多个记录器。

请允许我回答我自己的问题。 这里的根本问题是settings.py被导入两次,甚至更多(见这里 )。 (我仍然不明白为什么会这样。也许一些Django专家可以向我解释。)这似乎也适用于其他一些模块。 在这一点上,我认为假设将导入settings.py的次数是不明智的。 就此而言,这种假设一般不安全。 我在settings.py以外的地方有这个代码,结果很相似。

你必须围绕这个编码。 也就是说,在向其添加其他处理程序之前,您必须检查记录器中的现有处理程序。 这有点难看,因为将多个处理程序(即使是相同类型)连接到一个记录器是完全合理的。 有一些解决方案可以解决这个问题。 一个是检查记录器对象的处理程序属性。 如果您只需要一个处理程序且长度> 0,则不要添加它。 就个人而言,我不喜欢这个解决方案,因为它会让更多处理程序变得混乱。

我更喜欢这样的东西(感谢Thomas Guettler):

# file logconfig.py
if not hasattr(logging, "set_up_done"):
    logging.set_up_done=False

def set_up(myhome):
    if logging.set_up_done:
        return
    # set up your logging here
    # ...
    logging.set_up_done=True

我必须说,我希望Django多次导入settings.py更好地记录下来。 而且我会想象我的配置会以某种方式导致这种多重导入,但我无法找到导致问题的原因以及原因。 也许我只是在他们的文档中找不到,但我认为这是你需要警告用户的事情。

从版本1.3开始,Django使用标准的python日志记录,使用LOGGING设置进行配置(此处记录: 1.3dev )。

Django日志参考: 1.3dev

很难对您的具体案例发表评论。 如果settings.py执行两次,那么每发送一次日志就会得到两行是正常的。

我们遇到了同样的问题,所以我们在项目中设置了一个专门用于记录的模块。 那些模块有一个“模块单例”模式,所以我们只执行一次有趣的代码。

它看起来像这样:

def init_logging():
    stdoutHandler = logging.StreamHandler( sys.stdout )
    stdoutHandler.setLevel( DEBUG )
    stdoutHandler.setFormatter( logging.Formatter( LOG_FORMAT_WITH_TIME ) )
    logging.getLogger( LOG_AREA1 ).addHandler( stdoutHandler )

logInitDone=False #global variable controlling the singleton.
if not logInitDone:
    logInitDone = True
    init_logging()

首次导入log.py将正确配置日志记录。

恢复旧线程,但在使用dictConfig格式的 Django 1.3 Python日志记录时,我遇到了重复的消息。

disable_existing_loggers通过多个settings.py加载消除了重复的处理程序/日志记录问题,但如果未在特定logger上正确指定propagate布尔值,则仍可以获取重复的日志消息。 即,确保为子记录器设置propagate=False 例如,

'loggers': {
    'django': {
        'handlers':['null'],
        'propagate': True,
        'level':'INFO',
    },
    'django.request': {
        'handlers': ['console'],
        'level': 'ERROR',
        'propagate': False,
    },
    'project': {
        'handlers': ['console', 'project-log-file'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'project.customapp': {
        'handlers': ['console', 'customapp-log-file'],
        'level': 'DEBUG',
        'propagate': False,
    },
}

这里, project.customapp设置propagate=False以便它也不会被project记录器捕获。 Django日志记录文档一如既往地非常出色。

回答关于为什么“Django多次导入settings.py”的问题:它没有。

实际上,它确实会被导入两次(跳过第一个代码块以进入它,但如果你有时间则读取一个好的):

http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html

PS-抱歉恢复旧线程。

您可以通过在执行init时检查处理程序的数量来解决您的问题。

def init_logging():
    stdoutHandler = logging.StreamHandler( sys.stdout )
    stdoutHandler.setLevel( DEBUG )
    stdoutHandler.setFormatter( logging.Formatter( LOG_FORMAT_WITH_TIME ) )
    logger = logging.getLogger( LOG_AREA1 )
    if len(logger.handlers) < 1:
        logger.addHandler( stdoutHandler )

我不认为这是处理它的好方法。 就个人而言,为了使用python日志记录模块登录django,我在views.py中为我感兴趣的每个应用程序创建一个记录器,然后在每个视图函数中获取记录器。

from django.http import HttpResponse
from magic import makeLogger
from magic import getLogger

makeLogger('myLogName', '/path/to/myLogName.log')
def testLogger(request):
    logger = getLogger('myLogName')
    logger.debug('this worked')
    return HttpResponse('TEXT, HTML or WHATEVER')

这是关于调试django的一篇非常好的文章,并涵盖了一些日志记录: http//simonwillison.net/2008/May/22/debugging/

回答关于为什么“Django多次导入settings.py”的问题:它没有。

您可能正在运行一个多进程/多线程Web服务器,它创建了几个python子解释器,其中每个子解释器都会从您的django应用程序中导入一次代码。

在django测试服务器上测试,您应该看到多次导入设置。

前段时间,我用我的第一个django / apache应用程序设计了一个不错的单例(python borg成语版本更加精确),然后我很快意识到是的,我创建了多个单例实例...

您还可以使用一次运行的中间件来获得类似的效果,而不使用私有变量。 请注意,这只会配置Web请求的日志记录 - 如果要在shell或命令运行中登录,则需要找到不同的解决方案。

from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed
import logging
import logging.handlers
import logging.config

__all__ = ('LoggingConfigMiddleware',)


class LoggingConfigMiddleware:
    def __init__(self):
        '''Initialise the logging setup from settings, called on first request.'''
        if hasattr(settings, 'LOGGING'):
            logging.config.dictConfig(settings.LOGGING)
        elif getattr(settings, 'DEBUG', False):
            print 'No logging configured.'
        raise MiddlewareNotUsed('Logging setup only.')

为什么使用python logger而不是django-logging? 试一试它可能只是解决你的问题。

http://code.google.com/p/django-logging/wiki/Overview

目前它只允许查看根记录器,但您可以确保写入多个记录器。

一种hackish方式,但您可以尝试将日志代码放在admin.py中。 它应该只导入一次。

另外; 你能先检查MyApp.views.scans日志是否存在吗? 如果它存在(可能引发错误),您可以简单地跳过创建(因此不再添加处理程序)。 一个更干净的方式,但我没有尝试过这个。

还有一个更适合放置此代码的地方( __init__.py ?)。 settings.py用于设置。

要添加到A Lee帖子,python日志记录文档说明了有关传播的内容:

Logger.propagate

如果此计算结果为false,则此记录器或其子记录器不会将记录消息传递给更高级别(祖先)记录器的处理程序。 构造函数将此属性设置为1。

这意味着如果propagate == False子记录器不会将记录消息传递给其父记录器

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM