758 lines
56 KiB
HTML
758 lines
56 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 391 – Dictionary-Based Configuration For Logging | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0391/">
|
||
<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 391 – Dictionary-Based Configuration For Logging | peps.python.org'>
|
||
<meta property="og:description" content="This PEP describes a new way of configuring logging using a dictionary to hold configuration information.">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0391/">
|
||
<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 new way of configuring logging using a dictionary to hold configuration information.">
|
||
<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 391</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 391 – Dictionary-Based Configuration For Logging</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></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">15-Oct-2009</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">2.7, 3.2</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="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#naming">Naming</a></li>
|
||
<li><a class="reference internal" href="#api">API</a></li>
|
||
<li><a class="reference internal" href="#dictionary-schema-overview">Dictionary Schema - Overview</a><ul>
|
||
<li><a class="reference internal" href="#object-connections">Object connections</a></li>
|
||
<li><a class="reference internal" href="#user-defined-objects">User-defined objects</a></li>
|
||
<li><a class="reference internal" href="#access-to-external-objects">Access to external objects</a></li>
|
||
<li><a class="reference internal" href="#access-to-internal-objects">Access to internal objects</a></li>
|
||
<li><a class="reference internal" href="#handler-ids">Handler Ids</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#dictionary-schema-detail">Dictionary Schema - Detail</a></li>
|
||
<li><a class="reference internal" href="#a-working-example">A Working Example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#incremental-configuration">Incremental Configuration</a></li>
|
||
<li><a class="reference internal" href="#api-customization">API Customization</a></li>
|
||
<li><a class="reference internal" href="#change-to-socket-listener-implementation">Change to Socket Listener Implementation</a></li>
|
||
<li><a class="reference internal" href="#configuration-errors">Configuration Errors</a></li>
|
||
<li><a class="reference internal" href="#discussion-in-the-community">Discussion in the community</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference implementation</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 new way of configuring logging using a dictionary
|
||
to hold configuration information.</p>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>The present means for configuring Python’s logging package is either
|
||
by using the logging API to configure logging programmatically, or
|
||
else by means of ConfigParser-based configuration files.</p>
|
||
<p>Programmatic configuration, while offering maximal control, fixes the
|
||
configuration in Python code. This does not facilitate changing it
|
||
easily at runtime, and, as a result, the ability to flexibly turn the
|
||
verbosity of logging up and down for different parts of a using
|
||
application is lost. This limits the usability of logging as an aid
|
||
to diagnosing problems - and sometimes, logging is the only diagnostic
|
||
aid available in production environments.</p>
|
||
<p>The ConfigParser-based configuration system is usable, but does not
|
||
allow its users to configure all aspects of the logging package. For
|
||
example, Filters cannot be configured using this system. Furthermore,
|
||
the ConfigParser format appears to engender dislike (sometimes strong
|
||
dislike) in some quarters. Though it was chosen because it was the
|
||
only configuration format supported in the Python standard at that
|
||
time, many people regard it (or perhaps just the particular schema
|
||
chosen for logging’s configuration) as ‘crufty’ or ‘ugly’, in some
|
||
cases apparently on purely aesthetic grounds.</p>
|
||
<p>Recent versions of Python include JSON support in the standard
|
||
library, and this is also usable as a configuration format. In other
|
||
environments, such as Google App Engine, YAML is used to configure
|
||
applications, and usually the configuration of logging would be
|
||
considered an integral part of the application configuration.
|
||
Although the standard library does not contain YAML support at
|
||
present, support for both JSON and YAML can be provided in a common
|
||
way because both of these serialization formats allow deserialization
|
||
to Python dictionaries.</p>
|
||
<p>By providing a way to configure logging by passing the configuration
|
||
in a dictionary, logging will be easier to configure not only for
|
||
users of JSON and/or YAML, but also for users of custom configuration
|
||
methods, by providing a common format in which to describe the desired
|
||
configuration.</p>
|
||
<p>Another drawback of the current ConfigParser-based configuration
|
||
system is that it does not support incremental configuration: a new
|
||
configuration completely replaces the existing configuration.
|
||
Although full flexibility for incremental configuration is difficult
|
||
to provide in a multi-threaded environment, the new configuration
|
||
mechanism will allow the provision of limited support for incremental
|
||
configuration.</p>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>The specification consists of two parts: the API and the format of the
|
||
dictionary used to convey configuration information (i.e. the schema
|
||
to which it must conform).</p>
|
||
<section id="naming">
|
||
<h3><a class="toc-backref" href="#naming" role="doc-backlink">Naming</a></h3>
|
||
<p>Historically, the logging package has not been <a class="pep reference internal" href="../pep-0008/" title="PEP 8 – Style Guide for Python Code">PEP 8</a> conformant.
|
||
At some future time, this will be corrected by changing method and
|
||
function names in the package in order to conform with <a class="pep reference internal" href="../pep-0008/" title="PEP 8 – Style Guide for Python Code">PEP 8</a>.
|
||
However, in the interests of uniformity, the proposed additions to the
|
||
API use a naming scheme which is consistent with the present scheme
|
||
used by logging.</p>
|
||
</section>
|
||
<section id="api">
|
||
<h3><a class="toc-backref" href="#api" role="doc-backlink">API</a></h3>
|
||
<p>The logging.config module will have the following addition:</p>
|
||
<ul class="simple">
|
||
<li>A function, called <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code>, which takes a single argument
|
||
- the dictionary holding the configuration. Exceptions will be
|
||
raised if there are errors while processing the dictionary.</li>
|
||
</ul>
|
||
<p>It will be possible to customize this API - see the section on <a class="reference internal" href="#api-customization">API
|
||
Customization</a>. <a class="reference internal" href="#incremental-configuration">Incremental configuration</a> is covered in its own
|
||
section.</p>
|
||
</section>
|
||
<section id="dictionary-schema-overview">
|
||
<h3><a class="toc-backref" href="#dictionary-schema-overview" role="doc-backlink">Dictionary Schema - Overview</a></h3>
|
||
<p>Before describing the schema in detail, it is worth saying a few words
|
||
about object connections, support for user-defined objects and access
|
||
to external and internal objects.</p>
|
||
<section id="object-connections">
|
||
<h4><a class="toc-backref" href="#object-connections" role="doc-backlink">Object connections</a></h4>
|
||
<p>The schema is intended to describe a set of logging objects - loggers,
|
||
handlers, formatters, filters - which are connected to each other in
|
||
an object graph. Thus, the schema needs to represent connections
|
||
between the objects. For example, say that, once configured, a
|
||
particular logger has attached to it a particular handler. For the
|
||
purposes of this discussion, we can say that the logger represents the
|
||
source, and the handler the destination, of a connection between the
|
||
two. Of course in the configured objects this is represented by the
|
||
logger holding a reference to the handler. In the configuration dict,
|
||
this is done by giving each destination object an id which identifies
|
||
it unambiguously, and then using the id in the source object’s
|
||
configuration to indicate that a connection exists between the source
|
||
and the destination object with that id.</p>
|
||
<p>So, for example, consider the following YAML snippet:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">formatters</span><span class="p">:</span>
|
||
<span class="n">brief</span><span class="p">:</span>
|
||
<span class="c1"># configuration for formatter with id 'brief' goes here</span>
|
||
<span class="n">precise</span><span class="p">:</span>
|
||
<span class="c1"># configuration for formatter with id 'precise' goes here</span>
|
||
<span class="n">handlers</span><span class="p">:</span>
|
||
<span class="n">h1</span><span class="p">:</span> <span class="c1">#This is an id</span>
|
||
<span class="c1"># configuration of handler with id 'h1' goes here</span>
|
||
<span class="n">formatter</span><span class="p">:</span> <span class="n">brief</span>
|
||
<span class="n">h2</span><span class="p">:</span> <span class="c1">#This is another id</span>
|
||
<span class="c1"># configuration of handler with id 'h2' goes here</span>
|
||
<span class="n">formatter</span><span class="p">:</span> <span class="n">precise</span>
|
||
<span class="n">loggers</span><span class="p">:</span>
|
||
<span class="n">foo</span><span class="o">.</span><span class="n">bar</span><span class="o">.</span><span class="n">baz</span><span class="p">:</span>
|
||
<span class="c1"># other configuration for logger 'foo.bar.baz'</span>
|
||
<span class="n">handlers</span><span class="p">:</span> <span class="p">[</span><span class="n">h1</span><span class="p">,</span> <span class="n">h2</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>(Note: YAML will be used in this document as it is a little more
|
||
readable than the equivalent Python source form for the dictionary.)</p>
|
||
<p>The ids for loggers are the logger names which would be used
|
||
programmatically to obtain a reference to those loggers, e.g.
|
||
<code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code>. The ids for Formatters and Filters can be any string
|
||
value (such as <code class="docutils literal notranslate"><span class="pre">brief</span></code>, <code class="docutils literal notranslate"><span class="pre">precise</span></code> above) and they are transient,
|
||
in that they are only meaningful for processing the configuration
|
||
dictionary and used to determine connections between objects, and are
|
||
not persisted anywhere when the configuration call is complete.</p>
|
||
<p>Handler ids are treated specially, see the section on
|
||
<a class="reference internal" href="#handler-ids">Handler Ids</a>, below.</p>
|
||
<p>The above snippet indicates that logger named <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code> should
|
||
have two handlers attached to it, which are described by the handler
|
||
ids <code class="docutils literal notranslate"><span class="pre">h1</span></code> and <code class="docutils literal notranslate"><span class="pre">h2</span></code>. The formatter for <code class="docutils literal notranslate"><span class="pre">h1</span></code> is that described by id
|
||
<code class="docutils literal notranslate"><span class="pre">brief</span></code>, and the formatter for <code class="docutils literal notranslate"><span class="pre">h2</span></code> is that described by id
|
||
<code class="docutils literal notranslate"><span class="pre">precise</span></code>.</p>
|
||
</section>
|
||
<section id="user-defined-objects">
|
||
<h4><a class="toc-backref" href="#user-defined-objects" role="doc-backlink">User-defined objects</a></h4>
|
||
<p>The schema should support user-defined objects for handlers, filters
|
||
and formatters. (Loggers do not need to have different types for
|
||
different instances, so there is no support - in the configuration -
|
||
for user-defined logger classes.)</p>
|
||
<p>Objects to be configured will typically be described by dictionaries
|
||
which detail their configuration. In some places, the logging system
|
||
will be able to infer from the context how an object is to be
|
||
instantiated, but when a user-defined object is to be instantiated,
|
||
the system will not know how to do this. In order to provide complete
|
||
flexibility for user-defined object instantiation, the user will need
|
||
to provide a ‘factory’ - a callable which is called with a
|
||
configuration dictionary and which returns the instantiated object.
|
||
This will be signalled by an absolute import path to the factory being
|
||
made available under the special key <code class="docutils literal notranslate"><span class="pre">'()'</span></code>. Here’s a concrete
|
||
example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">formatters</span><span class="p">:</span>
|
||
<span class="n">brief</span><span class="p">:</span>
|
||
<span class="nb">format</span><span class="p">:</span> <span class="s1">'</span><span class="si">%(message)s</span><span class="s1">'</span>
|
||
<span class="n">default</span><span class="p">:</span>
|
||
<span class="nb">format</span><span class="p">:</span> <span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">'</span>
|
||
<span class="n">datefmt</span><span class="p">:</span> <span class="s1">'%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S'</span>
|
||
<span class="n">custom</span><span class="p">:</span>
|
||
<span class="p">():</span> <span class="n">my</span><span class="o">.</span><span class="n">package</span><span class="o">.</span><span class="n">customFormatterFactory</span>
|
||
<span class="n">bar</span><span class="p">:</span> <span class="n">baz</span>
|
||
<span class="n">spam</span><span class="p">:</span> <span class="mf">99.9</span>
|
||
<span class="n">answer</span><span class="p">:</span> <span class="mi">42</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The above YAML snippet defines three formatters. The first, with id
|
||
<code class="docutils literal notranslate"><span class="pre">brief</span></code>, is a standard <code class="docutils literal notranslate"><span class="pre">logging.Formatter</span></code> instance with the
|
||
specified format string. The second, with id <code class="docutils literal notranslate"><span class="pre">default</span></code>, has a
|
||
longer format and also defines the time format explicitly, and will
|
||
result in a <code class="docutils literal notranslate"><span class="pre">logging.Formatter</span></code> initialized with those two format
|
||
strings. Shown in Python source form, the <code class="docutils literal notranslate"><span class="pre">brief</span></code> and <code class="docutils literal notranslate"><span class="pre">default</span></code>
|
||
formatters have configuration sub-dictionaries:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||
<span class="s1">'format'</span> <span class="p">:</span> <span class="s1">'</span><span class="si">%(message)s</span><span class="s1">'</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||
<span class="s1">'format'</span> <span class="p">:</span> <span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">,</span>
|
||
<span class="s1">'datefmt'</span> <span class="p">:</span> <span class="s1">'%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S'</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>respectively, and as these dictionaries do not contain the special key
|
||
<code class="docutils literal notranslate"><span class="pre">'()'</span></code>, the instantiation is inferred from the context: as a result,
|
||
standard <code class="docutils literal notranslate"><span class="pre">logging.Formatter</span></code> instances are created. The
|
||
configuration sub-dictionary for the third formatter, with id
|
||
<code class="docutils literal notranslate"><span class="pre">custom</span></code>, is:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||
<span class="s1">'()'</span> <span class="p">:</span> <span class="s1">'my.package.customFormatterFactory'</span><span class="p">,</span>
|
||
<span class="s1">'bar'</span> <span class="p">:</span> <span class="s1">'baz'</span><span class="p">,</span>
|
||
<span class="s1">'spam'</span> <span class="p">:</span> <span class="mf">99.9</span><span class="p">,</span>
|
||
<span class="s1">'answer'</span> <span class="p">:</span> <span class="mi">42</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and this contains the special key <code class="docutils literal notranslate"><span class="pre">'()'</span></code>, which means that
|
||
user-defined instantiation is wanted. In this case, the specified
|
||
factory callable will be used. If it is an actual callable it will be
|
||
used directly - otherwise, if you specify a string (as in the example)
|
||
the actual callable will be located using normal import mechanisms.
|
||
The callable will be called with the <em>remaining</em> items in the
|
||
configuration sub-dictionary as keyword arguments. In the above
|
||
example, the formatter with id <code class="docutils literal notranslate"><span class="pre">custom</span></code> will be assumed to be
|
||
returned by the call:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">my</span><span class="o">.</span><span class="n">package</span><span class="o">.</span><span class="n">customFormatterFactory</span><span class="p">(</span><span class="n">bar</span><span class="o">=</span><span class="s1">'baz'</span><span class="p">,</span> <span class="n">spam</span><span class="o">=</span><span class="mf">99.9</span><span class="p">,</span> <span class="n">answer</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The key <code class="docutils literal notranslate"><span class="pre">'()'</span></code> has been used as the special key because it is not a
|
||
valid keyword parameter name, and so will not clash with the names of
|
||
the keyword arguments used in the call. The <code class="docutils literal notranslate"><span class="pre">'()'</span></code> also serves as a
|
||
mnemonic that the corresponding value is a callable.</p>
|
||
</section>
|
||
<section id="access-to-external-objects">
|
||
<h4><a class="toc-backref" href="#access-to-external-objects" role="doc-backlink">Access to external objects</a></h4>
|
||
<p>There are times where a configuration will need to refer to objects
|
||
external to the configuration, for example <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>. If the
|
||
configuration dict is constructed using Python code then this is
|
||
straightforward, but a problem arises when the configuration is
|
||
provided via a text file (e.g. JSON, YAML). In a text file, there is
|
||
no standard way to distinguish <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> from the literal string
|
||
<code class="docutils literal notranslate"><span class="pre">'sys.stderr'</span></code>. To facilitate this distinction, the configuration
|
||
system will look for certain special prefixes in string values and
|
||
treat them specially. For example, if the literal string
|
||
<code class="docutils literal notranslate"><span class="pre">'ext://sys.stderr'</span></code> is provided as a value in the configuration,
|
||
then the <code class="docutils literal notranslate"><span class="pre">ext://</span></code> will be stripped off and the remainder of the
|
||
value processed using normal import mechanisms.</p>
|
||
<p>The handling of such prefixes will be done in a way analogous to
|
||
protocol handling: there will be a generic mechanism to look for
|
||
prefixes which match the regular expression
|
||
<code class="docutils literal notranslate"><span class="pre">^(?P<prefix>[a-z]+)://(?P<suffix>.*)$</span></code> whereby, if the <code class="docutils literal notranslate"><span class="pre">prefix</span></code>
|
||
is recognised, the <code class="docutils literal notranslate"><span class="pre">suffix</span></code> is processed in a prefix-dependent
|
||
manner and the result of the processing replaces the string value. If
|
||
the prefix is not recognised, then the string value will be left
|
||
as-is.</p>
|
||
<p>The implementation will provide for a set of standard prefixes such as
|
||
<code class="docutils literal notranslate"><span class="pre">ext://</span></code> but it will be possible to disable the mechanism completely
|
||
or provide additional or different prefixes for special handling.</p>
|
||
</section>
|
||
<section id="access-to-internal-objects">
|
||
<h4><a class="toc-backref" href="#access-to-internal-objects" role="doc-backlink">Access to internal objects</a></h4>
|
||
<p>As well as external objects, there is sometimes also a need to refer
|
||
to objects in the configuration. This will be done implicitly by the
|
||
configuration system for things that it knows about. For example, the
|
||
string value <code class="docutils literal notranslate"><span class="pre">'DEBUG'</span></code> for a <code class="docutils literal notranslate"><span class="pre">level</span></code> in a logger or handler will
|
||
automatically be converted to the value <code class="docutils literal notranslate"><span class="pre">logging.DEBUG</span></code>, and the
|
||
<code class="docutils literal notranslate"><span class="pre">handlers</span></code>, <code class="docutils literal notranslate"><span class="pre">filters</span></code> and <code class="docutils literal notranslate"><span class="pre">formatter</span></code> entries will take an
|
||
object id and resolve to the appropriate destination object.</p>
|
||
<p>However, a more generic mechanism needs to be provided for the case
|
||
of user-defined objects which are not known to logging. For example,
|
||
take the instance of <code class="docutils literal notranslate"><span class="pre">logging.handlers.MemoryHandler</span></code>, which takes
|
||
a <code class="docutils literal notranslate"><span class="pre">target</span></code> which is another handler to delegate to. Since the system
|
||
already knows about this class, then in the configuration, the given
|
||
<code class="docutils literal notranslate"><span class="pre">target</span></code> just needs to be the object id of the relevant target
|
||
handler, and the system will resolve to the handler from the id. If,
|
||
however, a user defines a <code class="docutils literal notranslate"><span class="pre">my.package.MyHandler</span></code> which has a
|
||
<code class="docutils literal notranslate"><span class="pre">alternate</span></code> handler, the configuration system would not know that
|
||
the <code class="docutils literal notranslate"><span class="pre">alternate</span></code> referred to a handler. To cater for this, a
|
||
generic resolution system will be provided which allows the user to
|
||
specify:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">handlers</span><span class="p">:</span>
|
||
<span class="n">file</span><span class="p">:</span>
|
||
<span class="c1"># configuration of file handler goes here</span>
|
||
|
||
<span class="n">custom</span><span class="p">:</span>
|
||
<span class="p">():</span> <span class="n">my</span><span class="o">.</span><span class="n">package</span><span class="o">.</span><span class="n">MyHandler</span>
|
||
<span class="n">alternate</span><span class="p">:</span> <span class="n">cfg</span><span class="p">:</span><span class="o">//</span><span class="n">handlers</span><span class="o">.</span><span class="n">file</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The literal string <code class="docutils literal notranslate"><span class="pre">'cfg://handlers.file'</span></code> will be resolved in an
|
||
analogous way to the strings with the <code class="docutils literal notranslate"><span class="pre">ext://</span></code> prefix, but looking
|
||
in the configuration itself rather than the import namespace. The
|
||
mechanism will allow access by dot or by index, in a similar way to
|
||
that provided by <code class="docutils literal notranslate"><span class="pre">str.format</span></code>. Thus, given the following snippet:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">handlers</span><span class="p">:</span>
|
||
<span class="n">email</span><span class="p">:</span>
|
||
<span class="n">class</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">SMTPHandler</span>
|
||
<span class="n">mailhost</span><span class="p">:</span> <span class="n">localhost</span>
|
||
<span class="n">fromaddr</span><span class="p">:</span> <span class="n">my_app</span><span class="nd">@domain</span><span class="o">.</span><span class="n">tld</span>
|
||
<span class="n">toaddrs</span><span class="p">:</span>
|
||
<span class="o">-</span> <span class="n">support_team</span><span class="nd">@domain</span><span class="o">.</span><span class="n">tld</span>
|
||
<span class="o">-</span> <span class="n">dev_team</span><span class="nd">@domain</span><span class="o">.</span><span class="n">tld</span>
|
||
<span class="n">subject</span><span class="p">:</span> <span class="n">Houston</span><span class="p">,</span> <span class="n">we</span> <span class="n">have</span> <span class="n">a</span> <span class="n">problem</span><span class="o">.</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>in the configuration, the string <code class="docutils literal notranslate"><span class="pre">'cfg://handlers'</span></code> would resolve to
|
||
the dict with key <code class="docutils literal notranslate"><span class="pre">handlers</span></code>, the string <code class="docutils literal notranslate"><span class="pre">'cfg://handlers.email</span></code>
|
||
would resolve to the dict with key <code class="docutils literal notranslate"><span class="pre">email</span></code> in the <code class="docutils literal notranslate"><span class="pre">handlers</span></code> dict,
|
||
and so on. The string <code class="docutils literal notranslate"><span class="pre">'cfg://handlers.email.toaddrs[1]</span></code> would
|
||
resolve to <code class="docutils literal notranslate"><span class="pre">'dev_team.domain.tld'</span></code> and the string
|
||
<code class="docutils literal notranslate"><span class="pre">'cfg://handlers.email.toaddrs[0]'</span></code> would resolve to the value
|
||
<code class="docutils literal notranslate"><span class="pre">'support_team@domain.tld'</span></code>. The <code class="docutils literal notranslate"><span class="pre">subject</span></code> value could be accessed
|
||
using either <code class="docutils literal notranslate"><span class="pre">'cfg://handlers.email.subject'</span></code> or, equivalently,
|
||
<code class="docutils literal notranslate"><span class="pre">'cfg://handlers.email[subject]'</span></code>. The latter form only needs to be
|
||
used if the key contains spaces or non-alphanumeric characters. If an
|
||
index value consists only of decimal digits, access will be attempted
|
||
using the corresponding integer value, falling back to the string
|
||
value if needed.</p>
|
||
<p>Given a string <code class="docutils literal notranslate"><span class="pre">cfg://handlers.myhandler.mykey.123</span></code>, this will
|
||
resolve to <code class="docutils literal notranslate"><span class="pre">config_dict['handlers']['myhandler']['mykey']['123']</span></code>.
|
||
If the string is specified as <code class="docutils literal notranslate"><span class="pre">cfg://handlers.myhandler.mykey[123]</span></code>,
|
||
the system will attempt to retrieve the value from
|
||
<code class="docutils literal notranslate"><span class="pre">config_dict['handlers']['myhandler']['mykey'][123]</span></code>, and fall back
|
||
to <code class="docutils literal notranslate"><span class="pre">config_dict['handlers']['myhandler']['mykey']['123']</span></code> if that
|
||
fails.</p>
|
||
</section>
|
||
<section id="handler-ids">
|
||
<h4><a class="toc-backref" href="#handler-ids" role="doc-backlink">Handler Ids</a></h4>
|
||
<p>Some specific logging configurations require the use of handler levels
|
||
to achieve the desired effect. However, unlike loggers which can
|
||
always be identified by their names, handlers have no persistent
|
||
handles whereby levels can be changed via an incremental configuration
|
||
call.</p>
|
||
<p>Therefore, this PEP proposes to add an optional <code class="docutils literal notranslate"><span class="pre">name</span></code> property to
|
||
handlers. If used, this will add an entry in a dictionary which maps
|
||
the name to the handler. (The entry will be removed when the handler
|
||
is closed.) When an incremental configuration call is made, handlers
|
||
will be looked up in this dictionary to set the handler level
|
||
according to the value in the configuration. See the section on
|
||
<a class="reference internal" href="#incremental-configuration">incremental configuration</a> for more details.</p>
|
||
<p>In theory, such a “persistent name” facility could also be provided
|
||
for Filters and Formatters. However, there is not a strong case to be
|
||
made for being able to configure these incrementally. On the basis
|
||
that practicality beats purity, only Handlers will be given this new
|
||
<code class="docutils literal notranslate"><span class="pre">name</span></code> property. The id of a handler in the configuration will
|
||
become its <code class="docutils literal notranslate"><span class="pre">name</span></code>.</p>
|
||
<p>The handler name lookup dictionary is for configuration use only and
|
||
will not become part of the public API for the package.</p>
|
||
</section>
|
||
</section>
|
||
<section id="dictionary-schema-detail">
|
||
<h3><a class="toc-backref" href="#dictionary-schema-detail" role="doc-backlink">Dictionary Schema - Detail</a></h3>
|
||
<p>The dictionary passed to <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> must contain the following
|
||
keys:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">version</span></code> - to be set to an integer value representing the schema
|
||
version. The only valid value at present is 1, but having this key
|
||
allows the schema to evolve while still preserving backwards
|
||
compatibility.</li>
|
||
</ul>
|
||
<p>All other keys are optional, but if present they will be interpreted
|
||
as described below. In all cases below where a ‘configuring dict’ is
|
||
mentioned, it will be checked for the special <code class="docutils literal notranslate"><span class="pre">'()'</span></code> key to see if a
|
||
custom instantiation is required. If so, the mechanism described
|
||
above is used to instantiate; otherwise, the context is used to
|
||
determine how to instantiate.</p>
|
||
<ul>
|
||
<li><code class="docutils literal notranslate"><span class="pre">formatters</span></code> - the corresponding value will be a dict in which each
|
||
key is a formatter id and each value is a dict describing how to
|
||
configure the corresponding Formatter instance.<p>The configuring dict is searched for keys <code class="docutils literal notranslate"><span class="pre">format</span></code> and <code class="docutils literal notranslate"><span class="pre">datefmt</span></code>
|
||
(with defaults of <code class="docutils literal notranslate"><span class="pre">None</span></code>) and these are used to construct a
|
||
<code class="docutils literal notranslate"><span class="pre">logging.Formatter</span></code> instance.</p>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">filters</span></code> - the corresponding value will be a dict in which each key
|
||
is a filter id and each value is a dict describing how to configure
|
||
the corresponding Filter instance.<p>The configuring dict is searched for key <code class="docutils literal notranslate"><span class="pre">name</span></code> (defaulting to the
|
||
empty string) and this is used to construct a <code class="docutils literal notranslate"><span class="pre">logging.Filter</span></code>
|
||
instance.</p>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">handlers</span></code> - the corresponding value will be a dict in which each
|
||
key is a handler id and each value is a dict describing how to
|
||
configure the corresponding Handler instance.<p>The configuring dict is searched for the following keys:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">class</span></code> (mandatory). This is the fully qualified name of the
|
||
handler class.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">level</span></code> (optional). The level of the handler.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">formatter</span></code> (optional). The id of the formatter for this
|
||
handler.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">filters</span></code> (optional). A list of ids of the filters for this
|
||
handler.</li>
|
||
</ul>
|
||
<p>All <em>other</em> keys are passed through as keyword arguments to the
|
||
handler’s constructor. For example, given the snippet:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>handlers:
|
||
console:
|
||
class : logging.StreamHandler
|
||
formatter: brief
|
||
level : INFO
|
||
filters: [allow_foo]
|
||
stream : ext://sys.stdout
|
||
file:
|
||
class : logging.handlers.RotatingFileHandler
|
||
formatter: precise
|
||
filename: logconfig.log
|
||
maxBytes: 1024
|
||
backupCount: 3
|
||
</pre></div>
|
||
</div>
|
||
<p>the handler with id <code class="docutils literal notranslate"><span class="pre">console</span></code> is instantiated as a
|
||
<code class="docutils literal notranslate"><span class="pre">logging.StreamHandler</span></code>, using <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code> as the underlying
|
||
stream. The handler with id <code class="docutils literal notranslate"><span class="pre">file</span></code> is instantiated as a
|
||
<code class="docutils literal notranslate"><span class="pre">logging.handlers.RotatingFileHandler</span></code> with the keyword arguments
|
||
<code class="docutils literal notranslate"><span class="pre">filename='logconfig.log',</span> <span class="pre">maxBytes=1024,</span> <span class="pre">backupCount=3</span></code>.</p>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">loggers</span></code> - the corresponding value will be a dict in which each key
|
||
is a logger name and each value is a dict describing how to
|
||
configure the corresponding Logger instance.<p>The configuring dict is searched for the following keys:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">level</span></code> (optional). The level of the logger.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">propagate</span></code> (optional). The propagation setting of the logger.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">filters</span></code> (optional). A list of ids of the filters for this
|
||
logger.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">handlers</span></code> (optional). A list of ids of the handlers for this
|
||
logger.</li>
|
||
</ul>
|
||
<p>The specified loggers will be configured according to the level,
|
||
propagation, filters and handlers specified.</p>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">root</span></code> - this will be the configuration for the root logger.
|
||
Processing of the configuration will be as for any logger, except
|
||
that the <code class="docutils literal notranslate"><span class="pre">propagate</span></code> setting will not be applicable.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">incremental</span></code> - whether the configuration is to be interpreted as
|
||
incremental to the existing configuration. This value defaults to
|
||
<code class="docutils literal notranslate"><span class="pre">False</span></code>, which means that the specified configuration replaces the
|
||
existing configuration with the same semantics as used by the
|
||
existing <code class="docutils literal notranslate"><span class="pre">fileConfig()</span></code> API.<p>If the specified value is <code class="docutils literal notranslate"><span class="pre">True</span></code>, the configuration is processed
|
||
as described in the section on <a class="reference internal" href="#incremental-configuration">Incremental Configuration</a>, below.</p>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> - whether any existing loggers are to be
|
||
disabled. This setting mirrors the parameter of the same name in
|
||
<code class="docutils literal notranslate"><span class="pre">fileConfig()</span></code>. If absent, this parameter defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>.
|
||
This value is ignored if <code class="docutils literal notranslate"><span class="pre">incremental</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="a-working-example">
|
||
<h3><a class="toc-backref" href="#a-working-example" role="doc-backlink">A Working Example</a></h3>
|
||
<p>The following is an actual working configuration in YAML format
|
||
(except that the email addresses are bogus):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>formatters:
|
||
brief:
|
||
format: '%(levelname)-8s: %(name)-15s: %(message)s'
|
||
precise:
|
||
format: '%(asctime)s %(name)-15s %(levelname)-8s %(message)s'
|
||
filters:
|
||
allow_foo:
|
||
name: foo
|
||
handlers:
|
||
console:
|
||
class : logging.StreamHandler
|
||
formatter: brief
|
||
level : INFO
|
||
stream : ext://sys.stdout
|
||
filters: [allow_foo]
|
||
file:
|
||
class : logging.handlers.RotatingFileHandler
|
||
formatter: precise
|
||
filename: logconfig.log
|
||
maxBytes: 1024
|
||
backupCount: 3
|
||
debugfile:
|
||
class : logging.FileHandler
|
||
formatter: precise
|
||
filename: logconfig-detail.log
|
||
mode: a
|
||
email:
|
||
class: logging.handlers.SMTPHandler
|
||
mailhost: localhost
|
||
fromaddr: my_app@domain.tld
|
||
toaddrs:
|
||
- support_team@domain.tld
|
||
- dev_team@domain.tld
|
||
subject: Houston, we have a problem.
|
||
loggers:
|
||
foo:
|
||
level : ERROR
|
||
handlers: [debugfile]
|
||
spam:
|
||
level : CRITICAL
|
||
handlers: [debugfile]
|
||
propagate: no
|
||
bar.baz:
|
||
level: WARNING
|
||
root:
|
||
level : DEBUG
|
||
handlers : [console, file]
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="incremental-configuration">
|
||
<h2><a class="toc-backref" href="#incremental-configuration" role="doc-backlink">Incremental Configuration</a></h2>
|
||
<p>It is difficult to provide complete flexibility for incremental
|
||
configuration. For example, because objects such as filters
|
||
and formatters are anonymous, once a configuration is set up, it is
|
||
not possible to refer to such anonymous objects when augmenting a
|
||
configuration.</p>
|
||
<p>Furthermore, there is not a compelling case for arbitrarily altering
|
||
the object graph of loggers, handlers, filters, formatters at
|
||
run-time, once a configuration is set up; the verbosity of loggers and
|
||
handlers can be controlled just by setting levels (and, in the case of
|
||
loggers, propagation flags). Changing the object graph arbitrarily in
|
||
a safe way is problematic in a multi-threaded environment; while not
|
||
impossible, the benefits are not worth the complexity it adds to the
|
||
implementation.</p>
|
||
<p>Thus, when the <code class="docutils literal notranslate"><span class="pre">incremental</span></code> key of a configuration dict is present
|
||
and is <code class="docutils literal notranslate"><span class="pre">True</span></code>, the system will ignore any <code class="docutils literal notranslate"><span class="pre">formatters</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">filters</span></code> entries completely, and process only the <code class="docutils literal notranslate"><span class="pre">level</span></code>
|
||
settings in the <code class="docutils literal notranslate"><span class="pre">handlers</span></code> entries, and the <code class="docutils literal notranslate"><span class="pre">level</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">propagate</span></code> settings in the <code class="docutils literal notranslate"><span class="pre">loggers</span></code> and <code class="docutils literal notranslate"><span class="pre">root</span></code> entries.</p>
|
||
<p>It’s certainly possible to provide incremental configuration by other
|
||
means, for example making <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> take an <code class="docutils literal notranslate"><span class="pre">incremental</span></code>
|
||
keyword argument which defaults to <code class="docutils literal notranslate"><span class="pre">False</span></code>. The reason for
|
||
suggesting that a value in the configuration dict be used is that it
|
||
allows for configurations to be sent over the wire as pickled dicts
|
||
to a socket listener. Thus, the logging verbosity of a long-running
|
||
application can be altered over time with no need to stop and
|
||
restart the application.</p>
|
||
<p>Note: Feedback on incremental configuration needs based on your
|
||
practical experience will be particularly welcome.</p>
|
||
</section>
|
||
<section id="api-customization">
|
||
<h2><a class="toc-backref" href="#api-customization" role="doc-backlink">API Customization</a></h2>
|
||
<p>The bare-bones <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> API will not be sufficient for all
|
||
use cases. Provision for customization of the API will be made by
|
||
providing the following:</p>
|
||
<ul class="simple">
|
||
<li>A class, called <code class="docutils literal notranslate"><span class="pre">DictConfigurator</span></code>, whose constructor is passed
|
||
the dictionary used for configuration, and which has a
|
||
<code class="docutils literal notranslate"><span class="pre">configure()</span></code> method.</li>
|
||
<li>A callable, called <code class="docutils literal notranslate"><span class="pre">dictConfigClass</span></code>, which will (by default) be
|
||
set to <code class="docutils literal notranslate"><span class="pre">DictConfigurator</span></code>. This is provided so that if desired,
|
||
<code class="docutils literal notranslate"><span class="pre">DictConfigurator</span></code> can be replaced with a suitable user-defined
|
||
implementation.</li>
|
||
</ul>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> function will call <code class="docutils literal notranslate"><span class="pre">dictConfigClass</span></code> passing
|
||
the specified dictionary, and then call the <code class="docutils literal notranslate"><span class="pre">configure()</span></code> method on
|
||
the returned object to actually put the configuration into effect:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">dictConfig</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
|
||
<span class="n">dictConfigClass</span><span class="p">(</span><span class="n">config</span><span class="p">)</span><span class="o">.</span><span class="n">configure</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This should cater to all customization needs. For example, a subclass
|
||
of <code class="docutils literal notranslate"><span class="pre">DictConfigurator</span></code> could call <code class="docutils literal notranslate"><span class="pre">DictConfigurator.__init__()</span></code> in
|
||
its own <code class="docutils literal notranslate"><span class="pre">__init__()</span></code>, then set up custom prefixes which would be
|
||
usable in the subsequent <code class="docutils literal notranslate"><span class="pre">configure()</span> <span class="pre">call</span></code>. The <code class="docutils literal notranslate"><span class="pre">dictConfigClass</span></code>
|
||
would be bound to the subclass, and then <code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> could be
|
||
called exactly as in the default, uncustomized state.</p>
|
||
</section>
|
||
<section id="change-to-socket-listener-implementation">
|
||
<h2><a class="toc-backref" href="#change-to-socket-listener-implementation" role="doc-backlink">Change to Socket Listener Implementation</a></h2>
|
||
<p>The existing socket listener implementation will be modified as
|
||
follows: when a configuration message is received, an attempt will be
|
||
made to deserialize to a dictionary using the json module. If this
|
||
step fails, the message will be assumed to be in the fileConfig format
|
||
and processed as before. If deserialization is successful, then
|
||
<code class="docutils literal notranslate"><span class="pre">dictConfig()</span></code> will be called to process the resulting dictionary.</p>
|
||
</section>
|
||
<section id="configuration-errors">
|
||
<h2><a class="toc-backref" href="#configuration-errors" role="doc-backlink">Configuration Errors</a></h2>
|
||
<p>If an error is encountered during configuration, the system will raise
|
||
a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>, <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>, <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> or <code class="docutils literal notranslate"><span class="pre">ImportError</span></code>
|
||
with a suitably descriptive message. The following is a (possibly
|
||
incomplete) list of conditions which will raise an error:</p>
|
||
<ul class="simple">
|
||
<li>A <code class="docutils literal notranslate"><span class="pre">level</span></code> which is not a string or which is a string not
|
||
corresponding to an actual logging level</li>
|
||
<li>A <code class="docutils literal notranslate"><span class="pre">propagate</span></code> value which is not a boolean</li>
|
||
<li>An id which does not have a corresponding destination</li>
|
||
<li>A non-existent handler id found during an incremental call</li>
|
||
<li>An invalid logger name</li>
|
||
<li>Inability to resolve to an internal or external object</li>
|
||
</ul>
|
||
</section>
|
||
<section id="discussion-in-the-community">
|
||
<h2><a class="toc-backref" href="#discussion-in-the-community" role="doc-backlink">Discussion in the community</a></h2>
|
||
<p>The PEP has been announced on python-dev and python-list. While there
|
||
hasn’t been a huge amount of discussion, this is perhaps to be
|
||
expected for a niche topic.</p>
|
||
<p>Discussion threads on python-dev:</p>
|
||
<p><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2009-October/092695.html">https://mail.python.org/pipermail/python-dev/2009-October/092695.html</a>
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2009-October/092782.html">https://mail.python.org/pipermail/python-dev/2009-October/092782.html</a>
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2009-October/093062.html">https://mail.python.org/pipermail/python-dev/2009-October/093062.html</a></p>
|
||
<p>And on python-list:</p>
|
||
<p><a class="reference external" href="https://mail.python.org/pipermail/python-list/2009-October/1223658.html">https://mail.python.org/pipermail/python-list/2009-October/1223658.html</a>
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-list/2009-October/1224228.html">https://mail.python.org/pipermail/python-list/2009-October/1224228.html</a></p>
|
||
<p>There have been some comments in favour of the proposal, no
|
||
objections to the proposal as a whole, and some questions and
|
||
objections about specific details. These are believed by the author
|
||
to have been addressed by making changes to the PEP.</p>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference implementation</a></h2>
|
||
<p>A reference implementation of the changes is available as a module
|
||
dictconfig.py with accompanying unit tests in test_dictconfig.py, at:</p>
|
||
<p><a class="reference external" href="http://bitbucket.org/vinay.sajip/dictconfig">http://bitbucket.org/vinay.sajip/dictconfig</a></p>
|
||
<p>This incorporates all features other than the socket listener change.</p>
|
||
</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-0391.rst">https://github.com/python/peps/blob/main/peps/pep-0391.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0391.rst">2023-09-09 17:39:29 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="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#naming">Naming</a></li>
|
||
<li><a class="reference internal" href="#api">API</a></li>
|
||
<li><a class="reference internal" href="#dictionary-schema-overview">Dictionary Schema - Overview</a><ul>
|
||
<li><a class="reference internal" href="#object-connections">Object connections</a></li>
|
||
<li><a class="reference internal" href="#user-defined-objects">User-defined objects</a></li>
|
||
<li><a class="reference internal" href="#access-to-external-objects">Access to external objects</a></li>
|
||
<li><a class="reference internal" href="#access-to-internal-objects">Access to internal objects</a></li>
|
||
<li><a class="reference internal" href="#handler-ids">Handler Ids</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#dictionary-schema-detail">Dictionary Schema - Detail</a></li>
|
||
<li><a class="reference internal" href="#a-working-example">A Working Example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#incremental-configuration">Incremental Configuration</a></li>
|
||
<li><a class="reference internal" href="#api-customization">API Customization</a></li>
|
||
<li><a class="reference internal" href="#change-to-socket-listener-implementation">Change to Socket Listener Implementation</a></li>
|
||
<li><a class="reference internal" href="#configuration-errors">Configuration Errors</a></li>
|
||
<li><a class="reference internal" href="#discussion-in-the-community">Discussion in the community</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference implementation</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-0391.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> |