在Django中使用的日志系统是基于Python中的loggin模块。 首先简单介绍下logging。

一 Loggin模块简介

loggin模块主要包含以下四个部分:

  • Loggers           用户使用的直接接口,将日志传递给Handler
  • Handlers          控制日志输出到哪里,console,file…    一个logger可以有多个Handler
  • Filters          控制哪些日志可以从logger流向Handler
  • Formatters       控制日志的格式

1 Loggers  

A logger is configured to have a log level. This log level describes the severity of the messages that the logger will handle. Python defines the following log levels:

  • DEBUG: Low level system information for debugging purposes            
  • INFO: General system information
  • WARNING: Information describing a minor problem that has occurred.
  • ERROR: Information describing a major problem that has occurred.
  • CRITICAL: Information describing a critical problem that has 

每个日志信息都可以设定日志级别进行处理,

当logger对象接收到了一条日志消息时会对log level进行比较, 如果log level超过或满足等自己的log level那么消息会交给handler进一步处理,否则会忽略这条消息。 

2 Handlers

 handler决定了如何处理一条日志消息,它指定特定的日志记录行为比如将日志输出到屏幕或者输出到文件等等

 如何logger, handler也同样有log level 如果log level超过或满足等自己的log level那么消息会进一步处理,否则会忽略这条消息。

一个logger可以有多个hanlder,每个hanlder可以有不同的log level 通过这种方式,可以根据消息的重要性提供不同形式的日志输出,比如你可以用一个handler进行ERROR和CRITCAL的页面输出,也可以同时用第二个hanlder把所有的日志级别输出到文件进行分析

3 Filters 

过滤器用于控制哪些日志可以从logger流向Handler

默认情况下,将处理满足日志级别要求的任何日志消息。但是,通过过滤器,可以对日志记录过程设置附加条件。例如,可以配置一个过滤器,该过滤器仅允许从特定源发出ERROR消息。

 可以在logger或handle上安装筛选器, 也可以使用多个筛选器来执行多个筛选操作。

4 Formatters

formatters用于设定日志的输出格式, 输出格式的设置可以参考python LogRecord attributes

字段/属性名称 使用格式 描述
asctime %(asctime)s 日志事件发生的时间--人类可读时间,如:2003-07-08 16:49:45,896
created %(created)f 日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
relativeCreated %(relativeCreated)d 日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的)
msecs %(msecs)d 日志事件发生事件的毫秒部分
levelname %(levelname)s 该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
levelno %(levelno)s 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
name %(name)s 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
message %(message)s 日志记录的文本内容,通过 msg % args计算得到的
pathname %(pathname)s 调用日志记录函数的源码文件的全路径
filename %(filename)s pathname的文件名部分,包含文件后缀
module %(module)s filename的名称部分,不包含后缀
lineno %(lineno)d 调用日志记录函数的源代码所在的行号
funcName %(funcName)s 调用日志记录函数的函数名
process %(process)d 进程ID
processName %(processName)s 进程名称,Python 3.1新增
thread %(thread)d 线程ID
threadName %(thread)s 线程名称

 

二 使用logging

Once you have configured your loggers, handlers, filters and formatters, you need to place logging calls into your code. Using the logging framework is very simple. Here’s an example:

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')

每当bad_mojo条件满足,都会发送一个error级别的日志记录。实例代码中的__name__代表logger的名称。 
如果logger的定义如下,那么__name__就是’django’或’django.request’。

'loggers': {
    ...
    'django': {
        'handlers': ['console'],
        'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
        'propagate': True,
    },
    'django.request': {
        'handlers': ['file', 'mail_admins'],
        'level': 'WARNING',
        'propagate': False,
    },
    ...
}

三 记录日志

根据上述日志的5各级别,记录日志也有5个对应的方法。

logger.debug()
logger.info()
logger.warning()
logger.error()
logger.critical()
此外,还有两种日志方法

logger.log() 手动记录一个日志,随便你想记录什么都行
logger.exception() 为了捕获某些异常,创建一个ERROR级别的日志

四 配置日志

By default, the LOGGING setting is merged with Django’s default logging configuration using the following scheme.

If the disable_existing_loggers key in the LOGGING dictConfig is set to True (which is the default) then all loggers from the default configuration will be disabled. Disabled loggers are not the same as removed; the logger will still exist, but will silently discard anything logged to it, not even propagating entries to a parent logger. Thus you should be very careful using 'disable_existing_loggers':True; it’s probably not what you want. Instead, you can set disable_existing_loggers to False and redefine some or all of the default loggers; or you can set LOGGING_CONFIG to None and handle logging config yourself.

在django默认可以使用字典的形式配置, logger的配置都在setting.py中参考以下示例

1 本地文件形式输出日志

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/path/to/django/debug.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

2 在控制台中输出日志

这种方式在本地开发环境进行调试时比较有帮助,很直观,需要的时候马上就能看到输出,不必切换到文件或者查收邮件。不过在生产环境下最好不要输出到控制台。默认情况下,只有在DEBUG = True的时候才会将日志输出到控制台,而且只处理INFO以上级别的日志。默认情况下,这种日志并不会输出很多信息,如果你想看到操作数据库的细节,可以在logger的level中设置'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),这样就可以了。不过这样产生的日志也有点太多了。

import os

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
        },
    },
}

 Finally, here’s an example of a fairly complex logging setup:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

这个例子相比之前的会稍微复杂一些。
formatters中有两个格式的配置,'verbose'和'simple',这里'simple'定义的输出格式很简单,因为只是用来输出一些INFO信息,并不是重要的日志,因此也并不需要复杂的格式。'verbose'输出的信息就比较丰富了,可以用在ERROR或CRITICAL日志的输出。具体的格式请参考这里。

handlers中定义了两个handler:'console'和'mail_admins'。'console'配置'class': 'logging.StreamHandler',这个我们不用过多去说。重点看看'mail_admins',配置'class': 'django.utils.log.AdminEmailHandler',那么既然要配置为通过邮件发送日志,那么是不是有必要设置一下发送和接收的邮件呢?
邮箱的配置也在settings.py中:

# 邮件配置
EMAIL_HOST = 'smtp.maildomain.com'  # SMTP地址
EMAIL_PORT = 25  # SMTP端口
EMAIL_HOST_USER = 'sender@maildomain.com'  # 发送邮件的邮箱
EMAIL_HOST_PASSWORD = '******'  # 我的邮箱密码
EMAIL_SUBJECT_PREFIX = u'[prefix]'  # 为邮件Subject-line前缀,默认是'[django]'
EMAIL_USE_TLS = True  # 与SMTP服务器通信时,是否启动TLS链接(安全链接)。默认是false
# 管理员站点
SERVER_EMAIL = 'xinxinyu2011@163.com'  # The email address that error messages come from, such as those sent to ADMINS and MANAGERS.
ADMINS = (('receiver', 'receiver@maildomain.com'),)  # 接收邮件的邮箱(或邮件组)

 三个logger配置

  • django, which passes all messages to the console handler.
  • django.request, which passes all ERROR messages to the mail_admins handler. In addition, this logger is marked to notpropagate messages. This means that log messages written to django.request will not be handled by the django logger.
  • myproject.custom, which passes all messages at INFO or higher that also pass the special filter to two handlers – the console, and mail_admins. This means that all INFO level messages (or higher) will be printed to the console; ERROR and CRITICAL messages will also be output via email.

3 Django提供的内置logger

Django提供了一些内建的logger,比如上面例子中的'django'。

django
'django'只是一个最上级的logger,但实际上并不接收什么实际的信息,所有的信息都是通过下级logger接收。

django.request
django.request是要受理关于请求(request)的日志记录。如果response是5XX,则被认为是ERROR级别的日志信息,4XX则是WARNING级别。

django.server
django.server是要受理关于服务器端处理请求的结果的日志记录。如果response是5XX,则被认为是ERROR级别的日志信息,4XX则是WARNING级别,其他的都是INFO级别。

django.template
django.template受理关于模板(templates)的信息。语法错误是DEBUG级别,未被捕获的异常会产生WARNING。

django.db.backends
django.db.backends受理代码与数据库交互过程产生的日志信息。只记录application级别的SQL操作信息,并且都会产生DEBUG级别的信息。信息中包含耗时、SQL语句、参数信息。此logger只能在DEBUG = True时才有效。
这个logger并不记录framework-level的信息,如SET TIMEZONE,也不记录事务管理相关的查询,如BEGIN、COMMIT、ROLLBACK等。想知道这方面的信息,只有去查数据库的日志了,Django并不提供。