742 lines
50 KiB
HTML
742 lines
50 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 282 – A Logging System | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0282/">
|
||
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
||
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
||
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
||
<meta property="og:title" content='PEP 282 – A Logging System | peps.python.org'>
|
||
<meta property="og:description" content="This PEP describes a proposed logging package for Python’s standard library.">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0282/">
|
||
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
||
<meta property="og:image:alt" content="Python PEPs">
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="description" content="This PEP describes a proposed logging package for Python’s standard library.">
|
||
<meta name="theme-color" content="#3776ab">
|
||
</head>
|
||
<body>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Following system colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="9"></circle>
|
||
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected dark colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected light colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
<script>
|
||
|
||
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
||
</script>
|
||
<section id="pep-page-section">
|
||
<header>
|
||
<h1>Python Enhancement Proposals</h1>
|
||
<ul class="breadcrumbs">
|
||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 282</li>
|
||
</ul>
|
||
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
||
</button>
|
||
</header>
|
||
<article>
|
||
<section id="pep-content">
|
||
<h1 class="page-title">PEP 282 – A Logging System</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Vinay Sajip <vinay_sajip at red-dove.com>,
|
||
Trent Mick <trentm at activestate.com></dd>
|
||
<dt class="field-even">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
|
||
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-even">Created<span class="colon">:</span></dt>
|
||
<dd class="field-even">04-Feb-2002</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">2.3</dd>
|
||
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-even"><p></p></dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a></li>
|
||
<li><a class="reference internal" href="#influences">Influences</a></li>
|
||
<li><a class="reference internal" href="#simple-example">Simple Example</a></li>
|
||
<li><a class="reference internal" href="#control-flow">Control Flow</a></li>
|
||
<li><a class="reference internal" href="#levels">Levels</a></li>
|
||
<li><a class="reference internal" href="#loggers">Loggers</a></li>
|
||
<li><a class="reference internal" href="#handlers">Handlers</a></li>
|
||
<li><a class="reference internal" href="#logrecords">LogRecords</a></li>
|
||
<li><a class="reference internal" href="#formatters">Formatters</a></li>
|
||
<li><a class="reference internal" href="#filters">Filters</a></li>
|
||
<li><a class="reference internal" href="#configuration">Configuration</a></li>
|
||
<li><a class="reference internal" href="#thread-safety">Thread Safety</a></li>
|
||
<li><a class="reference internal" href="#module-level-functions">Module-Level Functions</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#packaging">Packaging</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PEP describes a proposed logging package for Python’s
|
||
standard library.</p>
|
||
<p>Basically the system involves the user creating one or more logger
|
||
objects on which methods are called to log debugging notes,
|
||
general information, warnings, errors etc. Different logging
|
||
‘levels’ can be used to distinguish important messages from less
|
||
important ones.</p>
|
||
<p>A registry of named singleton logger objects is maintained so that</p>
|
||
<ol class="arabic simple">
|
||
<li>different logical logging streams (or ‘channels’) exist
|
||
(say, one for ‘zope.zodb’ stuff and another for
|
||
‘mywebsite’-specific stuff)</li>
|
||
<li>one does not have to pass logger object references around.</li>
|
||
</ol>
|
||
<p>The system is configurable at runtime. This configuration
|
||
mechanism allows one to tune the level and type of logging done
|
||
while not touching the application itself.</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>If a single logging mechanism is enshrined in the standard
|
||
library, 1) logging is more likely to be done ‘well’, and 2)
|
||
multiple libraries will be able to be integrated into larger
|
||
applications which can be logged reasonably coherently.</p>
|
||
</section>
|
||
<section id="influences">
|
||
<h2><a class="toc-backref" href="#influences" role="doc-backlink">Influences</a></h2>
|
||
<p>This proposal was put together after having studied the
|
||
following logging packages:</p>
|
||
<ul class="simple">
|
||
<li>java.util.logging in JDK 1.4 (a.k.a. JSR047) <a class="footnote-reference brackets" href="#id11" id="id1">[1]</a></li>
|
||
<li>log4j <a class="footnote-reference brackets" href="#id12" id="id2">[2]</a></li>
|
||
<li>the Syslog package from the Protomatter project <a class="footnote-reference brackets" href="#id13" id="id3">[3]</a></li>
|
||
<li>MAL’s mx.Log package <a class="footnote-reference brackets" href="#id14" id="id4">[4]</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="simple-example">
|
||
<h2><a class="toc-backref" href="#simple-example" role="doc-backlink">Simple Example</a></h2>
|
||
<p>This shows a very simple example of how the logging package can be
|
||
used to generate simple logging output on stderr.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="o">---------</span> <span class="n">mymodule</span><span class="o">.</span><span class="n">py</span> <span class="o">-------------------------------</span>
|
||
<span class="kn">import</span> <span class="nn">logging</span>
|
||
<span class="n">log</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="s2">"MyModule"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">doIt</span><span class="p">():</span>
|
||
<span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Doin' stuff..."</span><span class="p">)</span>
|
||
<span class="c1">#do stuff...</span>
|
||
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="s2">"Bogus type error for testing"</span>
|
||
<span class="o">-----------------------------------------------------</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="o">---------</span> <span class="n">myapp</span><span class="o">.</span><span class="n">py</span> <span class="o">----------------------------------</span>
|
||
<span class="kn">import</span> <span class="nn">mymodule</span><span class="o">,</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">log</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="s2">"MyApp"</span><span class="p">)</span>
|
||
|
||
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Starting my app"</span><span class="p">)</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">mymodule</span><span class="o">.</span><span class="n">doIt</span><span class="p">()</span>
|
||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
|
||
<span class="n">log</span><span class="o">.</span><span class="n">exception</span><span class="p">(</span><span class="s2">"There was a problem."</span><span class="p">)</span>
|
||
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Ending my app"</span><span class="p">)</span>
|
||
<span class="o">-----------------------------------------------------</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>myapp.py
|
||
|
||
<span class="go">INFO:MyApp: Starting my app</span>
|
||
<span class="go">DEBUG:MyModule: Doin' stuff...</span>
|
||
<span class="go">ERROR:MyApp: There was a problem.</span>
|
||
<span class="go">Traceback (most recent call last):</span>
|
||
<span class="go"> File "myapp.py", line 9, in ?</span>
|
||
<span class="go"> mymodule.doIt()</span>
|
||
<span class="go"> File "mymodule.py", line 7, in doIt</span>
|
||
<span class="go"> raise TypeError, "Bogus type error for testing"</span>
|
||
<span class="go">TypeError: Bogus type error for testing</span>
|
||
|
||
<span class="go">INFO:MyApp: Ending my app</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The above example shows the default output format. All
|
||
aspects of the output format should be configurable, so that
|
||
you could have output formatted like this:</p>
|
||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>2002-04-19 07:56:58,174 MyModule DEBUG - Doin' stuff...
|
||
|
||
or just
|
||
|
||
Doin' stuff...
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="control-flow">
|
||
<h2><a class="toc-backref" href="#control-flow" role="doc-backlink">Control Flow</a></h2>
|
||
<p>Applications make logging calls on <strong>Logger</strong> objects. Loggers are
|
||
organized in a hierarchical namespace and child Loggers inherit
|
||
some logging properties from their parents in the namespace.</p>
|
||
<p>Logger names fit into a “dotted name” namespace, with dots
|
||
(periods) indicating sub-namespaces. The namespace of logger
|
||
objects therefore corresponds to a single tree data structure.</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">""</span></code> is the root of the namespace</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">"Zope"</span></code> would be a child node of the root</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">"Zope.ZODB"</span></code> would be a child node of <code class="docutils literal notranslate"><span class="pre">"Zope"</span></code></li>
|
||
</ul>
|
||
<p>These Logger objects create <strong>LogRecord</strong> objects which are passed
|
||
to <strong>Handler</strong> objects for output. Both Loggers and Handlers may
|
||
use logging <strong>levels</strong> and (optionally) <strong>Filters</strong> to decide if they
|
||
are interested in a particular LogRecord. When it is necessary to
|
||
output a LogRecord externally, a Handler can (optionally) use a
|
||
<strong>Formatter</strong> to localize and format the message before sending it
|
||
to an I/O stream.</p>
|
||
<p>Each Logger keeps track of a set of output Handlers. By default
|
||
all Loggers also send their output to all Handlers of their
|
||
ancestor Loggers. Loggers may, however, also be configured to
|
||
ignore Handlers higher up the tree.</p>
|
||
<p>The APIs are structured so that calls on the Logger APIs can be
|
||
cheap when logging is disabled. If logging is disabled for a
|
||
given log level, then the Logger can make a cheap comparison test
|
||
and return. If logging is enabled for a given log level, the
|
||
Logger is still careful to minimize costs before passing the
|
||
LogRecord into the Handlers. In particular, localization and
|
||
formatting (which are relatively expensive) are deferred until the
|
||
Handler requests them.</p>
|
||
<p>The overall Logger hierarchy can also have a level associated with
|
||
it, which takes precedence over the levels of individual Loggers.
|
||
This is done through a module-level function:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">disable</span><span class="p">(</span><span class="n">lvl</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Do not generate any LogRecords for requests with a severity less</span>
|
||
<span class="sd"> than 'lvl'.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="levels">
|
||
<h2><a class="toc-backref" href="#levels" role="doc-backlink">Levels</a></h2>
|
||
<p>The logging levels, in increasing order of importance, are:</p>
|
||
<ul class="simple">
|
||
<li>DEBUG</li>
|
||
<li>INFO</li>
|
||
<li>WARN</li>
|
||
<li>ERROR</li>
|
||
<li>CRITICAL</li>
|
||
</ul>
|
||
<p>The term CRITICAL is used in preference to FATAL, which is used by
|
||
log4j. The levels are conceptually the same - that of a serious,
|
||
or very serious, error. However, FATAL implies death, which in
|
||
Python implies a raised and uncaught exception, traceback, and
|
||
exit. Since the logging module does not enforce such an outcome
|
||
from a FATAL-level log entry, it makes sense to use CRITICAL in
|
||
preference to FATAL.</p>
|
||
<p>These are just integer constants, to allow simple comparison of
|
||
importance. Experience has shown that too many levels can be
|
||
confusing, as they lead to subjective interpretation of which
|
||
level should be applied to any particular log request.</p>
|
||
<p>Although the above levels are strongly recommended, the logging
|
||
system should not be prescriptive. Users may define their own
|
||
levels, as well as the textual representation of any levels. User
|
||
defined levels must, however, obey the constraints that they are
|
||
all positive integers and that they increase in order of
|
||
increasing severity.</p>
|
||
<p>User-defined logging levels are supported through two module-level
|
||
functions:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">getLevelName</span><span class="p">(</span><span class="n">lvl</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Return the text for level 'lvl'."""</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">addLevelName</span><span class="p">(</span><span class="n">lvl</span><span class="p">,</span> <span class="n">lvlName</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Add the level 'lvl' with associated text 'levelName', or</span>
|
||
<span class="sd"> set the textual representation of existing level 'lvl' to be</span>
|
||
<span class="sd"> 'lvlName'."""</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="loggers">
|
||
<h2><a class="toc-backref" href="#loggers" role="doc-backlink">Loggers</a></h2>
|
||
<p>Each Logger object keeps track of a log level (or threshold) that
|
||
it is interested in, and discards log requests below that level.</p>
|
||
<p>A <strong>Manager</strong> class instance maintains the hierarchical namespace of
|
||
named Logger objects. Generations are denoted with dot-separated
|
||
names: Logger “foo” is the parent of Loggers “foo.bar” and
|
||
“foo.baz”.</p>
|
||
<p>The Manager class instance is a singleton and is not directly
|
||
exposed to users, who interact with it using various module-level
|
||
functions.</p>
|
||
<p>The general logging method is:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Logger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">log</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lvl</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Log 'str(msg) % args' at logging level 'lvl'."""</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>However, convenience functions are defined for each logging level:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Logger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">debug</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="o">...</span>
|
||
<span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="o">...</span>
|
||
<span class="k">def</span> <span class="nf">warn</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="o">...</span>
|
||
<span class="k">def</span> <span class="nf">error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="o">...</span>
|
||
<span class="k">def</span> <span class="nf">critical</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Only one keyword argument is recognized at present - “exc_info”.
|
||
If true, the caller wants exception information to be provided in
|
||
the logging output. This mechanism is only needed if exception
|
||
information needs to be provided at <strong>any</strong> logging level. In the
|
||
more common case, where exception information needs to be added to
|
||
the log only when errors occur, i.e. at the ERROR level, then
|
||
another convenience method is provided:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Logger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">exception</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This should only be called in the context of an exception handler,
|
||
and is the preferred way of indicating a desire for exception
|
||
information in the log. The other convenience methods are
|
||
intended to be called with exc_info only in the unusual situation
|
||
where you might want to provide exception information in the
|
||
context of an INFO message, for example.</p>
|
||
<p>The “msg” argument shown above will normally be a format string;
|
||
however, it can be any object x for which <code class="docutils literal notranslate"><span class="pre">str(x)</span></code> returns the
|
||
format string. This facilitates, for example, the use of an
|
||
object which fetches a locale- specific message for an
|
||
internationalized/localized application, perhaps using the
|
||
standard gettext module. An outline example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Message</span><span class="p">:</span>
|
||
<span class="w"> </span><span class="sd">"""Represents a message"""</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Initialize with the message ID"""</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Return an appropriate localized message text"""</span>
|
||
|
||
<span class="o">...</span>
|
||
|
||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">"abc"</span><span class="p">),</span> <span class="o">...</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Gathering and formatting data for a log message may be expensive,
|
||
and a waste if the logger was going to discard the message anyway.
|
||
To see if a request will be honoured by the logger, the
|
||
<code class="docutils literal notranslate"><span class="pre">isEnabledFor()</span></code> method can be used:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Logger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">isEnabledFor</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lvl</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Return true if requests at level 'lvl' will NOT be</span>
|
||
<span class="sd"> discarded.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>so instead of this expensive and possibly wasteful DOM to XML
|
||
conversion:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
|
||
<span class="n">hamletStr</span> <span class="o">=</span> <span class="n">hamletDom</span><span class="o">.</span><span class="n">toxml</span><span class="p">()</span>
|
||
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">hamletStr</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>one can do this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">log</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">INFO</span><span class="p">):</span>
|
||
<span class="n">hamletStr</span> <span class="o">=</span> <span class="n">hamletDom</span><span class="o">.</span><span class="n">toxml</span><span class="p">()</span>
|
||
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">hamletStr</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When new loggers are created, they are initialized with a level
|
||
which signifies “no level”. A level can be set explicitly using
|
||
the <code class="docutils literal notranslate"><span class="pre">setLevel()</span></code> method:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Logger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">setLevel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lvl</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If a logger’s level is not set, the system consults all its
|
||
ancestors, walking up the hierarchy until an explicitly set level
|
||
is found. That is regarded as the “effective level” of the
|
||
logger, and can be queried via the getEffectiveLevel() method:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">getEffectiveLevel</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Loggers are never instantiated directly. Instead, a module-level
|
||
function is used:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">getLogger</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If no name is specified, the root logger is returned. Otherwise,
|
||
if a logger with that name exists, it is returned. If not, a new
|
||
logger is initialized and returned. Here, “name” is synonymous
|
||
with “channel name”.</p>
|
||
<p>Users can specify a custom subclass of Logger to be used by the
|
||
system when instantiating new loggers:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">setLoggerClass</span><span class="p">(</span><span class="n">klass</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The passed class should be a subclass of Logger, and its <code class="docutils literal notranslate"><span class="pre">__init__</span></code>
|
||
method should call <code class="docutils literal notranslate"><span class="pre">Logger.__init__</span></code>.</p>
|
||
</section>
|
||
<section id="handlers">
|
||
<h2><a class="toc-backref" href="#handlers" role="doc-backlink">Handlers</a></h2>
|
||
<p>Handlers are responsible for doing something useful with a given
|
||
<code class="docutils literal notranslate"><span class="pre">LogRecord</span></code>. The following core Handlers will be implemented:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">StreamHandler</span></code>: A handler for writing to a file-like object.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">FileHandler</span></code>: A handler for writing to a single file or set
|
||
of rotating files.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">SocketHandler</span></code>: A handler for writing to remote TCP ports.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">DatagramHandler</span></code>: A handler for writing to UDP sockets, for
|
||
low-cost logging. Jeff Bauer already had such a system <a class="footnote-reference brackets" href="#id15" id="id5">[5]</a>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">MemoryHandler</span></code>: A handler that buffers log records in memory
|
||
until the buffer is full or a particular condition occurs
|
||
<a class="footnote-reference brackets" href="#id11" id="id6">[1]</a>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">SMTPHandler</span></code>: A handler for sending to email addresses via SMTP.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">SysLogHandler</span></code>: A handler for writing to Unix syslog via UDP.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">NTEventLogHandler</span></code>: A handler for writing to event logs on
|
||
Windows NT, 2000 and XP.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">HTTPHandler</span></code>: A handler for writing to a Web server with
|
||
either GET or POST semantics.</li>
|
||
</ul>
|
||
<p>Handlers can also have levels set for them using the
|
||
<code class="docutils literal notranslate"><span class="pre">setLevel()</span></code> method:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">setLevel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lvl</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The FileHandler can be set up to create a rotating set of log
|
||
files. In this case, the file name passed to the constructor is
|
||
taken as a “base” file name. Additional file names for the
|
||
rotation are created by appending .1, .2, etc. to the base file
|
||
name, up to a maximum as specified when rollover is requested.
|
||
The setRollover method is used to specify a maximum size for a log
|
||
file and a maximum number of backup files in the rotation.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">setRollover</span><span class="p">(</span><span class="n">maxBytes</span><span class="p">,</span> <span class="n">backupCount</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If maxBytes is specified as zero, no rollover ever occurs and the
|
||
log file grows indefinitely. If a non-zero size is specified,
|
||
when that size is about to be exceeded, rollover occurs. The
|
||
rollover method ensures that the base file name is always the most
|
||
recent, .1 is the next most recent, .2 the next most recent after
|
||
that, and so on.</p>
|
||
<p>There are many additional handlers implemented in the test/example
|
||
scripts provided with <a class="footnote-reference brackets" href="#id16" id="id7">[6]</a> - for example, XMLHandler and
|
||
SOAPHandler.</p>
|
||
</section>
|
||
<section id="logrecords">
|
||
<h2><a class="toc-backref" href="#logrecords" role="doc-backlink">LogRecords</a></h2>
|
||
<p>A LogRecord acts as a receptacle for information about a
|
||
logging event. It is little more than a dictionary, though it
|
||
does define a <code class="docutils literal notranslate"><span class="pre">getMessage</span></code> method which merges a message with
|
||
optional runarguments.</p>
|
||
</section>
|
||
<section id="formatters">
|
||
<h2><a class="toc-backref" href="#formatters" role="doc-backlink">Formatters</a></h2>
|
||
<p>A Formatter is responsible for converting a LogRecord to a string
|
||
representation. A Handler may call its Formatter before writing a
|
||
record. The following core Formatters will be implemented:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">Formatter</span></code>: Provide printf-like formatting, using the % operator.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">BufferingFormatter</span></code>: Provide formatting for multiple
|
||
messages, with header and trailer formatting support.</li>
|
||
</ul>
|
||
<p>Formatters are associated with Handlers by calling <code class="docutils literal notranslate"><span class="pre">setFormatter()</span></code>
|
||
on a handler:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">setFormatter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Formatters use the % operator to format the logging message. The
|
||
format string should contain <code class="docutils literal notranslate"><span class="pre">%(name)x</span></code> and the attribute dictionary
|
||
of the LogRecord is used to obtain message-specific data. The
|
||
following attributes are provided:</p>
|
||
<table class="docutils align-default">
|
||
<tbody>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(name)s</span></code></td>
|
||
<td>Name of the logger (logging channel)</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(levelno)s</span></code></td>
|
||
<td>Numeric logging level for the message (DEBUG,
|
||
INFO, WARN, ERROR, CRITICAL)</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(levelname)s</span></code></td>
|
||
<td>Text logging level for the message (“DEBUG”, “INFO”,
|
||
“WARN”, “ERROR”, “CRITICAL”)</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(pathname)s</span></code></td>
|
||
<td>Full pathname of the source file where the logging
|
||
call was issued (if available)</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(filename)s</span></code></td>
|
||
<td>Filename portion of pathname</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(module)s</span></code></td>
|
||
<td>Module from which logging call was made</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(lineno)d</span></code></td>
|
||
<td>Source line number where the logging call was issued
|
||
(if available)</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(created)f</span></code></td>
|
||
<td>Time when the LogRecord was created (<code class="docutils literal notranslate"><span class="pre">time.time()</span></code>
|
||
return value)</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(asctime)s</span></code></td>
|
||
<td>Textual time when the LogRecord was created</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(msecs)d</span></code></td>
|
||
<td>Millisecond portion of the creation time</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(relativeCreated)d</span></code></td>
|
||
<td>Time in milliseconds when the LogRecord was created,
|
||
relative to the time the logging module was loaded
|
||
(typically at application startup time)</td>
|
||
</tr>
|
||
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">%(thread)d</span></code></td>
|
||
<td>Thread ID (if available)</td>
|
||
</tr>
|
||
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">%(message)s</span></code></td>
|
||
<td>The result of record.getMessage(), computed just as
|
||
the record is emitted</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>If a formatter sees that the format string includes “(asctime)s”,
|
||
the creation time is formatted into the LogRecord’s asctime
|
||
attribute. To allow flexibility in formatting dates, Formatters
|
||
are initialized with a format string for the message as a whole,
|
||
and a separate format string for date/time. The date/time format
|
||
string should be in time.strftime format. The default value for
|
||
the message format is “%(message)s”. The default date/time format
|
||
is ISO8601.</p>
|
||
<p>The formatter uses a class attribute, “converter”, to indicate how
|
||
to convert a time from seconds to a tuple. By default, the value
|
||
of “converter” is “time.localtime”. If needed, a different
|
||
converter (e.g. “time.gmtime”) can be set on an individual
|
||
formatter instance, or the class attribute changed to affect all
|
||
formatter instances.</p>
|
||
</section>
|
||
<section id="filters">
|
||
<h2><a class="toc-backref" href="#filters" role="doc-backlink">Filters</a></h2>
|
||
<p>When level-based filtering is insufficient, a Filter can be called
|
||
by a Logger or Handler to decide if a LogRecord should be output.
|
||
Loggers and Handlers can have multiple filters installed, and any
|
||
one of them can veto a LogRecord being output.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Filter</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Return a value indicating true if the record is to be</span>
|
||
<span class="sd"> processed. Possibly modify the record, if deemed</span>
|
||
<span class="sd"> appropriate by the filter.</span>
|
||
<span class="sd"> """</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The default behaviour allows a Filter to be initialized with a
|
||
Logger name. This will only allow through events which are
|
||
generated using the named logger or any of its children. For
|
||
example, a filter initialized with “A.B” will allow events logged
|
||
by loggers “A.B”, “A.B.C”, “A.B.C.D”, “A.B.D” etc. but not “A.BB”,
|
||
“B.A.B” etc. If initialized with the empty string, all events are
|
||
passed by the Filter. This filter behaviour is useful when it is
|
||
desired to focus attention on one particular area of an
|
||
application; the focus can be changed simply by changing a filter
|
||
attached to the root logger.</p>
|
||
<p>There are many examples of Filters provided in <a class="footnote-reference brackets" href="#id16" id="id8">[6]</a>.</p>
|
||
</section>
|
||
<section id="configuration">
|
||
<h2><a class="toc-backref" href="#configuration" role="doc-backlink">Configuration</a></h2>
|
||
<p>The main benefit of a logging system like this is that one can
|
||
control how much and what logging output one gets from an
|
||
application without changing that application’s source code.
|
||
Therefore, although configuration can be performed through the
|
||
logging API, it must also be possible to change the logging
|
||
configuration without changing an application at all. For
|
||
long-running programs like Zope, it should be possible to change
|
||
the logging configuration while the program is running.</p>
|
||
<p>Configuration includes the following:</p>
|
||
<ul class="simple">
|
||
<li>What logging level a logger or handler should be interested in.</li>
|
||
<li>What handlers should be attached to which loggers.</li>
|
||
<li>What filters should be attached to which handlers and loggers.</li>
|
||
<li>Specifying attributes specific to certain handlers and filters.</li>
|
||
</ul>
|
||
<p>In general each application will have its own requirements for how
|
||
a user may configure logging output. However, each application
|
||
will specify the required configuration to the logging system
|
||
through a standard mechanism.</p>
|
||
<p>The most simple configuration is that of a single handler, writing
|
||
to stderr, attached to the root logger. This configuration is set
|
||
up by calling the <code class="docutils literal notranslate"><span class="pre">basicConfig()</span></code> function once the logging module
|
||
has been imported.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">basicConfig</span><span class="p">():</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For more sophisticated configurations, this PEP makes no specific
|
||
proposals, for the following reasons:</p>
|
||
<ul class="simple">
|
||
<li>A specific proposal may be seen as prescriptive.</li>
|
||
<li>Without the benefit of wide practical experience in the
|
||
Python community, there is no way to know whether any given
|
||
configuration approach is a good one. That practice can’t
|
||
really come until the logging module is used, and that means
|
||
until <strong>after</strong> Python 2.3 has shipped.</li>
|
||
<li>There is a likelihood that different types of applications
|
||
may require different configuration approaches, so that no
|
||
“one size fits all”.</li>
|
||
</ul>
|
||
<p>The reference implementation <a class="footnote-reference brackets" href="#id16" id="id9">[6]</a> has a working configuration file
|
||
format, implemented for the purpose of proving the concept and
|
||
suggesting one possible alternative. It may be that separate
|
||
extension modules, not part of the core Python distribution, are
|
||
created for logging configuration and log viewing, supplemental
|
||
handlers and other features which are not of interest to the bulk
|
||
of the community.</p>
|
||
</section>
|
||
<section id="thread-safety">
|
||
<h2><a class="toc-backref" href="#thread-safety" role="doc-backlink">Thread Safety</a></h2>
|
||
<p>The logging system should support thread-safe operation without
|
||
any special action needing to be taken by its users.</p>
|
||
</section>
|
||
<section id="module-level-functions">
|
||
<h2><a class="toc-backref" href="#module-level-functions" role="doc-backlink">Module-Level Functions</a></h2>
|
||
<p>To support use of the logging mechanism in short scripts and small
|
||
applications, module-level functions <code class="docutils literal notranslate"><span class="pre">debug()</span></code>, <code class="docutils literal notranslate"><span class="pre">info()</span></code>, <code class="docutils literal notranslate"><span class="pre">warn()</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">error()</span></code>, <code class="docutils literal notranslate"><span class="pre">critical()</span></code> and <code class="docutils literal notranslate"><span class="pre">exception()</span></code> are provided. These work in
|
||
the same way as the correspondingly named methods of Logger - in
|
||
fact they delegate to the corresponding methods on the root
|
||
logger. A further convenience provided by these functions is that
|
||
if no configuration has been done, <code class="docutils literal notranslate"><span class="pre">basicConfig()</span></code> is automatically
|
||
called.</p>
|
||
<p>At application exit, all handlers can be flushed by calling the function:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">shutdown</span><span class="p">():</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will flush and close all handlers.</p>
|
||
</section>
|
||
<section id="implementation">
|
||
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
|
||
<p>The reference implementation is Vinay Sajip’s logging module <a class="footnote-reference brackets" href="#id16" id="id10">[6]</a>.</p>
|
||
</section>
|
||
<section id="packaging">
|
||
<h2><a class="toc-backref" href="#packaging" role="doc-backlink">Packaging</a></h2>
|
||
<p>The reference implementation is implemented as a single module.
|
||
This offers the simplest interface - all users have to do is
|
||
“import logging” and they are in a position to use all the
|
||
functionality available.</p>
|
||
</section>
|
||
<section id="references">
|
||
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id11" role="doc-footnote">
|
||
<dt class="label" id="id11">[1]<em> (<a href='#id1'>1</a>, <a href='#id6'>2</a>) </em></dt>
|
||
<dd>java.util.logging
|
||
<a class="reference external" href="http://java.sun.com/j2se/1.4/docs/guide/util/logging/">http://java.sun.com/j2se/1.4/docs/guide/util/logging/</a></aside>
|
||
<aside class="footnote brackets" id="id12" role="doc-footnote">
|
||
<dt class="label" id="id12">[<a href="#id2">2</a>]</dt>
|
||
<dd>log4j: a Java logging package
|
||
<a class="reference external" href="https://logging.apache.org/log4j/">https://logging.apache.org/log4j/</a></aside>
|
||
<aside class="footnote brackets" id="id13" role="doc-footnote">
|
||
<dt class="label" id="id13">[<a href="#id3">3</a>]</dt>
|
||
<dd>Protomatter’s Syslog
|
||
<a class="reference external" href="http://protomatter.sourceforge.net/1.1.6/index.html">http://protomatter.sourceforge.net/1.1.6/index.html</a>
|
||
<a class="reference external" href="http://protomatter.sourceforge.net/1.1.6/javadoc/com/protomatter/syslog/syslog-whitepaper.html">http://protomatter.sourceforge.net/1.1.6/javadoc/com/protomatter/syslog/syslog-whitepaper.html</a></aside>
|
||
<aside class="footnote brackets" id="id14" role="doc-footnote">
|
||
<dt class="label" id="id14">[<a href="#id4">4</a>]</dt>
|
||
<dd>MAL mentions his mx.Log logging module:
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2002-February/019767.html">https://mail.python.org/pipermail/python-dev/2002-February/019767.html</a></aside>
|
||
<aside class="footnote brackets" id="id15" role="doc-footnote">
|
||
<dt class="label" id="id15">[<a href="#id5">5</a>]</dt>
|
||
<dd>Jeff Bauer’s Mr. Creosote
|
||
<a class="reference external" href="http://starship.python.net/crew/jbauer/creosote/">http://starship.python.net/crew/jbauer/creosote/</a></aside>
|
||
<aside class="footnote brackets" id="id16" role="doc-footnote">
|
||
<dt class="label" id="id16">[6]<em> (<a href='#id7'>1</a>, <a href='#id8'>2</a>, <a href='#id9'>3</a>, <a href='#id10'>4</a>) </em></dt>
|
||
<dd>Vinay Sajip’s logging module.
|
||
<a class="reference external" href="https://old.red-dove.com/python_logging.html">https://old.red-dove.com/python_logging.html</a></aside>
|
||
</aside>
|
||
</section>
|
||
<section id="copyright">
|
||
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
||
<p>This document has been placed in the public domain.</p>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0282.rst">https://github.com/python/peps/blob/main/peps/pep-0282.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0282.rst">2023-10-10 05:32:07 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a></li>
|
||
<li><a class="reference internal" href="#influences">Influences</a></li>
|
||
<li><a class="reference internal" href="#simple-example">Simple Example</a></li>
|
||
<li><a class="reference internal" href="#control-flow">Control Flow</a></li>
|
||
<li><a class="reference internal" href="#levels">Levels</a></li>
|
||
<li><a class="reference internal" href="#loggers">Loggers</a></li>
|
||
<li><a class="reference internal" href="#handlers">Handlers</a></li>
|
||
<li><a class="reference internal" href="#logrecords">LogRecords</a></li>
|
||
<li><a class="reference internal" href="#formatters">Formatters</a></li>
|
||
<li><a class="reference internal" href="#filters">Filters</a></li>
|
||
<li><a class="reference internal" href="#configuration">Configuration</a></li>
|
||
<li><a class="reference internal" href="#thread-safety">Thread Safety</a></li>
|
||
<li><a class="reference internal" href="#module-level-functions">Module-Level Functions</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#packaging">Packaging</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
|
||
<br>
|
||
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0282.rst">Page Source (GitHub)</a>
|
||
</nav>
|
||
</section>
|
||
<script src="../_static/colour_scheme.js"></script>
|
||
<script src="../_static/wrap_tables.js"></script>
|
||
<script src="../_static/sticky_banner.js"></script>
|
||
</body>
|
||
</html> |