Skip to main content

记录

快速记录引擎

Django使用Python的内置 logging 模块来执行系统日志记录。这个模块的用法在Python自己的文档中详细讨论。但是,如果你从来没有使用Python的日志框架(或者即使你有),这里有一个快速入门。

玩家的演员

Python日志记录配置包括四个部分:

记录器

记录器是进入记录系统的入口点。每个记录器是一个命名桶,消息可以写入其中进行处理。

记录器配置为具有 日志级别。此日志级别描述记录器将处理的消息的严重性。 Python定义了以下日志级别:

  • DEBUG:用于调试目的的低级系统信息

  • INFO:一般系统信息

  • WARNING:描述发生的小问题的信息。

  • ERROR:描述发生的主要问题的信息。

  • CRITICAL:描述发生的关键问题的信息。

写入记录器的每条消息都是 日志记录。每个日志记录还具有指示该特定消息的严重性的 日志级别。日志记录还可以包含描述正在记录的事件的有用元数据。这可以包括诸如堆栈跟踪或错误代码的详细信息。

当向记录器发送消息时,将消息的日志级别与记录器的日志级别进行比较。如果消息的日志级别满足或超过日志记录器本身的日志级别,消息将进行进一步处理。如果没有,消息将被忽略。

一旦记录器确定消息需要被处理,它被传递到 Handler

处理程序

处理程序是确定日志记录器中每条消息发生的引擎。它描述了特定的日志记录行为,例如将消息写入屏幕,文件或网络套接字。

像日志记录器一样,处理程序也有日志级别。如果日志记录的日志级别不满足或超过处理程序的级别,处理程序将忽略该消息。

记录器可以有多个处理程序,每个处理程序可以有不同的日志级别。以这种方式,可以根据消息的重要性提供不同形式的通知。例如,您可以安装一个处理程序,将 ERRORCRITICAL 消息转发到分页服务,而另一个处理程序将所有消息(包括 ERRORCRITICAL 消息)记录到文件以供日后分析。

过滤器

过滤器用于提供对日志记录从记录器传递到处理程序的附加控制。

默认情况下,将处理满足日志级别要求的任何日志消息。但是,通过安装过滤器,可以在日志记录过程中添加其他条件。例如,您可以安装一个只允许来自特定源的 ERROR 消息的过滤器。

过滤器还可用于在发出日志记录之前修改日志记录。例如,如果满足特定的一组条件,您可以编写一个过滤器,将 ERROR 日志记录降级到 WARNING 记录。

过滤器可以安装在记录仪上或处理程序上;可以在链中使用多个过滤器来执行多个过滤动作。

格式化

最终,日志记录需要作为文本呈现。格式化程序描述该文本的确切格式。格式化器通常由包含 LogRecord属性 的Python格式化字符串组成;但是,您也可以编写自定义格式化程序来实现特定的格式化行为。

使用日志记录

配置记录器,处理程序,过滤器和格式化程序后,您需要将日志调用放入代码中。使用日志框架非常简单。这里有一个例子:

# 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 条件时,将写入错误日志记录。

命名记录器

logging.getLogger() 的调用获得(如果必要的话)创建记录器的实例。日志记录器实例由名称标识。此名称用于标识记录器以进行配置。

按照惯例,记录器名称通常是 __name__,包含记录器的python模块的名称。这允许您基于每个模块过滤和处理日志记录调用。但是,如果您有其他方式组织记录消息,您可以提供任何点分隔的名称来标识记录器:

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

记录器名称的虚线路径定义层次结构。 project.interesting 记录器被认为是 project.interesting.stuff 记录器的父节点; project 记录器是 project.interesting 记录器的父级。

为什么层次结构很重要?好吧,因为记录器可以设置为 propagate,他们的记录调用到他们的父母。这样,您可以在记录器树的根目录中定义一组处理程序,并捕获记录器子树中的所有日志记录调用。在 project 命名空间中定义的日志处理程序将捕获在 project.interestingproject.interesting.stuff 日志记录器上发出的所有日志消息。

这种传播可以在每个记录器的基础上进行控制。如果不想将特定的记录器传播到其父节点,则可以关闭此行为。

记录呼叫

记录器实例包含每个默认日志级别的条目方法:

  • logger.debug()

  • logger.info()

  • logger.warning()

  • logger.error()

  • logger.critical()

还有两个其他日志记录可用:

  • logger.log():手动发出具有特定日志级别的日志记录消息。

  • logger.exception():创建包装当前异常堆栈帧的 ERROR 级别日志记录消息。

配置日志记录

当然,仅仅将日志调用放入代码是不够的。您还需要配置记录器,处理程序,过滤器和格式化程序,以确保日志输出以有用的方式输出。

Python日志库提供了几种配置日志记录的技术,从编程接口到配置文件。默认情况下,Django使用 dictConfig格式

为了配置日志记录,您使用 LOGGING 定义日志设置的字典。这些设置描述了日志记录设置中所需的日志记录器,处理程序,过滤器和格式化程序,以及希望这些组件具有的日志级别和其他属性。

默认情况下,使用以下方案将 LOGGING 设置与 Django默认日志配置 合并。

如果 LOGGING dictConfig中的 disable_existing_loggers 密钥设置为 True (这是默认值),则将禁用默认配置中的所有记录器。禁用的记录器不同于删除;记录器仍然存在,但会静默地丢弃任何记录到它的东西,甚至不传播条目到父记录器。因此你应该非常小心使用 'disable_existing_loggers': True;它可能不是你想要的。相反,您可以将 disable_existing_loggers 设置为 False,并重新定义部分或全部默认记录器;或者您可以将 LOGGING_CONFIG 设置为 None自己处理日志配置

日志记录配置为常规Django setup() 功能的一部分。因此,您可以确定记录器总是可以在您的项目代码中使用。

例子

dictConfig格式 的完整文档是有关日志配置字典的最佳信息来源。然而,给你一个可能的味道,这里有几个例子。

首先,这里有一个简单的配置,将所有日志记录从 django 记录器写入本地文件:

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,
        },
    },
}

如果使用此示例,请务必将 'filename' 路径更改为运行Django应用程序的用户可写入的位置。

第二,这里有一个例子,让日志系统打印Django的日志到控制台。它可能在地方发展中有用。

默认情况下,此配置仅向控制台发送级别 INFO 或更高级别的消息(与Django的默认日志记录配置相同,除非默认值仅在 DEBUG=True 时显示日志记录)。 Django不记录很多这样的消息。但是,使用此配置,您还可以设置环境变量 DJANGO_LOG_LEVEL=DEBUG 以查看Django的所有调试日志记录,这非常详细,因为它包括所有数据库查询:

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'),
        },
    },
}
Changed in Django 1.9:

Django的默认日志配置已更改。有关更改的说明,请参阅 发布说明

最后,这里有一个相当复杂的日志设置的例子:

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',
        },
        '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']
        }
    }
}

此日志配置执行以下操作:

  • 将配置标识为“dictConfig版本1”格式。目前,这是唯一的dictConfig格式版本。

  • 定义两个格式化程序:

    • simple,它只是输出日志级别名称(例如,DEBUG)和日志消息。

      format 字符串是一个普通的Python格式化字符串,用于描述要在每个日志行上输出的详细信息。可以输出的详细信息的完整列表可以在 Formatter Objects 中找到。

    • verbose,它输出日志级别名称,日志消息,以及生成日志消息的时间,进程,线程和模块。

  • 定义两个过滤器:

    • project.logging.SpecialFilter,使用别名 special。如果此过滤器需要其他参数,则它们可以作为过滤器配置字典中的附加键。在这种情况下,当实例化 SpecialFilter 时,参数 foo 将被赋予值 bar

    • django.utils.log.RequireDebugTrue,当 DEBUGTrue 时传递记录。

  • 定义两个处理程序:

    • console,一个StreamHandler,它将打印任何 DEBUG (或更高)消息到stderr。此处理程序使用 simple 输出格式。

    • mail_admins,一个AdminEmailHandler,它将电子邮件任何 ERROR (或更高)消息到网站管理员。此处理程序使用 special 过滤器。

  • 配置三个记录器:

    • django,它将所有消息传递给 console 处理程序。

    • django.request,它将所有 ERROR 消息传递给 mail_admins 处理程序。此外,此记录器被标记为 not 传播消息。这意味着写入 django.request 的日志消息不会被 django 记录器处理。

    • myproject.custom,它传递所有在 INFO 或更高的消息,也通过 special 过滤器到两个处理程序 - consolemail_admins。这意味着所有 INFO 级别消息(或更高级别)将被打印到控制台; ERRORCRITICAL 消息也将通过电子邮件输出。

自定义日志配置

如果不想使用Python的dictConfig格式配置记录器,可以指定自己的配置方案。

LOGGING_CONFIG 设置定义将用于配置Django的记录器的可调用。默认情况下,它指向Python的 logging.config.dictConfig() 函数。但是,如果要使用不同的配置过程,可以使用任何其他可调用,只需要一个参数。当配置日志记录时,LOGGING 的内容将作为该参数的值提供。

禁用日志配置

如果您不想完全配置日志记录(或者您想使用自己的方法手动配置日志记录),您可以将 LOGGING_CONFIG 设置为 None。这将禁用 Django默认日志记录 的配置过程。这里有一个例子,禁用Django的日志配置,然后手动配置日志记录:

settings.py
LOGGING_CONFIG = None

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

LOGGING_CONFIG 设置为 None 仅意味着禁用自动配置过程,而不是记录自身。如果禁用配置过程,Django仍将进行日志调用,回退到定义的任何默认日志记录行为。

Django日志扩展

Django提供了许多实用程序来处理Web服务器环境中日志记录的独特需求。

记录器

Django提供了几个内置的记录器。

django

django 是所有的记录器。没有邮件直接发布到此记录器。

django.request

与请求处理相关的日志消息。 5XX响应作为 ERROR 消息提出; 4XX响应作为 WARNING 消息提出。

到这个记录器的消息有以下额外的上下文:

  • status_code:与请求相关联的HTTP响应代码。

  • request:生成日志记录消息的请求对象。

django.server

New in Django 1.10.

与由 runserver 命令调用的服务器接收的请求的处理相关的日志消息。 HTTP 5XX响应记录为 ERROR 消息,4XX响应记录为 WARNING 消息,其他一切记录为 INFO

到这个记录器的消息有以下额外的上下文:

  • status_code:与请求相关联的HTTP响应代码。

  • request:生成日志记录消息的请求对象。

django.template

New in Django 1.9.

与模板呈现相关的日志消息。

  • 缺少的上下文变量记录为 DEBUG 消息。

  • 在调试模式关闭时,在 {% include %} 呈现期间引发的未捕获异常记录为 WARNING 消息(由于 {% include %} 使异常静默并在这种情况下返回空字符串,因此有帮助)。

django.db.backends

与代码与数据库的交互相关的消息。例如,由请求执行的每个应用程序级SQL语句都在 DEBUG 级别记录到此记录器。

到这个记录器的消息有以下额外的上下文:

  • duration:执行SQL语句所需的时间。

  • sql:已执行的SQL语句。

  • params:在SQL调用中使用的参数。

出于性能原因,仅当 settings.DEBUG 设置为 True 时才会启用SQL日志记录,而不考虑安装的日志记录级别或处理程序。

此日志记录不包括框架级初始化(例如 SET TIMEZONE)或事务管理查询(例如 BEGINCOMMITROLLBACK)。如果希望查看所有数据库查询,请在数据库中打开查询日志记录。

django.security.*

安全记录器将在任何 SuspiciousOperation 发生时接收消息。对于SuspiciousOperation的每个子类型都有一个子日志记录器。日志事件的级别取决于处理异常的位置。大多数事件被记录为警告,而到达WSGI处理程序的任何 SuspiciousOperation 将被记录为错误。例如,当来自不匹配 ALLOWED_HOSTS 的客户机的请求中包括HTTP Host 头部时,Django将返回400响应,并且将错误消息记录到 django.security.DisallowedHost 记录器。

默认情况下,这些日志事件将到达“django”记录器,当 DEBUG=False 时,它会向管理员发送错误事件。导致由 SuspiciousOperation 引起的400响应的请求不会记录到 django.request 记录器,而只记录到 django.security 记录器。

要使特定类型的 SuspiciousOperation 静默,可以按照此示例覆盖特定的记录器:

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

django.db.backends.schema

将在 迁移框架 对数据库进行模式更改期间执行的SQL查询记录。请注意,它不会记录 RunPython 执行的查询。给这个记录器的消息在它们的额外上下文中具有 paramssql (但不同于 django.db.backends,而不是持续时间)。这些值具有与 django.db.backends 中所解释的相同的含义。

New in Django 1.10:

添加了 extra 上下文。

处理程序

除了Python日志模块提供的日志处理程序之外,Django还提供了一个日志处理程序。

class AdminEmailHandler(include_html=False, email_backend=None)[源代码]

此处理程序向网站管理员发送电子邮件,以接收每个日志消息。

如果日志记录包含 request 属性,则该请求的完整详细信息将包含在电子邮件中。如果客户端的IP地址在 INTERNAL_IPS 设置中,电子邮件主题将包括短语“内部IP”;如果没有,它将包括“EXTERNAL IP”。

如果日志记录包含堆栈跟踪信息,那么该堆栈跟踪将包含在电子邮件中。

AdminEmailHandlerinclude_html 参数用于控制追溯电子邮件是否包括包含调试网页的完整内容的HTML附件,如果 DEBUGTrue,则该附件将被产生。要在配置中设置此值,请将其包含在 django.utils.log.AdminEmailHandler 的处理程序定义中,如下所示:

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

请注意,此电子邮件的HTML版本包含完整的追溯,在堆栈的每个级别具有局部变量的名称和值,以及您的Django设置的值。此信息可能非常敏感,您可能不想通过电子邮件发送。考虑使用诸如 Sentry 之类的东西来获得两个世界中最好的 - 完整追踪的丰富信息以及 not 通过电子邮件发送信息的安全性。您还可以明确指定要从错误报告中滤除某些敏感信息 - 了解有关 Filtering error reports 的更多信息。

通过设置 AdminEmailHandleremail_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)[源代码]

向管理用户发送电子邮件。要自定义此行为,您可以子类化 AdminEmailHandler 类并覆盖此方法。

过滤器

Django除了Python日志记录模块提供的日志过滤器之外,还提供了两个日志过滤器。

class CallbackFilter(callback)[源代码]

此过滤器接受回调函数(应接受单个参数,要记录的记录),并为每个通过过滤器的记录调用它。如果回调返回False,则不会继续处理该记录。

例如,要从管理电子邮件中过滤出 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

然后将其添加到您的日志记录配置:

'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'
    }
},
class RequireDebugFalse[源代码]

此过滤器只会在settings.DEBUG为False时传递记录。

此过滤器在默认 LOGGING 配置中如下使用,以确保 AdminEmailHandler 只在 DEBUGFalse 时向管理员发送错误电子邮件:

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

此筛选器类似于 RequireDebugFalse,除了记录仅当 DEBUGTrue 时传递。

Django默认日志配置

默认情况下,Django配置以下日志记录:

DEBUGTrue 时:

  • django 捕获所有记录器将所有在 INFO 级别或更高级别的消息发送到控制台。

DEBUGFalse 时:

  • django 记录器将具有 ERRORCRITICAL 级别的消息发送到 AdminEmailHandler

独立于 DEBUG 的价值:

  • django.server 记录器将所有 INFO 级别或更高级别的消息发送到控制台。

Changed in Django 1.9:

Django的默认日志配置已更改。有关更改的说明,请参阅 发布说明

另请参阅 配置日志记录 以了解如何补充或替换此默认日志记录配置。