Django中Python日志的好的设置是什么?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (82)

我还没有找到与Django一起设置Python日志记录的方式,我很满意。我的要求相当简单:

  • 针对不同事件的不同日志处理程序 - 也就是说,我希望能够登录到不同的文件
  • 轻松访问我的模块中的记录器。该模块应该能够毫不费力地找到它的记录器。
  • 应该很容易适用于命令行模块。系统的一部分是独立的命令行或守护进程。记录应该很容易与这些模块一起使用。

我目前的设置是logging.conf在每个我登录的模块中使用文件和设置日志记录。它感觉不对。

你有你喜欢的日志记录设置吗?请详细说明:如何设置配置(是否使用logging.conf或设置了代码),何时/何时启动记录器,以及如何在模块中访问它们等。

提问于
用户回答回答于

到目前为止,我发现的最好方法是在settings.py中初始化日志记录设置 - 无处可以。可以使用配置文件,也可以通过编程方式逐步执行 - 这取决于您的要求。关键是我通常将我想要的处理程序添加到根记录器,使用级别和有时记录。筛选器将我想要的事件添加到适当的文件,控制台,系统日志等。当然可以将处理程序添加到任何其他记录器根据我的经验,通常不需要这样做。

在每个模块中,我使用了一个记录器

logger = logging.getLogger(__name__)

并用它来记录模块中的事件(并且,如果我想进一步区分)使用一个记录器,它是上面创建的记录器的子代。

如果我的应用程序可能会在未在settings.py中配置日志记录的站点中使用,那么我会在某处定义一个NullHandler,如下所示:

#someutils.py

class NullHandler(logging.Handler):
    def emit(self, record):
        pass

null_handler = NullHandler()

并确保它的一个实例被添加到我的应用程序中使用日志记录的模块中创建的所有记录器中。(注意:NullHandler已经在Python 3.1的日志包中,并且将在Python 2.7中。)所以:

logger = logging.getLogger(__name__)
logger.addHandler(someutils.null_handler)

这样做是为了确保模块在未配置settings.py配置日志的站点中很好地运行,并且不会感到烦恼“No handlers could be found for logger X.Y.Z”消息(这些消息是关于潜在的警告配置错误的日志记录)。

这样做符合你所陈述的要求:

  • 可以像现在一样为不同的事件设置不同的日志处理程序。
  • 轻松访问模块中的记录器 - 使用getLogger(__name__)
  • 轻松适用于命令行模块 - 它们也可以导入settings.py

请注意,从版本1.3开始,Django现在包含对日志记录的支持

用户回答回答于

从旧到新不是自动的,所以我想我会在这里写下来。

当然,还要检查一下django文档

这是基本的conf,由django-admin createproject v1.3默认创建 - 里程可能会随最新的django版本改变:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        }
    }
}

该结构基于标准的Python日志记录dictConfig,它规定了以下块:

  • formatters - 相应的值将是一个字典,其中每个键是格式化程序ID,每个值是描述如何配置相应的Formatter实例的字典。
  • filters - 相应的值将是一个字典,其中每个键是一个过滤器ID,每个值是一个字典,描述如何配置相应的过滤器实例。
  • handlers - 相应的值将是一个字典,其中每个键是一个处理程序ID,每个值是一个字典,描述如何配置相应的Handler实例。每个处理程序都有以下键:
    • class(强制)。这是处理程序类的完全限定名称。
    • level(可选的)。处理程序的级别。
    • formatter(可选的)。此处理程序的格式化程序的ID。
    • filters(可选的)。此处理程序的过滤器的id列表。

我通常至少这样做:

  • 添加一个.log文件
  • 配置我的应用程序写入此日志

其转化为:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'console':{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # I always add this handler to facilitate separating loggings
        'log_file':{
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(VAR_ROOT, 'logs/django.log'),
            'maxBytes': '16777216', # 16megabytes
            'formatter': 'verbose'
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
            'include_html': True,
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set
            'handlers': ['log_file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
    # you can also shortcut 'loggers' and just configure logging for EVERYTHING at once
    'root': {
        'handlers': ['console', 'mail_admins'],
        'level': 'INFO'
    },
}

应该添加一个过滤器:

'filters': {
    'require_debug_false': {
        '()': 'django.utils.log.RequireDebugFalse'
    }
},

并将其应用于邮件_管理员处理程序:

    'mail_admins': {
        'level': 'ERROR',
        'filters': ['require_debug_false'],
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }

否则,django.core.handers.base.handle_uncaught_exception如果settings.DEBUG为True,则不会将错误传递给'django.request'记录器。

如果你在Django 1.5中不这样做,你会得到一个

DeprecationWarning:在'mail_admins'日志处理程序中没有定义过滤器:添加隐式调试 - 仅限假过滤器

但事情仍然会在django 1.4和django 1.5中正常运行。

我还经常做以下几件事:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO'

...
    'level': LOG_LEVEL
...

然后,在我的python代码中,我总是添加一个NullHandler,以防没有定义任何日志记录conf。这样可以避免对未指定的Handler发出警告。对于不一定只在Django中调用的lib特别有用(参考文献)

import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
class NullHandler(logging.Handler): #exists in python 3.1
    def emit(self, record):
        pass
nullhandler = logger.addHandler(NullHandler())

# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file...
logger.warning('etc.etc.')

扫码关注云+社区

领取腾讯云代金券