日志记录 — Django 文档

来自菜鸟教程
Django/docs/2.2.x/topics/logging
跳转至:导航、​搜索

日志记录

快速记录入门

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 实例包含每个默认日志级别的入口方法:

  • logger.debug()
  • logger.info()
  • logger.warning()
  • logger.error()
  • logger.critical()

还有两个可用的日志记录调用:

  • logger.log():手动发出具有特定日志级别的日志消息。
  • logger.exception():创建一个 ERROR 级别的日志消息包装当前异常堆栈帧。


配置日志记录

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

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

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

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

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

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

例子

dictConfig format 的完整文档是有关日志记录配置字典的最佳信息来源。 但是,为了让您了解什么是可能的,这里有几个示例。

首先,这是一个简单的配置,它将所有日志从 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'),
        },
    },
}

最后,这是一个相当复杂的日志设置示例:

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

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

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

  • 定义两个格式化程序:

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

      format 字符串是一个普通的 Python 格式字符串,描述了要在每个日志记录行上输出的详细信息。 可以在 formatter-objects 中找到可以输出的完整详细信息列表。

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

  • 定义两个过滤器:

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

    • django.utils.log.RequireDebugTrue,当 :setting:`DEBUG`True 时传递记录。

  • 定义两个处理程序:

    • consoleStreamHandler,将任何 INFO(或更高)消息打印到 sys.stderr。 此处理程序使用 simple 输出格式。

    • mail_admins,一个 AdminEmailHandler,它将任何 ERROR(或更高版本)消息通过电子邮件发送到站点 :setting:`ADMINS`。 此处理程序使用 special 过滤器。

  • 配置三个记录器:

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

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

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


自定义日志配置

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

:setting:`LOGGING_CONFIG` 设置定义了将用于配置 Django 记录器的可调用对象。 默认情况下,它指向 Python 的 logging.config.dictConfig() 函数。 但是,如果您想使用不同的配置过程,您可以使用任何其他带有单个参数的可调用对象。 :setting:`LOGGING` 的内容将在配置日志记录时作为该参数的值提供。


禁用日志配置

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

设置.py

LOGGING_CONFIG = None

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

设置 :setting:`LOGGING_CONFIG`None 仅表示禁用自动配置过程,不记录本身。 如果您禁用配置过程,Django 仍将进行日志记录调用,回退到定义的任何默认日志记录行为。


Django 的日志扩展

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

记录器

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

django

django 层次结构中消息的全能记录器。 没有使用此名称发布消息,而是使用以下记录器之一。


django.request

与请求处理相关的日志消息。 5XX 响应作为 ERROR 消息提出; 4XX 响应作为 WARNING 消息提出。 记录到 django.security 记录器的请求不会记录到 django.request

发送到此记录器的消息具有以下额外上下文:

  • status_code:与请求关联的 HTTP 响应代码。
  • request:生成日志消息的请求对象。


django.server

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

发送到此记录器的消息具有以下额外上下文:

  • status_code:与请求关联的 HTTP 响应代码。
  • request:生成日志消息的请求对象。


django.template

与模板渲染相关的日志消息。

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


django.db.backends

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

发送到此记录器的消息具有以下额外上下文:

  • duration:执行 SQL 语句所花费的时间。
  • sql:执行的 SQL 语句。
  • params:在 SQL 调用中使用的参数。

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

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


django.security.*

安全记录器将收到有关 SuspiciousOperation 和其他与安全相关的错误的任何发生的消息。 每个子类型的安全错误都有一个子记录器,包括所有 SuspiciousOperation。 日志事件的级别取决于处理异常的位置。 大多数事件都记录为警告,而任何到达 WSGI 处理程序的 SuspiciousOperation 都将记录为错误。 例如,当来自客户端的请求中包含与 :setting:`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,
    },
},

其他不基于 SuspiciousOperationdjango.security 记录器是:


django.db.backends.schema

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


处理程序

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

class AdminEmailHandler(include_html=False, email_backend=None)

此处理程序为它收到的每条日志消息向站点 :setting:`ADMINS` 发送一封电子邮件。

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

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

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

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

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

通过设置 AdminEmailHandleremail_backend 参数,处理程序正在使用的 电子邮件后端 可以被覆盖,如下所示:

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

默认情况下,将使用 :setting:`EMAIL_BACKEND` 中指定的电子邮件后端实例。

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

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


过滤器

除了 Python 日志模块提供的过滤器之外,Django 还提供了一些日志过滤器。

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 时传递记录。

该过滤器在默认的 :setting:`LOGGING` 配置中使用如下,以确保 AdminEmailHandler 仅在 :setting:`DEBUG`[ X193X] 为 False

'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,不同之处在于仅当 :setting:`DEBUG`True 时才会传递记录。


Django 的默认日志配置

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

:setting:`DEBUG`True 时:

  • django logger 在 INFO 或更高级别的 django 层次结构(除了 django.server)中将消息发送到控制台。

:setting:`DEBUG`False 时:

  • django 记录器将具有 ERRORCRITICAL 级别的 django 层次结构(django.server 除外)中的消息发送到 AdminEmailHandler ]。

的值无关:setting:`DEBUG`:

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

除了 django.server 之外的所有记录器都将日志记录传播到它们的父记录器,直到根 django 记录器。 consolemail_admins 处理程序附加到根记录器以提供上述行为。

另请参阅 配置日志记录 以了解如何补充或替换在 :source:`django/utils/log.py` 中定义的默认日志记录配置。