Files
hustoj/web/python-docs/howto/logging.html
2025-03-09 17:10:56 +08:00

934 lines
112 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>日志指南 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="日志专题手册" href="logging-cookbook.html" />
<link rel="prev" title="函数式编程指引" href="functional.html" />
<link rel="canonical" href="https://docs.python.org/3/howto/logging.html" />
<style>
@media only screen {
table.full-width-table {
width: 100%;
}
}
</style>
<link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
<script type="text/javascript" src="../_static/copybutton.js"></script>
<script type="text/javascript" src="../_static/menu.js"></script>
</head>
<body>
<div class="mobile-nav">
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
<label for="menuToggler" class="toggler__label">
<span></span>
</label>
<nav class="nav-content" role="navigation">
<a href="https://www.python.org/" class="nav-logo">
<img src="../_static/py.svg" alt="Logo"/>
</a>
<div class="version_switcher_placeholder"></div>
<form role="search" class="search" action="../search.html" method="get">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
<path fill-rule="nonzero"
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="#444"></path>
</svg>
<input type="text" name="q" aria-label="快速搜索"/>
<input type="submit" value="转向"/>
</form>
</nav>
<div class="menu-wrapper">
<nav class="menu" role="navigation" aria-label="main navigation">
<div class="language_switcher_placeholder"></div>
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">日志指南</a><ul>
<li><a class="reference internal" href="#basic-logging-tutorial">日志基础教程</a><ul>
<li><a class="reference internal" href="#when-to-use-logging">什么时候使用日志</a></li>
<li><a class="reference internal" href="#a-simple-example">一个简单的例子</a></li>
<li><a class="reference internal" href="#logging-to-a-file">记录日志到文件</a></li>
<li><a class="reference internal" href="#logging-from-multiple-modules">从多个模块记录日志</a></li>
<li><a class="reference internal" href="#logging-variable-data">记录变量数据</a></li>
<li><a class="reference internal" href="#changing-the-format-of-displayed-messages">更改显示消息的格式</a></li>
<li><a class="reference internal" href="#displaying-the-date-time-in-messages">在消息中显示日期/时间</a></li>
<li><a class="reference internal" href="#next-steps">后续步骤</a></li>
</ul>
</li>
<li><a class="reference internal" href="#advanced-logging-tutorial">进阶日志教程</a><ul>
<li><a class="reference internal" href="#logging-flow">记录流程</a></li>
<li><a class="reference internal" href="#loggers">记录器</a></li>
<li><a class="reference internal" href="#handlers">处理器</a></li>
<li><a class="reference internal" href="#formatters">格式器</a></li>
<li><a class="reference internal" href="#configuring-logging">配置日志记录</a></li>
<li><a class="reference internal" href="#what-happens-if-no-configuration-is-provided">如果没有提供配置会发生什么</a></li>
<li><a class="reference internal" href="#configuring-logging-for-a-library">为库配置日志</a></li>
</ul>
</li>
<li><a class="reference internal" href="#logging-levels">日志级别</a><ul>
<li><a class="reference internal" href="#custom-levels">自定义级别</a></li>
</ul>
</li>
<li><a class="reference internal" href="#useful-handlers">有用的处理器</a></li>
<li><a class="reference internal" href="#exceptions-raised-during-logging">记录日志时引发的异常</a></li>
<li><a class="reference internal" href="#using-arbitrary-objects-as-messages">使用任意对象作为消息</a></li>
<li><a class="reference internal" href="#optimization">优化</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="functional.html"
title="上一章">函数式编程指引</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="logging-cookbook.html"
title="下一章">日志专题手册</a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/howto/logging.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<div id="outdated-warning" style="padding: .5em; text-align: center; background-color: #FFBABA; color: #6A0E0E;">
这个文档所针对的是一个已不再受支持的 Python 旧版本。
你应当升级版本,并阅读
<a href="/3/howto/logging.html"> Python 当前稳定版本的文档</a>.
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
accesskey="I">索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="logging-cookbook.html" title="日志专题手册"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="functional.html" title="函数式编程指引"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="logging-howto">
<h1>日志指南<a class="headerlink" href="#logging-howto" title="永久链接至标题"></a></h1>
<dl class="field-list simple">
<dt class="field-odd">作者</dt>
<dd class="field-odd"><p>Vinay Sajip &lt;vinay_sajip at red-dove dot com&gt;</p>
</dd>
</dl>
<section id="basic-logging-tutorial">
<span id="logging-basic-tutorial"></span><h2>日志基础教程<a class="headerlink" href="#basic-logging-tutorial" title="永久链接至标题"></a></h2>
<p>日志是对软件执行时所发生事件的一种追踪方式。软件开发人员对他们的代码添加日志调用,借此来指示某事件的发生。一个事件通过一些包含变量数据的描述信息来描述(比如:每个事件发生时的数据都是不同的)。开发者还会区分事件的重要性,重要性也被称为 <em>等级</em><em>严重性</em></p>
<section id="when-to-use-logging">
<h3>什么时候使用日志<a class="headerlink" href="#when-to-use-logging" title="永久链接至标题"></a></h3>
<p>对于简单的日志使用来说日志功能提供了一系列便利的函数。它们是 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a><a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a><a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a><a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a><a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a>。想要决定何时使用日志,请看下表,其中显示了对于每个通用任务集合来说最好的工具。</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 49%" />
<col style="width: 51%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>你想要执行的任务</p></th>
<th class="head"><p>此任务最好的工具</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>对于命令行或程序的应用,结果显示在控制台。</p></td>
<td><p><a class="reference internal" href="../library/functions.html#print" title="print"><code class="xref py py-func docutils literal notranslate"><span class="pre">print()</span></code></a></p></td>
</tr>
<tr class="row-odd"><td><p>在对程序的普通操作发生时提交事件报告(比如:状态监控和错误调查)</p></td>
<td><p><a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.info()</span></code></a> 函数(当有诊断目的需要详细输出信息时使用 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.debug()</span></code></a> 函数)</p></td>
</tr>
<tr class="row-even"><td><p>提出一个警告信息基于一个特殊的运行时事件</p></td>
<td><p><a class="reference internal" href="../library/warnings.html#warnings.warn" title="warnings.warn"><code class="xref py py-func docutils literal notranslate"><span class="pre">warnings.warn()</span></code></a> 位于代码库中,该事件是可以避免的,需要修改客户端应用以消除告警</p>
<p><a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.warning()</span></code></a> 不需要修改客户端应用,但是该事件还是需要引起关注</p>
</td>
</tr>
<tr class="row-odd"><td><p>对一个特殊的运行时事件报告错误</p></td>
<td><p>引发异常</p></td>
</tr>
<tr class="row-even"><td><p>报告错误而不引发异常(如在长时间运行中的服务端进程的错误处理)</p></td>
<td><p><a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.error()</span></code></a>, <a class="reference internal" href="../library/logging.html#logging.exception" title="logging.exception"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.exception()</span></code></a><a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.critical()</span></code></a> 分别适用于特定的错误及应用领域</p></td>
</tr>
</tbody>
</table>
<p>日志功能应以所追踪事件级别或严重性而定。各级别适用性如下(以严重性递增):</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 24%" />
<col style="width: 76%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>级别</p></th>
<th class="head"><p>何时使用</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code></p></td>
<td><p>细节信息,仅当诊断问题时适用。</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">INFO</span></code></p></td>
<td><p>确认程序按预期运行。</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WARNING</span></code></p></td>
<td><p>表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行。</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ERROR</span></code></p></td>
<td><p>由于严重的问题,程序的某些功能已经不能正常执行</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code></p></td>
<td><p>严重的错误,表明程序已不能继续执行</p></td>
</tr>
</tbody>
</table>
<p>默认的级别是 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code>,意味着只会追踪该级别及以上的事件,除非更改日志配置。</p>
<p>所追踪事件可以以不同形式处理。最简单的方式是输出到控制台。另一种常用的方式是写入磁盘文件。</p>
</section>
<section id="a-simple-example">
<span id="howto-minimal-example"></span><h3>一个简单的例子<a class="headerlink" href="#a-simple-example" title="永久链接至标题"></a></h3>
<p>一个非常简单的例子:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Watch out!&#39;</span><span class="p">)</span> <span class="c1"># will print a message to the console</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;I told you so&#39;</span><span class="p">)</span> <span class="c1"># will not print anything</span>
</pre></div>
</div>
<p>如果你在命令行中输入这些代码并运行,你将会看到:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>WARNING:root:Watch out!
</pre></div>
</div>
<p>输出到命令行。<code class="docutils literal notranslate"><span class="pre">INFO</span></code> 消息并没有出现,因为默认级别是 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 。打印的信息包含事件的级别以及在日志调用中的对于事件的描述,例如 “Watch out!”。暂时不用担心 “root” 部分:之后会作出解释。输出格式可按需要进行调整,格式化选项同样会在之后作出解释。</p>
</section>
<section id="logging-to-a-file">
<h3>记录日志到文件<a class="headerlink" href="#logging-to-a-file" title="永久链接至标题"></a></h3>
<p>一种非常常见的情况是将日志事件记录到文件让我们继续往下看。请确认启动新的Python 解释器,不要在上一个环境中继续操作:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;example.log&#39;</span><span class="p">,</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;This message should go to the log file&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;So should this&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;And this, too&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>现在,如果我们打开日志文件,我们应当能看到日志信息:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too
</pre></div>
</div>
<p>该示例同样展示了如何设置日志追踪级别的阈值。该示例中,由于我们设置的阈值是 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code>,所有信息都将被打印。</p>
<p>如果你想从命令行设置日志级别,例如:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>--log=INFO
</pre></div>
</div>
<p>并且你将 <code class="docutils literal notranslate"><span class="pre">--log</span></code> 命令的参数存进了变量 <em>loglevel</em>,你可以用:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="n">logging</span><span class="p">,</span> <span class="n">loglevel</span><span class="o">.</span><span class="n">upper</span><span class="p">())</span>
</pre></div>
</div>
<p>获取要通过 <em>level</em> 参数传给 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 的值。可如下对用户输入值进行错误检查:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># assuming loglevel is bound to the string value obtained from the</span>
<span class="c1"># command line argument. Convert to upper case to allow the user to</span>
<span class="c1"># specify --log=DEBUG or --log=debug</span>
<span class="n">numeric_level</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">logging</span><span class="p">,</span> <span class="n">loglevel</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">numeric_level</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Invalid log level: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">loglevel</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">numeric_level</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
</pre></div>
</div>
<p><a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 的调用应该在 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a> <a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a> 等的前面。因为它被设计为一次性的配置,只有第一次调用会进行操作,随后的调用不会产生有效操作。</p>
<p>如果多次运行上述脚本,则连续运行的消息将追加到文件 <em>example.log</em> 。 如果你希望每次运行重新开始,而不是记住先前运行的消息,则可以通过将上例中的调用更改为来指定 <em>filemode</em> 参数:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;example.log&#39;</span><span class="p">,</span> <span class="n">filemode</span><span class="o">=</span><span class="s1">&#39;w&#39;</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</pre></div>
</div>
<p>输出将与之前相同,但不再追加进日志文件,因此早期运行的消息将丢失。</p>
</section>
<section id="logging-from-multiple-modules">
<h3>从多个模块记录日志<a class="headerlink" href="#logging-from-multiple-modules" title="永久链接至标题"></a></h3>
<p>如果你的程序包含多个模块,这里有一个如何组织日志记录的示例:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># myapp.py</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">mylib</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;myapp.log&#39;</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Started&#39;</span><span class="p">)</span>
<span class="n">mylib</span><span class="o">.</span><span class="n">do_something</span><span class="p">()</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Finished&#39;</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># mylib.py</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="k">def</span> <span class="nf">do_something</span><span class="p">():</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Doing something&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>如果你运行 <em>myapp.py</em> ,你应该在 <em>myapp.log</em> 中看到:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>INFO:root:Started
INFO:root:Doing something
INFO:root:Finished
</pre></div>
</div>
<p>这是你期待看到的。 你可以使用 <em>mylib.py</em> 中的模式将此概括为多个模块。 请注意,对于这种简单的使用模式,除了查看事件描述之外,你不能通过查看日志文件来了解应用程序中消息的 <em>来源</em> 。 如果要跟踪消息的位置,则需要参考教程级别以外的文档 —— 请参阅 <a class="reference internal" href="#logging-advanced-tutorial"><span class="std std-ref">进阶日志教程</span></a></p>
</section>
<section id="logging-variable-data">
<h3>记录变量数据<a class="headerlink" href="#logging-variable-data" title="永久链接至标题"></a></h3>
<p>要记录变量数据,请使用格式字符串作为事件描述消息,并附加传入变量数据作为参数。 例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> before you </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;Look&#39;</span><span class="p">,</span> <span class="s1">&#39;leap!&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>将显示:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>WARNING:root:Look before you leap!
</pre></div>
</div>
<p>如你所见,将可变数据合并到事件描述消息中使用旧的 %-s形式的字符串格式化。 这是为了向后兼容logging 包的出现时间早于较新的格式化选项例如 <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a><a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal notranslate"><span class="pre">string.Template</span></code></a>。 这些较新格式化选项 <em></em> 受支持的,但探索它们超出了本教程的范围:有关详细信息,请参阅 <a class="reference internal" href="logging-cookbook.html#formatting-styles"><span class="std std-ref">生效于整个应用程序的格式化样式</span></a></p>
</section>
<section id="changing-the-format-of-displayed-messages">
<h3>更改显示消息的格式<a class="headerlink" href="#changing-the-format-of-displayed-messages" title="永久链接至标题"></a></h3>
<p>要更改用于显示消息的格式,你需要指定要使用的格式:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(levelname)s</span><span class="s1">:</span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;This message should appear on the console&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;So should this&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;And this, too&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这将输出:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too
</pre></div>
</div>
<p>注意在前面例子中出现的 “root” 已消失。文档 <a class="reference internal" href="../library/logging.html#logrecord-attributes"><span class="std std-ref">LogRecord 属性</span></a> 列出了可在格式字符串中出现的所有内容,但在简单的使用场景中,你只需要 <em>levelname</em> (严重性)、<em>message</em> (事件描述,包含可变的数据)或许再加上事件发生的时间。 这将在下一节中介绍。</p>
</section>
<section id="displaying-the-date-time-in-messages">
<h3>在消息中显示日期/时间<a class="headerlink" href="#displaying-the-date-time-in-messages" title="永久链接至标题"></a></h3>
<p>要显示事件的日期和时间,你可以在格式字符串中放置 '%(asctime)s'</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;is when this event was logged.&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>应该打印这样的东西:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>2010-12-12 11:41:42,612 is when this event was logged.
</pre></div>
</div>
<p>日期/时间显示的默认格式(如上所示)类似于 ISO8601 或 <span class="target" id="index-2"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc3339.html"><strong>RFC 3339</strong></a> 。 如果你需要更多地控制日期/时间的格式,请为 <code class="docutils literal notranslate"><span class="pre">basicConfig</span></code> 提供 <em>datefmt</em> 参数,如下例所示:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">datefmt</span><span class="o">=</span><span class="s1">&#39;%m/</span><span class="si">%d</span><span class="s1">/%Y %I:%M:%S %p&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;is when this event was logged.&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这会显示如下内容:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>12/12/2010 11:46:36 AM is when this event was logged.
</pre></div>
</div>
<p><em>datefmt</em> 参数的格式与 <a class="reference internal" href="../library/time.html#time.strftime" title="time.strftime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.strftime()</span></code></a> 支持的格式相同。</p>
</section>
<section id="next-steps">
<h3>后续步骤<a class="headerlink" href="#next-steps" title="永久链接至标题"></a></h3>
<p>基本教程到此结束。 它应该足以让你启动并运行日志记录。 logging 包提供了更多功能,但为了充分利用它,你需要花更多的时间来阅读以下部分。 如果你准备好了,可以拿一些你最喜欢的饮料然后继续。</p>
<p>如果你的日志记录需求很简单,那么使用上面的示例将日志记录合并到你自己的脚本中,如果你遇到问题或者不理解某些内容,请在 comp.lang.python Usenet 组上发布一个问题(在 <a class="reference external" href="https://groups.google.com/forum/#!forum/comp.lang.python">https://groups.google.com/forum/#!forum/comp.lang.python</a> ,你将在短时间内得到帮助。</p>
<p>还不够? 你可以继续阅读接下来的几个部分,这些部分提供了比上面基本部分更高级或深入的教程。 之后,你可以看一下 <a class="reference internal" href="logging-cookbook.html#logging-cookbook"><span class="std std-ref">日志专题手册</span></a></p>
</section>
</section>
<section id="advanced-logging-tutorial">
<span id="logging-advanced-tutorial"></span><h2>进阶日志教程<a class="headerlink" href="#advanced-logging-tutorial" title="永久链接至标题"></a></h2>
<p>日志库采用模块化方法,并提供几类组件:记录器、处理器、过滤器和格式器。</p>
<ul class="simple">
<li><p>记录器暴露了应用程序代码直接使用的接口。</p></li>
<li><p>处理器将日志记录(由记录器创建)发送到适当的目标。</p></li>
<li><p>过滤器提供了更细粒度的功能,用于确定要输出的日志记录。</p></li>
<li><p>格式器指定最终输出中日志记录的样式。</p></li>
</ul>
<p>日志事件信息在 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例中的记录器、处理器、过滤器和格式器之间传递。</p>
<p>通过调用 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 类(以下称为 <em class="dfn">loggers</em> 记录器)的实例来执行日志记录。 每个实例都有一个名称,它们在概念上以点(句点)作为分隔符排列在命名空间的层次结构中。 例如,名为 'scan' 的记录器是记录器 'scan.text' 'scan.html' 和 'scan.pdf' 的父级。 记录器名称可以是你想要的任何名称,并指示记录消息源自的应用程序区域。</p>
<p>在命名记录器时使用的一个好习惯是在每个使用日志记录的模块中使用模块级记录器,命名如下:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
<p>这意味着记录器名称跟踪包或模块的层次结构,并且直观地从记录器名称显示记录事件的位置。</p>
<p>记录器层次结构的根称为根记录器。 这是函数 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a><a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a><a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a><a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a><a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a> 使用的记录器,它们就是调用了根记录器的同名方法。 函数和方法具有相同的签名。 根记录器的名称在输出中打印为 'root' 。</p>
<p>当然,可以将消息记录到不同的地方。 软件包中的支持包含,用于将日志消息写入文件、 HTTP GET/POST 位置、通过 SMTP 发送电子邮件、通用套接字、队列或特定于操作系统的日志记录机制(如 syslog 或 Windows NT 事件日志)。 目标由 <em class="dfn">handler</em> 类提供。 如果你有任何内置处理器类未满足的特殊要求,则可以创建自己的日志目标类。</p>
<p>默认情况下,没有为任何日志消息设置目标。 你可以使用 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 指定目标(例如控制台或文件),如教程示例中所示。 如果你调用函数 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a><a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a><a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a><a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a><a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a> ,它们将检查是否有设置目标;如果没有设置,将在委托给根记录器进行实际的消息输出之前设置目标为控制台( <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> )并设置显示消息的默认格式。</p>
<p><a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 设置的消息默认格式为:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>severity:logger name:message
</pre></div>
</div>
<p>你可以通过使用 <em>format</em> 参数将格式字符串传递给 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 来更改此设置。有关如何构造格式字符串的所有选项,请参阅 <a class="reference internal" href="../library/logging.html#formatter-objects"><span class="std std-ref">格式器对象</span></a></p>
<section id="logging-flow">
<h3>记录流程<a class="headerlink" href="#logging-flow" title="永久链接至标题"></a></h3>
<p>记录器和处理器中的日志事件信息流程如下图所示。</p>
<img alt="../_images/logging_flow.png" src="../_images/logging_flow.png" />
</section>
<section id="loggers">
<h3>记录器<a class="headerlink" href="#loggers" title="永久链接至标题"></a></h3>
<p><a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 对象有三重任务。首先,它们向应用程序代码公开了几种方法,以便应用程序可以在运行时记录消息。其次,记录器对象根据严重性(默认过滤工具)或过滤器对象确定要处理的日志消息。第三,记录器对象将相关的日志消息传递给所有感兴趣的日志处理器。</p>
<p>记录器对象上使用最广泛的方法分为两类:配置和消息发送。</p>
<p>这些是最常见的配置方法:</p>
<ul class="simple">
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.setLevel" title="logging.Logger.setLevel"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.setLevel()</span></code></a> 指定记录器将处理的最低严重性日志消息,其中 debug 是最低内置严重性级别, critical 是最高内置严重性级别。 例如,如果严重性级别为 INFO ,则记录器将仅处理 INFO 、 WARNING 、 ERROR 和 CRITICAL 消息,并将忽略 DEBUG 消息。</p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.addHandler()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.removeHandler" title="logging.Logger.removeHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.removeHandler()</span></code></a> 从记录器对象中添加和删除处理器对象。处理器在以下内容中有更详细的介绍 <a class="reference internal" href="#handler-basic"><span class="std std-ref">处理器</span></a></p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.addFilter" title="logging.Logger.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.addFilter()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.removeFilter" title="logging.Logger.removeFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.removeFilter()</span></code></a> 可以添加或移除记录器对象中的过滤器。 <a class="reference internal" href="../library/logging.html#filter"><span class="std std-ref">过滤器对象</span></a> 包含更多的过滤器细节。</p></li>
</ul>
<p>你不需要总是在你创建的每个记录器上都调用这些方法。 请参阅本节的最后两段。</p>
<p>配置记录器对象后,以下方法将创建日志消息:</p>
<ul class="simple">
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.debug" title="logging.Logger.debug"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.debug()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.info" title="logging.Logger.info"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.info()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.warning" title="logging.Logger.warning"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.warning()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.error" title="logging.Logger.error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.error()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.critical" title="logging.Logger.critical"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.critical()</span></code></a> 都创建日志记录,包含消息和与其各自方法名称对应的级别。该消息实际上是一个格式化字符串,它可能包含标题字符串替换语法 <code class="docutils literal notranslate"><span class="pre">%s</span></code><code class="docutils literal notranslate"><span class="pre">%d</span></code><code class="docutils literal notranslate"><span class="pre">%f</span></code> 等等。其余参数是与消息中的替换字段对应的对象列表。关于 <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> ,日志记录方法只关注 <code class="docutils literal notranslate"><span class="pre">exc_info</span></code> 的关键字,并用它来确定是否记录异常信息。</p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.exception()</span></code></a> 创建与 <a class="reference internal" href="../library/logging.html#logging.Logger.error" title="logging.Logger.error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.error()</span></code></a> 相似的日志信息。 不同之处是, <a class="reference internal" href="../library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.exception()</span></code></a> 同时还记录当前的堆栈追踪。仅从异常处理程序调用此方法。</p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.log" title="logging.Logger.log"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.log()</span></code></a> 将日志级别作为显式参数。对于记录消息而言,这比使用上面列出的日志级别便利方法更加冗长,但这是使用自定义日志级别的方法。</p></li>
</ul>
<p><a class="reference internal" href="../library/logging.html#logging.getLogger" title="logging.getLogger"><code class="xref py py-func docutils literal notranslate"><span class="pre">getLogger()</span></code></a> 返回对具有指定名称的记录器实例的引用(如果已提供),或者如果没有则返回 <code class="docutils literal notranslate"><span class="pre">root</span></code> 。名称是以句点分隔的层次结构。多次调用 <a class="reference internal" href="../library/logging.html#logging.getLogger" title="logging.getLogger"><code class="xref py py-func docutils literal notranslate"><span class="pre">getLogger()</span></code></a> 具有相同的名称将返回对同一记录器对象的引用。在分层列表中较低的记录器是列表中较高的记录器的子项。例如,给定一个名为 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 的记录器,名称为 <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code><code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code><code class="docutils literal notranslate"><span class="pre">foo.bam</span></code> 的记录器都是 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 子项。</p>
<p>记录器具有 <em>有效等级</em> 的概念。如果未在记录器上显式设置级别,则使用其父记录器的级别作为其有效级别。如果父记录器没有明确的级别设置,则检查 <em></em> 父级。依此类推,搜索所有上级元素,直到找到明确设置的级别。根记录器始终具有明确的级别配置(默认情况下为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> )。在决定是否处理事件时,记录器的有效级别用于确定事件是否传递给记录器相关的处理器。</p>
<p>子记录器将消息传播到与其父级记录器关联的处理器。因此,不必为应用程序使用的所有记录器定义和配置处理器。一般为顶级记录器配置处理器,再根据需要创建子记录器就足够了。(但是,你可以通过将记录器的 <em>propagate</em> 属性设置为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 来关闭传播。)</p>
</section>
<section id="handlers">
<span id="handler-basic"></span><h3>处理器<a class="headerlink" href="#handlers" title="永久链接至标题"></a></h3>
<p><a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 对象负责将适当的日志消息(基于日志消息的严重性)分派给处理器的指定目标。 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 对象可以使用 <a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addHandler()</span></code></a> 方法向自己添加零个或多个处理器对象。作为示例场景,应用程序可能希望将所有日志消息发送到日志文件,将错误或更高的所有日志消息发送到标准输出,以及将所有关键消息发送至一个邮件地址。 此方案需要三个单独的处理器,其中每个处理器负责将特定严重性的消息发送到特定位置。</p>
<p>标准库包含很多处理器类型(参见 <a class="reference internal" href="#useful-handlers"><span class="std std-ref">有用的处理器</span></a> );教程主要使用 <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a><a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a></p>
<p>处理器中很少有方法可供应用程序开发人员使用。使用内置处理器对象(即不创建自定义处理器)的应用程序开发人员能用到的仅有以下配置方法:</p>
<ul class="simple">
<li><p><code class="xref py py-meth docutils literal notranslate"><span class="pre">setLevel()</span></code> 方法,就像在记录器对象中一样,指定将被分派到适当目标的最低严重性。为什么有两个 <code class="xref py py-func docutils literal notranslate"><span class="pre">setLevel()</span></code> 方法?记录器中设置的级别确定将传递给其处理器的消息的严重性。每个处理器中设置的级别确定该处理器将发送哪些消息。</p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Handler.setFormatter" title="logging.Handler.setFormatter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">setFormatter()</span></code></a> 选择一个该处理器使用的 Formatter 对象。</p></li>
<li><p><a class="reference internal" href="../library/logging.html#logging.Handler.addFilter" title="logging.Handler.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addFilter()</span></code></a><a class="reference internal" href="../library/logging.html#logging.Handler.removeFilter" title="logging.Handler.removeFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">removeFilter()</span></code></a> 分别在处理器上配置和取消配置过滤器对象。</p></li>
</ul>
<p>应用程序代码不应直接实例化并使用 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 的实例。 相反, <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 类是一个基类,它定义了所有处理器应该具有的接口,并建立了子类可以使用(或覆盖)的一些默认行为。</p>
</section>
<section id="formatters">
<h3>格式器<a class="headerlink" href="#formatters" title="永久链接至标题"></a></h3>
<p>格式化器对象配置日志消息的最终顺序、结构和内容。 与 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">logging.Handler</span></code></a> 类不同,应用程序代码可以实例化格式器类,但如果应用程序需要特殊行为,则可能会对格式化器进行子类化定制。构造函数有三个可选参数 —— 消息格式字符串、日期格式字符串和样式指示符。</p>
<dl class="method">
<dt id="logging.logging.Formatter.__init__">
<code class="sig-prename descclassname">logging.Formatter.</code><code class="sig-name descname">__init__</code><span class="sig-paren">(</span><em class="sig-param">fmt=None</em>, <em class="sig-param">datefmt=None</em>, <em class="sig-param">style='%'</em><span class="sig-paren">)</span><a class="headerlink" href="#logging.logging.Formatter.__init__" title="永久链接至目标"></a></dt>
<dd></dd></dl>
<p>如果没有消息格式字符串,则默认使用原始消息。如果没有日期格式字符串,则默认日期格式为:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>%Y-%m-%d %H:%M:%S
</pre></div>
</div>
<p>最后加上毫秒数。 <code class="docutils literal notranslate"><span class="pre">style</span></code><cite></cite>'{ ' 或 '$' 之一。 如果未指定,则将使用 ''。</p>
<p>如果 <code class="docutils literal notranslate"><span class="pre">style</span></code> 是 '',则消息格式字符串使用 <code class="docutils literal notranslate"><span class="pre">%(&lt;dictionary</span> <span class="pre">key&gt;)s</span></code> 样式字符串替换;可能的键值在 <a class="reference internal" href="../library/logging.html#logrecord-attributes"><span class="std std-ref">LogRecord 属性</span></a> 中。 如果样式为 '{',则假定消息格式字符串与 <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a> (使用关键字参数)兼容,而如果样式为 '$' ,则消息格式字符串应符合 <a class="reference internal" href="../library/string.html#string.Template.substitute" title="string.Template.substitute"><code class="xref py py-meth docutils literal notranslate"><span class="pre">string.Template.substitute()</span></code></a></p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.2 版更改: </span>添加 <code class="docutils literal notranslate"><span class="pre">style</span></code> 形参。</p>
</div>
<p>以下消息格式字符串将以人类可读的格式记录时间、消息的严重性以及消息的内容,按此顺序:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
</pre></div>
</div>
<p>格式器通过用户可配置的函数将记录的创建时间转换为元组。 默认情况下,使用 <a class="reference internal" href="../library/time.html#time.localtime" title="time.localtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.localtime()</span></code></a> ;要为特定格式器实例更改此项,请将实例的 <code class="docutils literal notranslate"><span class="pre">converter</span></code> 属性设置为与 <a class="reference internal" href="../library/time.html#time.localtime" title="time.localtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.localtime()</span></code></a><a class="reference internal" href="../library/time.html#time.gmtime" title="time.gmtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.gmtime()</span></code></a> 具有相同签名的函数。 要为所有格式器更改它,例如,如果你希望所有记录时间都以 GMT 显示,请在格式器类中设置 <code class="docutils literal notranslate"><span class="pre">converter</span></code> 属性(对于 GMT 显示,设置为 <code class="docutils literal notranslate"><span class="pre">time.gmtime</span></code> )。</p>
</section>
<section id="configuring-logging">
<h3>配置日志记录<a class="headerlink" href="#configuring-logging" title="永久链接至标题"></a></h3>
<p>开发者可以通过三种方式配置日志记录:</p>
<ol class="arabic simple">
<li><p>使用调用上面列出的配置方法的 Python 代码显式创建记录器、处理器和格式器。</p></li>
<li><p>创建日志配置文件并使用 <a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 函数读取它。</p></li>
<li><p>创建配置信息字典并将其传递给 <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">dictConfig()</span></code></a> 函数。</p></li>
</ol>
<p>有关最后两个选项的参考文档,请参阅 <a class="reference internal" href="../library/logging.config.html#logging-config-api"><span class="std std-ref">配置函数</span></a> 。 以下示例使用 Python 代码配置一个非常简单的记录器、一个控制台处理器和一个简单的格式器:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="c1"># create logger</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simple_example&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="c1"># create console handler and set level to debug</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="c1"># create formatter</span>
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(name)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
<span class="c1"># add formatter to ch</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
<span class="c1"># add ch to logger</span>
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
<span class="c1"># &#39;application&#39; code</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;warn message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;error message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;critical message&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>从命令行运行此模块将生成以下输出:</p>
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>simple_logging_module.py
<span class="go">2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message</span>
<span class="go">2005-03-19 15:10:26,620 - simple_example - INFO - info message</span>
<span class="go">2005-03-19 15:10:26,695 - simple_example - WARNING - warn message</span>
<span class="go">2005-03-19 15:10:26,697 - simple_example - ERROR - error message</span>
<span class="go">2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message</span>
</pre></div>
</div>
<p>以下 Python 模块创建的记录器、处理器和格式器几乎与上面列出的示例中的相同,唯一的区别是对象的名称:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">logging.config</span>
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="s1">&#39;logging.conf&#39;</span><span class="p">)</span>
<span class="c1"># create logger</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simpleExample&#39;</span><span class="p">)</span>
<span class="c1"># &#39;application&#39; code</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;warn message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;error message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;critical message&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这是 logging.conf 文件:</p>
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="k">[loggers]</span>
<span class="na">keys</span><span class="o">=</span><span class="s">root,simpleExample</span>
<span class="k">[handlers]</span>
<span class="na">keys</span><span class="o">=</span><span class="s">consoleHandler</span>
<span class="k">[formatters]</span>
<span class="na">keys</span><span class="o">=</span><span class="s">simpleFormatter</span>
<span class="k">[logger_root]</span>
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
<span class="na">handlers</span><span class="o">=</span><span class="s">consoleHandler</span>
<span class="k">[logger_simpleExample]</span>
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
<span class="na">handlers</span><span class="o">=</span><span class="s">consoleHandler</span>
<span class="na">qualname</span><span class="o">=</span><span class="s">simpleExample</span>
<span class="na">propagate</span><span class="o">=</span><span class="s">0</span>
<span class="k">[handler_consoleHandler]</span>
<span class="na">class</span><span class="o">=</span><span class="s">StreamHandler</span>
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
<span class="na">formatter</span><span class="o">=</span><span class="s">simpleFormatter</span>
<span class="na">args</span><span class="o">=</span><span class="s">(sys.stdout,)</span>
<span class="k">[formatter_simpleFormatter]</span>
<span class="na">format</span><span class="o">=</span><span class="s">%(asctime)s - %(name)s - %(levelname)s - %(message)s</span>
<span class="na">datefmt</span><span class="o">=</span>
</pre></div>
</div>
<p>其输出与不基于配置文件的示例几乎相同:</p>
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>simple_logging_config.py
<span class="go">2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message</span>
<span class="go">2005-03-19 15:38:55,979 - simpleExample - INFO - info message</span>
<span class="go">2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message</span>
<span class="go">2005-03-19 15:38:56,055 - simpleExample - ERROR - error message</span>
<span class="go">2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message</span>
</pre></div>
</div>
<p>你可以看到配置文件方法相较于 Python 代码方法有一些优势,主要是配置和代码的分离以及非开发者轻松修改日志记录属性的能力。</p>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p><a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 函数接受一个默认参数 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> ,出于向后兼容的原因,默认为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。这可能与您的期望不同,因为除非在配置中明确命名它们(或其父级),否则它将导致在 <a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 调用之前存在的任何非 root 记录器被禁用。有关更多信息,请参阅参考文档,如果需要,请将此参数指定为 <code class="docutils literal notranslate"><span class="pre">False</span></code></p>
<p>传递给 <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">dictConfig()</span></code></a> 的字典也可以用键 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> 指定一个布尔值,如果没有在字典中明确指定,也默认被解释为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。这会导致上面描述的记录器禁用行为,这可能与你的期望不同——在这种情况下,请明确地为其提供 <code class="docutils literal notranslate"><span class="pre">False</span></code> 值。</p>
</div>
<p>请注意,配置文件中引用的类名称需要相对于日志记录模块,或者可以使用常规导入机制解析的绝对值。因此,你可以使用 <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">WatchedFileHandler</span></code></a> (相对于日志记录模块)或 <code class="docutils literal notranslate"><span class="pre">mypackage.mymodule.MyHandler</span></code> (对于在 <code class="docutils literal notranslate"><span class="pre">mypackage</span></code> 包中定义的类和模块 <code class="docutils literal notranslate"><span class="pre">mymodule</span></code> ,其中 <code class="docutils literal notranslate"><span class="pre">mypackage</span></code> 在 Python 导入路径上可用)。</p>
<p>在 Python 3.2 中,引入了一种新的配置日志记录的方法,使用字典来保存配置信息。 这提供了上述基于配置文件方法的功能的超集,并且是新应用程序和部署的推荐配置方法。 因为 Python 字典用于保存配置信息,并且由于你可以使用不同的方式填充该字典,因此你有更多的配置选项。 例如,你可以使用 JSON 格式的配置文件,或者如果你有权访问 YAML 处理功能,则可以使用 YAML 格式的文件来填充配置字典。当然,你可以在 Python 代码中构造字典,通过套接字以 pickle 形式接收它,或者使用对你的应用程序合理的任何方法。</p>
<p>以下是与上述相同配置的示例,采用 YAML 格式,用于新的基于字典的方法:</p>
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span>
<span class="nt">formatters</span><span class="p">:</span>
<span class="w"> </span><span class="nt">simple</span><span class="p">:</span>
<span class="w"> </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="s">&#39;%(asctime)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(name)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(levelname)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(message)s&#39;</span>
<span class="nt">handlers</span><span class="p">:</span>
<span class="w"> </span><span class="nt">console</span><span class="p">:</span>
<span class="w"> </span><span class="nt">class</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">logging.StreamHandler</span>
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
<span class="w"> </span><span class="nt">formatter</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">simple</span>
<span class="w"> </span><span class="nt">stream</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ext://sys.stdout</span>
<span class="nt">loggers</span><span class="p">:</span>
<span class="w"> </span><span class="nt">simpleExample</span><span class="p">:</span>
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
<span class="w"> </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">console</span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">propagate</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">no</span>
<span class="nt">root</span><span class="p">:</span>
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
<span class="w"> </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">console</span><span class="p p-Indicator">]</span>
</pre></div>
</div>
<p>有关使用字典进行日志记录的更多信息,请参阅 <a class="reference internal" href="../library/logging.config.html#logging-config-api"><span class="std std-ref">配置函数</span></a></p>
</section>
<section id="what-happens-if-no-configuration-is-provided">
<h3>如果没有提供配置会发生什么<a class="headerlink" href="#what-happens-if-no-configuration-is-provided" title="永久链接至标题"></a></h3>
<p>如果未提供日志记录配置,则可能出现需要输出日志记录事件但无法找到输出事件的处理器的情况。 在这些情况下logging 包的行为取决于 Python 版本。</p>
<p>对于 3.2 之前的 Python 版本,行为如下:</p>
<ul class="simple">
<li><p>如果 <em>logging.raiseExceptions</em><code class="docutils literal notranslate"><span class="pre">False</span></code> (生产模式),则会以静默方式丢弃该事件。</p></li>
<li><p>如果 <em>logging.raiseExceptions</em><code class="docutils literal notranslate"><span class="pre">True</span></code> (开发模式),则会打印一条消息 'No handlers could be found for logger X.Y.Z'。</p></li>
</ul>
<p>在 Python 3.2 及更高版本中,行为如下:</p>
<ul class="simple">
<li><p>事件使用 “最后的处理器” 输出,存储在 <code class="docutils literal notranslate"><span class="pre">logging.lastResort</span></code> 中。 这个内部处理器与任何记录器都没有关联,它的作用类似于 <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> ,它将事件描述消息写入 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> 的当前值(因此服从任何可能的重定向影响)。 没有对消息进行格式化——只打印裸事件描述消息。处理器的级别设置为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code>,因此将输出此级别和更高级别的所有事件。</p></li>
</ul>
<p>要获得 3.2 之前的行为,可以设置 <code class="docutils literal notranslate"><span class="pre">logging.lastResort</span></code><code class="docutils literal notranslate"><span class="pre">None</span></code></p>
</section>
<section id="configuring-logging-for-a-library">
<span id="library-config"></span><h3>为库配置日志<a class="headerlink" href="#configuring-logging-for-a-library" title="永久链接至标题"></a></h3>
<p>在开发带日志的库时,你应该在文档中详细说明,你的库会如何使用日志——例如,使用的记录器的名称。还需要考虑其日志配置。如果使用库的应用程序不使用日志,且库代码调用日志进行记录,那么(如上一节所述)严重性为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 和更高级别的事件将被打印到 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>。这被认为是最好的默认行为。</p>
<p>如果由于某种原因,你 <em></em> 希望在没有任何日志记录配置的情况下打印这些消息,则可以将无操作处理器附加到库的顶级记录器。这样可以避免打印消息,因为将始终为库的事件找到处理器:它不会产生任何输出。如果库用户配置应用程序使用的日志记录,可能是配置将添加一些处理器,如果级别已适当配置,则在库代码中进行的日志记录调用将正常地将输出发送给这些处理器。</p>
<p>日志包中包含一个不做任何事情的处理器: <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> (自 Python 3.1 起)。可以将此处理器的实例添加到库使用的日志记录命名空间的顶级记录器中( <em>如果</em> 你希望在没有日志记录配置的情况下阻止库的记录事件输出到 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> )。如果库 <em>foo</em> 的所有日志记录都是使用名称匹配 'foo.x' 'foo.x.y' 等的记录器完成的,那么代码:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">NullHandler</span><span class="p">())</span>
</pre></div>
</div>
<p>应该有预计的效果。如果一个组织生成了许多库,则指定的记录器名称可以是 “orgname.foo” 而不仅仅是 “foo” 。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>强烈建议你 <em>不要将</em> <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> <em>以外的任何处理器添加到库的记录器中</em> 。这是因为处理器的配置是使用你的库的应用程序开发人员的权利。应用程序开发人员了解他们的目标受众以及哪些处理器最适合他们的应用程序:如果你在“底层”添加处理器,则可能会干扰他们执行单元测试和提供符合其要求的日志的能力。</p>
</div>
</section>
</section>
<section id="logging-levels">
<h2>日志级别<a class="headerlink" href="#logging-levels" title="永久链接至标题"></a></h2>
<p>日志记录级别的数值在下表中给出。如果你想要定义自己的级别,并且需要它们具有相对于预定义级别的特定值,那么这你可能对以下内容感兴趣。如果你定义具有相同数值的级别,它将覆盖预定义的值;预定义的名称将失效。</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 48%" />
<col style="width: 52%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>级别</p></th>
<th class="head"><p>数值</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code></p></td>
<td><p>50</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ERROR</span></code></p></td>
<td><p>40</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WARNING</span></code></p></td>
<td><p>30</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">INFO</span></code></p></td>
<td><p>20</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code></p></td>
<td><p>10</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">NOTSET</span></code></p></td>
<td><p>0</p></td>
</tr>
</tbody>
</table>
<p>级别也可以与记录器关联,可以由开发人员设置,也可以通过加载保存的日志配置来设置。在记录器上调用记录方法时,记录器会将自己的级别与调用的方法的级别进行比较。如果记录器的级别高于调用的方法的级别,则实际上不会生成任何记录消息。这是控制日志记录输出详细程度的基本机制。</p>
<p>日志消息被编码为 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 类的实例。当记录器决定实际记录一个事件时,将从记录消息创建一个 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例。</p>
<p>使用 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 类的子例的实例 <em class="dfn">handlers</em>,可以为日志消息建立分派机制。处理器负责确保记录的消息(以 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 的形式)最终到达对该消息的目标受众(如最终用户、技术支持员工、系统管理员或开发人员)有用的一个或多个位置上。想要去到特定目标的 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例会被传给相应的处理器。每个记录器可以有零、一或多个与之相关联的处理器(通过 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a><a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addHandler()</span></code></a> 方法)。除了与记录器直接关联的所有处理器之外,还会将消息分派给 <em>记录器的所有祖先关联的各个处理器*(除非某个记录器的 *propagate</em> 旗标被设为假值,这将使向祖先的传递在其处终止)。</p>
<p>就像记录器一样,处理器可以具有与它们相关联的级别。处理器的级别作为过滤器,其方式与记录器级别相同。如果处理器决定调度一个事件,则使用 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code> 方法将消息发送到其目标。大多数用户定义的 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 子类都需要重写 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code></p>
<section id="custom-levels">
<span id="id1"></span><h3>自定义级别<a class="headerlink" href="#custom-levels" title="永久链接至标题"></a></h3>
<p>定义你自己的级别是可能的,但不一定是必要的,因为现有级别是根据实践经验选择的。但是,如果你确信需要自定义级别,那么在执行此操作时应特别小心,如果你正在开发库,则 <em>定义自定义级别可能是一个非常糟糕的主意</em> 。 这是因为如果多个库作者都定义了他们自己的自定义级别,那么使用开发人员很难控制和解释这些多个库的日志记录输出,因为给定的数值对于不同的库可能意味着不同的东西。</p>
</section>
</section>
<section id="useful-handlers">
<span id="id2"></span><h2>有用的处理器<a class="headerlink" href="#useful-handlers" title="永久链接至标题"></a></h2>
<p>作为 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 基类的补充,提供了很多有用的子类:</p>
<ol class="arabic simple">
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> 实例发送消息到流(类似文件对象)。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a> 实例将消息发送到硬盘文件。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.BaseRotatingHandler" title="logging.handlers.BaseRotatingHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseRotatingHandler</span></code></a> 是轮换日志文件的处理器的基类。它并不应该直接实例化。而应该使用 <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">RotatingFileHandler</span></code></a><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">TimedRotatingFileHandler</span></code></a> 代替它。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">RotatingFileHandler</span></code></a> 实例将消息发送到硬盘文件,支持最大日志文件大小和日志文件轮换。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">TimedRotatingFileHandler</span></code></a> 实例将消息发送到硬盘文件,以特定的时间间隔轮换日志文件。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SocketHandler</span></code></a> 实例将消息发送到 TCP/IP 套接字。从 3.4 开始,也支持 Unix 域套接字。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.DatagramHandler" title="logging.handlers.DatagramHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">DatagramHandler</span></code></a> 实例将消息发送到 UDP 套接字。从 3.4 开始,也支持 Unix 域套接字。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SMTPHandler" title="logging.handlers.SMTPHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SMTPHandler</span></code></a> 实例将消息发送到指定的电子邮件地址。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SysLogHandler" title="logging.handlers.SysLogHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SysLogHandler</span></code></a> 实例将消息发送到 Unix syslog 守护程序,可能在远程计算机上。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.NTEventLogHandler" title="logging.handlers.NTEventLogHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NTEventLogHandler</span></code></a> 实例将消息发送到 Windows NT/2000/XP 事件日志。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.MemoryHandler" title="logging.handlers.MemoryHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">MemoryHandler</span></code></a> 实例将消息发送到内存中的缓冲区,只要满足特定条件,缓冲区就会刷新。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.HTTPHandler" title="logging.handlers.HTTPHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">HTTPHandler</span></code></a> 实例使用 <code class="docutils literal notranslate"><span class="pre">GET</span></code><code class="docutils literal notranslate"><span class="pre">POST</span></code> 方法将消息发送到 HTTP 服务器。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">WatchedFileHandler</span></code></a> 实例会监视他们要写入日志的文件。如果文件发生更改,则会关闭该文件并使用文件名重新打开。此处理器仅在类 Unix 系统上有用; Windows 不支持依赖的基础机制。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">QueueHandler</span></code></a> 实例将消息发送到队列,例如在 <a class="reference internal" href="../library/queue.html#module-queue" title="queue: A synchronized queue class."><code class="xref py py-mod docutils literal notranslate"><span class="pre">queue</span></code></a><a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal notranslate"><span class="pre">multiprocessing</span></code></a> 模块中实现的队列。</p></li>
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> 实例对错误消息不执行任何操作。它们由想要使用日志记录的库开发人员使用,但是想要避免如果库用户没有配置日志记录,则显示 'No handlers could be found for logger XXX' 消息的情况。更多有关信息,请参阅 <a class="reference internal" href="#library-config"><span class="std std-ref">为库配置日志</span></a></p></li>
</ol>
<div class="versionadded">
<p><span class="versionmodified added">3.1 新版功能: </span><a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> 类。</p>
</div>
<div class="versionadded">
<p><span class="versionmodified added">3.2 新版功能: </span><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">QueueHandler</span></code></a> 类。</p>
</div>
<p>The <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a><a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a><a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a> 类在核心日志包中定义。其他处理器定义在 <a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a> 中。(还有另一个子模块 <a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> ,用于配置功能)</p>
<p>记录的消息通过 <a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Formatter</span></code></a> 类的实例进行格式化后呈现。 它们使用能与 运算符一起使用的格式字符串和字典进行初始化。</p>
<p>要批量格式化多个消息,可以使用 <code class="xref py py-class docutils literal notranslate"><span class="pre">BufferingFormatter</span></code> 的实例。除了格式字符串(应用于批处理中的每个消息)之外,还提供了标题和尾部格式字符串。</p>
<p>当基于记录器级别和处理器级别的过滤不够时,可以将 <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Filter</span></code></a> 的实例添加到 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a><a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 实例(通过它们的 <a class="reference internal" href="../library/logging.html#logging.Handler.addFilter" title="logging.Handler.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addFilter()</span></code></a> 方法)。在决定进一步处理消息之前,记录器和处理器都会查询其所有过滤器以获得许可。如果任何过滤器返回 false 值,则不会进一步处理该消息。</p>
<p>基本 <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Filter</span></code></a> 的功能允许按特定的记录器名称进行过滤。如果使用此功能,则允许通过过滤器发送到指定记录器及其子项的消息,并丢弃其他所有消息。</p>
</section>
<section id="exceptions-raised-during-logging">
<span id="logging-exceptions"></span><h2>记录日志时引发的异常<a class="headerlink" href="#exceptions-raised-during-logging" title="永久链接至标题"></a></h2>
<p>logging 包被设计为,当在生产环境下使用时,忽略记录日志时发生的异常。这样,处理与日志相关的事件时发生的错误(例如日志配置错误、网络或其它类似错误)不会导致使用日志的应用程序终止。</p>
<p><a class="reference internal" href="../library/exceptions.html#SystemExit" title="SystemExit"><code class="xref py py-class docutils literal notranslate"><span class="pre">SystemExit</span></code></a><a class="reference internal" href="../library/exceptions.html#KeyboardInterrupt" title="KeyboardInterrupt"><code class="xref py py-class docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code></a> 异常永远不会被忽略。在 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 的子类的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code> 方法中发生的其它异常将被传递给其 <code class="xref py py-meth docutils literal notranslate"><span class="pre">handleError()</span></code> 方法。</p>
<p><a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 中的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">handleError()</span></code> 的默认实现是检查是否设置了模块级变量 <code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code>。如有设置,则会将回溯打印到 <a class="reference internal" href="../library/sys.html#sys.stderr" title="sys.stderr"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.stderr</span></code></a>。如果未设置,则忽略异常。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p><code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code> 的默认值是 <code class="docutils literal notranslate"><span class="pre">True</span></code>。这是因为在开发期间,你通常想要在发生异常时收到通知。建议你将 <code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code> 设为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 供生产环境下使用。</p>
</div>
</section>
<section id="using-arbitrary-objects-as-messages">
<span id="arbitrary-object-messages"></span><h2>使用任意对象作为消息<a class="headerlink" href="#using-arbitrary-objects-as-messages" title="永久链接至标题"></a></h2>
<p>在前面的部分和示例中,都假设记录事件时传递的消息是字符串。 但是,这不是唯一的可能性。你可以将任意对象作为消息传递,并且当日志记录系统需要将其转换为字符串表示时,将调用其 <code class="xref py py-meth docutils literal notranslate"><span class="pre">__</span> <span class="pre">str__()</span></code> 方法。实际上,如果你愿意,你可以完全避免计算字符串表示。例如, <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SocketHandler</span></code></a> 用 pickle 处理事件后,通过网络发送。</p>
</section>
<section id="optimization">
<h2>优化<a class="headerlink" href="#optimization" title="永久链接至标题"></a></h2>
<p>消息参数的格式化将被推迟,直到无法避免。但是,计算传递给日志记录方法的参数也可能很消耗资源,如果记录器只是丢弃你的事件,你可能希望避免这样做。要决定做什么,可以调用 <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> 方法,该方法接受一个 level 参数,如果记录器为该级别的调用创建了该事件,则返回 true 。 你可以写这样的代码:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">logger</span><span class="o">.</span><span class="n">isEnabledFor</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">):</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Message with </span><span class="si">%s</span><span class="s1">, </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">expensive_func1</span><span class="p">(),</span>
<span class="n">expensive_func2</span><span class="p">())</span>
</pre></div>
</div>
<p>因此如果记录器的阈值设置在“DEBUG”以上则永远不会调用 <code class="xref py py-func docutils literal notranslate"><span class="pre">expensive_func1()</span></code><code class="xref py py-func docutils literal notranslate"><span class="pre">expensive_func2()</span></code></p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>在某些情况下, <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> 本身可能比你想要的更消耗资源(例如,对于深度嵌套的记录器,其中仅在记录器层次结构中设置了显式级别)。在这种情况下(或者如果你想避免在紧密循环中调用方法),你可以在本地或实例变量中将调用的结果缓存到 <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> ,并使用它而不是每次调用方法。在日志记录配置在应用程序运行时动态更改(这不常见)时,只需要重新计算这样的缓存值即可。</p>
</div>
<p>对于需要对收集的日志信息进行更精确控制的特定应用程序,还可以进行其他优化。以下列出了在日志记录过程中您可以避免的非必须处理操作:</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 54%" />
<col style="width: 46%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>你不想收集的内容</p></th>
<th class="head"><p>如何避免收集它</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>有关调用来源的信息</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">logging._srcfile</span></code> 设置为 <code class="docutils literal notranslate"><span class="pre">None</span></code> 。这避免了调用 <a class="reference internal" href="../library/sys.html#sys._getframe" title="sys._getframe"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys._getframe()</span></code></a> ,如果 PyPy 支持 Python 3.x ,这可能有助于加速 PyPy (无法加速使用 <a class="reference internal" href="../library/sys.html#sys._getframe" title="sys._getframe"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys._getframe()</span></code></a> 的代码)等环境中的代码.</p></td>
</tr>
<tr class="row-odd"><td><p>线程信息</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">logging.logThreads</span></code> 置为 <code class="docutils literal notranslate"><span class="pre">0</span></code></p></td>
</tr>
<tr class="row-even"><td><p>进程信息</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">logging.logProcesses</span></code> 置为 <code class="docutils literal notranslate"><span class="pre">0</span></code></p></td>
</tr>
</tbody>
</table>
<p>另请注意,核心日志记录模块仅包含基本处理器。如果你不导入 <a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a><a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> ,它们将不会占用任何内存。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<dl class="simple">
<dt>模块 <a class="reference internal" href="../library/logging.html#module-logging" title="logging: Flexible event logging system for applications."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging</span></code></a></dt><dd><p>日志记录模块的 API 参考。</p>
</dd>
<dt><a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> 模块</dt><dd><p>日志记录模块的配置 API 。</p>
</dd>
<dt><a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a> 模块</dt><dd><p>日志记录模块附带的有用处理器。</p>
</dd>
</dl>
<p><a class="reference internal" href="logging-cookbook.html#logging-cookbook"><span class="std std-ref">日志操作手册</span></a></p>
</div>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">日志指南</a><ul>
<li><a class="reference internal" href="#basic-logging-tutorial">日志基础教程</a><ul>
<li><a class="reference internal" href="#when-to-use-logging">什么时候使用日志</a></li>
<li><a class="reference internal" href="#a-simple-example">一个简单的例子</a></li>
<li><a class="reference internal" href="#logging-to-a-file">记录日志到文件</a></li>
<li><a class="reference internal" href="#logging-from-multiple-modules">从多个模块记录日志</a></li>
<li><a class="reference internal" href="#logging-variable-data">记录变量数据</a></li>
<li><a class="reference internal" href="#changing-the-format-of-displayed-messages">更改显示消息的格式</a></li>
<li><a class="reference internal" href="#displaying-the-date-time-in-messages">在消息中显示日期/时间</a></li>
<li><a class="reference internal" href="#next-steps">后续步骤</a></li>
</ul>
</li>
<li><a class="reference internal" href="#advanced-logging-tutorial">进阶日志教程</a><ul>
<li><a class="reference internal" href="#logging-flow">记录流程</a></li>
<li><a class="reference internal" href="#loggers">记录器</a></li>
<li><a class="reference internal" href="#handlers">处理器</a></li>
<li><a class="reference internal" href="#formatters">格式器</a></li>
<li><a class="reference internal" href="#configuring-logging">配置日志记录</a></li>
<li><a class="reference internal" href="#what-happens-if-no-configuration-is-provided">如果没有提供配置会发生什么</a></li>
<li><a class="reference internal" href="#configuring-logging-for-a-library">为库配置日志</a></li>
</ul>
</li>
<li><a class="reference internal" href="#logging-levels">日志级别</a><ul>
<li><a class="reference internal" href="#custom-levels">自定义级别</a></li>
</ul>
</li>
<li><a class="reference internal" href="#useful-handlers">有用的处理器</a></li>
<li><a class="reference internal" href="#exceptions-raised-during-logging">记录日志时引发的异常</a></li>
<li><a class="reference internal" href="#using-arbitrary-objects-as-messages">使用任意对象作为消息</a></li>
<li><a class="reference internal" href="#optimization">优化</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="functional.html"
title="上一章">函数式编程指引</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="logging-cookbook.html"
title="下一章">日志专题手册</a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/howto/logging.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
>索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="logging-cookbook.html" title="日志专题手册"
>下一页</a> |</li>
<li class="right" >
<a href="functional.html" title="函数式编程指引"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>