天天看点

django 1.8 官方文档翻译:13-3 日志日志

日志

日志快速入门

Django 使用Python 内建的

logging

模块打印日志。该模块的用法在Python 本身的文档中有详细的讨论。如果你从来没有使用过Python 的logging 框架(或者即使使用过),请参见下面的快速导论。

logging 的组成

Python 的logging 配置由四个部分组成:

Logger 为日志系统的入口。每个logger 是一个具名的容器,可以向它写入需要处理的消息。

每个logger 都有一个日志级别。日志级别表示该logger 将要处理的消息的严重性。Python 定义以下几种日志级别:

  • DEBUG

    :用于调试目的的底层系统信息
  • INFO

    :普通的系统信息
  • WARNING

    :表示出现一个较小的问题。
  • ERROR

    :表示出现一个较大的问题。
  • CRITICAL

    :表示出现一个致命的问题。

写入logger 的每条消息都是一个日志记录。每个日志记录也具有一个日志级别,它表示对应的消息的严重性。每个日志记录还可以包含描述正在打印的事件的有用元信息。这些元信息可以包含很多细节,例如回溯栈或错误码。

当给一条消息给logger 时,会将消息的日志级别与logger 的日志级别进行比较。如果消息的日志级别大于等于logger 的日志级别,该消息将会往下继续处理。如果小于,该消息将被忽略。

Logger 一旦决定消息需要处理,它将传递该消息给一个Handler。

Handler 决定如何处理logger 中的每条消息。它表示一个特定的日志行为,例如将消息写到屏幕上、写到文件中或者写到网络socket。

与logger 一样,handler 也有一个日志级别。如果消息的日志级别小于handler 的级别,handler 将忽略该消息。

Logger 可以有多个handler,而每个handler 可以有不同的日志级别。利用这种方式,可以根据消息的重要性提供不同形式的处理。例如,你可以用一个handler 将

ERROR

CRITICAL

消息发送给一个页面服务,而用另外一个hander 将所有的消息(包括

ERROR

CRITICAL

消息)记录到一个文件中用于以后进行分析。

Filter 用于对从logger 传递给handler 的日志记录进行额外的控制。

默认情况下,满足日志级别的任何消息都将被处理。通过安装一个filter,你可以对日志处理添加额外的条件。例如,你可以安装一个filter,只允许处理来自特定源的

ERROR

消息。

Filters 还可以用于修改将要处理的日志记录的优先级。例如,如果日志记录满足特定的条件,你可以编写一个filter 将日志记录从

ERROR

降为

WARNING

Filters 可以安装在logger 上或者handler 上;多个filter 可以串联起来实现多层filter 行为。

最后,日志记录需要转换成文本。Formatter 表示文本的格式。Fomatter 通常由包含

日志记录属性

的Python 格式字符串组成;你也可以编写自定义的fomatter 来实现自己的格式。

使用logging

配置好logger、handler、filter 和formatter 之后,你需要在代码中放入logging 调用。使用logging 框架非常简单。下面是个例子:

# 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

条件,将写入一条错误日志记录。

命名logger

logging.getLogger()

调用获取(如有必要则创建)一个logger 的实例。Logger 实例通过名字标识。Logger 使用名称的目的是用于标识其配置。

Logger 的名称习惯上通常使用

__name__

,即包含该logger 的Python 模块的名字。这允许你基于模块filter 和handle 日志调用。如果你想使用其它方式组织日志消息,可以提供点号分隔的名称来标识你的logger:

# Get an instance of a specific named logger
logger = logging.getLogger('project.interesting.stuff')
           

点号分隔的logger 名称定义一个层级。

project.interesting

logger 被认为是

project.interesting.stuff

logger 的上一级;

project

logger 是

project.interesting

logger 的上一级。

层级为何如此重要?因为可以设置logger 传播它们的logging 调用给它们的上一级。利用这种方式,你可以在根logger 上定义一系列的handler,并捕获子logger 中的所有logging 调用。在

project

命名空间中定义的handler 将捕获

project.interesting

project.interesting.stuff

logger 上的所有日志消息。

这种传播行为可以基于每个logger 进行控制。如果你不想让某个logger 传播消息给它的上一级,你可以关闭这个行为。

logging 调用

Logger 实例为每个默认的日志级别提供一个入口方法:

  • logger.debug()

  • logger.info()

  • logger.warning()

  • logger.error()

  • logger.critical()

还有另外两个调用:

  • logger.log()

    :打印消息时手工指定日志级别。
  • logger.exception()

    :创建一个

    ERROR

    级别日志消息,它封装当前异常栈的帧。

配置logging

当然,只是将logging 调用放入你的代码中还是不够的。你还需要配置logger、handler、filter 和formatter 来确保日志的输出是有意义的。

Python 的logging 库提供几种配置logging 的技术,从程序接口到配置文件。默认情况下,Django 使用

dictConfig 格式

为了配置logging,你需要使用

LOGGING

来定义字典形式的logging 设置。这些设置描述你的logging 设置的logger、handler、filter 和formatter,以及它们的日志等级和其它属性。

默认情况下,

LOGGING

设置与

Django 的默认logging 配置

进行合并。

如果

LOGGING

中的

disable_existing_loggers

键为

True

(默认值),那么默认配置中的所有logger 都将禁用。Logger 的禁用与删除不同;logger 仍然存在,但是将默默丢弃任何传递给它的信息,也不会传播给上一级logger。所以,你应该非常小心使用

'disable_existing_loggers': True

;它可能不是你想要的。你可以设置

disable_existing_loggers

False

,并重新定义部分或所有的默认loggers;或者你可以设置

LOGGING_CONFIG

None

,并

自己处理logging 配置

Logging 的配置属于Django

setup()

函数的一部分。所以,你可以肯定在你的项目代码中logger 是永远可用的。

示例

的完整文档是logging 字典配置最好的信息源。但是为了让你尝尝,下面是几个例子。

首先,下面是一个简单的配置,它将来自

django.request

logger 的所有日志请求写入到一个本地文件:

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

如果你使用这个示例,请确保修改

'filename'

路径为运行Django 应用的用户有权限写入的一个位置。

其次,下面这个示例演示如何让日志系统将Django 的日志打印到控制台。

django.request

django.security

不会传播日志给上一级。它在本地开发期间可能有用。

默认情况下,这个配置只会将

INFO

和更高级别的日志发送到控制台。Django 中这样的日志信息不多。可以设置环境变量

DJANGO_LOG_LEVEL=DEBUG

来看看Django 的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'),
        },
    },
}
           

最后,下面是相当复杂的一个logging 设置:

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': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        }
    },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['null'],
            'propagate': True,
            'level': 'INFO',
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}
           

这个logging 配置完成以下事情:

  • 以‘dictConfig version 1’格式解析配置。目前为止,这是dictConfig 格式唯一的版本。
  • 定义两个formatter:
    • simple

      ,它只输出日志的级别(例如,

      DEBUG

      )和日志消息。

      format

      字符串是一个普通的Python 格式化字符串,描述每行日志的细节。输出的完整细节可以在 formatter 文档 中找到。
    • verbose

      ,它输出日志级别、日志消息,以及时间、进程、线程和生成日志消息的模块。
  • 定义filter ——

    project.logging.SpecialFilter

    ,并使用别名

    special

    。如果filter 在构造时要求额外的参数,可以在filter 的配置字段中用额外的键提供。在这个例子中,在实例化

    SpecialFilter

    时,

    foo

    参数的值将使用

    bar

  • 定义三个handler:
    • null

      ,一个NullHandler,它传递

      DEBUG

      (和更高级)的消息给

      /dev/null

    • console

      ,一个StreamHandler,它将打印

      DEBUG

      (和更高级)的消息到stderr。这个handler 使用

      simple

      输出格式。
    • mail_admins

      ,一个AdminEmailHandler,它将用邮件发送

      ERROR

      (和更高级)的消息到站点管理员。这个handler 使用

      special

      filter。
  • 配置三个logger:
    • django

      ,它传递所有

      INFO

      和更高级的消息给

      null

      handler。
    • django.request

      ERROR

      消息给

      mail_admins

      handler。另外,标记这个logger 不 向上传播消息。这表示写入

      django.request

      的日志信息将不会被

      django

      logger 处理。
    • myproject.custom

      INFO

      和更高级的消息并通过

      special

      filter 的消息给两个handler ——

      console

      mail_admins

      。这表示所有

      INFO

      (和更高级)的消息将打印到控制台上;

      ERROR

      CRITICAL

      消息还会通过邮件发送出来。

自定义logging 配置

如果你不想使用Python 的dictConfig 格式配置logger,你可以指定你自己的配置模式。

LOGGING_CONFIG

设置定义一个可调用对象,将它用来配置Django 的logger。默认情况下,它指向Python 的

logging.config.dictConfig()

函数。但是,如果你想使用不同的配置过程,你可以使用其它只接受一个参数的可调用对象。配置logging 时,将使用

LOGGING

的内容作为参数的值。

禁用logging 配置

如果你完全不想配置logging(或者你想使用自己的方法手工配置logging),你可以设置

LOGGING_CONFIG

None

。这将禁用

Django 默认logging

的配置过程。下面的示例禁用Django 的logging 配置,然后手工配置logging:

settings.py

LOGGING_CONFIG = None

import logging.config
logging.config.dictConfig(...)
           

设置

LOGGING_CONFIG

None

只表示禁用自动配置过程,而不是禁用logging 本身。如果你禁用配置过程,Django 仍然执行logging 调用,只是调用的是默认定义的logging 行为。

Django’s logging extensions

Django 提供许多工具用于处理在网站服务器环境中独特的日志需求。

Django 提供几个内建的logger。

django

django

是一个捕获所有信息的logger。消息不会直接提交给这个logger。

记录与处理请求相关的消息。5XX 响应作为

ERROR

消息;4XX 响应作为

WARNING

这个logger 的消息具有以下额外的上下文:

  • status_code

    :请求的HTTP 响应码。
  • request

    :生成日志信息的请求对象。

django.db.backends

与数据库交互的代码相关的消息。例如,HTTP请求执行应用级别的SQL 语句将以

DEBUG

级别记录到该logger。

  • duration

    :执行SQL 语句花费的时间。
  • sql

    :执行的SQL 语句。
  • params

    :SQL 调用中用到的参数。

由于性能原因,SQL的日志只在

设置

之后开启。DEBUG 设置为

True

,无论日志级别或者安装的处理器是什么。

这里的日志不包含框架级别的的初始化(例如,

SET TIMEZONE

)和事务管理查询(例如,

BEGIN

COMMIT

ROLLBACK

)。如果你希望看到所有的数据库查询,可以打开数据库中的查询日志。

django.security.*

Security logger 将收到任何出现

SuspiciousOperation

的消息。SuspiciousOperation 的每个子类型都有一个子logger。日志的级别取决于异常处理的位置。大部分情况是一个warning 日志,而如果

SuspiciousOperation

到达WSGI handler 则记录为一个error。例如,如果请求中包含的HTTP

Host

头部与

ALLOWED_HOSTS

不匹配,Django 将返回400 响应,同时将记录一个error 消息到

django.security.DisallowedHost

logger。

默认情况下只会配置

django.security

logger,其它所有的子logger 都将传播给上一级logger。

django.security

logger 的配置与

django.request

logger 相同,任何error 消息将用邮件发送给站点管理员。由于

SuspiciousOperation

导致400 响应的请求不会在

django.request

logger 中记录日志,而只在

django.security

logger 中记录日志。

若要默默丢弃某种类型的SuspiciousOperation,你可以按照下面的示例覆盖其logger:

'loggers': {
    'django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
    },
},
           

django.db.backends.schema

New in Django 1.7.

迁移框架

执行的SQL 查询会改变数据库的模式时,则记录这些SQL 查询。注意,它不会记录

RunPython

执行的查询。

在Python logging 模块提供的handler 基础之上,Django 还提供另外一个handler。

class

AdminEmailHandler

(include_html=False, email_backend=None)

[source]

这个handler 将它收到的每个日志信息用邮件发送给站点管理员。

如果日志记录包含

request

属性,该请求的完整细节都将包含在邮件中。

如果日志记录包含栈回溯信息,该栈回溯也将包含在邮件中。

AdminEmailHandler

include_html

参数用于控制邮件中是否包含HTML 附件,这个附件包含

DEBUG

True

时的完整网页。若要在配置中设置这个值,可以将它包含在

django.utils.log.AdminEmailHandler

handler 的定义中,像下面这样:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }
},
           

注意,邮件中的HTML 包含完整的回溯栈,包括栈每个层级局部变量的名称和值以及你的Django 设置。这些信息可能非常敏感,你也许不想通过邮件发送它们。此时可以考虑使用类似

Sentry

这样的东西,回溯栈的完整信息和安全信息不会 通过邮件发送。你还可以从错误报告中显式过滤掉特定的敏感信息 —— 更多信息参见

过滤错误报告

通过设置

AdminEmailHandler

email_backend

参数,可以覆盖handler 使用的

email backend

,像这样:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'email_backend': 'django.core.mail.backends.filebased.EmailBackend',
    }
},
           

默认情况下,将使用

EMAIL_BACKEND

中指定的邮件后端。

send_mail

(subject, message, *args, **kwargs)

New in Django 1.8.

发送邮件给管理员用户。若要自定它的行为,可以子类化

AdminEmailHandler

类并覆盖这个方法。

在Python logging 模块提供的过滤器的基础之上,Django 还提供两个过滤器。

CallbackFilter

(callback)

这个过滤器接受一个回调函数(它接受一个单一参数,也就是要记录的东西),并且对每个传递给过滤器的记录调用它。如果回调函数返回False,将不会进行记录的处理。

例如,要从admin邮件中过滤掉

UnreadablePostError

(只在用户取消上传时产生),你可以创建一个过滤器函数:

from django.http import UnreadablePostError

def skip_unreadable_post(record):
    if record.exc_info:
        exc_type, exc_value = record.exc_info[:2]
        if isinstance(exc_value, UnreadablePostError):
            return False
    return True
           

然后把它添加到logger的配置中:

'filters': {
    'skip_unreadable_posts': {
        '()': 'django.utils.log.CallbackFilter',
        'callback': skip_unreadable_post,
    }
},
'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'filters': ['skip_unreadable_posts'],
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
           

RequireDebugFalse

这个过滤器只在设置后传递记录。DEBUG 为 False。

这个过滤器遵循

LOGGING

默认的配置,以确保

AdminEmailHandler

只在

DEBUG

False

的时候发送错误邮件。

'filters': {
    'require_debug_false': {
        '()': 'django.utils.log.RequireDebugFalse',
    }
},
'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'filters': ['require_debug_false'],
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
           

RequireDebugTrue

这个过滤器类似于

RequireDebugFalse

,除了记录只在

DEBUG

True

时传递的情况。

Django’s default logging configuration

默认情况下,Django 的logging 配置如下:

DEBUG

True

时:

  • django

    的全局logger会向控制台发送级别等于或高级

    INFO

    的所有消息。Django在这个时候并不会做任何日志调用(所有在

    DEBUG

    级别上的日志,或者被

    django.request

    django.security

    处理的日志)。
  • py.warnings

    logger,它处理来自

    warnings.warn()

    的消息,会向控制台发送消息。

DEBUG

False

  • django.request

    django.security

    loggers 向

    AdminEmailHandler

    发送带有

    ERROR

    CRITICAL

    级别的消息。这些logger 会忽略任何级别等于或小于

    WARNING

    的信息,被记录的日志不会传递给其他logger(它们不会传递给

    django

    的全局 logger,即使

    DEBUG

    True

    )。

另见

配置日志

来了解如何补充或者替换默认的日志配置。

译者: Django 文档协作翻译小组 ,原文: Logging 本文以 CC BY-NC-SA 3.0 协议发布,转载请保留作者署名和文章出处。 人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。交流群:467338606。