Django中Python日志的优雅设置

问题描述:

我还没有找到一种方法来设置Django的Python日志记录,我很满意。我的要求是相当简单:Django中Python日志的优雅设置

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

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

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

+1

您可能会发现以下屏幕视频有用 - http://ericholscher.com/blog/2008/aug/29/screencast-2-logging-fun-and-profit/。另外,Simon Willison提出了更好的登录Django的支持(参见http://simonwillison.net/2009/Sep/28/ponies/)。 – 2009-10-21 05:20:00

+0

@Dominic Rodger - 您可以在Django中灵活地记录应用程序,Simon的建议主要是为了便于在Django内部进行日志记录。Python正在开展工作,将基于字典的配置添加到Python日志记录中,Django可能从中受益。 – 2009-10-21 06:05:43

迄今为止发现的最佳方式是在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中,并且你不会感到讨厌“记录器XYZ没有找到处理程序”消息(这是关于可能错误配置的日志记录的警告)。

这样做,这样满足你们所要求的:

  • 您可以设置为不同的事件不同的日志处理程序,因为你目前做的。
  • 轻松访问模块中的记录器 - 使用getLogger(__name__)
  • 很容易适用于命令行模块 - 它们也导入settings.py

更新:注意,从1.3版本,Django的现在合并support for logging

+0

这不会要求每个模块都有一个在配置中定义的处理程序(您不能使用foo的处理程序来处理foo.bar)?请参阅我们多年前在http://groups.google.com/group/comp.lang.python/browse_thread/thread/6a199393bcee6c1b/2ddf482a44bc4bb1 – 2010-10-04 00:04:22

+1

@andrew cooke上的对话:您*可以*使用'foo'的处理程序来处理处理记录到'foo.bar'的事件。回覆。该线程 - fileConfig和dictConfig现在都有选项来防止禁用旧的记录器。看到这个问题:http://bugs.python.org/issue3136,在你的问题http://bugs.python.org/issue2697发布几个月后 - 无论如何,它已被整理出2008年6月以来。 – 2010-10-04 12:01:16

+0

wouldn 'logger = someutils.getLogger(__ name __)'是更好的方法吗?其中'someutils.getLogger'从已经添加了null_handler的'logging.getLogger'返回记录器? – 7yl4r 2016-10-11 05:12:35

我目前正在使用我自己创建的日志记录系统。它使用CSV格式进行记录。

django-csvlog

该项目还没有完整的文档,但我的工作就可以了。

我们使用logging.ini文件初始化登录*urls.py中的日志。

logging.ini的位置在settings.py中提供,但仅此而已。

每个模块,然后做

logger = logging.getLogger(__name__) 

为了区分测试,开发和生产的情况下,我们有不同的logging.ini文件。大多数情况下,我们有一个“控制台日志”,只有错误才会发送到stderr。我们有一个“应用程序日志”,它使用转到日志目录的常规滚动日志文件。

+0

我最终使用这个,除了在settings.py中初始化而不是urls.py – Parand 2009-10-21 22:41:15

+0

如何使用logging.ini文件中settings.py的设置?例如,我需要BASE_DIR设置,所以我可以告诉它在哪里存储我的日志文件。 – slypete 2010-06-03 00:02:29

+0

@slypete:我们不使用logging.ini中的设置。由于日志记录很大程度上是独立的,因此我们不使用任何Django设置。是的,有可能重复一些事情。不,它没有太大的实际区别。 – 2010-06-03 00:58:23

我知道这已经是一个解决的答案,但根据django> = 1.3,有一个新的日志记录设置。

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

当然结账the django doc一些更多。

这是基本的conf,默认情况下使用Django管理员的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 logging dictConfig,这决定了以下块:

  • formatters - 对应的值将是一个字典,其中每个键是一个格式化器ID和每个值是描述如何配置对应格式化实例的字典。
  • 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' 
    }, 
} 

编辑

request exceptions are now always loggedTicket #16288

我更新了上述样品的conf明确包括mail_admins正确的过滤器,这样,在默认情况下,电子邮件不会在调试是真发。

你应该添加过滤器:

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

,并将其应用到mail_admins处理程序:

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

否则django.core.handers.base.handle_uncaught_exception不传递错误,如果设置了 'django.request' 记录仪.DEBUG是真的。

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

DeprecationWarning:你有没有关于“mail_admins”日志处理程序定义的过滤器:添加隐调试假只能过滤

但事情仍然会正常工作在Django 1.4和Django 1.5中。

**结束编辑**

那的conf强烈由Django的文档样本的conf的启发,但添加日志文件的一部分。

我也经常做到以下几点:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO' 

... 
    'level': LOG_LEVEL 
... 

然后在我的Python代码,我总是在增加的情况下没有日志记录的conf是任何定义的NullHandler。这避免了没有指定Handler的警告。对于库特别有用的不一定只调用在Django(ref

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.') 

希望这有助于!

+0

斯特凡诺,非常感谢您的详细解答,非常有帮助。这一点可能会使其值升级到1.3。 – Parand 2011-04-28 00:56:22

+0

Parand,它绝对是(恕我直言!)值得加紧到Django 1.3,但有几点要照顾平稳过渡 - 如果你遇到麻烦,打开一个新的SO问题;-) – Stefano 2011-04-28 09:55:18

+0

顺便说一下:我仍然使用这种设置和文件日志,但是我转到[sentry](https://github.com/dcramer/sentry)进行制作! – Stefano 2012-08-01 10:01:25