damien.h

在Django程序中如何用好logging模块

logging是Python 2.3起自带的标准模块,可以用来从运行状态的程序中记录日志。logging模块的功能非常强大,可以非常灵活的向各种预定或者自定的目标输出日志。而利用标准的logging模块,Django程序就可以轻松实现运行环境下的日志输出,这对于开发以及部署环境下程序运行具体情况的监控和调试都是不可或缺的,所以我在这里总结一下自己的一些经验。

Django程序使用logging输出的基本设置

要让Django程序正确得利用logging模块输出日志,首先需要在settings.py中配置好logging参数:

logging.basicConfig(
  level = logging.DEBUG, #设定DEBUG级别输出
  format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d %(message)s',
)

logging.basicConfig是logging模块提供的简便配置logging参数的方法。经过以上的配置,在Django程序中只需要通过logging.debug,logging.info等方法就可以输出日志了。logging.DEBUG及以上级别的日志都会直接输出到django运行时当前命令窗口,而在生产环境下,只需要相应的提高logging输出级别就可以控制日志输出的内容,避免输出过多日志内容。(关于logging级别和logging的基本知识请参考pydoc) 在本地调试使用manage.py runserver的时候,logging内容就会直接出现在console里。

输出日志到文件

以上的基本设置只能让日志直接输出到命令行窗口。需要把日志输出到文件保存的话最简便的方法是这样

logging.basicConfig(
  level = logging.DEBUG, #设定DEBUG级别输出
  format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d %(message)s',
  filename = '/path/to/logfile/filelog.log',
)

在logging.basicConfig方法中,只要指定了filename,那么日志就会直接输出到指定的文件了。

按日期循环保存日志文件

在生产环境下,不仅需要把日志写到文件,通常还需要把日志文件按日期分割保存。这样的任务用logging模块也很容易做到。在生产环境的settings.py里使用如下设置:

root = logging.getLogger()
if len(root.handlers) == 0: #避免重复设置handler,否则日志内容可能被重复输出
  level = logging.INFO
  filename = '/path/to/logfile/filelog.log'
  format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d %(message)s'
  hdlr = TimedRotatingFileHandler(filename, "midnight", 1, 5)
  fmt = Formatter(format)
  hdlr.setFormatter(fmt)
  root.addHandler(hdlr)
root.setLevel(level)

在这里使用了logging模块预定义的TimedRotatingFileHandler类,在每天半夜滚动日志文件,而最多保留5个以往的日志文件。由于需要指定特殊的Handler,所以这里不能使用logging.basicConfig的简便方法。

使用logging模块的更多好处

用好日志功能可以对开发和调试起到很多帮助作用。使用了logging模块可以通过日志级别非常方便的控制输出,不需要增减任何程序代码,只需要在settings.py中更改logging级别一行代码就行了。所以在开发过程中,可以尽量多用logging.debug输出对调试有帮助的内容。而在生产环境下,通过日志也可以方便的分析真实运行环境下的一些问题,便于调试修改bug。

如果用在Google App Engine,不需要指定输出文件,程序输出的日志都会直接保存在App Engine运行日志中,还可以通过正则表达式来搜索以往日志。

另外,通过Django debug toolbar,可以方便的直接在调试环境下直接在每个页面上查看输出的日志,非常好用。

所以,如果你在写Django程序,就不要再用原始的print了,用好logging可以事半功倍。