日志

快速记录引导

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

玩家阵容

Python日志记录配置由四部分组成:

记录器¶ T0>

记录器是登录系统的入口点。 每个记录器都是可以写入消息的命名存储桶。

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

  • DEBUG:用于调试目的的低级系统信息
  • INFO: General system information
  • WARNING:描述发生的小问题的信息。
  • ERROR:描述发生的主要问题的信息。
  • CRITICAL:描述发生的关键问题的信息。

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

向记录器发送消息时,会将消息的日志级别与记录器的日志级别进行比较。 如果消息的日志级别达到或超过记录器自身的日志级别,则消息将进一步处理。 如果没有,则该消息将被忽略。

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

处理程序¶ T0>

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

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

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

过滤器¶ T0>

一个过滤器用于提供额外的控制,以便将日志记录从记录器传递到处理程序。

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

过滤器也可以用来修改日志记录之前被发射。 For example, you could write a filter that downgrades ERROR log records to WARNING records if a particular set of criteria are met.

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

格式化¶ T0>

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

使用日志记录

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

# 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记录器的父项。

为什么层次很重要? 那么,因为记录器可以设置为传播他们的记录呼叫给他们的父母。 通过这种方式,您可以在记录器树的根部定义一组处理程序,并捕获记录器子树中的所有记录调用。 定义在project命名空间中的日志处理程序将捕获在project.interestingproject.interesting.stuff记录器上发布的所有日志消息。

这种传播可以在每个记录器的基础上进行控制。 如果您不希望特定记录器传播给其父母,则可以关闭此行为。

进行日志调用

记录器实例包含每个缺省日志级别的输入方法:

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

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

  • logger.log(): Manually emits a logging message with a specific log level.
  • logger.exception(): Creates an ERROR level logging message wrapping the current exception stack frame.

配置日志记录

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

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

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

默认情况下,使用下面的方案将LOGGING设置与Django’s default logging configuration合并。

如果LOGGING dictConfig中的disable_existing_loggers键设置为True(默认值),则默认配置中的所有记录器都将被禁用。 禁用的记录器与去除的不一样;记录器将仍然存在,但会默默地丢弃记录到它的任何东西,甚至不传播条目到父记录器。 所以你应该非常小心的使用 'disable_existing_loggers': 真正;这可能不是你想要的。 相反,您可以将disable_existing_loggers设置为False并重新定义部分或全部默认记录器;或者您可以将LOGGING_CONFIG设置为Nonehandle logging config yourself

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

实例¶ T0>

有关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)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,它将任何INFO(或更高)的消息打印到sys.stderr 这个处理程序使用simple输出格式。
    • mail_admins, an AdminEmailHandler, which emails any ERROR (or higher) message to the site ADMINS. 这个处理程序使用special过滤器。
  • 配置三个记录器:

    • django, which passes all messages to the console handler.
    • django.request,它将所有ERROR消息传递给mail_admins处理程序。 另外,这个记录器被标记为而不是传播消息。 这意味着写入django.request的日志消息不会被django记录器处理。
    • myproject.custom, which passes all messages at INFO or higher that also pass the special filter to two handlers – the console, and mail_admins. 这意味着所有INFO级消息(或更高)将被打印到控制台; ERRORCRITICAL讯息也会通过电子邮件输出。

自定义日志记录配置

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

The LOGGING_CONFIG setting defines the callable that will be used to configure Django’s loggers. 默认情况下,它指向Python的logging.config.dictConfig()函数。 但是,如果您想使用不同的配置过程,则可以使用任何其他只有一个参数的可调用对象。 在配置日志记录时,LOGGING的内容将作为该参数的值提供。

禁用日志配置

如果您不想配置日志记录(或者您想使用自己的方法手动配置日志记录),则可以将LOGGING_CONFIG设置为None 这将禁用Django’s default logging的配置过程。 以下是禁用Django的日志记录配置,然后手动配置日志记录的示例:

settings.py
LOGGING_CONFIG = None

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

LOGGING_CONFIG设置为None仅意味着自动配置过程被禁用,不记录自身。 如果你禁用配置过程,Django仍然会进行日志记录调用,回到默认的日志行为定义。

Django的日志扩展

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

记录器¶ T0>

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

django

用于django层次结构中消息的捕获记录器。 没有消息发布使用这个名字,而是使用下面的记录器之一。

django.request

记录与处理请求有关的消息。 5XX responses are raised as ERROR messages; 4XX responses are raised as WARNING messages.

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

  • status_code: The HTTP response code associated with the request.
  • request: The request object that generated the logging message.

django.server

记录与处理由runserver命令调用的服务器接收的请求有关的消息。 HTTP 5XX responses are logged as ERROR messages, 4XX responses are logged as WARNING messages, and everything else is logged as INFO.

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

  • status_code: The HTTP response code associated with the request.
  • request: The request object that generated the logging message.

django.template

记录与模板呈现相关的消息。

  • 丢失的上下文变量被记录为DEBUG消息。
  • Uncaught exceptions raised during the rendering of an {% include %} are logged as WARNING messages when debug mode is off (helpful since {% include %} silences the exception and returns an empty string in that case).

django.db.backends

有关代码与数据库交互的消息。 For example, every application-level SQL statement executed by a request is logged at the DEBUG level to this logger.

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

  • duration: The time taken to execute the SQL statement.
  • sql: The SQL statement that was executed.
  • params:在SQL调用中使用的参数。

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

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

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

不基于SuspiciousOperation的其他django.security记录器是:

django.db.backends.schema

通过migrations framework将模式更改期间执行的SQL查询记录到数据库中。 请注意,它不会记录由RunPython执行的查询。 这个记录器的消息在其额外的上下文中有paramssql(但不像django.db.backends,而不是持续时间)。 这些值的含义与django.db.backends中的解释相同。

处理程序¶ T0>

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

AdminEmailHandler(include_html=False, email_backend=None)[source]

这个处理程序发送一个电子邮件到它的站点ADMINS它收到的每个日志消息。

如果日志记录包含request属性,请求的全部细节将包含在电子邮件中。 如果客户端的IP地址在INTERNAL_IPS设置中,电子邮件主题将包含短语“内部IP”如果没有,则会包含“EXTERNAL IP”。

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

The include_html argument of AdminEmailHandler is used to control whether the traceback email includes an HTML attachment containing the full content of the debug Web page that would have been produced if DEBUG were True. 要在您的配置中设置此值,请将其包含在django.utils.log.AdminEmailHandler的处理程序定义中,如下所示:

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

请注意,这个HTML版本的电子邮件包含一个完整的回溯,堆栈的每个级别的本地变量的名称和值,以及您的Django设置的值。 这些信息可能非常敏感,您可能不希望通过电子邮件发送。 考虑使用诸如Sentry之类的东西来获得两全其美的好处 - 丰富的回溯信息加上的安全性,而不是通过电子邮件发送信息。 您也可以明确指定某些要从错误报告中过滤出来的敏感信息 - 详细了解Filtering error reports

通过设置AdminEmailHandleremail_backend参数,可以覆盖处理程序正在使用的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)[source]

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

过滤器¶ T0>

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

CallbackFilter(callback)[source]

这个过滤器接受一个回调函数(应该接受一个参数,即要记录的记录),并为每个通过过滤器的记录调用它。 如果回调返回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'
    }
},
RequireDebugFalse[source]

此过滤器只会在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'
    }
},
RequireDebugTrue[source]

这个过滤器类似于RequireDebugFalse,只是当DEBUGTrue时才传递记录。

Django的默认日志配置

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

DEBUGTrue

  • The django logger sends messages in the django hierarchy (except django.server) at the INFO level or higher to the console.

DEBUGFalse时:

  • django记录器在django层级(django.server除外)中以ERRORCRITICAL级别转换为AdminEmailHandler

独立于DEBUG的值:

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

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