{"title":"日志","version":"2.2","locale":"zh-hans","docname":"topics/logging","url":"/zh-hans/2.2/topics/logging/","canonical":"https://djangodocs.dev/zh-hans/2.2/topics/logging/","summary":"Django 使用 Python 内置的 logging 模块处理系统日志。关于该模块的使用，Python 文档里有更详细的讨论。","html":"<span id=\"logging\"></span><h1>日志<a class=\"heading-anchor\" href=\"#module-django.utils.log\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<section id=\"a-quick-logging-primer\">\n<h2>日志管理快速入门<a class=\"heading-anchor\" href=\"#a-quick-logging-primer\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 使用 Python 内置的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.html#module-logging\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">logging</code></a> 模块处理系统日志。关于该模块的使用，Python 文档里有更详细的讨论。不过，如果你从未用过 Python 的 logging 框架（或者即便你用过），这里是一篇快速入门。</p>\n<section id=\"the-cast-of-players\">\n<h3>日志框架的组成元素<a class=\"heading-anchor\" href=\"#the-cast-of-players\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>一份 Python logging 配置有下面四个部分组成：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"#topic-logging-parts-loggers\"><span class=\"std std-ref\">Loggers</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"#topic-logging-parts-handlers\"><span class=\"std std-ref\">Handlers</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"#topic-logging-parts-filters\"><span class=\"std std-ref\">过滤器</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"#topic-logging-parts-formatters\"><span class=\"std std-ref\">Formatters</span></a></p></li>\n</ul>\n<section id=\"loggers\">\n<span id=\"topic-logging-parts-loggers\"></span><h4>Loggers<a class=\"heading-anchor\" href=\"#loggers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>logger 是日志系统的入口。每个 logger 都是命名了的 bucket， 消息写入 bucket 以便进一步处理。</p>\n<p>logger 可以配置 <em>日志级别</em>。日志级别描述了由该 logger 处理的消息的严重性。Python 定义了下面几种日志级别：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">DEBUG</code>：排查故障时使用的低级别系统信息</p></li>\n<li><p><code class=\"docutils literal notranslate\">INFO</code>：一般的系统信息</p></li>\n<li><p><code class=\"docutils literal notranslate\">WARNING</code>：描述系统发生了一些小问题的信息</p></li>\n<li><p><code class=\"docutils literal notranslate\">ERROR</code>：描述系统发生了大问题的信息</p></li>\n<li><p><code class=\"docutils literal notranslate\">CRITICAL</code>：描述系统发生严重问题的信息</p></li>\n</ul>\n<p>每一条写入 logger 的消息都是一条 <em>日志记录</em>。每一条日志记录也包含 <em>日志级别</em>，代表对应消息的严重程度。日志记录还包含有用的元数据，来描述被记录了日志的事件细节，例如堆栈跟踪或者错误码。</p>\n<p>当 logger 处理一条消息时，会将自己的日志级别和这条消息的日志级别做对比。如果消息的日志级别匹配或者高于 logger 的日志级别，它就会被进一步处理。否则这条消息就会被忽略掉。</p>\n<p>当 logger 确定了一条消息需要处理之后，会把它传给 <em>Handler</em>。</p>\n</section>\n<section id=\"handlers\">\n<span id=\"topic-logging-parts-handlers\"></span><h4>Handlers<a class=\"heading-anchor\" href=\"#handlers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为，比如把消息输出到屏幕、文件或网络 socket。</p>\n<p>和 logger 一样，handler 也有日志级别的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别，对应的消息会被 handler 忽略。</p>\n<p>一个 logger 可以有多个 handler，每一个 handler 可以有不同的日志级别。这样就可以根据消息的重要性不同，来提供不同格式的输出。例如，你可以添加一个 handler 把  <code class=\"docutils literal notranslate\">ERROR</code> 和 <code class=\"docutils literal notranslate\">CRITICAL</code> 消息发到寻呼机，再添加另一个 handler 把所有的消息（包括 <code class=\"docutils literal notranslate\">ERROR</code> 和 <code class=\"docutils literal notranslate\">CRITICAL</code> 消息）保存到文件里以便日后分析。</p>\n</section>\n<section id=\"filters\">\n<span id=\"topic-logging-parts-filters\"></span><h4>过滤器<a class=\"heading-anchor\" href=\"#filters\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>在日志记录从 logger 传到 handler 的过程中，使用 Filter 来做额外的控制。</p>\n<p>默认情况下，只要级别匹配，任何日志消息都会被处理。不过，也可以通过添加 filter 来给日志处理的过程增加额外条件。例如，可以添加一个 filter 只允许某个特定来源的 <code class=\"docutils literal notranslate\">ERROR</code> 消息输出。</p>\n<p>Filter 还被用来在日志输出之前对日志记录做修改。例如，可以写一个 filter，当满足一定条件时，把日志记录从 <code class=\"docutils literal notranslate\">ERROR</code> 降到 <code class=\"docutils literal notranslate\">WARNING</code> 级别。</p>\n<p>Filter 在 logger 和 handler 中都可以添加；多个 filter 可以链接起来使用，来做多重过滤操作。</p>\n</section>\n<section id=\"formatters\">\n<span id=\"topic-logging-parts-formatters\"></span><h4>Formatters<a class=\"heading-anchor\" href=\"#formatters\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>日志记录最终是需要以文本来呈现的。Formatter 描述了文本的格式。一个 formatter 通常由包含 <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.html#logrecord-attributes\" title=\"(in Python v3.14)\"><span class=\"xref std std-ref\">LogRecord attributes</span></a> 的 Python 格式化字符串组成，不过你也可以为特定的格式来配置自定义的 formatter。</p>\n</section>\n</section>\n</section>\n<section id=\"using-logging\">\n<h2>使用 logging 模块<a class=\"heading-anchor\" href=\"#using-logging\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>配置好了 logger，handler，filter 和 formatter 之后，需要在代码里发起 logging 的调用。使用 logging 框架非常简单，下面是个例子：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"c1\"># import the logging library</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span>\n\n<span class=\"c1\"># Get an instance of a logger</span>\nlogger <span class=\"o\">=</span> logging<span class=\"o\">.</span>getLogger<span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">,</span> arg1<span class=\"p\">,</span> arg<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    <span class=\"k\">if</span> bad_mojo<span class=\"p\">:</span>\n        <span class=\"c1\"># Log an error message</span>\n        logger<span class=\"o\">.</span>error<span class=\"p\">(</span><span class=\"s1\">&#39;Something went wrong!&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>就这么简单！<code class=\"docutils literal notranslate\">bad_mojo</code> 条件每次满足都会写一条 error 日志。</p>\n<section id=\"naming-loggers\">\n<h3>为 logger 命名<a class=\"heading-anchor\" href=\"#naming-loggers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>对 <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.html#logging.getLogger\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">logging.getLogger()</code></a> 的调用会获取（必要时会创建）一个 logger 的实例。不同的 logger 实例用名字来区分。这个名字是为了在配置的时候指定 logger。</p>\n<p>按照惯例，logger 的名字通常是包含该 logger 的 Python 模块名，即  <code class=\"docutils literal notranslate\">__name__</code>。这样可以基于模块来过滤和处理日志请求。不过，如果你有其他的方式来组织你的日志消息，可以为 logger 提供点号分割的名字来标识它：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"c1\"># Get an instance of a specific named logger</span>\nlogger <span class=\"o\">=</span> logging<span class=\"o\">.</span>getLogger<span class=\"p\">(</span><span class=\"s1\">&#39;project.interesting.stuff&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这种 logger 的名字，用点号分隔的路径定义了一种层次结构。<code class=\"docutils literal notranslate\">project.interesting</code> 这个 logger 是 <code class=\"docutils literal notranslate\">project.interesting.stuff</code> logger 的上级；而 <code class=\"docutils literal notranslate\">project</code> logger 是 <code class=\"docutils literal notranslate\">project.interesting</code> logger 的上级。</p>\n<p>为什么这种层级结构是重要的呢？因为 logger 可以设置为将日志的请求*传播*给上级。这样就可以在 logger 树结构的顶层定义一组单独的 handler，来捕获所有下层的日志请求。在 <code class=\"docutils literal notranslate\">project</code> 命名空间中定义的 logger handler 将会捕获 <code class=\"docutils literal notranslate\">project.interesting</code> 和 <code class=\"docutils literal notranslate\">project.interesting.stuff</code> 这两个 logger 中的所有日志请求。</p>\n<p>可以基于 logger 来控制传播的行为。 如果你不希望某个 logger 传播给上级，可以关闭它。</p>\n</section>\n<section id=\"making-logging-calls\">\n<h3>发起 logging 调用<a class=\"heading-anchor\" href=\"#making-logging-calls\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>logger 实例包含了每种默认日志级别的入口方法：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">logger.debug()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">logger.info()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">logger.warning()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">logger.error()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">logger.critical()</code></p></li>\n</ul>\n<p>还有两种其他的调用方法：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">logger.log()</code>：手动输出一条指定日志级别的日志消息。</p></li>\n<li><p><code class=\"docutils literal notranslate\">logger.exception()</code>：创建一个包含当前异常堆栈帧的 <code class=\"docutils literal notranslate\">ERROR</code> 级别日志消息。</p></li>\n</ul>\n</section>\n</section>\n<section id=\"configuring-logging\">\n<span id=\"id1\"></span><h2>日志模块的配置<a class=\"heading-anchor\" href=\"#configuring-logging\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当然，仅仅在代码里调用 logging 是不够的。还需要配置 logger、handler、filter 和 formatter 来确保日志框架能有效地输出日志。</p>\n<p>Python 的日志库提供了一些配置方法，可以使用编程接口或者配置文件。Django默认使用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\" title=\"(in Python v3.14)\"><span class=\"xref std std-ref\">dictConfig format</span></a>。</p>\n<p>为了配置 logging ，用字典的格式定义一个 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING</code></a> 配置项，这些配置描述了你想要的 logger、handler、filter 和 formatter，以及它们的日志级别和其他你想要的属性。</p>\n<p>默认情况下 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING</code></a> 配置和 <a class=\"reference internal\" href=\"#default-logging-configuration\"><span class=\"std std-ref\">Django 默认日志配置</span></a>  按照下面的方式合并在一起：</p>\n<p>If the <code class=\"docutils literal notranslate\">disable_existing_loggers</code> key in the <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING</code></a> dictConfig is\nset to <code class=\"docutils literal notranslate\">True</code> (which is the <code class=\"docutils literal notranslate\">dictConfig</code> default if the key is missing)\nthen all loggers from the default configuration will be disabled. Disabled\nloggers are not the same as removed; the logger will still exist, but will\nsilently discard anything logged to it, not even propagating entries to a\nparent logger. Thus you should be very careful using\n<code class=\"docutils literal notranslate\">'disable_existing_loggers': True</code>; it's probably not what you want. Instead,\nyou can set <code class=\"docutils literal notranslate\">disable_existing_loggers</code> to <code class=\"docutils literal notranslate\">False</code> and redefine some or all\nof the default loggers; or you can set <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING_CONFIG\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING_CONFIG</code></a> to <code class=\"docutils literal notranslate\">None</code>\nand <a class=\"reference internal\" href=\"#disabling-logging-configuration\"><span class=\"std std-ref\">handle logging config yourself</span></a>.</p>\n<p>logging 被配置成了 Django  <code class=\"docutils literal notranslate\">setup()</code> 函数的一部分。因此，你可以确定的是，logger 一直都可以在项目代码里使用。</p>\n<section id=\"examples\">\n<h3>示例<a class=\"heading-anchor\" href=\"#examples\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\" title=\"(in Python v3.14)\"><span class=\"xref std std-ref\">dictConfig format</span></a> 文档是获取日志配置细节的最好资料。不过，为了让你知道能做什么，下面有几个例子。</p>\n<p>首先，这是一个简单配置，会将所有来自 <a class=\"reference internal\" href=\"#django-logger\"><span class=\"std std-ref\">django</span></a> 的日志输出至一个本地文件：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>LOGGING <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;version&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;disable_existing_loggers&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;file&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;DEBUG&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;logging.FileHandler&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;filename&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;/path/to/django/debug.log&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;loggers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;django&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;file&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;DEBUG&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;propagate&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>若你使用此例子，切记要将 <code class=\"docutils literal notranslate\">'filename'</code> 指向的路径改为当前运行 Django 应用的用户可写的路径。</p>\n<p>接着是一个如何使日志系统将 Django 的日志输出至控制台的例子。这在本地调试时会很实用。</p>\n<p>默认情况下，该配置只会将 <code class=\"docutils literal notranslate\">INFO</code> 或以上的信息发送至终端（与 Django 的默认配置相同，除了 Django 仅在 <code class=\"docutils literal notranslate\">DEBUG=True</code> 时显示日志）。Django 并未打印太多信息。你也可以设置环境变量 <code class=\"docutils literal notranslate\">DJANGO_LOG_LEVEL=DEBUG</code> ，这样可以看到 Django 的所有调试日志，这将会很冗长，因为它包含了所有的数据库查询记录：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\nLOGGING <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;version&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;disable_existing_loggers&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;console&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;logging.StreamHandler&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;loggers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;django&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;console&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> os<span class=\"o\">.</span>getenv<span class=\"p\">(</span><span class=\"s1\">&#39;DJANGO_LOG_LEVEL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>最后是一个完整的日志配置例子：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>LOGGING <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;version&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;disable_existing_loggers&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;formatters&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;verbose&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;format&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;</span><span class=\"si\">{levelname}</span><span class=\"s1\"> </span><span class=\"si\">{asctime}</span><span class=\"s1\"> </span><span class=\"si\">{module}</span><span class=\"s1\"> </span><span class=\"si\">{process:d}</span><span class=\"s1\"> </span><span class=\"si\">{thread:d}</span><span class=\"s1\"> </span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;style&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;{&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n        <span class=\"s1\">&#39;simple&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;format&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;</span><span class=\"si\">{levelname}</span><span class=\"s1\"> </span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;style&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;{&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;special&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;()&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;project.logging.SpecialFilter&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;bar&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n        <span class=\"s1\">&#39;require_debug_true&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;()&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.RequireDebugTrue&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;console&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;require_debug_true&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;logging.StreamHandler&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;formatter&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;simple&#39;</span>\n        <span class=\"p\">},</span>\n        <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;special&#39;</span><span class=\"p\">]</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;loggers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;django&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;console&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;propagate&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n        <span class=\"s1\">&#39;django.request&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;propagate&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n        <span class=\"s1\">&#39;myproject.custom&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;console&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;special&#39;</span><span class=\"p\">]</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>该日志配置做了以下事情：</p>\n<ul>\n<li><p>Identifies the configuration as being in 'dictConfig version 1'\nformat. At present, this is the only dictConfig format version.</p></li>\n<li><p>Defines two formatters:</p>\n<ul>\n<li><p><code class=\"docutils literal notranslate\">simple</code>, that just outputs the log level name (e.g.,\n<code class=\"docutils literal notranslate\">DEBUG</code>) and the log message.</p>\n<p>The <code class=\"docutils literal notranslate\">format</code> string is a normal Python formatting string\ndescribing the details that are to be output on each logging\nline. The full list of detail that can be output can be\nfound in <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.html#formatter-objects\" title=\"(in Python v3.14)\"><span>Formatter Objects</span></a>.</p>\n</li>\n<li><p><code class=\"docutils literal notranslate\">verbose</code>, that outputs the log level name, the log\nmessage, plus the time, process, thread and module that\ngenerate the log message.</p></li>\n</ul>\n</li>\n<li><p>Defines two filters:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">project.logging.SpecialFilter</code>, using the alias <code class=\"docutils literal notranslate\">special</code>. If this\nfilter required additional arguments, they can be provided as additional\nkeys in the filter configuration dictionary. In this case, the argument\n<code class=\"docutils literal notranslate\">foo</code> will be given a value of <code class=\"docutils literal notranslate\">bar</code> when instantiating\n<code class=\"docutils literal notranslate\">SpecialFilter</code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\">django.utils.log.RequireDebugTrue</code>, which passes on records when\n<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> is <code class=\"docutils literal notranslate\">True</code>.</p></li>\n</ul>\n</li>\n<li><p>Defines two handlers:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">console</code>, a <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.handlers.html#logging.StreamHandler\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">StreamHandler</code></a>, which prints any <code class=\"docutils literal notranslate\">INFO</code>\n(or higher) message to <code class=\"docutils literal notranslate\">sys.stderr</code>. This handler uses the <code class=\"docutils literal notranslate\">simple</code>\noutput format.</p></li>\n<li><p><code class=\"docutils literal notranslate\">mail_admins</code>, an <a class=\"reference internal\" href=\"#django.utils.log.AdminEmailHandler\" title=\"django.utils.log.AdminEmailHandler\"><code class=\"xref py py-class docutils literal notranslate\">AdminEmailHandler</code></a>, which emails any <code class=\"docutils literal notranslate\">ERROR</code>\n(or higher) message to the site <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-ADMINS\"><code class=\"xref std std-setting docutils literal notranslate\">ADMINS</code></a>. This handler uses the\n<code class=\"docutils literal notranslate\">special</code> filter.</p></li>\n</ul>\n</li>\n<li><p>Configures three loggers:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">django</code>, which passes all messages to the <code class=\"docutils literal notranslate\">console</code> handler.</p></li>\n<li><p><code class=\"docutils literal notranslate\">django.request</code>, which passes all <code class=\"docutils literal notranslate\">ERROR</code> messages to\nthe <code class=\"docutils literal notranslate\">mail_admins</code> handler. In addition, this logger is\nmarked to <em>not</em> propagate messages. This means that log\nmessages written to <code class=\"docutils literal notranslate\">django.request</code> will not be handled\nby the <code class=\"docutils literal notranslate\">django</code> logger.</p></li>\n<li><p><code class=\"docutils literal notranslate\">myproject.custom</code>, which passes all messages at <code class=\"docutils literal notranslate\">INFO</code>\nor higher that also pass the <code class=\"docutils literal notranslate\">special</code> filter to two\nhandlers -- the <code class=\"docutils literal notranslate\">console</code>, and <code class=\"docutils literal notranslate\">mail_admins</code>. This\nmeans that all <code class=\"docutils literal notranslate\">INFO</code> level messages (or higher) will be\nprinted to the console; <code class=\"docutils literal notranslate\">ERROR</code> and <code class=\"docutils literal notranslate\">CRITICAL</code>\nmessages will also be output via email.</p></li>\n</ul>\n</li>\n</ul>\n</section>\n<section id=\"custom-logging-configuration\">\n<h3>Custom logging configuration<a class=\"heading-anchor\" href=\"#custom-logging-configuration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you don't want to use Python's dictConfig format to configure your\nlogger, you can specify your own configuration scheme.</p>\n<p>The <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING_CONFIG\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING_CONFIG</code></a> setting defines the callable that will\nbe used to configure Django's loggers. By default, it points at\nPython's <a class=\"reference external\" href=\"https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">logging.config.dictConfig()</code></a> function. However, if you want to\nuse a different configuration process, you can use any other callable\nthat takes a single argument. The contents of <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING</code></a> will\nbe provided as the value of that argument when logging is configured.</p>\n</section>\n<section id=\"disabling-logging-configuration\">\n<span id=\"id2\"></span><h3>Disabling logging configuration<a class=\"heading-anchor\" href=\"#disabling-logging-configuration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you don't want to configure logging at all (or you want to manually\nconfigure logging using your own approach), you can set\n<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING_CONFIG\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING_CONFIG</code></a> to <code class=\"docutils literal notranslate\">None</code>. This will disable the\nconfiguration process for <a class=\"reference internal\" href=\"#default-logging-configuration\"><span class=\"std std-ref\">Django's default logging</span></a>. Here's an example that disables Django's\nlogging configuration and then manually configures logging:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">settings.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code>LOGGING_CONFIG <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">logging.config</span>\nlogging<span class=\"o\">.</span>config<span class=\"o\">.</span>dictConfig<span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Setting <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING_CONFIG\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING_CONFIG</code></a> to <code class=\"docutils literal notranslate\">None</code> only means that the automatic\nconfiguration process is disabled, not logging itself. If you disable the\nconfiguration process, Django will still make logging calls, falling back to\nwhatever default logging behavior is defined.</p>\n</section>\n</section>\n<section id=\"django-s-logging-extensions\">\n<h2>Django's logging extensions<a class=\"heading-anchor\" href=\"#django-s-logging-extensions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django provides a number of utilities to handle the unique\nrequirements of logging in Web server environment.</p>\n<section id=\"id3\">\n<h3>Loggers<a class=\"heading-anchor\" href=\"#id3\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django provides several built-in loggers.</p>\n<section id=\"django\">\n<span id=\"django-logger\"></span><h4><code class=\"docutils literal notranslate\">django</code><a class=\"heading-anchor\" href=\"#django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>The catch-all logger for messages in the  <code class=\"docutils literal notranslate\">django</code> hierarchy. No messages are\nposted using this name but instead using one of the loggers below.</p>\n</section>\n<section id=\"django-request\">\n<span id=\"django-request-logger\"></span><h4><code class=\"docutils literal notranslate\">django.request</code><a class=\"heading-anchor\" href=\"#django-request\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Log messages related to the handling of requests. 5XX responses are\nraised as <code class=\"docutils literal notranslate\">ERROR</code> messages; 4XX responses are raised as <code class=\"docutils literal notranslate\">WARNING</code>\nmessages. Requests that are logged to the <code class=\"docutils literal notranslate\">django.security</code> logger aren't\nlogged to <code class=\"docutils literal notranslate\">django.request</code>.</p>\n<p>Messages to this logger have the following extra context:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">status_code</code>: The HTTP response code associated with the\nrequest.</p></li>\n<li><p><code class=\"docutils literal notranslate\">request</code>: The request object that generated the logging\nmessage.</p></li>\n</ul>\n</section>\n<section id=\"django-server\">\n<span id=\"django-server-logger\"></span><h4><code class=\"docutils literal notranslate\">django.server</code><a class=\"heading-anchor\" href=\"#django-server\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Log messages related to the handling of requests received by the server invoked\nby the <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/django-admin/#django-admin-runserver\"><code class=\"xref std std-djadmin docutils literal notranslate\">runserver</code></a> command. HTTP 5XX responses are logged as <code class=\"docutils literal notranslate\">ERROR</code>\nmessages, 4XX responses are logged as <code class=\"docutils literal notranslate\">WARNING</code> messages, and everything else\nis logged as <code class=\"docutils literal notranslate\">INFO</code>.</p>\n<p>Messages to this logger have the following extra context:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">status_code</code>: The HTTP response code associated with the request.</p></li>\n<li><p><code class=\"docutils literal notranslate\">request</code>: The request object that generated the logging message.</p></li>\n</ul>\n</section>\n<section id=\"django-template\">\n<span id=\"django-template-logger\"></span><h4><code class=\"docutils literal notranslate\">django.template</code><a class=\"heading-anchor\" href=\"#django-template\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Log messages related to the rendering of templates.</p>\n<ul class=\"simple\">\n<li><p>Missing context variables are logged as <code class=\"docutils literal notranslate\">DEBUG</code> messages.</p></li>\n</ul>\n</section>\n<section id=\"django-db-backends\">\n<span id=\"django-db-logger\"></span><h4><code class=\"docutils literal notranslate\">django.db.backends</code><a class=\"heading-anchor\" href=\"#django-db-backends\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Messages relating to the interaction of code with the database. For example,\nevery application-level SQL statement executed by a request is logged at the\n<code class=\"docutils literal notranslate\">DEBUG</code> level to this logger.</p>\n<p>Messages to this logger have the following extra context:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">duration</code>: The time taken to execute the SQL statement.</p></li>\n<li><p><code class=\"docutils literal notranslate\">sql</code>: The SQL statement that was executed.</p></li>\n<li><p><code class=\"docutils literal notranslate\">params</code>: The parameters that were used in the SQL call.</p></li>\n</ul>\n<p>For performance reasons, SQL logging is only enabled when\n<code class=\"docutils literal notranslate\">settings.DEBUG</code> is set to <code class=\"docutils literal notranslate\">True</code>, regardless of the logging\nlevel or handlers that are installed.</p>\n<p>This logging does not include framework-level initialization (e.g.\n<code class=\"docutils literal notranslate\">SET TIMEZONE</code>) or transaction management queries (e.g. <code class=\"docutils literal notranslate\">BEGIN</code>,\n<code class=\"docutils literal notranslate\">COMMIT</code>, and <code class=\"docutils literal notranslate\">ROLLBACK</code>). Turn on query logging in your database if you\nwish to view all database queries.</p>\n</section>\n<section id=\"django-security\">\n<span id=\"django-security-logger\"></span><h4><code class=\"docutils literal notranslate\">django.security.*</code><a class=\"heading-anchor\" href=\"#django-security\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>The security loggers will receive messages on any occurrence of\n<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/exceptions/#django.core.exceptions.SuspiciousOperation\" title=\"django.core.exceptions.SuspiciousOperation\"><code class=\"xref py py-exc docutils literal notranslate\">SuspiciousOperation</code></a> and other security-related\nerrors. There is a sub-logger for each subtype of security error, including all\n<code class=\"docutils literal notranslate\">SuspiciousOperation</code>s. The level of the log event depends on where the\nexception is handled.  Most occurrences are logged as a warning, while\nany <code class=\"docutils literal notranslate\">SuspiciousOperation</code> that reaches the WSGI handler will be logged as an\nerror. For example, when an HTTP <code class=\"docutils literal notranslate\">Host</code> header is included in a request from\na client that does not match <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-ALLOWED_HOSTS\"><code class=\"xref std std-setting docutils literal notranslate\">ALLOWED_HOSTS</code></a>, Django will return a 400\nresponse, and an error message will be logged to the\n<code class=\"docutils literal notranslate\">django.security.DisallowedHost</code> logger.</p>\n<p>These log events will reach the <code class=\"docutils literal notranslate\">django</code> logger by default, which mails error\nevents to admins when <code class=\"docutils literal notranslate\">DEBUG=False</code>. Requests resulting in a 400 response due\nto a <code class=\"docutils literal notranslate\">SuspiciousOperation</code> will not be logged to the <code class=\"docutils literal notranslate\">django.request</code>\nlogger, but only to the <code class=\"docutils literal notranslate\">django.security</code> logger.</p>\n<p>To silence a particular type of <code class=\"docutils literal notranslate\">SuspiciousOperation</code>, you can override that\nspecific logger following this example:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;null&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;logging.NullHandler&#39;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">},</span>\n<span class=\"s1\">&#39;loggers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;django.security.DisallowedHost&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;null&#39;</span><span class=\"p\">],</span>\n        <span class=\"s1\">&#39;propagate&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">},</span>\n</code></pre></div>\n<p>Other <code class=\"docutils literal notranslate\">django.security</code> loggers not based on <code class=\"docutils literal notranslate\">SuspiciousOperation</code> are:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">django.security.csrf</code>: For <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/csrf/#csrf-rejected-requests\"><span class=\"std std-ref\">CSRF failures</span></a>.</p></li>\n</ul>\n</section>\n<section id=\"django-db-backends-schema\">\n<h4><code class=\"docutils literal notranslate\">django.db.backends.schema</code><a class=\"heading-anchor\" href=\"#django-db-backends-schema\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Logs the SQL queries that are executed during schema changes to the database by\nthe <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/migrations/\"><span class=\"doc\">migrations framework</span></a>. Note that it won't log the\nqueries executed by <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/migration-operations/#django.db.migrations.operations.RunPython\" title=\"django.db.migrations.operations.RunPython\"><code class=\"xref py py-class docutils literal notranslate\">RunPython</code></a>.\nMessages to this logger have <code class=\"docutils literal notranslate\">params</code> and <code class=\"docutils literal notranslate\">sql</code> in their extra context (but\nunlike <code class=\"docutils literal notranslate\">django.db.backends</code>, not duration). The values have the same meaning\nas explained in <a class=\"reference internal\" href=\"#django-db-logger\"><span class=\"std std-ref\">django.db.backends</span></a>.</p>\n</section>\n</section>\n<section id=\"id4\">\n<h3>Handlers<a class=\"heading-anchor\" href=\"#id4\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django provides one log handler in addition to those provided by the\nPython logging module.</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.utils.log.AdminEmailHandler\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">AdminEmailHandler</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">include_html<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">email_backend<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.utils.log.AdminEmailHandler\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>This handler sends an email to the site <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-ADMINS\"><code class=\"xref std std-setting docutils literal notranslate\">ADMINS</code></a> for each log\nmessage it receives.</p>\n<p>If the log record contains a <code class=\"docutils literal notranslate\">request</code> attribute, the full details\nof the request will be included in the email. The email subject will\ninclude the phrase &quot;internal IP&quot; if the client's IP address is in the\n<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-INTERNAL_IPS\"><code class=\"xref std std-setting docutils literal notranslate\">INTERNAL_IPS</code></a> setting; if not, it will include &quot;EXTERNAL IP&quot;.</p>\n<p>If the log record contains stack trace information, that stack\ntrace will be included in the email.</p>\n<p>The <code class=\"docutils literal notranslate\">include_html</code> argument of <code class=\"docutils literal notranslate\">AdminEmailHandler</code> is used to\ncontrol whether the traceback email includes an HTML attachment\ncontaining the full content of the debug Web page that would have been\nproduced if <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> were <code class=\"docutils literal notranslate\">True</code>. To set this value in your\nconfiguration, include it in the handler definition for\n<code class=\"docutils literal notranslate\">django.utils.log.AdminEmailHandler</code>, like this:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;include_html&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n</code></pre></div>\n<p>Note that this HTML version of the email contains a full traceback,\nwith names and values of local variables at each level of the stack, plus\nthe values of your Django settings. This information is potentially very\nsensitive, and you may not want to send it over email. Consider using\nsomething such as <a class=\"reference external\" href=\"https://pypi.org/project/sentry/\">Sentry</a> to get the best of both worlds -- the\nrich information of full tracebacks plus the security of <em>not</em> sending the\ninformation over email. You may also explicitly designate certain\nsensitive information to be filtered out of error reports -- learn more on\n<a class=\"reference internal\" href=\"/zh-hans/2.2/howto/error-reporting/#filtering-error-reports\"><span class=\"std std-ref\">Filtering error reports</span></a>.</p>\n<p>By setting the <code class=\"docutils literal notranslate\">email_backend</code> argument of <code class=\"docutils literal notranslate\">AdminEmailHandler</code>, the\n<a class=\"reference internal\" href=\"/zh-hans/2.2/topics/email/#topic-email-backends\"><span class=\"std std-ref\">email backend</span></a> that is being used by the\nhandler can be overridden, like this:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;email_backend&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.core.mail.backends.filebased.EmailBackend&#39;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n</code></pre></div>\n<p>By default, an instance of the email backend specified in\n<a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-EMAIL_BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">EMAIL_BACKEND</code></a> will be used.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.utils.log.AdminEmailHandler.send_mail\">\n<span class=\"sig-name descname\">send_mail</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">subject</em>, <em class=\"sig-param\">message</em>, <em class=\"sig-param\"><span class=\"o\">*</span>args</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.utils.log.AdminEmailHandler.send_mail\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Sends emails to admin users. To customize this behavior, you can\nsubclass the <a class=\"reference internal\" href=\"#django.utils.log.AdminEmailHandler\" title=\"django.utils.log.AdminEmailHandler\"><code class=\"xref py py-class docutils literal notranslate\">AdminEmailHandler</code></a> class and\noverride this method.</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"id5\">\n<h3>过滤器<a class=\"heading-anchor\" href=\"#id5\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django provides some log filters in addition to those provided by the Python\nlogging module.</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.utils.log.CallbackFilter\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">CallbackFilter</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">callback</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.utils.log.CallbackFilter\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>This filter accepts a callback function (which should accept a single\nargument, the record to be logged), and calls it for each record that\npasses through the filter. Handling of that record will not proceed if the\ncallback returns False.</p>\n<p>For instance, to filter out <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/exceptions/#django.http.UnreadablePostError\" title=\"django.http.UnreadablePostError\"><code class=\"xref py py-exc docutils literal notranslate\">UnreadablePostError</code></a>\n(raised when a user cancels an upload) from the admin emails, you would\ncreate a filter function:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.http</span> <span class=\"kn\">import</span> UnreadablePostError\n\n<span class=\"k\">def</span> <span class=\"nf\">skip_unreadable_post</span><span class=\"p\">(</span>record<span class=\"p\">):</span>\n    <span class=\"k\">if</span> record<span class=\"o\">.</span>exc_info<span class=\"p\">:</span>\n        exc_type<span class=\"p\">,</span> exc_value <span class=\"o\">=</span> record<span class=\"o\">.</span>exc_info<span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span>exc_value<span class=\"p\">,</span> UnreadablePostError<span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n    <span class=\"k\">return</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>and then add it to your logging config:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;skip_unreadable_posts&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;()&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.CallbackFilter&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;callback&#39;</span><span class=\"p\">:</span> skip_unreadable_post<span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n<span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;skip_unreadable_posts&#39;</span><span class=\"p\">],</span>\n        <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.AdminEmailHandler&#39;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.utils.log.RequireDebugFalse\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">RequireDebugFalse</span><a class=\"heading-anchor\" href=\"#django.utils.log.RequireDebugFalse\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>This filter will only pass on records when settings.DEBUG is False.</p>\n<p>This filter is used as follows in the default <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-LOGGING\"><code class=\"xref std std-setting docutils literal notranslate\">LOGGING</code></a>\nconfiguration to ensure that the <a class=\"reference internal\" href=\"#django.utils.log.AdminEmailHandler\" title=\"django.utils.log.AdminEmailHandler\"><code class=\"xref py py-class docutils literal notranslate\">AdminEmailHandler</code></a> only sends\nerror emails to admins when <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> is <code class=\"docutils literal notranslate\">False</code>:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;require_debug_false&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;()&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.RequireDebugFalse&#39;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n<span class=\"s1\">&#39;handlers&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;mail_admins&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;level&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;filters&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;require_debug_false&#39;</span><span class=\"p\">],</span>\n        <span class=\"s1\">&#39;class&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.utils.log.AdminEmailHandler&#39;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">},</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.utils.log.RequireDebugTrue\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">RequireDebugTrue</span><a class=\"heading-anchor\" href=\"#django.utils.log.RequireDebugTrue\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>This filter is similar to <a class=\"reference internal\" href=\"#django.utils.log.RequireDebugFalse\" title=\"django.utils.log.RequireDebugFalse\"><code class=\"xref py py-class docutils literal notranslate\">RequireDebugFalse</code></a>, except that records are\npassed only when <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> is <code class=\"docutils literal notranslate\">True</code>.</p>\n</dd></dl>\n\n</section>\n</section>\n<section id=\"django-s-default-logging-configuration\">\n<span id=\"default-logging-configuration\"></span><h2>Django's default logging configuration<a class=\"heading-anchor\" href=\"#django-s-default-logging-configuration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>By default, Django configures the following logging:</p>\n<p>When <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> is <code class=\"docutils literal notranslate\">True</code>:</p>\n<ul class=\"simple\">\n<li><p>The <code class=\"docutils literal notranslate\">django</code> logger sends messages in the <code class=\"docutils literal notranslate\">django</code> hierarchy (except\n<code class=\"docutils literal notranslate\">django.server</code>) at the <code class=\"docutils literal notranslate\">INFO</code> level or higher to the console.</p></li>\n</ul>\n<p>When <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> is <code class=\"docutils literal notranslate\">False</code>:</p>\n<ul class=\"simple\">\n<li><p>The <code class=\"docutils literal notranslate\">django</code> logger sends messages in the <code class=\"docutils literal notranslate\">django</code> hierarchy (except\n<code class=\"docutils literal notranslate\">django.server</code>)  with <code class=\"docutils literal notranslate\">ERROR</code> or <code class=\"docutils literal notranslate\">CRITICAL</code> level to\n<a class=\"reference internal\" href=\"#django.utils.log.AdminEmailHandler\" title=\"django.utils.log.AdminEmailHandler\"><code class=\"xref py py-class docutils literal notranslate\">AdminEmailHandler</code></a>.</p></li>\n</ul>\n<p>Independent of the value of <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a>:</p>\n<ul class=\"simple\">\n<li><p>The <a class=\"reference internal\" href=\"#django-server-logger\"><span class=\"std std-ref\">django.server</span></a> logger sends messages at the <code class=\"docutils literal notranslate\">INFO</code> level\nor higher to the console.</p></li>\n</ul>\n<p>All loggers except <a class=\"reference internal\" href=\"#django-server-logger\"><span class=\"std std-ref\">django.server</span></a> propagate logging to their\nparents, up to the root <code class=\"docutils literal notranslate\">django</code> logger. The <code class=\"docutils literal notranslate\">console</code> and <code class=\"docutils literal notranslate\">mail_admins</code>\nhandlers are attached to the root logger to provide the behavior described\nabove.</p>\n<p>See also <a class=\"reference internal\" href=\"#configuring-logging\"><span class=\"std std-ref\">Configuring logging</span></a> to learn how you can\ncomplement or replace this default logging configuration defined in\n<a class=\"extlink-source reference external\" href=\"https://github.com/django/django/blob/stable/2.2.x/django/utils/log.py\">django/utils/log.py</a>.</p>\n</section>","rootId":"module-django.utils.log","toc":[{"title":"日志管理快速入门","anchor":"a-quick-logging-primer","children":[{"title":"日志框架的组成元素","anchor":"the-cast-of-players","children":[{"title":"Loggers","anchor":"loggers","children":[]},{"title":"Handlers","anchor":"handlers","children":[]},{"title":"过滤器","anchor":"filters","children":[]},{"title":"Formatters","anchor":"formatters","children":[]}]}]},{"title":"使用 logging 模块","anchor":"using-logging","children":[{"title":"为 logger 命名","anchor":"naming-loggers","children":[]},{"title":"发起 logging 调用","anchor":"making-logging-calls","children":[]}]},{"title":"日志模块的配置","anchor":"configuring-logging","children":[{"title":"示例","anchor":"examples","children":[]},{"title":"Custom logging configuration","anchor":"custom-logging-configuration","children":[]},{"title":"Disabling logging configuration","anchor":"disabling-logging-configuration","children":[]}]},{"title":"Django's logging extensions","anchor":"django-s-logging-extensions","children":[{"title":"Loggers","anchor":"id3","children":[{"title":"django","anchor":"django","children":[]},{"title":"django.request","anchor":"django-request","children":[]},{"title":"django.server","anchor":"django-server","children":[]},{"title":"django.template","anchor":"django-template","children":[]},{"title":"django.db.backends","anchor":"django-db-backends","children":[]},{"title":"django.security.*","anchor":"django-security","children":[]},{"title":"django.db.backends.schema","anchor":"django-db-backends-schema","children":[]}]},{"title":"Handlers","anchor":"id4","children":[]},{"title":"过滤器","anchor":"id5","children":[]}]},{"title":"Django's default logging configuration","anchor":"django-s-default-logging-configuration","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/2.2/topics/"}],"prev":{"docname":"topics/i18n/timezones","title":"Time zones","url":"/zh-hans/2.2/topics/i18n/timezones/"},"next":{"docname":"topics/pagination","title":"分页","url":"/zh-hans/2.2/topics/pagination/"},"formats":{"html":"/zh-hans/2.2/topics/logging/","markdown":"/zh-hans/2.2/topics/logging.md","json":"/zh-hans/2.2/topics/logging.json"},"source":"https://github.com/django/django/blob/stable/2.2.x/docs/topics/logging.txt","official":"https://docs.djangoproject.com/zh-hans/2.2/topics/logging/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}