~dkuhlman/python-training-materials/Materials

« back to all changes in this revision

Viewing changes to python-3.5.2-docs-html/howto/logging-cookbook.html

  • Committer: Dave Kuhlman
  • Date: 2017-04-15 16:24:56 UTC
  • Revision ID: dkuhlman@davekuhlman.org-20170415162456-iav9vozzg4iwqwv3
Updated docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
2
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
3
 
 
4
 
 
5
<html xmlns="http://www.w3.org/1999/xhtml">
 
6
  <head>
 
7
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
8
    
 
9
    <title>Logging Cookbook &mdash; Python 3.5.2 documentation</title>
 
10
    
 
11
    <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
 
12
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 
13
    
 
14
    <script type="text/javascript">
 
15
      var DOCUMENTATION_OPTIONS = {
 
16
        URL_ROOT:    '../',
 
17
        VERSION:     '3.5.2',
 
18
        COLLAPSE_INDEX: false,
 
19
        FILE_SUFFIX: '.html',
 
20
        HAS_SOURCE:  true
 
21
      };
 
22
    </script>
 
23
    <script type="text/javascript" src="../_static/jquery.js"></script>
 
24
    <script type="text/javascript" src="../_static/underscore.js"></script>
 
25
    <script type="text/javascript" src="../_static/doctools.js"></script>
 
26
    <script type="text/javascript" src="../_static/sidebar.js"></script>
 
27
    <link rel="search" type="application/opensearchdescription+xml"
 
28
          title="Search within Python 3.5.2 documentation"
 
29
          href="../_static/opensearch.xml"/>
 
30
    <link rel="author" title="About these documents" href="../about.html" />
 
31
    <link rel="copyright" title="Copyright" href="../copyright.html" />
 
32
    <link rel="top" title="Python 3.5.2 documentation" href="../contents.html" />
 
33
    <link rel="up" title="Python HOWTOs" href="index.html" />
 
34
    <link rel="next" title="Regular Expression HOWTO" href="regex.html" />
 
35
    <link rel="prev" title="Logging HOWTO" href="logging.html" />
 
36
    <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
 
37
    
 
38
    <script type="text/javascript" src="../_static/copybutton.js"></script>
 
39
    <script type="text/javascript" src="../_static/version_switch.js"></script>
 
40
    
 
41
    
 
42
 
 
43
 
 
44
  </head>
 
45
  <body role="document">  
 
46
    <div class="related" role="navigation" aria-label="related navigation">
 
47
      <h3>Navigation</h3>
 
48
      <ul>
 
49
        <li class="right" style="margin-right: 10px">
 
50
          <a href="../genindex.html" title="General Index"
 
51
             accesskey="I">index</a></li>
 
52
        <li class="right" >
 
53
          <a href="../py-modindex.html" title="Python Module Index"
 
54
             >modules</a> |</li>
 
55
        <li class="right" >
 
56
          <a href="regex.html" title="Regular Expression HOWTO"
 
57
             accesskey="N">next</a> |</li>
 
58
        <li class="right" >
 
59
          <a href="logging.html" title="Logging HOWTO"
 
60
             accesskey="P">previous</a> |</li>
 
61
        <li><img src="../_static/py.png" alt=""
 
62
                 style="vertical-align: middle; margin-top: -1px"/></li>
 
63
        <li><a href="https://www.python.org/">Python</a> &raquo;</li>
 
64
        <li>
 
65
          <span class="version_switcher_placeholder">3.5.2</span>
 
66
          <a href="../index.html">Documentation </a> &raquo;
 
67
        </li>
 
68
 
 
69
          <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python HOWTOs</a> &raquo;</li>
 
70
    <li class="right">
 
71
        
 
72
 
 
73
    <div class="inline-search" style="display: none" role="search">
 
74
        <form class="inline-search" action="../search.html" method="get">
 
75
          <input placeholder="Quick search" type="text" name="q" />
 
76
          <input type="submit" value="Go" />
 
77
          <input type="hidden" name="check_keywords" value="yes" />
 
78
          <input type="hidden" name="area" value="default" />
 
79
        </form>
 
80
    </div>
 
81
    <script type="text/javascript">$('.inline-search').show(0);</script>
 
82
         |
 
83
    </li>
 
84
 
 
85
      </ul>
 
86
    </div>    
 
87
 
 
88
    <div class="document">
 
89
      <div class="documentwrapper">
 
90
        <div class="bodywrapper">
 
91
          <div class="body" role="main">
 
92
            
 
93
  <div class="section" id="logging-cookbook">
 
94
<span id="id1"></span><h1>Logging Cookbook<a class="headerlink" href="#logging-cookbook" title="Permalink to this headline">¶</a></h1>
 
95
<table class="docutils field-list" frame="void" rules="none">
 
96
<col class="field-name" />
 
97
<col class="field-body" />
 
98
<tbody valign="top">
 
99
<tr class="field-odd field"><th class="field-name">Author:</th><td class="field-body">Vinay Sajip &lt;vinay_sajip at red-dove dot com&gt;</td>
 
100
</tr>
 
101
</tbody>
 
102
</table>
 
103
<p>This page contains a number of recipes related to logging, which have been found
 
104
useful in the past.</p>
 
105
<div class="section" id="using-logging-in-multiple-modules">
 
106
<h2>Using logging in multiple modules<a class="headerlink" href="#using-logging-in-multiple-modules" title="Permalink to this headline">¶</a></h2>
 
107
<p>Multiple calls to <code class="docutils literal"><span class="pre">logging.getLogger('someLogger')</span></code> return a reference to the
 
108
same logger object.  This is true not only within the same module, but also
 
109
across modules as long as it is in the same Python interpreter process.  It is
 
110
true for references to the same object; additionally, application code can
 
111
define and configure a parent logger in one module and create (but not
 
112
configure) a child logger in a separate module, and all logger calls to the
 
113
child will pass up to the parent.  Here is a main module:</p>
 
114
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
115
<span class="kn">import</span> <span class="nn">auxiliary_module</span>
 
116
 
 
117
<span class="c1"># create logger with &#39;spam_application&#39;</span>
 
118
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;spam_application&#39;</span><span class="p">)</span>
 
119
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
120
<span class="c1"># create file handler which logs even debug messages</span>
 
121
<span class="n">fh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="s1">&#39;spam.log&#39;</span><span class="p">)</span>
 
122
<span class="n">fh</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
123
<span class="c1"># create console handler with a higher log level</span>
 
124
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
125
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span>
 
126
<span class="c1"># create formatter and add it to the handlers</span>
 
127
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(name)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
128
<span class="n">fh</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
129
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
130
<span class="c1"># add the handlers to the logger</span>
 
131
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">fh</span><span class="p">)</span>
 
132
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
 
133
 
 
134
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;creating an instance of auxiliary_module.Auxiliary&#39;</span><span class="p">)</span>
 
135
<span class="n">a</span> <span class="o">=</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">Auxiliary</span><span class="p">()</span>
 
136
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;created an instance of auxiliary_module.Auxiliary&#39;</span><span class="p">)</span>
 
137
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;calling auxiliary_module.Auxiliary.do_something&#39;</span><span class="p">)</span>
 
138
<span class="n">a</span><span class="o">.</span><span class="n">do_something</span><span class="p">()</span>
 
139
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;finished auxiliary_module.Auxiliary.do_something&#39;</span><span class="p">)</span>
 
140
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;calling auxiliary_module.some_function()&#39;</span><span class="p">)</span>
 
141
<span class="n">auxiliary_module</span><span class="o">.</span><span class="n">some_function</span><span class="p">()</span>
 
142
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;done with auxiliary_module.some_function()&#39;</span><span class="p">)</span>
 
143
</pre></div>
 
144
</div>
 
145
<p>Here is the auxiliary module:</p>
 
146
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
147
 
 
148
<span class="c1"># create logger</span>
 
149
<span class="n">module_logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;spam_application.auxiliary&#39;</span><span class="p">)</span>
 
150
 
 
151
<span class="k">class</span> <span class="nc">Auxiliary</span><span class="p">:</span>
 
152
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
153
        <span class="bp">self</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;spam_application.auxiliary.Auxiliary&#39;</span><span class="p">)</span>
 
154
        <span class="bp">self</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="s1">&#39;creating an instance of Auxiliary&#39;</span><span class="p">)</span>
 
155
 
 
156
    <span class="k">def</span> <span class="nf">do_something</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
157
        <span class="bp">self</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="s1">&#39;doing something&#39;</span><span class="p">)</span>
 
158
        <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">1</span>
 
159
        <span class="bp">self</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="s1">&#39;done doing something&#39;</span><span class="p">)</span>
 
160
 
 
161
<span class="k">def</span> <span class="nf">some_function</span><span class="p">():</span>
 
162
    <span class="n">module_logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;received a call to &quot;some_function&quot;&#39;</span><span class="p">)</span>
 
163
</pre></div>
 
164
</div>
 
165
<p>The output looks like this:</p>
 
166
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">663</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
167
   <span class="n">creating</span> <span class="n">an</span> <span class="n">instance</span> <span class="n">of</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">Auxiliary</span>
 
168
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">665</span> <span class="o">-</span> <span class="n">spam_application</span><span class="o">.</span><span class="n">auxiliary</span><span class="o">.</span><span class="n">Auxiliary</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
169
   <span class="n">creating</span> <span class="n">an</span> <span class="n">instance</span> <span class="n">of</span> <span class="n">Auxiliary</span>
 
170
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">665</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
171
   <span class="n">created</span> <span class="n">an</span> <span class="n">instance</span> <span class="n">of</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">Auxiliary</span>
 
172
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">668</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
173
   <span class="n">calling</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">Auxiliary</span><span class="o">.</span><span class="n">do_something</span>
 
174
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">668</span> <span class="o">-</span> <span class="n">spam_application</span><span class="o">.</span><span class="n">auxiliary</span><span class="o">.</span><span class="n">Auxiliary</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
175
   <span class="n">doing</span> <span class="n">something</span>
 
176
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">669</span> <span class="o">-</span> <span class="n">spam_application</span><span class="o">.</span><span class="n">auxiliary</span><span class="o">.</span><span class="n">Auxiliary</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
177
   <span class="n">done</span> <span class="n">doing</span> <span class="n">something</span>
 
178
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">670</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
179
   <span class="n">finished</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">Auxiliary</span><span class="o">.</span><span class="n">do_something</span>
 
180
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">671</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
181
   <span class="n">calling</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">some_function</span><span class="p">()</span>
 
182
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">672</span> <span class="o">-</span> <span class="n">spam_application</span><span class="o">.</span><span class="n">auxiliary</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
183
   <span class="n">received</span> <span class="n">a</span> <span class="n">call</span> <span class="n">to</span> <span class="s1">&#39;some_function&#39;</span>
 
184
<span class="mi">2005</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">23</span> <span class="mi">23</span><span class="p">:</span><span class="mi">47</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span><span class="mi">673</span> <span class="o">-</span> <span class="n">spam_application</span> <span class="o">-</span> <span class="n">INFO</span> <span class="o">-</span>
 
185
   <span class="n">done</span> <span class="k">with</span> <span class="n">auxiliary_module</span><span class="o">.</span><span class="n">some_function</span><span class="p">()</span>
 
186
</pre></div>
 
187
</div>
 
188
</div>
 
189
<div class="section" id="logging-from-multiple-threads">
 
190
<h2>Logging from multiple threads<a class="headerlink" href="#logging-from-multiple-threads" title="Permalink to this headline">¶</a></h2>
 
191
<p>Logging from multiple threads requires no special effort. The following example
 
192
shows logging from the main (initial) thread and another thread:</p>
 
193
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
194
<span class="kn">import</span> <span class="nn">threading</span>
 
195
<span class="kn">import</span> <span class="nn">time</span>
 
196
 
 
197
<span class="k">def</span> <span class="nf">worker</span><span class="p">(</span><span class="n">arg</span><span class="p">):</span>
 
198
    <span class="k">while</span> <span class="ow">not</span> <span class="n">arg</span><span class="p">[</span><span class="s1">&#39;stop&#39;</span><span class="p">]:</span>
 
199
        <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Hi from myfunc&#39;</span><span class="p">)</span>
 
200
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
 
201
 
 
202
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
203
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(relativeCreated)6d</span><span class="s1"> </span><span class="si">%(threadName)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
204
    <span class="n">info</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;stop&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
 
205
    <span class="n">thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">worker</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">info</span><span class="p">,))</span>
 
206
    <span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
207
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
 
208
        <span class="k">try</span><span class="p">:</span>
 
209
            <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Hello from main&#39;</span><span class="p">)</span>
 
210
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.75</span><span class="p">)</span>
 
211
        <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
 
212
            <span class="n">info</span><span class="p">[</span><span class="s1">&#39;stop&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
 
213
            <span class="k">break</span>
 
214
    <span class="n">thread</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
215
 
 
216
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
217
    <span class="n">main</span><span class="p">()</span>
 
218
</pre></div>
 
219
</div>
 
220
<p>When run, the script should print something like the following:</p>
 
221
<div class="highlight-python3"><div class="highlight"><pre><span></span>   <span class="mi">0</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
222
   <span class="mi">3</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
223
 <span class="mi">505</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
224
 <span class="mi">755</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
225
<span class="mi">1007</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
226
<span class="mi">1507</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
227
<span class="mi">1508</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
228
<span class="mi">2010</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
229
<span class="mi">2258</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
230
<span class="mi">2512</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
231
<span class="mi">3009</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
232
<span class="mi">3013</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
233
<span class="mi">3515</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
234
<span class="mi">3761</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
235
<span class="mi">4017</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
236
<span class="mi">4513</span> <span class="n">MainThread</span> <span class="n">Hello</span> <span class="kn">from</span> <span class="nn">main</span>
 
237
<span class="mi">4518</span> <span class="n">Thread</span><span class="o">-</span><span class="mi">1</span> <span class="n">Hi</span> <span class="kn">from</span> <span class="nn">myfunc</span>
 
238
</pre></div>
 
239
</div>
 
240
<p>This shows the logging output interspersed as one might expect. This approach
 
241
works for more threads than shown here, of course.</p>
 
242
</div>
 
243
<div class="section" id="multiple-handlers-and-formatters">
 
244
<h2>Multiple handlers and formatters<a class="headerlink" href="#multiple-handlers-and-formatters" title="Permalink to this headline">¶</a></h2>
 
245
<p>Loggers are plain Python objects.  The <a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal"><span class="pre">addHandler()</span></code></a> method has no
 
246
minimum or maximum quota for the number of handlers you may add.  Sometimes it
 
247
will be beneficial for an application to log all messages of all severities to a
 
248
text file while simultaneously logging errors or above to the console.  To set
 
249
this up, simply configure the appropriate handlers.  The logging calls in the
 
250
application code will remain unchanged.  Here is a slight modification to the
 
251
previous simple module-based configuration example:</p>
 
252
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
253
 
 
254
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simple_example&#39;</span><span class="p">)</span>
 
255
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
256
<span class="c1"># create file handler which logs even debug messages</span>
 
257
<span class="n">fh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="s1">&#39;spam.log&#39;</span><span class="p">)</span>
 
258
<span class="n">fh</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
259
<span class="c1"># create console handler with a higher log level</span>
 
260
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
261
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span>
 
262
<span class="c1"># create formatter and add it to the handlers</span>
 
263
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(name)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
264
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
265
<span class="n">fh</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
266
<span class="c1"># add the handlers to logger</span>
 
267
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
 
268
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">fh</span><span class="p">)</span>
 
269
 
 
270
<span class="c1"># &#39;application&#39; code</span>
 
271
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
 
272
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>
 
273
<span class="n">logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s1">&#39;warn message&#39;</span><span class="p">)</span>
 
274
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;error message&#39;</span><span class="p">)</span>
 
275
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;critical message&#39;</span><span class="p">)</span>
 
276
</pre></div>
 
277
</div>
 
278
<p>Notice that the &#8216;application&#8217; code does not care about multiple handlers.  All
 
279
that changed was the addition and configuration of a new handler named <em>fh</em>.</p>
 
280
<p>The ability to create new handlers with higher- or lower-severity filters can be
 
281
very helpful when writing and testing an application.  Instead of using many
 
282
<code class="docutils literal"><span class="pre">print</span></code> statements for debugging, use <code class="docutils literal"><span class="pre">logger.debug</span></code>: Unlike the print
 
283
statements, which you will have to delete or comment out later, the logger.debug
 
284
statements can remain intact in the source code and remain dormant until you
 
285
need them again.  At that time, the only change that needs to happen is to
 
286
modify the severity level of the logger and/or handler to debug.</p>
 
287
</div>
 
288
<div class="section" id="logging-to-multiple-destinations">
 
289
<span id="multiple-destinations"></span><h2>Logging to multiple destinations<a class="headerlink" href="#logging-to-multiple-destinations" title="Permalink to this headline">¶</a></h2>
 
290
<p>Let&#8217;s say you want to log to console and file with different message formats and
 
291
in differing circumstances. Say you want to log messages with levels of DEBUG
 
292
and higher to file, and those messages at level INFO and higher to the console.
 
293
Let&#8217;s also assume that the file should contain timestamps, but the console
 
294
messages should not. Here&#8217;s how you can achieve this:</p>
 
295
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
296
 
 
297
<span class="c1"># set up logging to file - see previous section for more details</span>
 
298
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span>
 
299
                    <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(name)-12s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">,</span>
 
300
                    <span class="n">datefmt</span><span class="o">=</span><span class="s1">&#39;%m-</span><span class="si">%d</span><span class="s1"> %H:%M&#39;</span><span class="p">,</span>
 
301
                    <span class="n">filename</span><span class="o">=</span><span class="s1">&#39;/temp/myapp.log&#39;</span><span class="p">,</span>
 
302
                    <span class="n">filemode</span><span class="o">=</span><span class="s1">&#39;w&#39;</span><span class="p">)</span>
 
303
<span class="c1"># define a Handler which writes INFO messages or higher to the sys.stderr</span>
 
304
<span class="n">console</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
305
<span class="n">console</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
 
306
<span class="c1"># set a format which is simpler for console use</span>
 
307
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(name)-12s</span><span class="s1">: </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
308
<span class="c1"># tell the handler to use this format</span>
 
309
<span class="n">console</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
310
<span class="c1"># add the handler to the root logger</span>
 
311
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">console</span><span class="p">)</span>
 
312
 
 
313
<span class="c1"># Now, we can log to the root logger, or any other logger. First the root...</span>
 
314
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Jackdaws love my big sphinx of quartz.&#39;</span><span class="p">)</span>
 
315
 
 
316
<span class="c1"># Now, define a couple of other loggers which might represent areas in your</span>
 
317
<span class="c1"># application:</span>
 
318
 
 
319
<span class="n">logger1</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;myapp.area1&#39;</span><span class="p">)</span>
 
320
<span class="n">logger2</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;myapp.area2&#39;</span><span class="p">)</span>
 
321
 
 
322
<span class="n">logger1</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Quick zephyrs blow, vexing daft Jim.&#39;</span><span class="p">)</span>
 
323
<span class="n">logger1</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;How quickly daft jumping zebras vex.&#39;</span><span class="p">)</span>
 
324
<span class="n">logger2</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Jail zesty vixen who grabbed pay from quack.&#39;</span><span class="p">)</span>
 
325
<span class="n">logger2</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;The five boxing wizards jump quickly.&#39;</span><span class="p">)</span>
 
326
</pre></div>
 
327
</div>
 
328
<p>When you run this, on the console you will see</p>
 
329
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">root</span>        <span class="p">:</span> <span class="n">INFO</span>     <span class="n">Jackdaws</span> <span class="n">love</span> <span class="n">my</span> <span class="n">big</span> <span class="n">sphinx</span> <span class="n">of</span> <span class="n">quartz</span><span class="o">.</span>
 
330
<span class="n">myapp</span><span class="o">.</span><span class="n">area1</span> <span class="p">:</span> <span class="n">INFO</span>     <span class="n">How</span> <span class="n">quickly</span> <span class="n">daft</span> <span class="n">jumping</span> <span class="n">zebras</span> <span class="n">vex</span><span class="o">.</span>
 
331
<span class="n">myapp</span><span class="o">.</span><span class="n">area2</span> <span class="p">:</span> <span class="n">WARNING</span>  <span class="n">Jail</span> <span class="n">zesty</span> <span class="n">vixen</span> <span class="n">who</span> <span class="n">grabbed</span> <span class="n">pay</span> <span class="kn">from</span> <span class="nn">quack.</span>
 
332
<span class="n">myapp</span><span class="o">.</span><span class="n">area2</span> <span class="p">:</span> <span class="n">ERROR</span>    <span class="n">The</span> <span class="n">five</span> <span class="n">boxing</span> <span class="n">wizards</span> <span class="n">jump</span> <span class="n">quickly</span><span class="o">.</span>
 
333
</pre></div>
 
334
</div>
 
335
<p>and in the file you will see something like</p>
 
336
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="mi">10</span><span class="o">-</span><span class="mi">22</span> <span class="mi">22</span><span class="p">:</span><span class="mi">19</span> <span class="n">root</span>         <span class="n">INFO</span>     <span class="n">Jackdaws</span> <span class="n">love</span> <span class="n">my</span> <span class="n">big</span> <span class="n">sphinx</span> <span class="n">of</span> <span class="n">quartz</span><span class="o">.</span>
 
337
<span class="mi">10</span><span class="o">-</span><span class="mi">22</span> <span class="mi">22</span><span class="p">:</span><span class="mi">19</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area1</span>  <span class="n">DEBUG</span>    <span class="n">Quick</span> <span class="n">zephyrs</span> <span class="n">blow</span><span class="p">,</span> <span class="n">vexing</span> <span class="n">daft</span> <span class="n">Jim</span><span class="o">.</span>
 
338
<span class="mi">10</span><span class="o">-</span><span class="mi">22</span> <span class="mi">22</span><span class="p">:</span><span class="mi">19</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area1</span>  <span class="n">INFO</span>     <span class="n">How</span> <span class="n">quickly</span> <span class="n">daft</span> <span class="n">jumping</span> <span class="n">zebras</span> <span class="n">vex</span><span class="o">.</span>
 
339
<span class="mi">10</span><span class="o">-</span><span class="mi">22</span> <span class="mi">22</span><span class="p">:</span><span class="mi">19</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area2</span>  <span class="n">WARNING</span>  <span class="n">Jail</span> <span class="n">zesty</span> <span class="n">vixen</span> <span class="n">who</span> <span class="n">grabbed</span> <span class="n">pay</span> <span class="kn">from</span> <span class="nn">quack.</span>
 
340
<span class="mi">10</span><span class="o">-</span><span class="mi">22</span> <span class="mi">22</span><span class="p">:</span><span class="mi">19</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area2</span>  <span class="n">ERROR</span>    <span class="n">The</span> <span class="n">five</span> <span class="n">boxing</span> <span class="n">wizards</span> <span class="n">jump</span> <span class="n">quickly</span><span class="o">.</span>
 
341
</pre></div>
 
342
</div>
 
343
<p>As you can see, the DEBUG message only shows up in the file. The other messages
 
344
are sent to both destinations.</p>
 
345
<p>This example uses console and file handlers, but you can use any number and
 
346
combination of handlers you choose.</p>
 
347
</div>
 
348
<div class="section" id="configuration-server-example">
 
349
<h2>Configuration server example<a class="headerlink" href="#configuration-server-example" title="Permalink to this headline">¶</a></h2>
 
350
<p>Here is an example of a module using the logging configuration server:</p>
 
351
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
352
<span class="kn">import</span> <span class="nn">logging.config</span>
 
353
<span class="kn">import</span> <span class="nn">time</span>
 
354
<span class="kn">import</span> <span class="nn">os</span>
 
355
 
 
356
<span class="c1"># read initial config file</span>
 
357
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="s1">&#39;logging.conf&#39;</span><span class="p">)</span>
 
358
 
 
359
<span class="c1"># create and start listener on port 9999</span>
 
360
<span class="n">t</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">9999</span><span class="p">)</span>
 
361
<span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
362
 
 
363
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simpleExample&#39;</span><span class="p">)</span>
 
364
 
 
365
<span class="k">try</span><span class="p">:</span>
 
366
    <span class="c1"># loop through logging calls to see the difference</span>
 
367
    <span class="c1"># new configurations make, until Ctrl+C is pressed</span>
 
368
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
 
369
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
 
370
        <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>
 
371
        <span class="n">logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s1">&#39;warn message&#39;</span><span class="p">)</span>
 
372
        <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;error message&#39;</span><span class="p">)</span>
 
373
        <span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;critical message&#39;</span><span class="p">)</span>
 
374
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
 
375
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
 
376
    <span class="c1"># cleanup</span>
 
377
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">stopListening</span><span class="p">()</span>
 
378
    <span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
379
</pre></div>
 
380
</div>
 
381
<p>And here is a script that takes a filename and sends that file to the server,
 
382
properly preceded with the binary-encoded length, as the new logging
 
383
configuration:</p>
 
384
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span>
 
385
<span class="kn">import</span> <span class="nn">socket</span><span class="o">,</span> <span class="nn">sys</span><span class="o">,</span> <span class="nn">struct</span>
 
386
 
 
387
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
 
388
    <span class="n">data_to_send</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
 
389
 
 
390
<span class="n">HOST</span> <span class="o">=</span> <span class="s1">&#39;localhost&#39;</span>
 
391
<span class="n">PORT</span> <span class="o">=</span> <span class="mi">9999</span>
 
392
<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
 
393
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;connecting...&#39;</span><span class="p">)</span>
 
394
<span class="n">s</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span>
 
395
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;sending config...&#39;</span><span class="p">)</span>
 
396
<span class="n">s</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&gt;L&#39;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">data_to_send</span><span class="p">)))</span>
 
397
<span class="n">s</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">data_to_send</span><span class="p">)</span>
 
398
<span class="n">s</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
 
399
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;complete&#39;</span><span class="p">)</span>
 
400
</pre></div>
 
401
</div>
 
402
</div>
 
403
<div class="section" id="dealing-with-handlers-that-block">
 
404
<h2>Dealing with handlers that block<a class="headerlink" href="#dealing-with-handlers-that-block" title="Permalink to this headline">¶</a></h2>
 
405
<p>Sometimes you have to get your logging handlers to do their work without
 
406
blocking the thread you&#8217;re logging from. This is common in Web applications,
 
407
though of course it also occurs in other scenarios.</p>
 
408
<p>A common culprit which demonstrates sluggish behaviour is the
 
409
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SMTPHandler" title="logging.handlers.SMTPHandler"><code class="xref py py-class docutils literal"><span class="pre">SMTPHandler</span></code></a>: sending emails can take a long time, for a
 
410
number of reasons outside the developer&#8217;s control (for example, a poorly
 
411
performing mail or network infrastructure). But almost any network-based
 
412
handler can block: Even a <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></code></a> operation may do a
 
413
DNS query under the hood which is too slow (and this query can be deep in the
 
414
socket library code, below the Python layer, and outside your control).</p>
 
415
<p>One solution is to use a two-part approach. For the first part, attach only a
 
416
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal"><span class="pre">QueueHandler</span></code></a> to those loggers which are accessed from
 
417
performance-critical threads. They simply write to their queue, which can be
 
418
sized to a large enough capacity or initialized with no upper bound to their
 
419
size. The write to the queue will typically be accepted quickly, though you
 
420
will probably need to catch the <a class="reference internal" href="../library/queue.html#queue.Full" title="queue.Full"><code class="xref py py-exc docutils literal"><span class="pre">queue.Full</span></code></a> exception as a precaution
 
421
in your code. If you are a library developer who has performance-critical
 
422
threads in their code, be sure to document this (together with a suggestion to
 
423
attach only <code class="docutils literal"><span class="pre">QueueHandlers</span></code> to your loggers) for the benefit of other
 
424
developers who will use your code.</p>
 
425
<p>The second part of the solution is <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueListener" title="logging.handlers.QueueListener"><code class="xref py py-class docutils literal"><span class="pre">QueueListener</span></code></a>, which has been
 
426
designed as the counterpart to <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal"><span class="pre">QueueHandler</span></code></a>.  A
 
427
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueListener" title="logging.handlers.QueueListener"><code class="xref py py-class docutils literal"><span class="pre">QueueListener</span></code></a> is very simple: it&#8217;s passed a queue and some handlers,
 
428
and it fires up an internal thread which listens to its queue for LogRecords
 
429
sent from <code class="docutils literal"><span class="pre">QueueHandlers</span></code> (or any other source of <code class="docutils literal"><span class="pre">LogRecords</span></code>, for that
 
430
matter). The <code class="docutils literal"><span class="pre">LogRecords</span></code> are removed from the queue and passed to the
 
431
handlers for processing.</p>
 
432
<p>The advantage of having a separate <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueListener" title="logging.handlers.QueueListener"><code class="xref py py-class docutils literal"><span class="pre">QueueListener</span></code></a> class is that you
 
433
can use the same instance to service multiple <code class="docutils literal"><span class="pre">QueueHandlers</span></code>. This is more
 
434
resource-friendly than, say, having threaded versions of the existing handler
 
435
classes, which would eat up one thread per handler for no particular benefit.</p>
 
436
<p>An example of using these two classes follows (imports omitted):</p>
 
437
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">que</span> <span class="o">=</span> <span class="n">queue</span><span class="o">.</span><span class="n">Queue</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>  <span class="c1"># no limit on size</span>
 
438
<span class="n">queue_handler</span> <span class="o">=</span> <span class="n">QueueHandler</span><span class="p">(</span><span class="n">que</span><span class="p">)</span>
 
439
<span class="n">handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
440
<span class="n">listener</span> <span class="o">=</span> <span class="n">QueueListener</span><span class="p">(</span><span class="n">que</span><span class="p">,</span> <span class="n">handler</span><span class="p">)</span>
 
441
<span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
442
<span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">queue_handler</span><span class="p">)</span>
 
443
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(threadName)s</span><span class="s1">: </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
444
<span class="n">handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
 
445
<span class="n">listener</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
446
<span class="c1"># The log output will display the thread which generated</span>
 
447
<span class="c1"># the event (the main thread) rather than the internal</span>
 
448
<span class="c1"># thread which monitors the internal queue. This is what</span>
 
449
<span class="c1"># you want to happen.</span>
 
450
<span class="n">root</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Look out!&#39;</span><span class="p">)</span>
 
451
<span class="n">listener</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
 
452
</pre></div>
 
453
</div>
 
454
<p>which, when run, will produce:</p>
 
455
<div class="highlight-none"><div class="highlight"><pre><span></span>MainThread: Look out!
 
456
</pre></div>
 
457
</div>
 
458
<div class="versionchanged">
 
459
<p><span class="versionmodified">Changed in version 3.5: </span>Prior to Python 3.5, the <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueListener" title="logging.handlers.QueueListener"><code class="xref py py-class docutils literal"><span class="pre">QueueListener</span></code></a> always passed every message
 
460
received from the queue to every handler it was initialized with. (This was
 
461
because it was assumed that level filtering was all done on the other side,
 
462
where the queue is filled.) From 3.5 onwards, this behaviour can be changed
 
463
by passing a keyword argument <code class="docutils literal"><span class="pre">respect_handler_level=True</span></code> to the
 
464
listener&#8217;s constructor. When this is done, the listener compares the level
 
465
of each message with the handler&#8217;s level, and only passes a message to a
 
466
handler if it&#8217;s appropriate to do so.</p>
 
467
</div>
 
468
</div>
 
469
<div class="section" id="sending-and-receiving-logging-events-across-a-network">
 
470
<span id="network-logging"></span><h2>Sending and receiving logging events across a network<a class="headerlink" href="#sending-and-receiving-logging-events-across-a-network" title="Permalink to this headline">¶</a></h2>
 
471
<p>Let&#8217;s say you want to send logging events across a network, and handle them at
 
472
the receiving end. A simple way of doing this is attaching a
 
473
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></code></a> instance to the root logger at the sending end:</p>
 
474
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span><span class="o">,</span> <span class="nn">logging.handlers</span>
 
475
 
 
476
<span class="n">rootLogger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
 
477
<span class="n">rootLogger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
478
<span class="n">socketHandler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">SocketHandler</span><span class="p">(</span><span class="s1">&#39;localhost&#39;</span><span class="p">,</span>
 
479
                    <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">DEFAULT_TCP_LOGGING_PORT</span><span class="p">)</span>
 
480
<span class="c1"># don&#39;t bother with a formatter, since a socket handler sends the event as</span>
 
481
<span class="c1"># an unformatted pickle</span>
 
482
<span class="n">rootLogger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">socketHandler</span><span class="p">)</span>
 
483
 
 
484
<span class="c1"># Now, we can log to the root logger, or any other logger. First the root...</span>
 
485
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Jackdaws love my big sphinx of quartz.&#39;</span><span class="p">)</span>
 
486
 
 
487
<span class="c1"># Now, define a couple of other loggers which might represent areas in your</span>
 
488
<span class="c1"># application:</span>
 
489
 
 
490
<span class="n">logger1</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;myapp.area1&#39;</span><span class="p">)</span>
 
491
<span class="n">logger2</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;myapp.area2&#39;</span><span class="p">)</span>
 
492
 
 
493
<span class="n">logger1</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Quick zephyrs blow, vexing daft Jim.&#39;</span><span class="p">)</span>
 
494
<span class="n">logger1</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;How quickly daft jumping zebras vex.&#39;</span><span class="p">)</span>
 
495
<span class="n">logger2</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Jail zesty vixen who grabbed pay from quack.&#39;</span><span class="p">)</span>
 
496
<span class="n">logger2</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;The five boxing wizards jump quickly.&#39;</span><span class="p">)</span>
 
497
</pre></div>
 
498
</div>
 
499
<p>At the receiving end, you can set up a receiver using the <a class="reference internal" href="../library/socketserver.html#module-socketserver" title="socketserver: A framework for network servers."><code class="xref py py-mod docutils literal"><span class="pre">socketserver</span></code></a>
 
500
module. Here is a basic working example:</p>
 
501
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pickle</span>
 
502
<span class="kn">import</span> <span class="nn">logging</span>
 
503
<span class="kn">import</span> <span class="nn">logging.handlers</span>
 
504
<span class="kn">import</span> <span class="nn">socketserver</span>
 
505
<span class="kn">import</span> <span class="nn">struct</span>
 
506
 
 
507
 
 
508
<span class="k">class</span> <span class="nc">LogRecordStreamHandler</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">StreamRequestHandler</span><span class="p">):</span>
 
509
    <span class="sd">&quot;&quot;&quot;Handler for a streaming logging request.</span>
 
510
 
 
511
<span class="sd">    This basically logs the record using whatever logging policy is</span>
 
512
<span class="sd">    configured locally.</span>
 
513
<span class="sd">    &quot;&quot;&quot;</span>
 
514
 
 
515
    <span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
516
        <span class="sd">&quot;&quot;&quot;</span>
 
517
<span class="sd">        Handle multiple requests - each expected to be a 4-byte length,</span>
 
518
<span class="sd">        followed by the LogRecord in pickle format. Logs the record</span>
 
519
<span class="sd">        according to whatever policy is configured locally.</span>
 
520
<span class="sd">        &quot;&quot;&quot;</span>
 
521
        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
 
522
            <span class="n">chunk</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
 
523
            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">:</span>
 
524
                <span class="k">break</span>
 
525
            <span class="n">slen</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&gt;L&#39;</span><span class="p">,</span> <span class="n">chunk</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
 
526
            <span class="n">chunk</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="n">slen</span><span class="p">)</span>
 
527
            <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">slen</span><span class="p">:</span>
 
528
                <span class="n">chunk</span> <span class="o">=</span> <span class="n">chunk</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="n">slen</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">chunk</span><span class="p">))</span>
 
529
            <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">unPickle</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
 
530
            <span class="n">record</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">makeLogRecord</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
 
531
            <span class="bp">self</span><span class="o">.</span><span class="n">handleLogRecord</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
532
 
 
533
    <span class="k">def</span> <span class="nf">unPickle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
 
534
        <span class="k">return</span> <span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
 
535
 
 
536
    <span class="k">def</span> <span class="nf">handleLogRecord</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
537
        <span class="c1"># if a name is specified, we use the named logger rather than the one</span>
 
538
        <span class="c1"># implied by the record.</span>
 
539
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">logname</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
 
540
            <span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">logname</span>
 
541
        <span class="k">else</span><span class="p">:</span>
 
542
            <span class="n">name</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">name</span>
 
543
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
 
544
        <span class="c1"># N.B. EVERY record gets logged. This is because Logger.handle</span>
 
545
        <span class="c1"># is normally called AFTER logger-level filtering. If you want</span>
 
546
        <span class="c1"># to do filtering, do it at the client end to save wasting</span>
 
547
        <span class="c1"># cycles and network bandwidth!</span>
 
548
        <span class="n">logger</span><span class="o">.</span><span class="n">handle</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
549
 
 
550
<span class="k">class</span> <span class="nc">LogRecordSocketReceiver</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">ThreadingTCPServer</span><span class="p">):</span>
 
551
    <span class="sd">&quot;&quot;&quot;</span>
 
552
<span class="sd">    Simple TCP socket-based logging receiver suitable for testing.</span>
 
553
<span class="sd">    &quot;&quot;&quot;</span>
 
554
 
 
555
    <span class="n">allow_reuse_address</span> <span class="o">=</span> <span class="kc">True</span>
 
556
 
 
557
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">host</span><span class="o">=</span><span class="s1">&#39;localhost&#39;</span><span class="p">,</span>
 
558
                 <span class="n">port</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">DEFAULT_TCP_LOGGING_PORT</span><span class="p">,</span>
 
559
                 <span class="n">handler</span><span class="o">=</span><span class="n">LogRecordStreamHandler</span><span class="p">):</span>
 
560
        <span class="n">socketserver</span><span class="o">.</span><span class="n">ThreadingTCPServer</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">),</span> <span class="n">handler</span><span class="p">)</span>
 
561
        <span class="bp">self</span><span class="o">.</span><span class="n">abort</span> <span class="o">=</span> <span class="mi">0</span>
 
562
        <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="mi">1</span>
 
563
        <span class="bp">self</span><span class="o">.</span><span class="n">logname</span> <span class="o">=</span> <span class="kc">None</span>
 
564
 
 
565
    <span class="k">def</span> <span class="nf">serve_until_stopped</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
566
        <span class="kn">import</span> <span class="nn">select</span>
 
567
        <span class="n">abort</span> <span class="o">=</span> <span class="mi">0</span>
 
568
        <span class="k">while</span> <span class="ow">not</span> <span class="n">abort</span><span class="p">:</span>
 
569
            <span class="n">rd</span><span class="p">,</span> <span class="n">wr</span><span class="p">,</span> <span class="n">ex</span> <span class="o">=</span> <span class="n">select</span><span class="o">.</span><span class="n">select</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">fileno</span><span class="p">()],</span>
 
570
                                       <span class="p">[],</span> <span class="p">[],</span>
 
571
                                       <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span>
 
572
            <span class="k">if</span> <span class="n">rd</span><span class="p">:</span>
 
573
                <span class="bp">self</span><span class="o">.</span><span class="n">handle_request</span><span class="p">()</span>
 
574
            <span class="n">abort</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">abort</span>
 
575
 
 
576
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
577
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span>
 
578
        <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(relativeCreated)5d</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
579
    <span class="n">tcpserver</span> <span class="o">=</span> <span class="n">LogRecordSocketReceiver</span><span class="p">()</span>
 
580
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;About to start TCP server...&#39;</span><span class="p">)</span>
 
581
    <span class="n">tcpserver</span><span class="o">.</span><span class="n">serve_until_stopped</span><span class="p">()</span>
 
582
 
 
583
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
584
    <span class="n">main</span><span class="p">()</span>
 
585
</pre></div>
 
586
</div>
 
587
<p>First run the server, and then the client. On the client side, nothing is
 
588
printed on the console; on the server side, you should see something like:</p>
 
589
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">About</span> <span class="n">to</span> <span class="n">start</span> <span class="n">TCP</span> <span class="n">server</span><span class="o">...</span>
 
590
   <span class="mi">59</span> <span class="n">root</span>            <span class="n">INFO</span>     <span class="n">Jackdaws</span> <span class="n">love</span> <span class="n">my</span> <span class="n">big</span> <span class="n">sphinx</span> <span class="n">of</span> <span class="n">quartz</span><span class="o">.</span>
 
591
   <span class="mi">59</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area1</span>     <span class="n">DEBUG</span>    <span class="n">Quick</span> <span class="n">zephyrs</span> <span class="n">blow</span><span class="p">,</span> <span class="n">vexing</span> <span class="n">daft</span> <span class="n">Jim</span><span class="o">.</span>
 
592
   <span class="mi">69</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area1</span>     <span class="n">INFO</span>     <span class="n">How</span> <span class="n">quickly</span> <span class="n">daft</span> <span class="n">jumping</span> <span class="n">zebras</span> <span class="n">vex</span><span class="o">.</span>
 
593
   <span class="mi">69</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area2</span>     <span class="n">WARNING</span>  <span class="n">Jail</span> <span class="n">zesty</span> <span class="n">vixen</span> <span class="n">who</span> <span class="n">grabbed</span> <span class="n">pay</span> <span class="kn">from</span> <span class="nn">quack.</span>
 
594
   <span class="mi">69</span> <span class="n">myapp</span><span class="o">.</span><span class="n">area2</span>     <span class="n">ERROR</span>    <span class="n">The</span> <span class="n">five</span> <span class="n">boxing</span> <span class="n">wizards</span> <span class="n">jump</span> <span class="n">quickly</span><span class="o">.</span>
 
595
</pre></div>
 
596
</div>
 
597
<p>Note that there are some security issues with pickle in some scenarios. If
 
598
these affect you, you can use an alternative serialization scheme by overriding
 
599
the <code class="xref py py-meth docutils literal"><span class="pre">makePickle()</span></code> method and implementing your
 
600
alternative there, as well as adapting the above script to use your alternative
 
601
serialization.</p>
 
602
</div>
 
603
<div class="section" id="adding-contextual-information-to-your-logging-output">
 
604
<span id="context-info"></span><h2>Adding contextual information to your logging output<a class="headerlink" href="#adding-contextual-information-to-your-logging-output" title="Permalink to this headline">¶</a></h2>
 
605
<p>Sometimes you want logging output to contain contextual information in
 
606
addition to the parameters passed to the logging call. For example, in a
 
607
networked application, it may be desirable to log client-specific information
 
608
in the log (e.g. remote client&#8217;s username, or IP address). Although you could
 
609
use the <em>extra</em> parameter to achieve this, it&#8217;s not always convenient to pass
 
610
the information in this way. While it might be tempting to create
 
611
<code class="xref py py-class docutils literal"><span class="pre">Logger</span></code> instances on a per-connection basis, this is not a good idea
 
612
because these instances are not garbage collected. While this is not a problem
 
613
in practice, when the number of <code class="xref py py-class docutils literal"><span class="pre">Logger</span></code> instances is dependent on the
 
614
level of granularity you want to use in logging an application, it could
 
615
be hard to manage if the number of <code class="xref py py-class docutils literal"><span class="pre">Logger</span></code> instances becomes
 
616
effectively unbounded.</p>
 
617
<div class="section" id="using-loggeradapters-to-impart-contextual-information">
 
618
<h3>Using LoggerAdapters to impart contextual information<a class="headerlink" href="#using-loggeradapters-to-impart-contextual-information" title="Permalink to this headline">¶</a></h3>
 
619
<p>An easy way in which you can pass contextual information to be output along
 
620
with logging event information is to use the <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code> class.
 
621
This class is designed to look like a <code class="xref py py-class docutils literal"><span class="pre">Logger</span></code>, so that you can call
 
622
<code class="xref py py-meth docutils literal"><span class="pre">debug()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">info()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">warning()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">error()</span></code>,
 
623
<code class="xref py py-meth docutils literal"><span class="pre">exception()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">critical()</span></code> and <code class="xref py py-meth docutils literal"><span class="pre">log()</span></code>. These methods have the
 
624
same signatures as their counterparts in <code class="xref py py-class docutils literal"><span class="pre">Logger</span></code>, so you can use the
 
625
two types of instances interchangeably.</p>
 
626
<p>When you create an instance of <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code>, you pass it a
 
627
<code class="xref py py-class docutils literal"><span class="pre">Logger</span></code> instance and a dict-like object which contains your contextual
 
628
information. When you call one of the logging methods on an instance of
 
629
<code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code>, it delegates the call to the underlying instance of
 
630
<code class="xref py py-class docutils literal"><span class="pre">Logger</span></code> passed to its constructor, and arranges to pass the contextual
 
631
information in the delegated call. Here&#8217;s a snippet from the code of
 
632
<code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code>:</p>
 
633
<div class="highlight-python3"><div class="highlight"><pre><span></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>
 
634
    <span class="sd">&quot;&quot;&quot;</span>
 
635
<span class="sd">    Delegate a debug call to the underlying logger, after adding</span>
 
636
<span class="sd">    contextual information from this adapter instance.</span>
 
637
<span class="sd">    &quot;&quot;&quot;</span>
 
638
    <span class="n">msg</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
 
639
    <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">debug</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>
 
640
</pre></div>
 
641
</div>
 
642
<p>The <code class="xref py py-meth docutils literal"><span class="pre">process()</span></code> method of <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code> is where the
 
643
contextual information is added to the logging output. It&#8217;s passed the message
 
644
and keyword arguments of the logging call, and it passes back (potentially)
 
645
modified versions of these to use in the call to the underlying logger. The
 
646
default implementation of this method leaves the message alone, but inserts
 
647
an &#8216;extra&#8217; key in the keyword argument whose value is the dict-like object
 
648
passed to the constructor. Of course, if you had passed an &#8216;extra&#8217; keyword
 
649
argument in the call to the adapter, it will be silently overwritten.</p>
 
650
<p>The advantage of using &#8216;extra&#8217; is that the values in the dict-like object are
 
651
merged into the <code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code> instance&#8217;s __dict__, allowing you to use
 
652
customized strings with your <code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code> instances which know about
 
653
the keys of the dict-like object. If you need a different method, e.g. if you
 
654
want to prepend or append the contextual information to the message string,
 
655
you just need to subclass <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code> and override
 
656
<code class="xref py py-meth docutils literal"><span class="pre">process()</span></code> to do what you need. Here is a simple example:</p>
 
657
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CustomAdapter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">LoggerAdapter</span><span class="p">):</span>
 
658
    <span class="sd">&quot;&quot;&quot;</span>
 
659
<span class="sd">    This example adapter expects the passed in dict-like object to have a</span>
 
660
<span class="sd">    &#39;connid&#39; key, whose value in brackets is prepended to the log message.</span>
 
661
<span class="sd">    &quot;&quot;&quot;</span>
 
662
    <span class="k">def</span> <span class="nf">process</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="n">kwargs</span><span class="p">):</span>
 
663
        <span class="k">return</span> <span class="s1">&#39;[</span><span class="si">%s</span><span class="s1">] </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">extra</span><span class="p">[</span><span class="s1">&#39;connid&#39;</span><span class="p">],</span> <span class="n">msg</span><span class="p">),</span> <span class="n">kwargs</span>
 
664
</pre></div>
 
665
</div>
 
666
<p>which you can use like this:</p>
 
667
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
 
668
<span class="n">adapter</span> <span class="o">=</span> <span class="n">CustomAdapter</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;connid&#39;</span><span class="p">:</span> <span class="n">some_conn_id</span><span class="p">})</span>
 
669
</pre></div>
 
670
</div>
 
671
<p>Then any events that you log to the adapter will have the value of
 
672
<code class="docutils literal"><span class="pre">some_conn_id</span></code> prepended to the log messages.</p>
 
673
<div class="section" id="using-objects-other-than-dicts-to-pass-contextual-information">
 
674
<h4>Using objects other than dicts to pass contextual information<a class="headerlink" href="#using-objects-other-than-dicts-to-pass-contextual-information" title="Permalink to this headline">¶</a></h4>
 
675
<p>You don&#8217;t need to pass an actual dict to a <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code> - you could
 
676
pass an instance of a class which implements <code class="docutils literal"><span class="pre">__getitem__</span></code> and <code class="docutils literal"><span class="pre">__iter__</span></code> so
 
677
that it looks like a dict to logging. This would be useful if you want to
 
678
generate values dynamically (whereas the values in a dict would be constant).</p>
 
679
</div>
 
680
</div>
 
681
<div class="section" id="using-filters-to-impart-contextual-information">
 
682
<span id="filters-contextual"></span><h3>Using Filters to impart contextual information<a class="headerlink" href="#using-filters-to-impart-contextual-information" title="Permalink to this headline">¶</a></h3>
 
683
<p>You can also add contextual information to log output using a user-defined
 
684
<code class="xref py py-class docutils literal"><span class="pre">Filter</span></code>. <code class="docutils literal"><span class="pre">Filter</span></code> instances are allowed to modify the <code class="docutils literal"><span class="pre">LogRecords</span></code>
 
685
passed to them, including adding additional attributes which can then be output
 
686
using a suitable format string, or if needed a custom <code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code>.</p>
 
687
<p>For example in a web application, the request being processed (or at least,
 
688
the interesting parts of it) can be stored in a threadlocal
 
689
(<a class="reference internal" href="../library/threading.html#threading.local" title="threading.local"><code class="xref py py-class docutils literal"><span class="pre">threading.local</span></code></a>) variable, and then accessed from a <code class="docutils literal"><span class="pre">Filter</span></code> to
 
690
add, say, information from the request - say, the remote IP address and remote
 
691
user&#8217;s username - to the <code class="docutils literal"><span class="pre">LogRecord</span></code>, using the attribute names &#8216;ip&#8217; and
 
692
&#8216;user&#8217; as in the <code class="docutils literal"><span class="pre">LoggerAdapter</span></code> example above. In that case, the same format
 
693
string can be used to get similar output to that shown above. Here&#8217;s an example
 
694
script:</p>
 
695
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
696
<span class="kn">from</span> <span class="nn">random</span> <span class="k">import</span> <span class="n">choice</span>
 
697
 
 
698
<span class="k">class</span> <span class="nc">ContextFilter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
 
699
    <span class="sd">&quot;&quot;&quot;</span>
 
700
<span class="sd">    This is a filter which injects contextual information into the log.</span>
 
701
 
 
702
<span class="sd">    Rather than use actual contextual information, we just use random</span>
 
703
<span class="sd">    data in this demo.</span>
 
704
<span class="sd">    &quot;&quot;&quot;</span>
 
705
 
 
706
    <span class="n">USERS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;jim&#39;</span><span class="p">,</span> <span class="s1">&#39;fred&#39;</span><span class="p">,</span> <span class="s1">&#39;sheila&#39;</span><span class="p">]</span>
 
707
    <span class="n">IPS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;123.231.231.123&#39;</span><span class="p">,</span> <span class="s1">&#39;127.0.0.1&#39;</span><span class="p">,</span> <span class="s1">&#39;192.168.0.1&#39;</span><span class="p">]</span>
 
708
 
 
709
    <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>
 
710
 
 
711
        <span class="n">record</span><span class="o">.</span><span class="n">ip</span> <span class="o">=</span> <span class="n">choice</span><span class="p">(</span><span class="n">ContextFilter</span><span class="o">.</span><span class="n">IPS</span><span class="p">)</span>
 
712
        <span class="n">record</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">choice</span><span class="p">(</span><span class="n">ContextFilter</span><span class="o">.</span><span class="n">USERS</span><span class="p">)</span>
 
713
        <span class="k">return</span> <span class="kc">True</span>
 
714
 
 
715
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
716
    <span class="n">levels</span> <span class="o">=</span> <span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">CRITICAL</span><span class="p">)</span>
 
717
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span>
 
718
                        <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(asctime)-15s</span><span class="s1"> </span><span class="si">%(name)-5s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> IP: </span><span class="si">%(ip)-15s</span><span class="s1"> User: </span><span class="si">%(user)-8s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
719
    <span class="n">a1</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;a.b.c&#39;</span><span class="p">)</span>
 
720
    <span class="n">a2</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;d.e.f&#39;</span><span class="p">)</span>
 
721
 
 
722
    <span class="n">f</span> <span class="o">=</span> <span class="n">ContextFilter</span><span class="p">()</span>
 
723
    <span class="n">a1</span><span class="o">.</span><span class="n">addFilter</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
 
724
    <span class="n">a2</span><span class="o">.</span><span class="n">addFilter</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
 
725
    <span class="n">a1</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;A debug message&#39;</span><span class="p">)</span>
 
726
    <span class="n">a1</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;An info message with </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;some parameters&#39;</span><span class="p">)</span>
 
727
    <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
 
728
        <span class="n">lvl</span> <span class="o">=</span> <span class="n">choice</span><span class="p">(</span><span class="n">levels</span><span class="p">)</span>
 
729
        <span class="n">lvlname</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLevelName</span><span class="p">(</span><span class="n">lvl</span><span class="p">)</span>
 
730
        <span class="n">a2</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">lvl</span><span class="p">,</span> <span class="s1">&#39;A message at </span><span class="si">%s</span><span class="s1"> level with </span><span class="si">%d</span><span class="s1"> </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">lvlname</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;parameters&#39;</span><span class="p">)</span>
 
731
</pre></div>
 
732
</div>
 
733
<p>which, when run, produces something like:</p>
 
734
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">292</span> <span class="n">a</span><span class="o">.</span><span class="n">b</span><span class="o">.</span><span class="n">c</span> <span class="n">DEBUG</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">123.231</span><span class="o">.</span><span class="mf">231.123</span> <span class="n">User</span><span class="p">:</span> <span class="n">fred</span>     <span class="n">A</span> <span class="n">debug</span> <span class="n">message</span>
 
735
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">a</span><span class="o">.</span><span class="n">b</span><span class="o">.</span><span class="n">c</span> <span class="n">INFO</span>     <span class="n">IP</span><span class="p">:</span> <span class="mf">192.168</span><span class="o">.</span><span class="mf">0.1</span>     <span class="n">User</span><span class="p">:</span> <span class="n">sheila</span>   <span class="n">An</span> <span class="n">info</span> <span class="n">message</span> <span class="k">with</span> <span class="n">some</span> <span class="n">parameters</span>
 
736
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">CRITICAL</span> <span class="n">IP</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>       <span class="n">User</span><span class="p">:</span> <span class="n">sheila</span>   <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">CRITICAL</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
737
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">ERROR</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>       <span class="n">User</span><span class="p">:</span> <span class="n">jim</span>      <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">ERROR</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
738
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">DEBUG</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>       <span class="n">User</span><span class="p">:</span> <span class="n">sheila</span>   <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
739
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">ERROR</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">123.231</span><span class="o">.</span><span class="mf">231.123</span> <span class="n">User</span><span class="p">:</span> <span class="n">fred</span>     <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">ERROR</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
740
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">CRITICAL</span> <span class="n">IP</span><span class="p">:</span> <span class="mf">192.168</span><span class="o">.</span><span class="mf">0.1</span>     <span class="n">User</span><span class="p">:</span> <span class="n">jim</span>      <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">CRITICAL</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
741
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">CRITICAL</span> <span class="n">IP</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>       <span class="n">User</span><span class="p">:</span> <span class="n">sheila</span>   <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">CRITICAL</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
742
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">300</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">DEBUG</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">192.168</span><span class="o">.</span><span class="mf">0.1</span>     <span class="n">User</span><span class="p">:</span> <span class="n">jim</span>      <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
743
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">301</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">ERROR</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>       <span class="n">User</span><span class="p">:</span> <span class="n">sheila</span>   <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">ERROR</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
744
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">301</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">DEBUG</span>    <span class="n">IP</span><span class="p">:</span> <span class="mf">123.231</span><span class="o">.</span><span class="mf">231.123</span> <span class="n">User</span><span class="p">:</span> <span class="n">fred</span>     <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
745
<span class="mi">2010</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">06</span> <span class="mi">22</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">15</span><span class="p">,</span><span class="mi">301</span> <span class="n">d</span><span class="o">.</span><span class="n">e</span><span class="o">.</span><span class="n">f</span> <span class="n">INFO</span>     <span class="n">IP</span><span class="p">:</span> <span class="mf">123.231</span><span class="o">.</span><span class="mf">231.123</span> <span class="n">User</span><span class="p">:</span> <span class="n">fred</span>     <span class="n">A</span> <span class="n">message</span> <span class="n">at</span> <span class="n">INFO</span> <span class="n">level</span> <span class="k">with</span> <span class="mi">2</span> <span class="n">parameters</span>
 
746
</pre></div>
 
747
</div>
 
748
</div>
 
749
</div>
 
750
<div class="section" id="logging-to-a-single-file-from-multiple-processes">
 
751
<span id="multiple-processes"></span><h2>Logging to a single file from multiple processes<a class="headerlink" href="#logging-to-a-single-file-from-multiple-processes" title="Permalink to this headline">¶</a></h2>
 
752
<p>Although logging is thread-safe, and logging to a single file from multiple
 
753
threads in a single process <em>is</em> supported, logging to a single file from
 
754
<em>multiple processes</em> is <em>not</em> supported, because there is no standard way to
 
755
serialize access to a single file across multiple processes in Python. If you
 
756
need to log to a single file from multiple processes, one way of doing this is
 
757
to have all the processes log to a <code class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></code>, and have a
 
758
separate process which implements a socket server which reads from the socket
 
759
and logs to file. (If you prefer, you can dedicate one thread in one of the
 
760
existing processes to perform this function.)
 
761
<a class="reference internal" href="#network-logging"><span>This section</span></a> documents this approach in more detail and
 
762
includes a working socket receiver which can be used as a starting point for you
 
763
to adapt in your own applications.</p>
 
764
<p>If you are using a recent version of Python which includes the
 
765
<a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">multiprocessing</span></code></a> module, you could write your own handler which uses the
 
766
<a class="reference internal" href="../library/multiprocessing.html#multiprocessing.Lock" title="multiprocessing.Lock"><code class="xref py py-class docutils literal"><span class="pre">Lock</span></code></a> class from this module to serialize access to the
 
767
file from your processes. The existing <code class="xref py py-class docutils literal"><span class="pre">FileHandler</span></code> and subclasses do
 
768
not make use of <a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">multiprocessing</span></code></a> at present, though they may do so in the
 
769
future. Note that at present, the <a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">multiprocessing</span></code></a> module does not provide
 
770
working lock functionality on all platforms (see
 
771
<a class="reference external" href="https://bugs.python.org/issue3770">https://bugs.python.org/issue3770</a>).</p>
 
772
<p>Alternatively, you can use a <code class="docutils literal"><span class="pre">Queue</span></code> and a <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal"><span class="pre">QueueHandler</span></code></a> to send
 
773
all logging events to one of the processes in your multi-process application.
 
774
The following example script demonstrates how you can do this; in the example
 
775
a separate listener process listens for events sent by other processes and logs
 
776
them according to its own logging configuration. Although the example only
 
777
demonstrates one way of doing it (for example, you may want to use a listener
 
778
thread rather than a separate listener process &#8211; the implementation would be
 
779
analogous) it does allow for completely different logging configurations for
 
780
the listener and the other processes in your application, and can be used as
 
781
the basis for code meeting your own specific requirements:</p>
 
782
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="c1"># You&#39;ll need these imports in your own code</span>
 
783
<span class="kn">import</span> <span class="nn">logging</span>
 
784
<span class="kn">import</span> <span class="nn">logging.handlers</span>
 
785
<span class="kn">import</span> <span class="nn">multiprocessing</span>
 
786
 
 
787
<span class="c1"># Next two import lines for this demo only</span>
 
788
<span class="kn">from</span> <span class="nn">random</span> <span class="k">import</span> <span class="n">choice</span><span class="p">,</span> <span class="n">random</span>
 
789
<span class="kn">import</span> <span class="nn">time</span>
 
790
 
 
791
<span class="c1">#</span>
 
792
<span class="c1"># Because you&#39;ll want to define the logging configurations for listener and workers, the</span>
 
793
<span class="c1"># listener and worker process functions take a configurer parameter which is a callable</span>
 
794
<span class="c1"># for configuring logging for that process. These functions are also passed the queue,</span>
 
795
<span class="c1"># which they use for communication.</span>
 
796
<span class="c1">#</span>
 
797
<span class="c1"># In practice, you can configure the listener however you want, but note that in this</span>
 
798
<span class="c1"># simple example, the listener does not apply level or filter logic to received records.</span>
 
799
<span class="c1"># In practice, you would probably want to do this logic in the worker processes, to avoid</span>
 
800
<span class="c1"># sending events which would be filtered out between processes.</span>
 
801
<span class="c1">#</span>
 
802
<span class="c1"># The size of the rotated files is made small so you can see the results easily.</span>
 
803
<span class="k">def</span> <span class="nf">listener_configurer</span><span class="p">():</span>
 
804
    <span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
805
    <span class="n">h</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">RotatingFileHandler</span><span class="p">(</span><span class="s1">&#39;mptest.log&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
 
806
    <span class="n">f</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(processName)-10s</span><span class="s1"> </span><span class="si">%(name)s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
807
    <span class="n">h</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
 
808
    <span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
 
809
 
 
810
<span class="c1"># This is the listener process top-level loop: wait for logging events</span>
 
811
<span class="c1"># (LogRecords)on the queue and handle them, quit when you get a None for a</span>
 
812
<span class="c1"># LogRecord.</span>
 
813
<span class="k">def</span> <span class="nf">listener_process</span><span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">configurer</span><span class="p">):</span>
 
814
    <span class="n">configurer</span><span class="p">()</span>
 
815
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
 
816
        <span class="k">try</span><span class="p">:</span>
 
817
            <span class="n">record</span> <span class="o">=</span> <span class="n">queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
 
818
            <span class="k">if</span> <span class="n">record</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>  <span class="c1"># We send this as a sentinel to tell the listener to quit.</span>
 
819
                <span class="k">break</span>
 
820
            <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">record</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
 
821
            <span class="n">logger</span><span class="o">.</span><span class="n">handle</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>  <span class="c1"># No level or filter logic applied - just do it!</span>
 
822
        <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
 
823
            <span class="kn">import</span> <span class="nn">sys</span><span class="o">,</span> <span class="nn">traceback</span>
 
824
            <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Whoops! Problem:&#39;</span><span class="p">,</span> <span class="n">file</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">)</span>
 
825
            <span class="n">traceback</span><span class="o">.</span><span class="n">print_exc</span><span class="p">(</span><span class="n">file</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">)</span>
 
826
 
 
827
<span class="c1"># Arrays used for random selections in this demo</span>
 
828
 
 
829
<span class="n">LEVELS</span> <span class="o">=</span> <span class="p">[</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span>
 
830
          <span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">CRITICAL</span><span class="p">]</span>
 
831
 
 
832
<span class="n">LOGGERS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;a.b.c&#39;</span><span class="p">,</span> <span class="s1">&#39;d.e.f&#39;</span><span class="p">]</span>
 
833
 
 
834
<span class="n">MESSAGES</span> <span class="o">=</span> <span class="p">[</span>
 
835
    <span class="s1">&#39;Random message #1&#39;</span><span class="p">,</span>
 
836
    <span class="s1">&#39;Random message #2&#39;</span><span class="p">,</span>
 
837
    <span class="s1">&#39;Random message #3&#39;</span><span class="p">,</span>
 
838
<span class="p">]</span>
 
839
 
 
840
<span class="c1"># The worker configuration is done at the start of the worker process run.</span>
 
841
<span class="c1"># Note that on Windows you can&#39;t rely on fork semantics, so each process</span>
 
842
<span class="c1"># will run the logging configuration code when it starts.</span>
 
843
<span class="k">def</span> <span class="nf">worker_configurer</span><span class="p">(</span><span class="n">queue</span><span class="p">):</span>
 
844
    <span class="n">h</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">QueueHandler</span><span class="p">(</span><span class="n">queue</span><span class="p">)</span>  <span class="c1"># Just the one handler needed</span>
 
845
    <span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
846
    <span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
 
847
    <span class="c1"># send all messages, for demo; no other level or filter logic applied.</span>
 
848
    <span class="n">root</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
849
 
 
850
<span class="c1"># This is the worker process top-level loop, which just logs ten events with</span>
 
851
<span class="c1"># random intervening delays before terminating.</span>
 
852
<span class="c1"># The print messages are just so you know it&#39;s doing something!</span>
 
853
<span class="k">def</span> <span class="nf">worker_process</span><span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">configurer</span><span class="p">):</span>
 
854
    <span class="n">configurer</span><span class="p">(</span><span class="n">queue</span><span class="p">)</span>
 
855
    <span class="n">name</span> <span class="o">=</span> <span class="n">multiprocessing</span><span class="o">.</span><span class="n">current_process</span><span class="p">()</span><span class="o">.</span><span class="n">name</span>
 
856
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Worker started: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
 
857
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
 
858
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">random</span><span class="p">())</span>
 
859
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">choice</span><span class="p">(</span><span class="n">LOGGERS</span><span class="p">))</span>
 
860
        <span class="n">level</span> <span class="o">=</span> <span class="n">choice</span><span class="p">(</span><span class="n">LEVELS</span><span class="p">)</span>
 
861
        <span class="n">message</span> <span class="o">=</span> <span class="n">choice</span><span class="p">(</span><span class="n">MESSAGES</span><span class="p">)</span>
 
862
        <span class="n">logger</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
 
863
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Worker finished: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
 
864
 
 
865
<span class="c1"># Here&#39;s where the demo gets orchestrated. Create the queue, create and start</span>
 
866
<span class="c1"># the listener, create ten workers and start them, wait for them to finish,</span>
 
867
<span class="c1"># then send a None to the queue to tell the listener to finish.</span>
 
868
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
869
    <span class="n">queue</span> <span class="o">=</span> <span class="n">multiprocessing</span><span class="o">.</span><span class="n">Queue</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
 
870
    <span class="n">listener</span> <span class="o">=</span> <span class="n">multiprocessing</span><span class="o">.</span><span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">listener_process</span><span class="p">,</span>
 
871
                                       <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">listener_configurer</span><span class="p">))</span>
 
872
    <span class="n">listener</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
873
    <span class="n">workers</span> <span class="o">=</span> <span class="p">[]</span>
 
874
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
 
875
        <span class="n">worker</span> <span class="o">=</span> <span class="n">multiprocessing</span><span class="o">.</span><span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">worker_process</span><span class="p">,</span>
 
876
                                         <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">worker_configurer</span><span class="p">))</span>
 
877
        <span class="n">workers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">worker</span><span class="p">)</span>
 
878
        <span class="n">worker</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
879
    <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">workers</span><span class="p">:</span>
 
880
        <span class="n">w</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
881
    <span class="n">queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
 
882
    <span class="n">listener</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
883
 
 
884
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
885
    <span class="n">main</span><span class="p">()</span>
 
886
</pre></div>
 
887
</div>
 
888
<p>A variant of the above script keeps the logging in the main process, in a
 
889
separate thread:</p>
 
890
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
891
<span class="kn">import</span> <span class="nn">logging.config</span>
 
892
<span class="kn">import</span> <span class="nn">logging.handlers</span>
 
893
<span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="k">import</span> <span class="n">Process</span><span class="p">,</span> <span class="n">Queue</span>
 
894
<span class="kn">import</span> <span class="nn">random</span>
 
895
<span class="kn">import</span> <span class="nn">threading</span>
 
896
<span class="kn">import</span> <span class="nn">time</span>
 
897
 
 
898
<span class="k">def</span> <span class="nf">logger_thread</span><span class="p">(</span><span class="n">q</span><span class="p">):</span>
 
899
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
 
900
        <span class="n">record</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
 
901
        <span class="k">if</span> <span class="n">record</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
 
902
            <span class="k">break</span>
 
903
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">record</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
 
904
        <span class="n">logger</span><span class="o">.</span><span class="n">handle</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
905
 
 
906
 
 
907
<span class="k">def</span> <span class="nf">worker_process</span><span class="p">(</span><span class="n">q</span><span class="p">):</span>
 
908
    <span class="n">qh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">QueueHandler</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
 
909
    <span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
910
    <span class="n">root</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
911
    <span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">qh</span><span class="p">)</span>
 
912
    <span class="n">levels</span> <span class="o">=</span> <span class="p">[</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">,</span>
 
913
              <span class="n">logging</span><span class="o">.</span><span class="n">CRITICAL</span><span class="p">]</span>
 
914
    <span class="n">loggers</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="s1">&#39;foo.bar&#39;</span><span class="p">,</span> <span class="s1">&#39;foo.bar.baz&#39;</span><span class="p">,</span>
 
915
               <span class="s1">&#39;spam&#39;</span><span class="p">,</span> <span class="s1">&#39;spam.ham&#39;</span><span class="p">,</span> <span class="s1">&#39;spam.ham.eggs&#39;</span><span class="p">]</span>
 
916
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span>
 
917
        <span class="n">lvl</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">levels</span><span class="p">)</span>
 
918
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">loggers</span><span class="p">))</span>
 
919
        <span class="n">logger</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">lvl</span><span class="p">,</span> <span class="s1">&#39;Message no. </span><span class="si">%d</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
 
920
 
 
921
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
922
    <span class="n">q</span> <span class="o">=</span> <span class="n">Queue</span><span class="p">()</span>
 
923
    <span class="n">d</span> <span class="o">=</span> <span class="p">{</span>
 
924
        <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
925
        <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
926
            <span class="s1">&#39;detailed&#39;</span><span class="p">:</span> <span class="p">{</span>
 
927
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.Formatter&#39;</span><span class="p">,</span>
 
928
                <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(processName)-10s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
929
            <span class="p">}</span>
 
930
        <span class="p">},</span>
 
931
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
932
            <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
 
933
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
934
                <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
 
935
            <span class="p">},</span>
 
936
            <span class="s1">&#39;file&#39;</span><span class="p">:</span> <span class="p">{</span>
 
937
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
938
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog.log&#39;</span><span class="p">,</span>
 
939
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
940
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
941
            <span class="p">},</span>
 
942
            <span class="s1">&#39;foofile&#39;</span><span class="p">:</span> <span class="p">{</span>
 
943
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
944
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog-foo.log&#39;</span><span class="p">,</span>
 
945
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
946
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
947
            <span class="p">},</span>
 
948
            <span class="s1">&#39;errors&#39;</span><span class="p">:</span> <span class="p">{</span>
 
949
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
950
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog-errors.log&#39;</span><span class="p">,</span>
 
951
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
952
                <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
 
953
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
954
            <span class="p">},</span>
 
955
        <span class="p">},</span>
 
956
        <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
957
            <span class="s1">&#39;foo&#39;</span><span class="p">:</span> <span class="p">{</span>
 
958
                <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;foofile&#39;</span><span class="p">]</span>
 
959
            <span class="p">}</span>
 
960
        <span class="p">},</span>
 
961
        <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
962
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
963
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="s1">&#39;errors&#39;</span><span class="p">]</span>
 
964
        <span class="p">},</span>
 
965
    <span class="p">}</span>
 
966
    <span class="n">workers</span> <span class="o">=</span> <span class="p">[]</span>
 
967
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
 
968
        <span class="n">wp</span> <span class="o">=</span> <span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">worker_process</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;worker </span><span class="si">%d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">q</span><span class="p">,))</span>
 
969
        <span class="n">workers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">wp</span><span class="p">)</span>
 
970
        <span class="n">wp</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
971
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
 
972
    <span class="n">lp</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">logger_thread</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">q</span><span class="p">,))</span>
 
973
    <span class="n">lp</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
974
    <span class="c1"># At this point, the main process could do some useful work of its own</span>
 
975
    <span class="c1"># Once it&#39;s done that, it can wait for the workers to terminate...</span>
 
976
    <span class="k">for</span> <span class="n">wp</span> <span class="ow">in</span> <span class="n">workers</span><span class="p">:</span>
 
977
        <span class="n">wp</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
978
    <span class="c1"># And now tell the logging thread to finish up, too</span>
 
979
    <span class="n">q</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
 
980
    <span class="n">lp</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
981
</pre></div>
 
982
</div>
 
983
<p>This variant shows how you can e.g. apply configuration for particular loggers
 
984
- e.g. the <code class="docutils literal"><span class="pre">foo</span></code> logger has a special handler which stores all events in the
 
985
<code class="docutils literal"><span class="pre">foo</span></code> subsystem in a file <code class="docutils literal"><span class="pre">mplog-foo.log</span></code>. This will be used by the logging
 
986
machinery in the main process (even though the logging events are generated in
 
987
the worker processes) to direct the messages to the appropriate destinations.</p>
 
988
</div>
 
989
<div class="section" id="using-file-rotation">
 
990
<h2>Using file rotation<a class="headerlink" href="#using-file-rotation" title="Permalink to this headline">¶</a></h2>
 
991
<p>Sometimes you want to let a log file grow to a certain size, then open a new
 
992
file and log to that. You may want to keep a certain number of these files, and
 
993
when that many files have been created, rotate the files so that the number of
 
994
files and the size of the files both remain bounded. For this usage pattern, the
 
995
logging package provides a <code class="xref py py-class docutils literal"><span class="pre">RotatingFileHandler</span></code>:</p>
 
996
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">glob</span>
 
997
<span class="kn">import</span> <span class="nn">logging</span>
 
998
<span class="kn">import</span> <span class="nn">logging.handlers</span>
 
999
 
 
1000
<span class="n">LOG_FILENAME</span> <span class="o">=</span> <span class="s1">&#39;logging_rotatingfile_example.out&#39;</span>
 
1001
 
 
1002
<span class="c1"># Set up a specific logger with our desired output level</span>
 
1003
<span class="n">my_logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;MyLogger&#39;</span><span class="p">)</span>
 
1004
<span class="n">my_logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
1005
 
 
1006
<span class="c1"># Add the log message handler to the logger</span>
 
1007
<span class="n">handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">RotatingFileHandler</span><span class="p">(</span>
 
1008
              <span class="n">LOG_FILENAME</span><span class="p">,</span> <span class="n">maxBytes</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">backupCount</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
 
1009
 
 
1010
<span class="n">my_logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span>
 
1011
 
 
1012
<span class="c1"># Log some messages</span>
 
1013
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">):</span>
 
1014
    <span class="n">my_logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;i = </span><span class="si">%d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">i</span><span class="p">)</span>
 
1015
 
 
1016
<span class="c1"># See what files are created</span>
 
1017
<span class="n">logfiles</span> <span class="o">=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">*&#39;</span> <span class="o">%</span> <span class="n">LOG_FILENAME</span><span class="p">)</span>
 
1018
 
 
1019
<span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">logfiles</span><span class="p">:</span>
 
1020
    <span class="nb">print</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
 
1021
</pre></div>
 
1022
</div>
 
1023
<p>The result should be 6 separate files, each with part of the log history for the
 
1024
application:</p>
 
1025
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span>
 
1026
<span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="mi">1</span>
 
1027
<span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="mi">2</span>
 
1028
<span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="mi">3</span>
 
1029
<span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="mi">4</span>
 
1030
<span class="n">logging_rotatingfile_example</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="mi">5</span>
 
1031
</pre></div>
 
1032
</div>
 
1033
<p>The most current file is always <code class="file docutils literal"><span class="pre">logging_rotatingfile_example.out</span></code>,
 
1034
and each time it reaches the size limit it is renamed with the suffix
 
1035
<code class="docutils literal"><span class="pre">.1</span></code>. Each of the existing backup files is renamed to increment the suffix
 
1036
(<code class="docutils literal"><span class="pre">.1</span></code> becomes <code class="docutils literal"><span class="pre">.2</span></code>, etc.)  and the <code class="docutils literal"><span class="pre">.6</span></code> file is erased.</p>
 
1037
<p>Obviously this example sets the log length much too small as an extreme
 
1038
example.  You would want to set <em>maxBytes</em> to an appropriate value.</p>
 
1039
</div>
 
1040
<div class="section" id="use-of-alternative-formatting-styles">
 
1041
<span id="format-styles"></span><h2>Use of alternative formatting styles<a class="headerlink" href="#use-of-alternative-formatting-styles" title="Permalink to this headline">¶</a></h2>
 
1042
<p>When logging was added to the Python standard library, the only way of
 
1043
formatting messages with variable content was to use the %-formatting
 
1044
method. Since then, Python has gained two new formatting approaches:
 
1045
<a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a> (added in Python 2.4) and <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a>
 
1046
(added in Python 2.6).</p>
 
1047
<p>Logging (as of 3.2) provides improved support for these two additional
 
1048
formatting styles. The <code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code> class been enhanced to take an
 
1049
additional, optional keyword parameter named <code class="docutils literal"><span class="pre">style</span></code>. This defaults to
 
1050
<code class="docutils literal"><span class="pre">'%'</span></code>, but other possible values are <code class="docutils literal"><span class="pre">'{'</span></code> and <code class="docutils literal"><span class="pre">'$'</span></code>, which correspond
 
1051
to the other two formatting styles. Backwards compatibility is maintained by
 
1052
default (as you would expect), but by explicitly specifying a style parameter,
 
1053
you get the ability to specify format strings which work with
 
1054
<a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a> or <a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a>. Here&#8217;s an example console
 
1055
session to show the possibilities:</p>
 
1056
<div class="highlight-pycon"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">logging</span>
 
1057
<span class="gp">&gt;&gt;&gt; </span><span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
1058
<span class="gp">&gt;&gt;&gt; </span><span class="n">root</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
1059
<span class="gp">&gt;&gt;&gt; </span><span class="n">handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
1060
<span class="gp">&gt;&gt;&gt; </span><span class="n">bf</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;{asctime} {name} {levelname:8s} {message}&#39;</span><span class="p">,</span>
 
1061
<span class="gp">... </span>                       <span class="n">style</span><span class="o">=</span><span class="s1">&#39;{&#39;</span><span class="p">)</span>
 
1062
<span class="gp">&gt;&gt;&gt; </span><span class="n">handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">bf</span><span class="p">)</span>
 
1063
<span class="gp">&gt;&gt;&gt; </span><span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span>
 
1064
<span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;foo.bar&#39;</span><span class="p">)</span>
 
1065
<span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;This is a DEBUG message&#39;</span><span class="p">)</span>
 
1066
<span class="go">2010-10-28 15:11:55,341 foo.bar DEBUG    This is a DEBUG message</span>
 
1067
<span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;This is a CRITICAL message&#39;</span><span class="p">)</span>
 
1068
<span class="go">2010-10-28 15:12:11,526 foo.bar CRITICAL This is a CRITICAL message</span>
 
1069
<span class="gp">&gt;&gt;&gt; </span><span class="n">df</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;$asctime $name ${levelname} $message&#39;</span><span class="p">,</span>
 
1070
<span class="gp">... </span>                       <span class="n">style</span><span class="o">=</span><span class="s1">&#39;$&#39;</span><span class="p">)</span>
 
1071
<span class="gp">&gt;&gt;&gt; </span><span class="n">handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
 
1072
<span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;This is a DEBUG message&#39;</span><span class="p">)</span>
 
1073
<span class="go">2010-10-28 15:13:06,924 foo.bar DEBUG This is a DEBUG message</span>
 
1074
<span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;This is a CRITICAL message&#39;</span><span class="p">)</span>
 
1075
<span class="go">2010-10-28 15:13:11,494 foo.bar CRITICAL This is a CRITICAL message</span>
 
1076
<span class="go">&gt;&gt;&gt;</span>
 
1077
</pre></div>
 
1078
</div>
 
1079
<p>Note that the formatting of logging messages for final output to logs is
 
1080
completely independent of how an individual logging message is constructed.
 
1081
That can still use %-formatting, as shown here:</p>
 
1082
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;This is an</span><span class="si">%s</span><span class="s1"> </span><span class="si">%s</span><span class="s1"> </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;other,&#39;</span><span class="p">,</span> <span class="s1">&#39;ERROR,&#39;</span><span class="p">,</span> <span class="s1">&#39;message&#39;</span><span class="p">)</span>
 
1083
<span class="go">2010-10-28 15:19:29,833 foo.bar ERROR This is another, ERROR, message</span>
 
1084
<span class="go">&gt;&gt;&gt;</span>
 
1085
</pre></div>
 
1086
</div>
 
1087
<p>Logging calls (<code class="docutils literal"><span class="pre">logger.debug()</span></code>, <code class="docutils literal"><span class="pre">logger.info()</span></code> etc.) only take
 
1088
positional parameters for the actual logging message itself, with keyword
 
1089
parameters used only for determining options for how to handle the actual
 
1090
logging call (e.g. the <code class="docutils literal"><span class="pre">exc_info</span></code> keyword parameter to indicate that
 
1091
traceback information should be logged, or the <code class="docutils literal"><span class="pre">extra</span></code> keyword parameter
 
1092
to indicate additional contextual information to be added to the log). So
 
1093
you cannot directly make logging calls using <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a> or
 
1094
<a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a> syntax, because internally the logging package
 
1095
uses %-formatting to merge the format string and the variable arguments.
 
1096
There would no changing this while preserving backward compatibility, since
 
1097
all logging calls which are out there in existing code will be using %-format
 
1098
strings.</p>
 
1099
<p>There is, however, a way that you can use {}- and $- formatting to construct
 
1100
your individual log messages. Recall that for a message you can use an
 
1101
arbitrary object as a message format string, and that the logging package will
 
1102
call <code class="docutils literal"><span class="pre">str()</span></code> on that object to get the actual format string. Consider the
 
1103
following two classes:</p>
 
1104
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BraceMessage</span><span class="p">:</span>
 
1105
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fmt</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>
 
1106
        <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span> <span class="o">=</span> <span class="n">fmt</span>
 
1107
        <span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="n">args</span>
 
1108
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1109
 
 
1110
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1111
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
 
1112
 
 
1113
<span class="k">class</span> <span class="nc">DollarMessage</span><span class="p">:</span>
 
1114
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fmt</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
 
1115
        <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span> <span class="o">=</span> <span class="n">fmt</span>
 
1116
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1117
 
 
1118
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1119
        <span class="kn">from</span> <span class="nn">string</span> <span class="k">import</span> <span class="n">Template</span>
 
1120
        <span class="k">return</span> <span class="n">Template</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fmt</span><span class="p">)</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
 
1121
</pre></div>
 
1122
</div>
 
1123
<p>Either of these can be used in place of a format string, to allow {}- or
 
1124
$-formatting to be used to build the actual &#8220;message&#8221; part which appears in the
 
1125
formatted log output in place of &#8220;%(message)s&#8221; or &#8220;{message}&#8221; or &#8220;$message&#8221;.
 
1126
It&#8217;s a little unwieldy to use the class names whenever you want to log
 
1127
something, but it&#8217;s quite palatable if you use an alias such as __ (double
 
1128
underscore – not to be confused with _, the single underscore used as a
 
1129
synonym/alias for <a class="reference internal" href="../library/gettext.html#gettext.gettext" title="gettext.gettext"><code class="xref py py-func docutils literal"><span class="pre">gettext.gettext()</span></code></a> or its brethren).</p>
 
1130
<p>The above classes are not included in Python, though they&#8217;re easy enough to
 
1131
copy and paste into your own code. They can be used as follows (assuming that
 
1132
they&#8217;re declared in a module called <code class="docutils literal"><span class="pre">wherever</span></code>):</p>
 
1133
<div class="highlight-pycon"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">wherever</span> <span class="kn">import</span> <span class="n">BraceMessage</span> <span class="k">as</span> <span class="n">__</span>
 
1134
<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with {0} {name}&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;placeholders&#39;</span><span class="p">))</span>
 
1135
<span class="go">Message with 2 placeholders</span>
 
1136
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Point</span><span class="p">:</span> <span class="k">pass</span>
 
1137
<span class="gp">...</span>
 
1138
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span> <span class="o">=</span> <span class="n">Point</span><span class="p">()</span>
 
1139
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mf">0.5</span>
 
1140
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="mf">0.5</span>
 
1141
<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with coordinates: ({point.x:.2f}, {point.y:.2f})&#39;</span><span class="p">,</span>
 
1142
<span class="gp">... </span>      <span class="n">point</span><span class="o">=</span><span class="n">p</span><span class="p">))</span>
 
1143
<span class="go">Message with coordinates: (0.50, 0.50)</span>
 
1144
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">wherever</span> <span class="kn">import</span> <span class="n">DollarMessage</span> <span class="k">as</span> <span class="n">__</span>
 
1145
<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with $num $what&#39;</span><span class="p">,</span> <span class="n">num</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">what</span><span class="o">=</span><span class="s1">&#39;placeholders&#39;</span><span class="p">))</span>
 
1146
<span class="go">Message with 2 placeholders</span>
 
1147
<span class="go">&gt;&gt;&gt;</span>
 
1148
</pre></div>
 
1149
</div>
 
1150
<p>While the above examples use <code class="docutils literal"><span class="pre">print()</span></code> to show how the formatting works, you
 
1151
would of course use <code class="docutils literal"><span class="pre">logger.debug()</span></code> or similar to actually log using this
 
1152
approach.</p>
 
1153
<p>One thing to note is that you pay no significant performance penalty with this
 
1154
approach: the actual formatting happens not when you make the logging call, but
 
1155
when (and if) the logged message is actually about to be output to a log by a
 
1156
handler. So the only slightly unusual thing which might trip you up is that the
 
1157
parentheses go around the format string and the arguments, not just the format
 
1158
string. That&#8217;s because the __ notation is just syntax sugar for a constructor
 
1159
call to one of the XXXMessage classes.</p>
 
1160
<p>If you prefer, you can use a <code class="xref py py-class docutils literal"><span class="pre">LoggerAdapter</span></code> to achieve a similar effect
 
1161
to the above, as in the following example:</p>
 
1162
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
1163
 
 
1164
<span class="k">class</span> <span class="nc">Message</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
1165
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fmt</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
 
1166
        <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span> <span class="o">=</span> <span class="n">fmt</span>
 
1167
        <span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="n">args</span>
 
1168
 
 
1169
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1170
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
 
1171
 
 
1172
<span class="k">class</span> <span class="nc">StyleAdapter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">LoggerAdapter</span><span class="p">):</span>
 
1173
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">logger</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
1174
        <span class="nb">super</span><span class="p">(</span><span class="n">StyleAdapter</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="n">extra</span> <span class="ow">or</span> <span class="p">{})</span>
 
1175
 
 
1176
    <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">level</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>
 
1177
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">isEnabledFor</span><span class="p">(</span><span class="n">level</span><span class="p">):</span>
 
1178
            <span class="n">msg</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
 
1179
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">_log</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">Message</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">args</span><span class="p">),</span> <span class="p">(),</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
 
1180
 
 
1181
<span class="n">logger</span> <span class="o">=</span> <span class="n">StyleAdapter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">))</span>
 
1182
 
 
1183
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
1184
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Hello, </span><span class="si">{}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;world!&#39;</span><span class="p">)</span>
 
1185
 
 
1186
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
1187
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
1188
    <span class="n">main</span><span class="p">()</span>
 
1189
</pre></div>
 
1190
</div>
 
1191
<p>The above script should log the message <code class="docutils literal"><span class="pre">Hello,</span> <span class="pre">world!</span></code> when run with
 
1192
Python 3.2 or later.</p>
 
1193
</div>
 
1194
<div class="section" id="customizing-logrecord">
 
1195
<span id="custom-logrecord"></span><h2>Customizing <code class="docutils literal"><span class="pre">LogRecord</span></code><a class="headerlink" href="#customizing-logrecord" title="Permalink to this headline">¶</a></h2>
 
1196
<p>Every logging event is represented by a <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> instance.
 
1197
When an event is logged and not filtered out by a logger&#8217;s level, a
 
1198
<a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> is created, populated with information about the event and
 
1199
then passed to the handlers for that logger (and its ancestors, up to and
 
1200
including the logger where further propagation up the hierarchy is disabled).
 
1201
Before Python 3.2, there were only two places where this creation was done:</p>
 
1202
<ul class="simple">
 
1203
<li><a class="reference internal" href="../library/logging.html#logging.Logger.makeRecord" title="logging.Logger.makeRecord"><code class="xref py py-meth docutils literal"><span class="pre">Logger.makeRecord()</span></code></a>, which is called in the normal process of
 
1204
logging an event. This invoked <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> directly to create an
 
1205
instance.</li>
 
1206
<li><a class="reference internal" href="../library/logging.html#logging.makeLogRecord" title="logging.makeLogRecord"><code class="xref py py-func docutils literal"><span class="pre">makeLogRecord()</span></code></a>, which is called with a dictionary containing
 
1207
attributes to be added to the LogRecord. This is typically invoked when a
 
1208
suitable dictionary has been received over the network (e.g. in pickle form
 
1209
via a <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></code></a>, or in JSON form via an
 
1210
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.HTTPHandler" title="logging.handlers.HTTPHandler"><code class="xref py py-class docutils literal"><span class="pre">HTTPHandler</span></code></a>).</li>
 
1211
</ul>
 
1212
<p>This has usually meant that if you need to do anything special with a
 
1213
<a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a>, you&#8217;ve had to do one of the following.</p>
 
1214
<ul class="simple">
 
1215
<li>Create your own <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal"><span class="pre">Logger</span></code></a> subclass, which overrides
 
1216
<a class="reference internal" href="../library/logging.html#logging.Logger.makeRecord" title="logging.Logger.makeRecord"><code class="xref py py-meth docutils literal"><span class="pre">Logger.makeRecord()</span></code></a>, and set it using <a class="reference internal" href="../library/logging.html#logging.setLoggerClass" title="logging.setLoggerClass"><code class="xref py py-func docutils literal"><span class="pre">setLoggerClass()</span></code></a>
 
1217
before any loggers that you care about are instantiated.</li>
 
1218
<li>Add a <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal"><span class="pre">Filter</span></code></a> to a logger or handler, which does the
 
1219
necessary special manipulation you need when its
 
1220
<a class="reference internal" href="../library/logging.html#logging.Filter.filter" title="logging.Filter.filter"><code class="xref py py-meth docutils literal"><span class="pre">filter()</span></code></a> method is called.</li>
 
1221
</ul>
 
1222
<p>The first approach would be a little unwieldy in the scenario where (say)
 
1223
several different libraries wanted to do different things. Each would attempt
 
1224
to set its own <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal"><span class="pre">Logger</span></code></a> subclass, and the one which did this last would
 
1225
win.</p>
 
1226
<p>The second approach works reasonably well for many cases, but does not allow
 
1227
you to e.g. use a specialized subclass of <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a>. Library
 
1228
developers can set a suitable filter on their loggers, but they would have to
 
1229
remember to do this every time they introduced a new logger (which they would
 
1230
do simply by adding new packages or modules and doing</p>
 
1231
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
 
1232
</pre></div>
 
1233
</div>
 
1234
<p>at module level). It&#8217;s probably one too many things to think about. Developers
 
1235
could also add the filter to a <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal"><span class="pre">NullHandler</span></code></a> attached to their
 
1236
top-level logger, but this would not be invoked if an application developer
 
1237
attached a handler to a lower-level library logger – so output from that
 
1238
handler would not reflect the intentions of the library developer.</p>
 
1239
<p>In Python 3.2 and later, <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> creation is done through a
 
1240
factory, which you can specify. The factory is just a callable you can set with
 
1241
<a class="reference internal" href="../library/logging.html#logging.setLogRecordFactory" title="logging.setLogRecordFactory"><code class="xref py py-func docutils literal"><span class="pre">setLogRecordFactory()</span></code></a>, and interrogate with
 
1242
<a class="reference internal" href="../library/logging.html#logging.getLogRecordFactory" title="logging.getLogRecordFactory"><code class="xref py py-func docutils literal"><span class="pre">getLogRecordFactory()</span></code></a>. The factory is invoked with the same
 
1243
signature as the <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> constructor, as <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a>
 
1244
is the default setting for the factory.</p>
 
1245
<p>This approach allows a custom factory to control all aspects of LogRecord
 
1246
creation. For example, you could return a subclass, or just add some additional
 
1247
attributes to the record once created, using a pattern similar to this:</p>
 
1248
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">old_factory</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogRecordFactory</span><span class="p">()</span>
 
1249
 
 
1250
<span class="k">def</span> <span class="nf">record_factory</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>
 
1251
    <span class="n">record</span> <span class="o">=</span> <span class="n">old_factory</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>
 
1252
    <span class="n">record</span><span class="o">.</span><span class="n">custom_attribute</span> <span class="o">=</span> <span class="mh">0xdecafbad</span>
 
1253
    <span class="k">return</span> <span class="n">record</span>
 
1254
 
 
1255
<span class="n">logging</span><span class="o">.</span><span class="n">setLogRecordFactory</span><span class="p">(</span><span class="n">record_factory</span><span class="p">)</span>
 
1256
</pre></div>
 
1257
</div>
 
1258
<p>This pattern allows different libraries to chain factories together, and as
 
1259
long as they don&#8217;t overwrite each other&#8217;s attributes or unintentionally
 
1260
overwrite the attributes provided as standard, there should be no surprises.
 
1261
However, it should be borne in mind that each link in the chain adds run-time
 
1262
overhead to all logging operations, and the technique should only be used when
 
1263
the use of a <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal"><span class="pre">Filter</span></code></a> does not provide the desired result.</p>
 
1264
</div>
 
1265
<div class="section" id="subclassing-queuehandler-a-zeromq-example">
 
1266
<span id="zeromq-handlers"></span><h2>Subclassing QueueHandler - a ZeroMQ example<a class="headerlink" href="#subclassing-queuehandler-a-zeromq-example" title="Permalink to this headline">¶</a></h2>
 
1267
<p>You can use a <code class="xref py py-class docutils literal"><span class="pre">QueueHandler</span></code> subclass to send messages to other kinds
 
1268
of queues, for example a ZeroMQ &#8216;publish&#8217; socket. In the example below,the
 
1269
socket is created separately and passed to the handler (as its &#8216;queue&#8217;):</p>
 
1270
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">zmq</span>   <span class="c1"># using pyzmq, the Python binding for ZeroMQ</span>
 
1271
<span class="kn">import</span> <span class="nn">json</span>  <span class="c1"># for serializing records portably</span>
 
1272
 
 
1273
<span class="n">ctx</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Context</span><span class="p">()</span>
 
1274
<span class="n">sock</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Socket</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">zmq</span><span class="o">.</span><span class="n">PUB</span><span class="p">)</span>  <span class="c1"># or zmq.PUSH, or other suitable value</span>
 
1275
<span class="n">sock</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="s1">&#39;tcp://*:5556&#39;</span><span class="p">)</span>        <span class="c1"># or wherever</span>
 
1276
 
 
1277
<span class="k">class</span> <span class="nc">ZeroMQSocketHandler</span><span class="p">(</span><span class="n">QueueHandler</span><span class="p">):</span>
 
1278
    <span class="k">def</span> <span class="nf">enqueue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
1279
        <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">record</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span>
 
1280
        <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
 
1281
 
 
1282
<span class="n">handler</span> <span class="o">=</span> <span class="n">ZeroMQSocketHandler</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
 
1283
</pre></div>
 
1284
</div>
 
1285
<p>Of course there are other ways of organizing this, for example passing in the
 
1286
data needed by the handler to create the socket:</p>
 
1287
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ZeroMQSocketHandler</span><span class="p">(</span><span class="n">QueueHandler</span><span class="p">):</span>
 
1288
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uri</span><span class="p">,</span> <span class="n">socktype</span><span class="o">=</span><span class="n">zmq</span><span class="o">.</span><span class="n">PUB</span><span class="p">,</span> <span class="n">ctx</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
1289
        <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span> <span class="o">=</span> <span class="n">ctx</span> <span class="ow">or</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Context</span><span class="p">()</span>
 
1290
        <span class="n">socket</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Socket</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="p">,</span> <span class="n">socktype</span><span class="p">)</span>
 
1291
        <span class="n">socket</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
 
1292
        <span class="n">QueueHandler</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">socket</span><span class="p">)</span>
 
1293
 
 
1294
    <span class="k">def</span> <span class="nf">enqueue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
1295
        <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">record</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span>
 
1296
        <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
 
1297
 
 
1298
    <span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1299
        <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
 
1300
</pre></div>
 
1301
</div>
 
1302
</div>
 
1303
<div class="section" id="subclassing-queuelistener-a-zeromq-example">
 
1304
<h2>Subclassing QueueListener - a ZeroMQ example<a class="headerlink" href="#subclassing-queuelistener-a-zeromq-example" title="Permalink to this headline">¶</a></h2>
 
1305
<p>You can also subclass <code class="xref py py-class docutils literal"><span class="pre">QueueListener</span></code> to get messages from other kinds
 
1306
of queues, for example a ZeroMQ &#8216;subscribe&#8217; socket. Here&#8217;s an example:</p>
 
1307
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ZeroMQSocketListener</span><span class="p">(</span><span class="n">QueueListener</span><span class="p">):</span>
 
1308
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uri</span><span class="p">,</span> <span class="o">*</span><span class="n">handlers</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
 
1309
        <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;ctx&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Context</span><span class="p">()</span>
 
1310
        <span class="n">socket</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Socket</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="p">,</span> <span class="n">zmq</span><span class="o">.</span><span class="n">SUB</span><span class="p">)</span>
 
1311
        <span class="n">socket</span><span class="o">.</span><span class="n">setsockopt</span><span class="p">(</span><span class="n">zmq</span><span class="o">.</span><span class="n">SUBSCRIBE</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>  <span class="c1"># subscribe to everything</span>
 
1312
        <span class="n">socket</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
 
1313
 
 
1314
    <span class="k">def</span> <span class="nf">dequeue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1315
        <span class="n">msg</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">queue</span><span class="o">.</span><span class="n">recv</span><span class="p">()</span>
 
1316
        <span class="k">return</span> <span class="n">logging</span><span class="o">.</span><span class="n">makeLogRecord</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">msg</span><span class="p">))</span>
 
1317
</pre></div>
 
1318
</div>
 
1319
<div class="admonition seealso">
 
1320
<p class="first admonition-title">See also</p>
 
1321
<dl class="docutils">
 
1322
<dt>Module <a class="reference internal" href="../library/logging.html#module-logging" title="logging: Flexible event logging system for applications."><code class="xref py py-mod docutils literal"><span class="pre">logging</span></code></a></dt>
 
1323
<dd>API reference for the logging module.</dd>
 
1324
<dt>Module <a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal"><span class="pre">logging.config</span></code></a></dt>
 
1325
<dd>Configuration API for the logging module.</dd>
 
1326
<dt>Module <a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal"><span class="pre">logging.handlers</span></code></a></dt>
 
1327
<dd>Useful handlers included with the logging module.</dd>
 
1328
</dl>
 
1329
<p><a class="reference internal" href="logging.html#logging-basic-tutorial"><span>A basic logging tutorial</span></a></p>
 
1330
<p class="last"><a class="reference internal" href="logging.html#logging-advanced-tutorial"><span>A more advanced logging tutorial</span></a></p>
 
1331
</div>
 
1332
</div>
 
1333
<div class="section" id="an-example-dictionary-based-configuration">
 
1334
<h2>An example dictionary-based configuration<a class="headerlink" href="#an-example-dictionary-based-configuration" title="Permalink to this headline">¶</a></h2>
 
1335
<p>Below is an example of a logging configuration dictionary - it&#8217;s taken from
 
1336
the <a class="reference external" href="https://docs.djangoproject.com/en/1.9/topics/logging/#configuring-logging">documentation on the Django project</a>.
 
1337
This dictionary is passed to <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a> to put the configuration into effect:</p>
 
1338
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
 
1339
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1340
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
 
1341
    <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1342
        <span class="s1">&#39;verbose&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1343
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(module)s</span><span class="s1"> </span><span class="si">%(process)d</span><span class="s1"> </span><span class="si">%(thread)d</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1344
        <span class="p">},</span>
 
1345
        <span class="s1">&#39;simple&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1346
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1347
        <span class="p">},</span>
 
1348
    <span class="p">},</span>
 
1349
    <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1350
        <span class="s1">&#39;special&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1351
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;project.logging.SpecialFilter&#39;</span><span class="p">,</span>
 
1352
            <span class="s1">&#39;foo&#39;</span><span class="p">:</span> <span class="s1">&#39;bar&#39;</span><span class="p">,</span>
 
1353
        <span class="p">}</span>
 
1354
    <span class="p">},</span>
 
1355
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1356
        <span class="s1">&#39;null&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1357
            <span class="s1">&#39;level&#39;</span><span class="p">:</span><span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1358
            <span class="s1">&#39;class&#39;</span><span class="p">:</span><span class="s1">&#39;django.utils.log.NullHandler&#39;</span><span class="p">,</span>
 
1359
        <span class="p">},</span>
 
1360
        <span class="s1">&#39;console&#39;</span><span class="p">:{</span>
 
1361
            <span class="s1">&#39;level&#39;</span><span class="p">:</span><span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1362
            <span class="s1">&#39;class&#39;</span><span class="p">:</span><span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
1363
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;simple&#39;</span>
 
1364
        <span class="p">},</span>
 
1365
        <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1366
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
 
1367
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class="p">,</span>
 
1368
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;special&#39;</span><span class="p">]</span>
 
1369
        <span class="p">}</span>
 
1370
    <span class="p">},</span>
 
1371
    <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1372
        <span class="s1">&#39;django&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1373
            <span class="s1">&#39;handlers&#39;</span><span class="p">:[</span><span class="s1">&#39;null&#39;</span><span class="p">],</span>
 
1374
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
 
1375
            <span class="s1">&#39;level&#39;</span><span class="p">:</span><span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
 
1376
        <span class="p">},</span>
 
1377
        <span class="s1">&#39;django.request&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1378
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;mail_admins&#39;</span><span class="p">],</span>
 
1379
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
 
1380
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
 
1381
        <span class="p">},</span>
 
1382
        <span class="s1">&#39;myproject.custom&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1383
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="s1">&#39;mail_admins&#39;</span><span class="p">],</span>
 
1384
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
 
1385
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;special&#39;</span><span class="p">]</span>
 
1386
        <span class="p">}</span>
 
1387
    <span class="p">}</span>
 
1388
<span class="p">}</span>
 
1389
</pre></div>
 
1390
</div>
 
1391
<p>For more information about this configuration, you can see the <a class="reference external" href="https://docs.djangoproject.com/en/1.9/topics/logging/#configuring-logging">relevant
 
1392
section</a>
 
1393
of the Django documentation.</p>
 
1394
</div>
 
1395
<div class="section" id="using-a-rotator-and-namer-to-customize-log-rotation-processing">
 
1396
<span id="cookbook-rotator-namer"></span><h2>Using a rotator and namer to customize log rotation processing<a class="headerlink" href="#using-a-rotator-and-namer-to-customize-log-rotation-processing" title="Permalink to this headline">¶</a></h2>
 
1397
<p>An example of how you can define a namer and rotator is given in the following
 
1398
snippet, which shows zlib-based compression of the log file:</p>
 
1399
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">namer</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
 
1400
    <span class="k">return</span> <span class="n">name</span> <span class="o">+</span> <span class="s2">&quot;.gz&quot;</span>
 
1401
 
 
1402
<span class="k">def</span> <span class="nf">rotator</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">dest</span><span class="p">):</span>
 
1403
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="s2">&quot;rb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">sf</span><span class="p">:</span>
 
1404
        <span class="n">data</span> <span class="o">=</span> <span class="n">sf</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
 
1405
        <span class="n">compressed</span> <span class="o">=</span> <span class="n">zlib</span><span class="o">.</span><span class="n">compress</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
 
1406
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="s2">&quot;wb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">df</span><span class="p">:</span>
 
1407
            <span class="n">df</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">compressed</span><span class="p">)</span>
 
1408
    <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
 
1409
 
 
1410
<span class="n">rh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">RotatingFileHandler</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
 
1411
<span class="n">rh</span><span class="o">.</span><span class="n">rotator</span> <span class="o">=</span> <span class="n">rotator</span>
 
1412
<span class="n">rh</span><span class="o">.</span><span class="n">namer</span> <span class="o">=</span> <span class="n">namer</span>
 
1413
</pre></div>
 
1414
</div>
 
1415
<p>These are not &#8220;true&#8221; .gz files, as they are bare compressed data, with no
 
1416
&#8220;container&#8221; such as you’d find in an actual gzip file. This snippet is just
 
1417
for illustration purposes.</p>
 
1418
</div>
 
1419
<div class="section" id="a-more-elaborate-multiprocessing-example">
 
1420
<h2>A more elaborate multiprocessing example<a class="headerlink" href="#a-more-elaborate-multiprocessing-example" title="Permalink to this headline">¶</a></h2>
 
1421
<p>The following working example shows how logging can be used with multiprocessing
 
1422
using configuration files. The configurations are fairly simple, but serve to
 
1423
illustrate how more complex ones could be implemented in a real multiprocessing
 
1424
scenario.</p>
 
1425
<p>In the example, the main process spawns a listener process and some worker
 
1426
processes. Each of the main process, the listener and the workers have three
 
1427
separate configurations (the workers all share the same configuration). We can
 
1428
see logging in the main process, how the workers log to a QueueHandler and how
 
1429
the listener implements a QueueListener and a more complex logging
 
1430
configuration, and arranges to dispatch events received via the queue to the
 
1431
handlers specified in the configuration. Note that these configurations are
 
1432
purely illustrative, but you should be able to adapt this example to your own
 
1433
scenario.</p>
 
1434
<p>Here&#8217;s the script - the docstrings and the comments hopefully explain how it
 
1435
works:</p>
 
1436
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
1437
<span class="kn">import</span> <span class="nn">logging.config</span>
 
1438
<span class="kn">import</span> <span class="nn">logging.handlers</span>
 
1439
<span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="k">import</span> <span class="n">Process</span><span class="p">,</span> <span class="n">Queue</span><span class="p">,</span> <span class="n">Event</span><span class="p">,</span> <span class="n">current_process</span>
 
1440
<span class="kn">import</span> <span class="nn">os</span>
 
1441
<span class="kn">import</span> <span class="nn">random</span>
 
1442
<span class="kn">import</span> <span class="nn">time</span>
 
1443
 
 
1444
<span class="k">class</span> <span class="nc">MyHandler</span><span class="p">:</span>
 
1445
    <span class="sd">&quot;&quot;&quot;</span>
 
1446
<span class="sd">    A simple handler for logging events. It runs in the listener process and</span>
 
1447
<span class="sd">    dispatches events to loggers based on the name in the received record,</span>
 
1448
<span class="sd">    which then get dispatched, by the logging system, to the handlers</span>
 
1449
<span class="sd">    configured for those loggers.</span>
 
1450
<span class="sd">    &quot;&quot;&quot;</span>
 
1451
    <span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
1452
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">record</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
 
1453
        <span class="c1"># The process name is transformed just to show that it&#39;s the listener</span>
 
1454
        <span class="c1"># doing the logging to files and console</span>
 
1455
        <span class="n">record</span><span class="o">.</span><span class="n">processName</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> (for </span><span class="si">%s</span><span class="s1">)&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">current_process</span><span class="p">()</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">record</span><span class="o">.</span><span class="n">processName</span><span class="p">)</span>
 
1456
        <span class="n">logger</span><span class="o">.</span><span class="n">handle</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
1457
 
 
1458
<span class="k">def</span> <span class="nf">listener_process</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">config</span><span class="p">):</span>
 
1459
    <span class="sd">&quot;&quot;&quot;</span>
 
1460
<span class="sd">    This could be done in the main process, but is just done in a separate</span>
 
1461
<span class="sd">    process for illustrative purposes.</span>
 
1462
 
 
1463
<span class="sd">    This initialises logging according to the specified configuration,</span>
 
1464
<span class="sd">    starts the listener and waits for the main process to signal completion</span>
 
1465
<span class="sd">    via the event. The listener is then stopped, and the process exits.</span>
 
1466
<span class="sd">    &quot;&quot;&quot;</span>
 
1467
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
 
1468
    <span class="n">listener</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">QueueListener</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">MyHandler</span><span class="p">())</span>
 
1469
    <span class="n">listener</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
1470
    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s1">&#39;posix&#39;</span><span class="p">:</span>
 
1471
        <span class="c1"># On POSIX, the setup logger will have been configured in the</span>
 
1472
        <span class="c1"># parent process, but should have been disabled following the</span>
 
1473
        <span class="c1"># dictConfig call.</span>
 
1474
        <span class="c1"># On Windows, since fork isn&#39;t used, the setup logger won&#39;t</span>
 
1475
        <span class="c1"># exist in the child, so it would be created and the message</span>
 
1476
        <span class="c1"># would appear - hence the &quot;if posix&quot; clause.</span>
 
1477
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;setup&#39;</span><span class="p">)</span>
 
1478
        <span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;Should not appear, because of disabled logger ...&#39;</span><span class="p">)</span>
 
1479
    <span class="n">stop_event</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
 
1480
    <span class="n">listener</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
 
1481
 
 
1482
<span class="k">def</span> <span class="nf">worker_process</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
 
1483
    <span class="sd">&quot;&quot;&quot;</span>
 
1484
<span class="sd">    A number of these are spawned for the purpose of illustration. In</span>
 
1485
<span class="sd">    practice, they could be a heterogeneous bunch of processes rather than</span>
 
1486
<span class="sd">    ones which are identical to each other.</span>
 
1487
 
 
1488
<span class="sd">    This initialises logging according to the specified configuration,</span>
 
1489
<span class="sd">    and logs a hundred messages with random levels to randomly selected</span>
 
1490
<span class="sd">    loggers.</span>
 
1491
 
 
1492
<span class="sd">    A small sleep is added to allow other processes a chance to run. This</span>
 
1493
<span class="sd">    is not strictly needed, but it mixes the output from the different</span>
 
1494
<span class="sd">    processes a bit more than if it&#39;s left out.</span>
 
1495
<span class="sd">    &quot;&quot;&quot;</span>
 
1496
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
 
1497
    <span class="n">levels</span> <span class="o">=</span> <span class="p">[</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span> <span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">,</span>
 
1498
              <span class="n">logging</span><span class="o">.</span><span class="n">CRITICAL</span><span class="p">]</span>
 
1499
    <span class="n">loggers</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="s1">&#39;foo.bar&#39;</span><span class="p">,</span> <span class="s1">&#39;foo.bar.baz&#39;</span><span class="p">,</span>
 
1500
               <span class="s1">&#39;spam&#39;</span><span class="p">,</span> <span class="s1">&#39;spam.ham&#39;</span><span class="p">,</span> <span class="s1">&#39;spam.ham.eggs&#39;</span><span class="p">]</span>
 
1501
    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s1">&#39;posix&#39;</span><span class="p">:</span>
 
1502
        <span class="c1"># On POSIX, the setup logger will have been configured in the</span>
 
1503
        <span class="c1"># parent process, but should have been disabled following the</span>
 
1504
        <span class="c1"># dictConfig call.</span>
 
1505
        <span class="c1"># On Windows, since fork isn&#39;t used, the setup logger won&#39;t</span>
 
1506
        <span class="c1"># exist in the child, so it would be created and the message</span>
 
1507
        <span class="c1"># would appear - hence the &quot;if posix&quot; clause.</span>
 
1508
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;setup&#39;</span><span class="p">)</span>
 
1509
        <span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;Should not appear, because of disabled logger ...&#39;</span><span class="p">)</span>
 
1510
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span>
 
1511
        <span class="n">lvl</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">levels</span><span class="p">)</span>
 
1512
        <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">loggers</span><span class="p">))</span>
 
1513
        <span class="n">logger</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">lvl</span><span class="p">,</span> <span class="s1">&#39;Message no. </span><span class="si">%d</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
 
1514
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.01</span><span class="p">)</span>
 
1515
 
 
1516
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
1517
    <span class="n">q</span> <span class="o">=</span> <span class="n">Queue</span><span class="p">()</span>
 
1518
    <span class="c1"># The main process gets a simple configuration which prints to the console.</span>
 
1519
    <span class="n">config_initial</span> <span class="o">=</span> <span class="p">{</span>
 
1520
        <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1521
        <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1522
            <span class="s1">&#39;detailed&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1523
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.Formatter&#39;</span><span class="p">,</span>
 
1524
                <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(processName)-10s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1525
            <span class="p">}</span>
 
1526
        <span class="p">},</span>
 
1527
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1528
            <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1529
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
1530
                <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
 
1531
            <span class="p">},</span>
 
1532
        <span class="p">},</span>
 
1533
        <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1534
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1535
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">]</span>
 
1536
        <span class="p">},</span>
 
1537
    <span class="p">}</span>
 
1538
    <span class="c1"># The worker process configuration is just a QueueHandler attached to the</span>
 
1539
    <span class="c1"># root logger, which allows all messages to be sent to the queue.</span>
 
1540
    <span class="c1"># We disable existing loggers to disable the &quot;setup&quot; logger used in the</span>
 
1541
    <span class="c1"># parent process. This is needed on POSIX because the logger will</span>
 
1542
    <span class="c1"># be there in the child following a fork().</span>
 
1543
    <span class="n">config_worker</span> <span class="o">=</span> <span class="p">{</span>
 
1544
        <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1545
        <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
 
1546
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1547
            <span class="s1">&#39;queue&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1548
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.handlers.QueueHandler&#39;</span><span class="p">,</span>
 
1549
                <span class="s1">&#39;queue&#39;</span><span class="p">:</span> <span class="n">q</span><span class="p">,</span>
 
1550
            <span class="p">},</span>
 
1551
        <span class="p">},</span>
 
1552
        <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1553
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1554
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;queue&#39;</span><span class="p">]</span>
 
1555
        <span class="p">},</span>
 
1556
    <span class="p">}</span>
 
1557
    <span class="c1"># The listener process configuration shows that the full flexibility of</span>
 
1558
    <span class="c1"># logging configuration is available to dispatch events to handlers however</span>
 
1559
    <span class="c1"># you want.</span>
 
1560
    <span class="c1"># We disable existing loggers to disable the &quot;setup&quot; logger used in the</span>
 
1561
    <span class="c1"># parent process. This is needed on POSIX because the logger will</span>
 
1562
    <span class="c1"># be there in the child following a fork().</span>
 
1563
    <span class="n">config_listener</span> <span class="o">=</span> <span class="p">{</span>
 
1564
        <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1565
        <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
 
1566
        <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1567
            <span class="s1">&#39;detailed&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1568
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.Formatter&#39;</span><span class="p">,</span>
 
1569
                <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(processName)-10s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1570
            <span class="p">},</span>
 
1571
            <span class="s1">&#39;simple&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1572
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.Formatter&#39;</span><span class="p">,</span>
 
1573
                <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(name)-15s</span><span class="s1"> </span><span class="si">%(levelname)-8s</span><span class="s1"> </span><span class="si">%(processName)-10s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1574
            <span class="p">}</span>
 
1575
        <span class="p">},</span>
 
1576
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1577
            <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1578
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
1579
                <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
 
1580
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;simple&#39;</span><span class="p">,</span>
 
1581
            <span class="p">},</span>
 
1582
            <span class="s1">&#39;file&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1583
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
1584
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog.log&#39;</span><span class="p">,</span>
 
1585
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
1586
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
1587
            <span class="p">},</span>
 
1588
            <span class="s1">&#39;foofile&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1589
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
1590
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog-foo.log&#39;</span><span class="p">,</span>
 
1591
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
1592
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
1593
            <span class="p">},</span>
 
1594
            <span class="s1">&#39;errors&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1595
                <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
 
1596
                <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;mplog-errors.log&#39;</span><span class="p">,</span>
 
1597
                <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
1598
                <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
 
1599
                <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;detailed&#39;</span><span class="p">,</span>
 
1600
            <span class="p">},</span>
 
1601
        <span class="p">},</span>
 
1602
        <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1603
            <span class="s1">&#39;foo&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1604
                <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;foofile&#39;</span><span class="p">]</span>
 
1605
            <span class="p">}</span>
 
1606
        <span class="p">},</span>
 
1607
        <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1608
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1609
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="s1">&#39;errors&#39;</span><span class="p">]</span>
 
1610
        <span class="p">},</span>
 
1611
    <span class="p">}</span>
 
1612
    <span class="c1"># Log some initial events, just to show that logging in the parent works</span>
 
1613
    <span class="c1"># normally.</span>
 
1614
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">config_initial</span><span class="p">)</span>
 
1615
    <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;setup&#39;</span><span class="p">)</span>
 
1616
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;About to create workers ...&#39;</span><span class="p">)</span>
 
1617
    <span class="n">workers</span> <span class="o">=</span> <span class="p">[]</span>
 
1618
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
 
1619
        <span class="n">wp</span> <span class="o">=</span> <span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">worker_process</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;worker </span><span class="si">%d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span>
 
1620
                     <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">config_worker</span><span class="p">,))</span>
 
1621
        <span class="n">workers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">wp</span><span class="p">)</span>
 
1622
        <span class="n">wp</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
1623
        <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Started worker: </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">wp</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
 
1624
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;About to create listener ...&#39;</span><span class="p">)</span>
 
1625
    <span class="n">stop_event</span> <span class="o">=</span> <span class="n">Event</span><span class="p">()</span>
 
1626
    <span class="n">lp</span> <span class="o">=</span> <span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">listener_process</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;listener&#39;</span><span class="p">,</span>
 
1627
                 <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">config_listener</span><span class="p">))</span>
 
1628
    <span class="n">lp</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
 
1629
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Started listener&#39;</span><span class="p">)</span>
 
1630
    <span class="c1"># We now hang around for the workers to finish their work.</span>
 
1631
    <span class="k">for</span> <span class="n">wp</span> <span class="ow">in</span> <span class="n">workers</span><span class="p">:</span>
 
1632
        <span class="n">wp</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
1633
    <span class="c1"># Workers all done, listening can now stop.</span>
 
1634
    <span class="c1"># Logging in the parent still works normally.</span>
 
1635
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Telling listener to stop ...&#39;</span><span class="p">)</span>
 
1636
    <span class="n">stop_event</span><span class="o">.</span><span class="n">set</span><span class="p">()</span>
 
1637
    <span class="n">lp</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
 
1638
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;All done.&#39;</span><span class="p">)</span>
 
1639
 
 
1640
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
1641
    <span class="n">main</span><span class="p">()</span>
 
1642
</pre></div>
 
1643
</div>
 
1644
</div>
 
1645
<div class="section" id="inserting-a-bom-into-messages-sent-to-a-sysloghandler">
 
1646
<h2>Inserting a BOM into messages sent to a SysLogHandler<a class="headerlink" href="#inserting-a-bom-into-messages-sent-to-a-sysloghandler" title="Permalink to this headline">¶</a></h2>
 
1647
<p><a class="reference external" href="https://tools.ietf.org/html/rfc5424">RFC 5424</a> requires that a
 
1648
Unicode message be sent to a syslog daemon as a set of bytes which have the
 
1649
following structure: an optional pure-ASCII component, followed by a UTF-8 Byte
 
1650
Order Mark (BOM), followed by Unicode encoded using UTF-8. (See the <a class="reference external" href="https://tools.ietf.org/html/rfc5424#section-6">relevant
 
1651
section of the specification</a>.)</p>
 
1652
<p>In Python 3.1, code was added to
 
1653
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SysLogHandler" title="logging.handlers.SysLogHandler"><code class="xref py py-class docutils literal"><span class="pre">SysLogHandler</span></code></a> to insert a BOM into the message, but
 
1654
unfortunately, it was implemented incorrectly, with the BOM appearing at the
 
1655
beginning of the message and hence not allowing any pure-ASCII component to
 
1656
appear before it.</p>
 
1657
<p>As this behaviour is broken, the incorrect BOM insertion code is being removed
 
1658
from Python 3.2.4 and later. However, it is not being replaced, and if you
 
1659
want to produce RFC 5424-compliant messages which include a BOM, an optional
 
1660
pure-ASCII sequence before it and arbitrary Unicode after it, encoded using
 
1661
UTF-8, then you need to do the following:</p>
 
1662
<ol class="arabic">
 
1663
<li><p class="first">Attach a <a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code></a> instance to your
 
1664
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SysLogHandler" title="logging.handlers.SysLogHandler"><code class="xref py py-class docutils literal"><span class="pre">SysLogHandler</span></code></a> instance, with a format string
 
1665
such as:</p>
 
1666
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="s1">&#39;ASCII section</span><span class="se">\ufeff</span><span class="s1">Unicode section&#39;</span>
 
1667
</pre></div>
 
1668
</div>
 
1669
<p>The Unicode code point U+FEFF, when encoded using UTF-8, will be
 
1670
encoded as a UTF-8 BOM &#8211; the byte-string <code class="docutils literal"><span class="pre">b'\xef\xbb\xbf'</span></code>.</p>
 
1671
</li>
 
1672
<li><p class="first">Replace the ASCII section with whatever placeholders you like, but make sure
 
1673
that the data that appears in there after substitution is always ASCII (that
 
1674
way, it will remain unchanged after UTF-8 encoding).</p>
 
1675
</li>
 
1676
<li><p class="first">Replace the Unicode section with whatever placeholders you like; if the data
 
1677
which appears there after substitution contains characters outside the ASCII
 
1678
range, that&#8217;s fine &#8211; it will be encoded using UTF-8.</p>
 
1679
</li>
 
1680
</ol>
 
1681
<p>The formatted message <em>will</em> be encoded using UTF-8 encoding by
 
1682
<code class="docutils literal"><span class="pre">SysLogHandler</span></code>. If you follow the above rules, you should be able to produce
 
1683
RFC 5424-compliant messages. If you don&#8217;t, logging may not complain, but your
 
1684
messages will not be RFC 5424-compliant, and your syslog daemon may complain.</p>
 
1685
</div>
 
1686
<div class="section" id="implementing-structured-logging">
 
1687
<h2>Implementing structured logging<a class="headerlink" href="#implementing-structured-logging" title="Permalink to this headline">¶</a></h2>
 
1688
<p>Although most logging messages are intended for reading by humans, and thus not
 
1689
readily machine-parseable, there might be cirumstances where you want to output
 
1690
messages in a structured format which <em>is</em> capable of being parsed by a program
 
1691
(without needing complex regular expressions to parse the log message). This is
 
1692
straightforward to achieve using the logging package. There are a number of
 
1693
ways in which this could be achieved, but the following is a simple approach
 
1694
which uses JSON to serialise the event in a machine-parseable manner:</p>
 
1695
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">json</span>
 
1696
<span class="kn">import</span> <span class="nn">logging</span>
 
1697
 
 
1698
<span class="k">class</span> <span class="nc">StructuredMessage</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
1699
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
 
1700
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
 
1701
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1702
 
 
1703
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1704
        <span class="k">return</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> &gt;&gt;&gt; </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">))</span>
 
1705
 
 
1706
<span class="n">_</span> <span class="o">=</span> <span class="n">StructuredMessage</span>   <span class="c1"># optional, to improve readability</span>
 
1707
 
 
1708
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
1709
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s1">&#39;message 1&#39;</span><span class="p">,</span> <span class="n">foo</span><span class="o">=</span><span class="s1">&#39;bar&#39;</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s1">&#39;baz&#39;</span><span class="p">,</span> <span class="n">num</span><span class="o">=</span><span class="mi">123</span><span class="p">,</span> <span class="n">fnum</span><span class="o">=</span><span class="mf">123.456</span><span class="p">))</span>
 
1710
</pre></div>
 
1711
</div>
 
1712
<p>If the above script is run, it prints:</p>
 
1713
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">message</span> <span class="mi">1</span> <span class="o">&gt;&gt;&gt;</span> <span class="p">{</span><span class="s2">&quot;fnum&quot;</span><span class="p">:</span> <span class="mf">123.456</span><span class="p">,</span> <span class="s2">&quot;num&quot;</span><span class="p">:</span> <span class="mi">123</span><span class="p">,</span> <span class="s2">&quot;bar&quot;</span><span class="p">:</span> <span class="s2">&quot;baz&quot;</span><span class="p">,</span> <span class="s2">&quot;foo&quot;</span><span class="p">:</span> <span class="s2">&quot;bar&quot;</span><span class="p">}</span>
 
1714
</pre></div>
 
1715
</div>
 
1716
<p>Note that the order of items might be different according to the version of
 
1717
Python used.</p>
 
1718
<p>If you need more specialised processing, you can use a custom JSON encoder,
 
1719
as in the following complete example:</p>
 
1720
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="k">import</span> <span class="n">unicode_literals</span>
 
1721
 
 
1722
<span class="kn">import</span> <span class="nn">json</span>
 
1723
<span class="kn">import</span> <span class="nn">logging</span>
 
1724
 
 
1725
<span class="c1"># This next bit is to ensure the script runs unchanged on 2.x and 3.x</span>
 
1726
<span class="k">try</span><span class="p">:</span>
 
1727
    <span class="n">unicode</span>
 
1728
<span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
 
1729
    <span class="n">unicode</span> <span class="o">=</span> <span class="nb">str</span>
 
1730
 
 
1731
<span class="k">class</span> <span class="nc">Encoder</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">JSONEncoder</span><span class="p">):</span>
 
1732
    <span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">o</span><span class="p">):</span>
 
1733
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="nb">set</span><span class="p">):</span>
 
1734
            <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
 
1735
        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">unicode</span><span class="p">):</span>
 
1736
            <span class="k">return</span> <span class="n">o</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;unicode_escape&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;ascii&#39;</span><span class="p">)</span>
 
1737
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">Encoder</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">default</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
 
1738
 
 
1739
<span class="k">class</span> <span class="nc">StructuredMessage</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
1740
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
 
1741
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
 
1742
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1743
 
 
1744
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1745
        <span class="n">s</span> <span class="o">=</span> <span class="n">Encoder</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
 
1746
        <span class="k">return</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> &gt;&gt;&gt; </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
 
1747
 
 
1748
<span class="n">_</span> <span class="o">=</span> <span class="n">StructuredMessage</span>   <span class="c1"># optional, to improve readability</span>
 
1749
 
 
1750
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
1751
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>
 
1752
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s1">&#39;message 1&#39;</span><span class="p">,</span> <span class="n">set_value</span><span class="o">=</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">},</span> <span class="n">snowman</span><span class="o">=</span><span class="s1">&#39;</span><span class="se">\u2603</span><span class="s1">&#39;</span><span class="p">))</span>
 
1753
 
 
1754
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
1755
    <span class="n">main</span><span class="p">()</span>
 
1756
</pre></div>
 
1757
</div>
 
1758
<p>When the above script is run, it prints:</p>
 
1759
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">message</span> <span class="mi">1</span> <span class="o">&gt;&gt;&gt;</span> <span class="p">{</span><span class="s2">&quot;snowman&quot;</span><span class="p">:</span> <span class="s2">&quot;</span><span class="se">\u2603</span><span class="s2">&quot;</span><span class="p">,</span> <span class="s2">&quot;set_value&quot;</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]}</span>
 
1760
</pre></div>
 
1761
</div>
 
1762
<p>Note that the order of items might be different according to the version of
 
1763
Python used.</p>
 
1764
</div>
 
1765
<div class="section" id="customizing-handlers-with-dictconfig">
 
1766
<span id="custom-handlers"></span><h2>Customizing handlers with <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a><a class="headerlink" href="#customizing-handlers-with-dictconfig" title="Permalink to this headline">¶</a></h2>
 
1767
<p>There are times when you want to customize logging handlers in particular ways,
 
1768
and if you use <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a> you may be able to do this without
 
1769
subclassing. As an example, consider that you may want to set the ownership of a
 
1770
log file. On POSIX, this is easily done using <a class="reference internal" href="../library/shutil.html#shutil.chown" title="shutil.chown"><code class="xref py py-func docutils literal"><span class="pre">shutil.chown()</span></code></a>, but the file
 
1771
handlers in the stdlib don&#8217;t offer built-in support. You can customize handler
 
1772
creation using a plain function such as:</p>
 
1773
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">owned_file_handler</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
1774
    <span class="k">if</span> <span class="n">owner</span><span class="p">:</span>
 
1775
        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
 
1776
            <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
 
1777
        <span class="n">shutil</span><span class="o">.</span><span class="n">chown</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="o">*</span><span class="n">owner</span><span class="p">)</span>
 
1778
    <span class="k">return</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">encoding</span><span class="p">)</span>
 
1779
</pre></div>
 
1780
</div>
 
1781
<p>You can then specify, in a logging configuration passed to <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a>,
 
1782
that a logging handler be created by calling this function:</p>
 
1783
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
 
1784
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1785
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
 
1786
    <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1787
        <span class="s1">&#39;default&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1788
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(name)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1789
        <span class="p">},</span>
 
1790
    <span class="p">},</span>
 
1791
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1792
        <span class="s1">&#39;file&#39;</span><span class="p">:{</span>
 
1793
            <span class="c1"># The values below are popped from this dictionary and</span>
 
1794
            <span class="c1"># used to create the handler, set the handler&#39;s level and</span>
 
1795
            <span class="c1"># its formatter.</span>
 
1796
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="n">owned_file_handler</span><span class="p">,</span>
 
1797
            <span class="s1">&#39;level&#39;</span><span class="p">:</span><span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1798
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;default&#39;</span><span class="p">,</span>
 
1799
            <span class="c1"># The values below are passed to the handler creator callable</span>
 
1800
            <span class="c1"># as keyword arguments.</span>
 
1801
            <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;pulse&#39;</span><span class="p">,</span> <span class="s1">&#39;pulse&#39;</span><span class="p">],</span>
 
1802
            <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;chowntest.log&#39;</span><span class="p">,</span>
 
1803
            <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
1804
            <span class="s1">&#39;encoding&#39;</span><span class="p">:</span> <span class="s1">&#39;utf-8&#39;</span><span class="p">,</span>
 
1805
        <span class="p">},</span>
 
1806
    <span class="p">},</span>
 
1807
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1808
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">],</span>
 
1809
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1810
    <span class="p">},</span>
 
1811
<span class="p">}</span>
 
1812
</pre></div>
 
1813
</div>
 
1814
<p>In this example I am setting the ownership using the <code class="docutils literal"><span class="pre">pulse</span></code> user and group,
 
1815
just for the purposes of illustration. Putting it together into a working
 
1816
script, <code class="docutils literal"><span class="pre">chowntest.py</span></code>:</p>
 
1817
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span><span class="o">,</span> <span class="nn">logging.config</span><span class="o">,</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">shutil</span>
 
1818
 
 
1819
<span class="k">def</span> <span class="nf">owned_file_handler</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
1820
    <span class="k">if</span> <span class="n">owner</span><span class="p">:</span>
 
1821
        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
 
1822
            <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
 
1823
        <span class="n">shutil</span><span class="o">.</span><span class="n">chown</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="o">*</span><span class="n">owner</span><span class="p">)</span>
 
1824
    <span class="k">return</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">encoding</span><span class="p">)</span>
 
1825
 
 
1826
<span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
 
1827
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
1828
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
 
1829
    <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1830
        <span class="s1">&#39;default&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1831
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(name)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span>
 
1832
        <span class="p">},</span>
 
1833
    <span class="p">},</span>
 
1834
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1835
        <span class="s1">&#39;file&#39;</span><span class="p">:{</span>
 
1836
            <span class="c1"># The values below are popped from this dictionary and</span>
 
1837
            <span class="c1"># used to create the handler, set the handler&#39;s level and</span>
 
1838
            <span class="c1"># its formatter.</span>
 
1839
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="n">owned_file_handler</span><span class="p">,</span>
 
1840
            <span class="s1">&#39;level&#39;</span><span class="p">:</span><span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1841
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;default&#39;</span><span class="p">,</span>
 
1842
            <span class="c1"># The values below are passed to the handler creator callable</span>
 
1843
            <span class="c1"># as keyword arguments.</span>
 
1844
            <span class="s1">&#39;owner&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;pulse&#39;</span><span class="p">,</span> <span class="s1">&#39;pulse&#39;</span><span class="p">],</span>
 
1845
            <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;chowntest.log&#39;</span><span class="p">,</span>
 
1846
            <span class="s1">&#39;mode&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span>
 
1847
            <span class="s1">&#39;encoding&#39;</span><span class="p">:</span> <span class="s1">&#39;utf-8&#39;</span><span class="p">,</span>
 
1848
        <span class="p">},</span>
 
1849
    <span class="p">},</span>
 
1850
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
1851
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">],</span>
 
1852
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
1853
    <span class="p">},</span>
 
1854
<span class="p">}</span>
 
1855
 
 
1856
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">LOGGING</span><span class="p">)</span>
 
1857
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;mylogger&#39;</span><span class="p">)</span>
 
1858
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;A debug message&#39;</span><span class="p">)</span>
 
1859
</pre></div>
 
1860
</div>
 
1861
<p>To run this, you will probably need to run as <code class="docutils literal"><span class="pre">root</span></code>:</p>
 
1862
<div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo python3.3 chowntest.py
 
1863
<span class="gp">$</span> cat chowntest.log
 
1864
<span class="go">2013-11-05 09:34:51,128 DEBUG mylogger A debug message</span>
 
1865
<span class="gp">$</span> ls -l chowntest.log
 
1866
<span class="go">-rw-r--r-- 1 pulse pulse 55 2013-11-05 09:34 chowntest.log</span>
 
1867
</pre></div>
 
1868
</div>
 
1869
<p>Note that this example uses Python 3.3 because that&#8217;s where <a class="reference internal" href="../library/shutil.html#shutil.chown" title="shutil.chown"><code class="xref py py-func docutils literal"><span class="pre">shutil.chown()</span></code></a>
 
1870
makes an appearance. This approach should work with any Python version that
 
1871
supports <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a> - namely, Python 2.7, 3.2 or later. With pre-3.3
 
1872
versions, you would need to implement the actual ownership change using e.g.
 
1873
<a class="reference internal" href="../library/os.html#os.chown" title="os.chown"><code class="xref py py-func docutils literal"><span class="pre">os.chown()</span></code></a>.</p>
 
1874
<p>In practice, the handler-creating function may be in a utility module somewhere
 
1875
in your project. Instead of the line in the configuration:</p>
 
1876
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="n">owned_file_handler</span><span class="p">,</span>
 
1877
</pre></div>
 
1878
</div>
 
1879
<p>you could use e.g.:</p>
 
1880
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;ext://project.util.owned_file_handler&#39;</span><span class="p">,</span>
 
1881
</pre></div>
 
1882
</div>
 
1883
<p>where <code class="docutils literal"><span class="pre">project.util</span></code> can be replaced with the actual name of the package
 
1884
where the function resides. In the above working script, using
 
1885
<code class="docutils literal"><span class="pre">'ext://__main__.owned_file_handler'</span></code> should work. Here, the actual callable
 
1886
is resolved by <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a> from the <code class="docutils literal"><span class="pre">ext://</span></code> specification.</p>
 
1887
<p>This example hopefully also points the way to how you could implement other
 
1888
types of file change - e.g. setting specific POSIX permission bits - in the
 
1889
same way, using <a class="reference internal" href="../library/os.html#os.chmod" title="os.chmod"><code class="xref py py-func docutils literal"><span class="pre">os.chmod()</span></code></a>.</p>
 
1890
<p>Of course, the approach could also be extended to types of handler other than a
 
1891
<a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal"><span class="pre">FileHandler</span></code></a> - for example, one of the rotating file handlers,
 
1892
or a different type of handler altogether.</p>
 
1893
</div>
 
1894
<div class="section" id="using-particular-formatting-styles-throughout-your-application">
 
1895
<span id="formatting-styles"></span><h2>Using particular formatting styles throughout your application<a class="headerlink" href="#using-particular-formatting-styles-throughout-your-application" title="Permalink to this headline">¶</a></h2>
 
1896
<p>In Python 3.2, the <a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code></a> gained a <code class="docutils literal"><span class="pre">style</span></code> keyword
 
1897
parameter which, while defaulting to <code class="docutils literal"><span class="pre">%</span></code> for backward compatibility, allowed
 
1898
the specification of <code class="docutils literal"><span class="pre">{</span></code> or <code class="docutils literal"><span class="pre">$</span></code> to support the formatting approaches
 
1899
supported by <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a> and <a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a>. Note that this
 
1900
governs the formatting of logging messages for final output to logs, and is
 
1901
completely orthogonal to how an individual logging message is constructed.</p>
 
1902
<p>Logging calls (<a class="reference internal" href="../library/logging.html#logging.Logger.debug" title="logging.Logger.debug"><code class="xref py py-meth docutils literal"><span class="pre">debug()</span></code></a>, <a class="reference internal" href="../library/logging.html#logging.Logger.info" title="logging.Logger.info"><code class="xref py py-meth docutils literal"><span class="pre">info()</span></code></a> etc.) only take
 
1903
positional parameters for the actual logging message itself, with keyword
 
1904
parameters used only for determining options for how to handle the logging call
 
1905
(e.g. the <code class="docutils literal"><span class="pre">exc_info</span></code> keyword parameter to indicate that traceback information
 
1906
should be logged, or the <code class="docutils literal"><span class="pre">extra</span></code> keyword parameter to indicate additional
 
1907
contextual information to be added to the log). So you cannot directly make
 
1908
logging calls using <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a> or <a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a> syntax,
 
1909
because internally the logging package uses %-formatting to merge the format
 
1910
string and the variable arguments. There would no changing this while preserving
 
1911
backward compatibility, since all logging calls which are out there in existing
 
1912
code will be using %-format strings.</p>
 
1913
<p>There have been suggestions to associate format styles with specific loggers,
 
1914
but that approach also runs into backward compatibility problems because any
 
1915
existing code could be using a given logger name and using %-formatting.</p>
 
1916
<p>For logging to work interoperably between any third-party libraries and your
 
1917
code, decisions about formatting need to be made at the level of the
 
1918
individual logging call. This opens up a couple of ways in which alternative
 
1919
formatting styles can be accommodated.</p>
 
1920
<div class="section" id="using-logrecord-factories">
 
1921
<h3>Using LogRecord factories<a class="headerlink" href="#using-logrecord-factories" title="Permalink to this headline">¶</a></h3>
 
1922
<p>In Python 3.2, along with the <a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code></a> changes mentioned
 
1923
above, the logging package gained the ability to allow users to set their own
 
1924
<a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> subclasses, using the <a class="reference internal" href="../library/logging.html#logging.setLogRecordFactory" title="logging.setLogRecordFactory"><code class="xref py py-func docutils literal"><span class="pre">setLogRecordFactory()</span></code></a> function.
 
1925
You can use this to set your own subclass of <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a>, which does the
 
1926
Right Thing by overriding the <a class="reference internal" href="../library/logging.html#logging.LogRecord.getMessage" title="logging.LogRecord.getMessage"><code class="xref py py-meth docutils literal"><span class="pre">getMessage()</span></code></a> method. The base
 
1927
class implementation of this method is where the <code class="docutils literal"><span class="pre">msg</span> <span class="pre">%</span> <span class="pre">args</span></code> formatting
 
1928
happens, and where you can substitute your alternate formatting; however, you
 
1929
should be careful to support all formatting styles and allow %-formatting as
 
1930
the default, to ensure interoperability with other code. Care should also be
 
1931
taken to call <code class="docutils literal"><span class="pre">str(self.msg)</span></code>, just as the base implementation does.</p>
 
1932
<p>Refer to the reference documentation on <a class="reference internal" href="../library/logging.html#logging.setLogRecordFactory" title="logging.setLogRecordFactory"><code class="xref py py-func docutils literal"><span class="pre">setLogRecordFactory()</span></code></a> and
 
1933
<a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal"><span class="pre">LogRecord</span></code></a> for more information.</p>
 
1934
</div>
 
1935
<div class="section" id="using-custom-message-objects">
 
1936
<h3>Using custom message objects<a class="headerlink" href="#using-custom-message-objects" title="Permalink to this headline">¶</a></h3>
 
1937
<p>There is another, perhaps simpler way that you can use {}- and $- formatting to
 
1938
construct your individual log messages. You may recall (from
 
1939
<a class="reference internal" href="logging.html#arbitrary-object-messages"><span>Using arbitrary objects as messages</span></a>) that when logging you can use an arbitrary
 
1940
object as a message format string, and that the logging package will call
 
1941
<a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-func docutils literal"><span class="pre">str()</span></code></a> on that object to get the actual format string. Consider the
 
1942
following two classes:</p>
 
1943
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BraceMessage</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
1944
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fmt</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>
 
1945
        <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span> <span class="o">=</span> <span class="n">fmt</span>
 
1946
        <span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="n">args</span>
 
1947
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1948
 
 
1949
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1950
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
 
1951
 
 
1952
<span class="k">class</span> <span class="nc">DollarMessage</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
1953
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fmt</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
 
1954
        <span class="bp">self</span><span class="o">.</span><span class="n">fmt</span> <span class="o">=</span> <span class="n">fmt</span>
 
1955
        <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
 
1956
 
 
1957
    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
1958
        <span class="kn">from</span> <span class="nn">string</span> <span class="k">import</span> <span class="n">Template</span>
 
1959
        <span class="k">return</span> <span class="n">Template</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fmt</span><span class="p">)</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
 
1960
</pre></div>
 
1961
</div>
 
1962
<p>Either of these can be used in place of a format string, to allow {}- or
 
1963
$-formatting to be used to build the actual &#8220;message&#8221; part which appears in the
 
1964
formatted log output in place of “%(message)s” or “{message}” or “$message”.
 
1965
If you find it a little unwieldy to use the class names whenever you want to log
 
1966
something, you can make it more palatable if you use an alias such as <code class="docutils literal"><span class="pre">M</span></code> or
 
1967
<code class="docutils literal"><span class="pre">_</span></code> for the message (or perhaps <code class="docutils literal"><span class="pre">__</span></code>, if you are using <code class="docutils literal"><span class="pre">_</span></code> for
 
1968
localization).</p>
 
1969
<p>Examples of this approach are given below. Firstly, formatting with
 
1970
<a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal"><span class="pre">str.format()</span></code></a>:</p>
 
1971
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">__</span> <span class="o">=</span> <span class="n">BraceMessage</span>
 
1972
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with </span><span class="si">{0}</span><span class="s1"> </span><span class="si">{1}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;placeholders&#39;</span><span class="p">))</span>
 
1973
<span class="go">Message with 2 placeholders</span>
 
1974
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Point</span><span class="p">:</span> <span class="k">pass</span>
 
1975
<span class="gp">...</span>
 
1976
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span> <span class="o">=</span> <span class="n">Point</span><span class="p">()</span>
 
1977
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mf">0.5</span>
 
1978
<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="mf">0.5</span>
 
1979
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with coordinates: (</span><span class="si">{point.x:.2f}</span><span class="s1">, </span><span class="si">{point.y:.2f}</span><span class="s1">)&#39;</span><span class="p">,</span> <span class="n">point</span><span class="o">=</span><span class="n">p</span><span class="p">))</span>
 
1980
<span class="go">Message with coordinates: (0.50, 0.50)</span>
 
1981
</pre></div>
 
1982
</div>
 
1983
<p>Secondly, formatting with <a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal"><span class="pre">string.Template</span></code></a>:</p>
 
1984
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">__</span> <span class="o">=</span> <span class="n">DollarMessage</span>
 
1985
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">__</span><span class="p">(</span><span class="s1">&#39;Message with $num $what&#39;</span><span class="p">,</span> <span class="n">num</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">what</span><span class="o">=</span><span class="s1">&#39;placeholders&#39;</span><span class="p">))</span>
 
1986
<span class="go">Message with 2 placeholders</span>
 
1987
<span class="go">&gt;&gt;&gt;</span>
 
1988
</pre></div>
 
1989
</div>
 
1990
<p>One thing to note is that you pay no significant performance penalty with this
 
1991
approach: the actual formatting happens not when you make the logging call, but
 
1992
when (and if) the logged message is actually about to be output to a log by a
 
1993
handler. So the only slightly unusual thing which might trip you up is that the
 
1994
parentheses go around the format string and the arguments, not just the format
 
1995
string. That’s because the __ notation is just syntax sugar for a constructor
 
1996
call to one of the <code class="docutils literal"><span class="pre">XXXMessage</span></code> classes shown above.</p>
 
1997
</div>
 
1998
</div>
 
1999
<div class="section" id="configuring-filters-with-dictconfig">
 
2000
<span id="filters-dictconfig"></span><h2>Configuring filters with <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a><a class="headerlink" href="#configuring-filters-with-dictconfig" title="Permalink to this headline">¶</a></h2>
 
2001
<p>You <em>can</em> configure filters using <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a>, though it
 
2002
might not be obvious at first glance how to do it (hence this recipe). Since
 
2003
<a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal"><span class="pre">Filter</span></code></a> is the only filter class included in the standard
 
2004
library, and it is unlikely to cater to many requirements (it&#8217;s only there as a
 
2005
base class), you will typically need to define your own <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal"><span class="pre">Filter</span></code></a>
 
2006
subclass with an overridden <a class="reference internal" href="../library/logging.html#logging.Filter.filter" title="logging.Filter.filter"><code class="xref py py-meth docutils literal"><span class="pre">filter()</span></code></a> method. To do this,
 
2007
specify the <code class="docutils literal"><span class="pre">()</span></code> key in the configuration dictionary for the filter,
 
2008
specifying a callable which will be used to create the filter (a class is the
 
2009
most obvious, but you can provide any callable which returns a
 
2010
<a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal"><span class="pre">Filter</span></code></a> instance). Here is a complete example:</p>
 
2011
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2012
<span class="kn">import</span> <span class="nn">logging.config</span>
 
2013
<span class="kn">import</span> <span class="nn">sys</span>
 
2014
 
 
2015
<span class="k">class</span> <span class="nc">MyFilter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
 
2016
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">param</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
2017
        <span class="bp">self</span><span class="o">.</span><span class="n">param</span> <span class="o">=</span> <span class="n">param</span>
 
2018
 
 
2019
    <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>
 
2020
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">param</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
 
2021
            <span class="n">allow</span> <span class="o">=</span> <span class="kc">True</span>
 
2022
        <span class="k">else</span><span class="p">:</span>
 
2023
            <span class="n">allow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">param</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">record</span><span class="o">.</span><span class="n">msg</span>
 
2024
        <span class="k">if</span> <span class="n">allow</span><span class="p">:</span>
 
2025
            <span class="n">record</span><span class="o">.</span><span class="n">msg</span> <span class="o">=</span> <span class="s1">&#39;changed: &#39;</span> <span class="o">+</span> <span class="n">record</span><span class="o">.</span><span class="n">msg</span>
 
2026
        <span class="k">return</span> <span class="n">allow</span>
 
2027
 
 
2028
<span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
 
2029
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
2030
    <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2031
        <span class="s1">&#39;myfilter&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2032
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="n">MyFilter</span><span class="p">,</span>
 
2033
            <span class="s1">&#39;param&#39;</span><span class="p">:</span> <span class="s1">&#39;noshow&#39;</span><span class="p">,</span>
 
2034
        <span class="p">}</span>
 
2035
    <span class="p">},</span>
 
2036
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2037
        <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2038
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
2039
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;myfilter&#39;</span><span class="p">]</span>
 
2040
        <span class="p">}</span>
 
2041
    <span class="p">},</span>
 
2042
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2043
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
 
2044
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">]</span>
 
2045
    <span class="p">},</span>
 
2046
<span class="p">}</span>
 
2047
 
 
2048
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2049
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">LOGGING</span><span class="p">)</span>
 
2050
    <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">)</span>
 
2051
    <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;hello - noshow&#39;</span><span class="p">)</span>
 
2052
</pre></div>
 
2053
</div>
 
2054
<p>This example shows how you can pass configuration data to the callable which
 
2055
constructs the instance, in the form of keyword parameters. When run, the above
 
2056
script will print:</p>
 
2057
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">changed</span><span class="p">:</span> <span class="n">hello</span>
 
2058
</pre></div>
 
2059
</div>
 
2060
<p>which shows that the filter is working as configured.</p>
 
2061
<p>A couple of extra points to note:</p>
 
2062
<ul class="simple">
 
2063
<li>If you can&#8217;t refer to the callable directly in the configuration (e.g. if it
 
2064
lives in a different module, and you can&#8217;t import it directly where the
 
2065
configuration dictionary is), you can use the form <code class="docutils literal"><span class="pre">ext://...</span></code> as described
 
2066
in <a class="reference internal" href="../library/logging.config.html#logging-config-dict-externalobj"><span>Access to external objects</span></a>. For example, you could have used
 
2067
the text <code class="docutils literal"><span class="pre">'ext://__main__.MyFilter'</span></code> instead of <code class="docutils literal"><span class="pre">MyFilter</span></code> in the above
 
2068
example.</li>
 
2069
<li>As well as for filters, this technique can also be used to configure custom
 
2070
handlers and formatters. See <a class="reference internal" href="../library/logging.config.html#logging-config-dict-userdef"><span>User-defined objects</span></a> for more
 
2071
information on how logging supports using user-defined objects in its
 
2072
configuration, and see the other cookbook recipe <a class="reference internal" href="#custom-handlers"><span>Customizing handlers with dictConfig()</span></a> above.</li>
 
2073
</ul>
 
2074
</div>
 
2075
<div class="section" id="customized-exception-formatting">
 
2076
<span id="custom-format-exception"></span><h2>Customized exception formatting<a class="headerlink" href="#customized-exception-formatting" title="Permalink to this headline">¶</a></h2>
 
2077
<p>There might be times when you want to do customized exception formatting - for
 
2078
argument&#8217;s sake, let&#8217;s say you want exactly one line per logged event, even
 
2079
when exception information is present. You can do this with a custom formatter
 
2080
class, as shown in the following example:</p>
 
2081
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2082
 
 
2083
<span class="k">class</span> <span class="nc">OneLineExceptionFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">):</span>
 
2084
    <span class="k">def</span> <span class="nf">formatException</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc_info</span><span class="p">):</span>
 
2085
        <span class="sd">&quot;&quot;&quot;</span>
 
2086
<span class="sd">        Format an exception so that it prints on a single line.</span>
 
2087
<span class="sd">        &quot;&quot;&quot;</span>
 
2088
        <span class="n">result</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">OneLineExceptionFormatter</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">formatException</span><span class="p">(</span><span class="n">exc_info</span><span class="p">)</span>
 
2089
        <span class="k">return</span> <span class="nb">repr</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>  <span class="c1"># or format into one line however you want to</span>
 
2090
 
 
2091
    <span class="k">def</span> <span class="nf">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
2092
        <span class="n">s</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">OneLineExceptionFormatter</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
2093
        <span class="k">if</span> <span class="n">record</span><span class="o">.</span><span class="n">exc_text</span><span class="p">:</span>
 
2094
            <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;|&#39;</span>
 
2095
        <span class="k">return</span> <span class="n">s</span>
 
2096
 
 
2097
<span class="k">def</span> <span class="nf">configure_logging</span><span class="p">():</span>
 
2098
    <span class="n">fh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="s1">&#39;output.txt&#39;</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span>
 
2099
    <span class="n">f</span> <span class="o">=</span> <span class="n">OneLineExceptionFormatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1">|</span><span class="si">%(levelname)s</span><span class="s1">|</span><span class="si">%(message)s</span><span class="s1">|&#39;</span><span class="p">,</span>
 
2100
                                  <span class="s1">&#39;</span><span class="si">%d</span><span class="s1">/%m/%Y %H:%M:%S&#39;</span><span class="p">)</span>
 
2101
    <span class="n">fh</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
 
2102
    <span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
2103
    <span class="n">root</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
2104
    <span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">fh</span><span class="p">)</span>
 
2105
 
 
2106
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
2107
    <span class="n">configure_logging</span><span class="p">()</span>
 
2108
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Sample message&#39;</span><span class="p">)</span>
 
2109
    <span class="k">try</span><span class="p">:</span>
 
2110
        <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">0</span>
 
2111
    <span class="k">except</span> <span class="ne">ZeroDivisionError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
 
2112
        <span class="n">logging</span><span class="o">.</span><span class="n">exception</span><span class="p">(</span><span class="s1">&#39;ZeroDivisionError: </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
 
2113
 
 
2114
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2115
    <span class="n">main</span><span class="p">()</span>
 
2116
</pre></div>
 
2117
</div>
 
2118
<p>When run, this produces a file with exactly two lines:</p>
 
2119
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="mi">28</span><span class="o">/</span><span class="mi">01</span><span class="o">/</span><span class="mi">2015</span> <span class="mi">07</span><span class="p">:</span><span class="mi">21</span><span class="p">:</span><span class="mi">23</span><span class="o">|</span><span class="n">INFO</span><span class="o">|</span><span class="n">Sample</span> <span class="n">message</span><span class="o">|</span>
 
2120
<span class="mi">28</span><span class="o">/</span><span class="mi">01</span><span class="o">/</span><span class="mi">2015</span> <span class="mi">07</span><span class="p">:</span><span class="mi">21</span><span class="p">:</span><span class="mi">23</span><span class="o">|</span><span class="n">ERROR</span><span class="o">|</span><span class="ne">ZeroDivisionError</span><span class="p">:</span> <span class="n">integer</span> <span class="n">division</span> <span class="ow">or</span> <span class="n">modulo</span> <span class="n">by</span> <span class="n">zero</span><span class="o">|</span><span class="s1">&#39;Traceback (most recent call last):</span><span class="se">\n</span><span class="s1">  File &quot;logtest7.py&quot;, line 30, in main</span><span class="se">\n</span><span class="s1">    x = 1 / 0</span><span class="se">\n</span><span class="s1">ZeroDivisionError: integer division or modulo by zero&#39;</span><span class="o">|</span>
 
2121
</pre></div>
 
2122
</div>
 
2123
<p>While the above treatment is simplistic, it points the way to how exception
 
2124
information can be formatted to your liking. The <a class="reference internal" href="../library/traceback.html#module-traceback" title="traceback: Print or retrieve a stack traceback."><code class="xref py py-mod docutils literal"><span class="pre">traceback</span></code></a> module may be
 
2125
helpful for more specialized needs.</p>
 
2126
</div>
 
2127
<div class="section" id="speaking-logging-messages">
 
2128
<span id="spoken-messages"></span><h2>Speaking logging messages<a class="headerlink" href="#speaking-logging-messages" title="Permalink to this headline">¶</a></h2>
 
2129
<p>There might be situations when it is desirable to have logging messages rendered
 
2130
in an audible rather than a visible format. This is easy to do if you have text-
 
2131
to-speech (TTS) functionality available in your system, even if it doesn&#8217;t have
 
2132
a Python binding. Most TTS systems have a command line program you can run, and
 
2133
this can be invoked from a handler using <a class="reference internal" href="../library/subprocess.html#module-subprocess" title="subprocess: Subprocess management."><code class="xref py py-mod docutils literal"><span class="pre">subprocess</span></code></a>. It&#8217;s assumed here
 
2134
that TTS command line programs won&#8217;t expect to interact with users or take a
 
2135
long time to complete, and that the frequency of logged messages will be not so
 
2136
high as to swamp the user with messages, and that it&#8217;s acceptable to have the
 
2137
messages spoken one at a time rather than concurrently, The example implementation
 
2138
below waits for one message to be spoken before the next is processed, and this
 
2139
might cause other handlers to be kept waiting. Here is a short example showing
 
2140
the approach, which assumes that the <code class="docutils literal"><span class="pre">espeak</span></code> TTS package is available:</p>
 
2141
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2142
<span class="kn">import</span> <span class="nn">subprocess</span>
 
2143
<span class="kn">import</span> <span class="nn">sys</span>
 
2144
 
 
2145
<span class="k">class</span> <span class="nc">TTSHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Handler</span><span class="p">):</span>
 
2146
    <span class="k">def</span> <span class="nf">emit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span>
 
2147
        <span class="n">msg</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>
 
2148
        <span class="c1"># Speak slowly in a female English voice</span>
 
2149
        <span class="n">cmd</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;espeak&#39;</span><span class="p">,</span> <span class="s1">&#39;-s150&#39;</span><span class="p">,</span> <span class="s1">&#39;-ven+f3&#39;</span><span class="p">,</span> <span class="n">msg</span><span class="p">]</span>
 
2150
        <span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span>
 
2151
                             <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">STDOUT</span><span class="p">)</span>
 
2152
        <span class="c1"># wait for the program to finish</span>
 
2153
        <span class="n">p</span><span class="o">.</span><span class="n">communicate</span><span class="p">()</span>
 
2154
 
 
2155
<span class="k">def</span> <span class="nf">configure_logging</span><span class="p">():</span>
 
2156
    <span class="n">h</span> <span class="o">=</span> <span class="n">TTSHandler</span><span class="p">()</span>
 
2157
    <span class="n">root</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
 
2158
    <span class="n">root</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
 
2159
    <span class="c1"># the default formatter just returns the message</span>
 
2160
    <span class="n">root</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
2161
 
 
2162
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
 
2163
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Hello&#39;</span><span class="p">)</span>
 
2164
    <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Goodbye&#39;</span><span class="p">)</span>
 
2165
 
 
2166
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2167
    <span class="n">configure_logging</span><span class="p">()</span>
 
2168
    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
 
2169
</pre></div>
 
2170
</div>
 
2171
<p>When run, this script should say &#8220;Hello&#8221; and then &#8220;Goodbye&#8221; in a female voice.</p>
 
2172
<p>The above approach can, of course, be adapted to other TTS systems and even
 
2173
other systems altogether which can process messages via external programs run
 
2174
from a command line.</p>
 
2175
</div>
 
2176
<div class="section" id="buffering-logging-messages-and-outputting-them-conditionally">
 
2177
<span id="buffered-logging"></span><h2>Buffering logging messages and outputting them conditionally<a class="headerlink" href="#buffering-logging-messages-and-outputting-them-conditionally" title="Permalink to this headline">¶</a></h2>
 
2178
<p>There might be situations where you want to log messages in a temporary area
 
2179
and only output them if a certain condition occurs. For example, you may want to
 
2180
start logging debug events in a function, and if the function completes without
 
2181
errors, you don&#8217;t want to clutter the log with the collected debug information,
 
2182
but if there is an error, you want all the debug information to be output as well
 
2183
as the error.</p>
 
2184
<p>Here is an example which shows how you could do this using a decorator for your
 
2185
functions where you want logging to behave this way. It makes use of the
 
2186
<a class="reference internal" href="../library/logging.handlers.html#logging.handlers.MemoryHandler" title="logging.handlers.MemoryHandler"><code class="xref py py-class docutils literal"><span class="pre">logging.handlers.MemoryHandler</span></code></a>, which allows buffering of logged events
 
2187
until some condition occurs, at which point the buffered events are <code class="docutils literal"><span class="pre">flushed</span></code>
 
2188
- passed to another handler (the <code class="docutils literal"><span class="pre">target</span></code> handler) for processing. By default,
 
2189
the <code class="docutils literal"><span class="pre">MemoryHandler</span></code> flushed when its buffer gets filled up or an event whose
 
2190
level is greater than or equal to a specified threshold is seen. You can use this
 
2191
recipe with a more specialised subclass of <code class="docutils literal"><span class="pre">MemoryHandler</span></code> if you want custom
 
2192
flushing behavior.</p>
 
2193
<p>The example script has a simple function, <code class="docutils literal"><span class="pre">foo</span></code>, which just cycles through
 
2194
all the logging levels, writing to <code class="docutils literal"><span class="pre">sys.stderr</span></code> to say what level it&#8217;s about
 
2195
to log at, and then actually logging a message at that level. You can pass a
 
2196
parameter to <code class="docutils literal"><span class="pre">foo</span></code> which, if true, will log at ERROR and CRITICAL levels -
 
2197
otherwise, it only logs at DEBUG, INFO and WARNING levels.</p>
 
2198
<p>The script just arranges to decorate <code class="docutils literal"><span class="pre">foo</span></code> with a decorator which will do the
 
2199
conditional logging that&#8217;s required. The decorator takes a logger as a parameter
 
2200
and attaches a memory handler for the duration of the call to the decorated
 
2201
function. The decorator can be additionally parameterised using a target handler,
 
2202
a level at which flushing should occur, and a capacity for the buffer. These
 
2203
default to a <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal"><span class="pre">StreamHandler</span></code></a> which writes to <code class="docutils literal"><span class="pre">sys.stderr</span></code>,
 
2204
<code class="docutils literal"><span class="pre">logging.ERROR</span></code> and <code class="docutils literal"><span class="pre">100</span></code> respectively.</p>
 
2205
<p>Here&#8217;s the script:</p>
 
2206
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2207
<span class="kn">from</span> <span class="nn">logging.handlers</span> <span class="k">import</span> <span class="n">MemoryHandler</span>
 
2208
<span class="kn">import</span> <span class="nn">sys</span>
 
2209
 
 
2210
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
 
2211
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">NullHandler</span><span class="p">())</span>
 
2212
 
 
2213
<span class="k">def</span> <span class="nf">log_if_errors</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="n">target_handler</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">flush_level</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 
2214
    <span class="k">if</span> <span class="n">target_handler</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
 
2215
        <span class="n">target_handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
 
2216
    <span class="k">if</span> <span class="n">flush_level</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
 
2217
        <span class="n">flush_level</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span>
 
2218
    <span class="k">if</span> <span class="n">capacity</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
 
2219
        <span class="n">capacity</span> <span class="o">=</span> <span class="mi">100</span>
 
2220
    <span class="n">handler</span> <span class="o">=</span> <span class="n">MemoryHandler</span><span class="p">(</span><span class="n">capacity</span><span class="p">,</span> <span class="n">flushLevel</span><span class="o">=</span><span class="n">flush_level</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="n">target_handler</span><span class="p">)</span>
 
2221
 
 
2222
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">fn</span><span class="p">):</span>
 
2223
        <span class="k">def</span> <span class="nf">wrapper</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>
 
2224
            <span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span>
 
2225
            <span class="k">try</span><span class="p">:</span>
 
2226
                <span class="k">return</span> <span class="n">fn</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>
 
2227
            <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
 
2228
                <span class="n">logger</span><span class="o">.</span><span class="n">exception</span><span class="p">(</span><span class="s1">&#39;call failed&#39;</span><span class="p">)</span>
 
2229
                <span class="k">raise</span>
 
2230
            <span class="k">finally</span><span class="p">:</span>
 
2231
                <span class="nb">super</span><span class="p">(</span><span class="n">MemoryHandler</span><span class="p">,</span> <span class="n">handler</span><span class="p">)</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
 
2232
                <span class="n">logger</span><span class="o">.</span><span class="n">removeHandler</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span>
 
2233
        <span class="k">return</span> <span class="n">wrapper</span>
 
2234
 
 
2235
    <span class="k">return</span> <span class="n">decorator</span>
 
2236
 
 
2237
<span class="k">def</span> <span class="nf">write_line</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
 
2238
    <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="se">\n</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">s</span><span class="p">)</span>
 
2239
 
 
2240
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">fail</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
 
2241
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;about to log at DEBUG ...&#39;</span><span class="p">)</span>
 
2242
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;Actually logged at DEBUG&#39;</span><span class="p">)</span>
 
2243
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;about to log at INFO ...&#39;</span><span class="p">)</span>
 
2244
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Actually logged at INFO&#39;</span><span class="p">)</span>
 
2245
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;about to log at WARNING ...&#39;</span><span class="p">)</span>
 
2246
    <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Actually logged at WARNING&#39;</span><span class="p">)</span>
 
2247
    <span class="k">if</span> <span class="n">fail</span><span class="p">:</span>
 
2248
        <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;about to log at ERROR ...&#39;</span><span class="p">)</span>
 
2249
        <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;Actually logged at ERROR&#39;</span><span class="p">)</span>
 
2250
        <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;about to log at CRITICAL ...&#39;</span><span class="p">)</span>
 
2251
        <span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">&#39;Actually logged at CRITICAL&#39;</span><span class="p">)</span>
 
2252
    <span class="k">return</span> <span class="n">fail</span>
 
2253
 
 
2254
<span class="n">decorated_foo</span> <span class="o">=</span> <span class="n">log_if_errors</span><span class="p">(</span><span class="n">logger</span><span class="p">)(</span><span class="n">foo</span><span class="p">)</span>
 
2255
 
 
2256
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2257
    <span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
 
2258
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;Calling undecorated foo with False&#39;</span><span class="p">)</span>
 
2259
    <span class="k">assert</span> <span class="ow">not</span> <span class="n">foo</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
 
2260
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;Calling undecorated foo with True&#39;</span><span class="p">)</span>
 
2261
    <span class="k">assert</span> <span class="n">foo</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
 
2262
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;Calling decorated foo with False&#39;</span><span class="p">)</span>
 
2263
    <span class="k">assert</span> <span class="ow">not</span> <span class="n">decorated_foo</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
 
2264
    <span class="n">write_line</span><span class="p">(</span><span class="s1">&#39;Calling decorated foo with True&#39;</span><span class="p">)</span>
 
2265
    <span class="k">assert</span> <span class="n">decorated_foo</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
 
2266
</pre></div>
 
2267
</div>
 
2268
<p>When this script is run, the following output should be observed:</p>
 
2269
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">Calling</span> <span class="n">undecorated</span> <span class="n">foo</span> <span class="k">with</span> <span class="kc">False</span>
 
2270
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="o">...</span>
 
2271
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">INFO</span> <span class="o">...</span>
 
2272
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">WARNING</span> <span class="o">...</span>
 
2273
<span class="n">Calling</span> <span class="n">undecorated</span> <span class="n">foo</span> <span class="k">with</span> <span class="kc">True</span>
 
2274
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="o">...</span>
 
2275
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">INFO</span> <span class="o">...</span>
 
2276
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">WARNING</span> <span class="o">...</span>
 
2277
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">ERROR</span> <span class="o">...</span>
 
2278
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">CRITICAL</span> <span class="o">...</span>
 
2279
<span class="n">Calling</span> <span class="n">decorated</span> <span class="n">foo</span> <span class="k">with</span> <span class="kc">False</span>
 
2280
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="o">...</span>
 
2281
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">INFO</span> <span class="o">...</span>
 
2282
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">WARNING</span> <span class="o">...</span>
 
2283
<span class="n">Calling</span> <span class="n">decorated</span> <span class="n">foo</span> <span class="k">with</span> <span class="kc">True</span>
 
2284
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">DEBUG</span> <span class="o">...</span>
 
2285
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">INFO</span> <span class="o">...</span>
 
2286
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">WARNING</span> <span class="o">...</span>
 
2287
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">ERROR</span> <span class="o">...</span>
 
2288
<span class="n">Actually</span> <span class="n">logged</span> <span class="n">at</span> <span class="n">DEBUG</span>
 
2289
<span class="n">Actually</span> <span class="n">logged</span> <span class="n">at</span> <span class="n">INFO</span>
 
2290
<span class="n">Actually</span> <span class="n">logged</span> <span class="n">at</span> <span class="n">WARNING</span>
 
2291
<span class="n">Actually</span> <span class="n">logged</span> <span class="n">at</span> <span class="n">ERROR</span>
 
2292
<span class="n">about</span> <span class="n">to</span> <span class="n">log</span> <span class="n">at</span> <span class="n">CRITICAL</span> <span class="o">...</span>
 
2293
<span class="n">Actually</span> <span class="n">logged</span> <span class="n">at</span> <span class="n">CRITICAL</span>
 
2294
</pre></div>
 
2295
</div>
 
2296
<p>As you can see, actual logging output only occurs when an event is logged whose
 
2297
severity is ERROR or greater, but in that case, any previous events at lower
 
2298
severities are also logged.</p>
 
2299
<p>You can of course use the conventional means of decoration:</p>
 
2300
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="nd">@log_if_errors</span><span class="p">(</span><span class="n">logger</span><span class="p">)</span>
 
2301
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">fail</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
 
2302
    <span class="o">...</span>
 
2303
</pre></div>
 
2304
</div>
 
2305
</div>
 
2306
<div class="section" id="formatting-times-using-utc-gmt-via-configuration">
 
2307
<span id="utc-formatting"></span><h2>Formatting times using UTC (GMT) via configuration<a class="headerlink" href="#formatting-times-using-utc-gmt-via-configuration" title="Permalink to this headline">¶</a></h2>
 
2308
<p>Sometimes you want to format times using UTC, which can be done using a class
 
2309
such as <cite>UTCFormatter</cite>, shown below:</p>
 
2310
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2311
<span class="kn">import</span> <span class="nn">time</span>
 
2312
 
 
2313
<span class="k">class</span> <span class="nc">UTCFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">):</span>
 
2314
    <span class="n">converter</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span>
 
2315
</pre></div>
 
2316
</div>
 
2317
<p>and you can then use the <code class="docutils literal"><span class="pre">UTCFormatter</span></code> in your code instead of
 
2318
<a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal"><span class="pre">Formatter</span></code></a>. If you want to do that via configuration, you can
 
2319
use the <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></code></a> API with an approach illustrated by
 
2320
the following complete example:</p>
 
2321
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2322
<span class="kn">import</span> <span class="nn">logging.config</span>
 
2323
<span class="kn">import</span> <span class="nn">time</span>
 
2324
 
 
2325
<span class="k">class</span> <span class="nc">UTCFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">):</span>
 
2326
    <span class="n">converter</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span>
 
2327
 
 
2328
<span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
 
2329
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
 
2330
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
 
2331
    <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2332
        <span class="s1">&#39;utc&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2333
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="n">UTCFormatter</span><span class="p">,</span>
 
2334
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">,</span>
 
2335
        <span class="p">},</span>
 
2336
        <span class="s1">&#39;local&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2337
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">,</span>
 
2338
        <span class="p">}</span>
 
2339
    <span class="p">},</span>
 
2340
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2341
        <span class="s1">&#39;console1&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2342
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
2343
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;utc&#39;</span><span class="p">,</span>
 
2344
        <span class="p">},</span>
 
2345
        <span class="s1">&#39;console2&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2346
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
 
2347
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;local&#39;</span><span class="p">,</span>
 
2348
        <span class="p">},</span>
 
2349
    <span class="p">},</span>
 
2350
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
 
2351
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console1&#39;</span><span class="p">,</span> <span class="s1">&#39;console2&#39;</span><span class="p">],</span>
 
2352
   <span class="p">}</span>
 
2353
<span class="p">}</span>
 
2354
 
 
2355
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2356
    <span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">LOGGING</span><span class="p">)</span>
 
2357
    <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;The local time is </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">asctime</span><span class="p">())</span>
 
2358
</pre></div>
 
2359
</div>
 
2360
<p>When this script is run, it should print something like:</p>
 
2361
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="mi">2015</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="mi">17</span> <span class="mi">12</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">29</span><span class="p">,</span><span class="mi">501</span> <span class="n">The</span> <span class="n">local</span> <span class="n">time</span> <span class="ow">is</span> <span class="n">Sat</span> <span class="n">Oct</span> <span class="mi">17</span> <span class="mi">13</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">29</span> <span class="mi">2015</span>
 
2362
<span class="mi">2015</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="mi">17</span> <span class="mi">13</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">29</span><span class="p">,</span><span class="mi">501</span> <span class="n">The</span> <span class="n">local</span> <span class="n">time</span> <span class="ow">is</span> <span class="n">Sat</span> <span class="n">Oct</span> <span class="mi">17</span> <span class="mi">13</span><span class="p">:</span><span class="mi">53</span><span class="p">:</span><span class="mi">29</span> <span class="mi">2015</span>
 
2363
</pre></div>
 
2364
</div>
 
2365
<p>showing how the time is formatted both as local time and UTC, one for each
 
2366
handler.</p>
 
2367
</div>
 
2368
<div class="section" id="using-a-context-manager-for-selective-logging">
 
2369
<span id="context-manager"></span><h2>Using a context manager for selective logging<a class="headerlink" href="#using-a-context-manager-for-selective-logging" title="Permalink to this headline">¶</a></h2>
 
2370
<p>There are times when it would be useful to temporarily change the logging
 
2371
configuration and revert it back after doing something. For this, a context
 
2372
manager is the most obvious way of saving and restoring the logging context.
 
2373
Here is a simple example of such a context manager, which allows you to
 
2374
optionally change the logging level and add a logging handler purely in the
 
2375
scope of the context manager:</p>
 
2376
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
 
2377
<span class="kn">import</span> <span class="nn">sys</span>
 
2378
 
 
2379
<span class="k">class</span> <span class="nc">LoggingContext</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 
2380
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">logger</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">handler</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">close</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
 
2381
        <span class="bp">self</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="n">logger</span>
 
2382
        <span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="n">level</span>
 
2383
        <span class="bp">self</span><span class="o">.</span><span class="n">handler</span> <span class="o">=</span> <span class="n">handler</span>
 
2384
        <span class="bp">self</span><span class="o">.</span><span class="n">close</span> <span class="o">=</span> <span class="n">close</span>
 
2385
 
 
2386
    <span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 
2387
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
 
2388
            <span class="bp">self</span><span class="o">.</span><span class="n">old_level</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">level</span>
 
2389
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">level</span><span class="p">)</span>
 
2390
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">handler</span><span class="p">:</span>
 
2391
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">handler</span><span class="p">)</span>
 
2392
 
 
2393
    <span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">et</span><span class="p">,</span> <span class="n">ev</span><span class="p">,</span> <span class="n">tb</span><span class="p">):</span>
 
2394
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
 
2395
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">old_level</span><span class="p">)</span>
 
2396
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">handler</span><span class="p">:</span>
 
2397
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">removeHandler</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">handler</span><span class="p">)</span>
 
2398
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">handler</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">:</span>
 
2399
            <span class="bp">self</span><span class="o">.</span><span class="n">handler</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
 
2400
        <span class="c1"># implicit return of None =&gt; don&#39;t swallow exceptions</span>
 
2401
</pre></div>
 
2402
</div>
 
2403
<p>If you specify a level value, the logger&#8217;s level is set to that value in the
 
2404
scope of the with block covered by the context manager. If you specify a
 
2405
handler, it is added to the logger on entry to the block and removed on exit
 
2406
from the block. You can also ask the manager to close the handler for you on
 
2407
block exit - you could do this if you don&#8217;t need the handler any more.</p>
 
2408
<p>To illustrate how it works, we can add the following block of code to the
 
2409
above:</p>
 
2410
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
 
2411
    <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span>
 
2412
    <span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">())</span>
 
2413
    <span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
 
2414
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;1. This should appear just once on stderr.&#39;</span><span class="p">)</span>
 
2415
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;2. This should not appear.&#39;</span><span class="p">)</span>
 
2416
    <span class="k">with</span> <span class="n">LoggingContext</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">):</span>
 
2417
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;3. This should appear once on stderr.&#39;</span><span class="p">)</span>
 
2418
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;4. This should not appear.&#39;</span><span class="p">)</span>
 
2419
    <span class="n">h</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span>
 
2420
    <span class="k">with</span> <span class="n">LoggingContext</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span> <span class="n">handler</span><span class="o">=</span><span class="n">h</span><span class="p">,</span> <span class="n">close</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
 
2421
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;5. This should appear twice - once on stderr and once on stdout.&#39;</span><span class="p">)</span>
 
2422
    <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;6. This should appear just once on stderr.&#39;</span><span class="p">)</span>
 
2423
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;7. This should not appear.&#39;</span><span class="p">)</span>
 
2424
</pre></div>
 
2425
</div>
 
2426
<p>We initially set the logger&#8217;s level to <code class="docutils literal"><span class="pre">INFO</span></code>, so message #1 appears and
 
2427
message #2 doesn&#8217;t. We then change the level to <code class="docutils literal"><span class="pre">DEBUG</span></code> temporarily in the
 
2428
following <code class="docutils literal"><span class="pre">with</span></code> block, and so message #3 appears. After the block exits, the
 
2429
logger&#8217;s level is restored to <code class="docutils literal"><span class="pre">INFO</span></code> and so message #4 doesn&#8217;t appear. In the
 
2430
next <code class="docutils literal"><span class="pre">with</span></code> block, we set the level to <code class="docutils literal"><span class="pre">DEBUG</span></code> again but also add a handler
 
2431
writing to <code class="docutils literal"><span class="pre">sys.stdout</span></code>. Thus, message #5 appears twice on the console (once
 
2432
via <code class="docutils literal"><span class="pre">stderr</span></code> and once via <code class="docutils literal"><span class="pre">stdout</span></code>). After the <code class="docutils literal"><span class="pre">with</span></code> statement&#8217;s
 
2433
completion, the status is as it was before so message #6 appears (like message
 
2434
#1) whereas message #7 doesn&#8217;t (just like message #2).</p>
 
2435
<p>If we run the resulting script, the result is as follows:</p>
 
2436
<div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python logctx.py
 
2437
<span class="go">1. This should appear just once on stderr.</span>
 
2438
<span class="go">3. This should appear once on stderr.</span>
 
2439
<span class="go">5. This should appear twice - once on stderr and once on stdout.</span>
 
2440
<span class="go">5. This should appear twice - once on stderr and once on stdout.</span>
 
2441
<span class="go">6. This should appear just once on stderr.</span>
 
2442
</pre></div>
 
2443
</div>
 
2444
<p>If we run it again, but pipe <code class="docutils literal"><span class="pre">stderr</span></code> to <code class="docutils literal"><span class="pre">/dev/null</span></code>, we see the following,
 
2445
which is the only message written to <code class="docutils literal"><span class="pre">stdout</span></code>:</p>
 
2446
<div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python logctx.py 2&gt;/dev/null
 
2447
<span class="go">5. This should appear twice - once on stderr and once on stdout.</span>
 
2448
</pre></div>
 
2449
</div>
 
2450
<p>Once again, but piping <code class="docutils literal"><span class="pre">stdout</span></code> to <code class="docutils literal"><span class="pre">/dev/null</span></code>, we get:</p>
 
2451
<div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python logctx.py &gt;/dev/null
 
2452
<span class="go">1. This should appear just once on stderr.</span>
 
2453
<span class="go">3. This should appear once on stderr.</span>
 
2454
<span class="go">5. This should appear twice - once on stderr and once on stdout.</span>
 
2455
<span class="go">6. This should appear just once on stderr.</span>
 
2456
</pre></div>
 
2457
</div>
 
2458
<p>In this case, the message #5 printed to <code class="docutils literal"><span class="pre">stdout</span></code> doesn&#8217;t appear, as expected.</p>
 
2459
<p>Of course, the approach described here can be generalised, for example to attach
 
2460
logging filters temporarily. Note that the above code works in Python 2 as well
 
2461
as Python 3.</p>
 
2462
</div>
 
2463
</div>
 
2464
 
 
2465
 
 
2466
          </div>
 
2467
        </div>
 
2468
      </div>
 
2469
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
 
2470
        <div class="sphinxsidebarwrapper">
 
2471
  <h3><a href="../contents.html">Table Of Contents</a></h3>
 
2472
  <ul>
 
2473
<li><a class="reference internal" href="#">Logging Cookbook</a><ul>
 
2474
<li><a class="reference internal" href="#using-logging-in-multiple-modules">Using logging in multiple modules</a></li>
 
2475
<li><a class="reference internal" href="#logging-from-multiple-threads">Logging from multiple threads</a></li>
 
2476
<li><a class="reference internal" href="#multiple-handlers-and-formatters">Multiple handlers and formatters</a></li>
 
2477
<li><a class="reference internal" href="#logging-to-multiple-destinations">Logging to multiple destinations</a></li>
 
2478
<li><a class="reference internal" href="#configuration-server-example">Configuration server example</a></li>
 
2479
<li><a class="reference internal" href="#dealing-with-handlers-that-block">Dealing with handlers that block</a></li>
 
2480
<li><a class="reference internal" href="#sending-and-receiving-logging-events-across-a-network">Sending and receiving logging events across a network</a></li>
 
2481
<li><a class="reference internal" href="#adding-contextual-information-to-your-logging-output">Adding contextual information to your logging output</a><ul>
 
2482
<li><a class="reference internal" href="#using-loggeradapters-to-impart-contextual-information">Using LoggerAdapters to impart contextual information</a><ul>
 
2483
<li><a class="reference internal" href="#using-objects-other-than-dicts-to-pass-contextual-information">Using objects other than dicts to pass contextual information</a></li>
 
2484
</ul>
 
2485
</li>
 
2486
<li><a class="reference internal" href="#using-filters-to-impart-contextual-information">Using Filters to impart contextual information</a></li>
 
2487
</ul>
 
2488
</li>
 
2489
<li><a class="reference internal" href="#logging-to-a-single-file-from-multiple-processes">Logging to a single file from multiple processes</a></li>
 
2490
<li><a class="reference internal" href="#using-file-rotation">Using file rotation</a></li>
 
2491
<li><a class="reference internal" href="#use-of-alternative-formatting-styles">Use of alternative formatting styles</a></li>
 
2492
<li><a class="reference internal" href="#customizing-logrecord">Customizing <code class="docutils literal"><span class="pre">LogRecord</span></code></a></li>
 
2493
<li><a class="reference internal" href="#subclassing-queuehandler-a-zeromq-example">Subclassing QueueHandler - a ZeroMQ example</a></li>
 
2494
<li><a class="reference internal" href="#subclassing-queuelistener-a-zeromq-example">Subclassing QueueListener - a ZeroMQ example</a></li>
 
2495
<li><a class="reference internal" href="#an-example-dictionary-based-configuration">An example dictionary-based configuration</a></li>
 
2496
<li><a class="reference internal" href="#using-a-rotator-and-namer-to-customize-log-rotation-processing">Using a rotator and namer to customize log rotation processing</a></li>
 
2497
<li><a class="reference internal" href="#a-more-elaborate-multiprocessing-example">A more elaborate multiprocessing example</a></li>
 
2498
<li><a class="reference internal" href="#inserting-a-bom-into-messages-sent-to-a-sysloghandler">Inserting a BOM into messages sent to a SysLogHandler</a></li>
 
2499
<li><a class="reference internal" href="#implementing-structured-logging">Implementing structured logging</a></li>
 
2500
<li><a class="reference internal" href="#customizing-handlers-with-dictconfig">Customizing handlers with <code class="docutils literal"><span class="pre">dictConfig()</span></code></a></li>
 
2501
<li><a class="reference internal" href="#using-particular-formatting-styles-throughout-your-application">Using particular formatting styles throughout your application</a><ul>
 
2502
<li><a class="reference internal" href="#using-logrecord-factories">Using LogRecord factories</a></li>
 
2503
<li><a class="reference internal" href="#using-custom-message-objects">Using custom message objects</a></li>
 
2504
</ul>
 
2505
</li>
 
2506
<li><a class="reference internal" href="#configuring-filters-with-dictconfig">Configuring filters with <code class="docutils literal"><span class="pre">dictConfig()</span></code></a></li>
 
2507
<li><a class="reference internal" href="#customized-exception-formatting">Customized exception formatting</a></li>
 
2508
<li><a class="reference internal" href="#speaking-logging-messages">Speaking logging messages</a></li>
 
2509
<li><a class="reference internal" href="#buffering-logging-messages-and-outputting-them-conditionally">Buffering logging messages and outputting them conditionally</a></li>
 
2510
<li><a class="reference internal" href="#formatting-times-using-utc-gmt-via-configuration">Formatting times using UTC (GMT) via configuration</a></li>
 
2511
<li><a class="reference internal" href="#using-a-context-manager-for-selective-logging">Using a context manager for selective logging</a></li>
 
2512
</ul>
 
2513
</li>
 
2514
</ul>
 
2515
 
 
2516
  <h4>Previous topic</h4>
 
2517
  <p class="topless"><a href="logging.html"
 
2518
                        title="previous chapter">Logging HOWTO</a></p>
 
2519
  <h4>Next topic</h4>
 
2520
  <p class="topless"><a href="regex.html"
 
2521
                        title="next chapter">Regular Expression HOWTO</a></p>
 
2522
  <div role="note" aria-label="source link">
 
2523
    <h3>This Page</h3>
 
2524
    <ul class="this-page-menu">
 
2525
      <li><a href="../bugs.html">Report a Bug</a></li>
 
2526
      <li><a href="../_sources/howto/logging-cookbook.txt"
 
2527
            rel="nofollow">Show Source</a></li>
 
2528
    </ul>
 
2529
  </div>
 
2530
        </div>
 
2531
      </div>
 
2532
      <div class="clearer"></div>
 
2533
    </div>  
 
2534
    <div class="related" role="navigation" aria-label="related navigation">
 
2535
      <h3>Navigation</h3>
 
2536
      <ul>
 
2537
        <li class="right" style="margin-right: 10px">
 
2538
          <a href="../genindex.html" title="General Index"
 
2539
             >index</a></li>
 
2540
        <li class="right" >
 
2541
          <a href="../py-modindex.html" title="Python Module Index"
 
2542
             >modules</a> |</li>
 
2543
        <li class="right" >
 
2544
          <a href="regex.html" title="Regular Expression HOWTO"
 
2545
             >next</a> |</li>
 
2546
        <li class="right" >
 
2547
          <a href="logging.html" title="Logging HOWTO"
 
2548
             >previous</a> |</li>
 
2549
        <li><img src="../_static/py.png" alt=""
 
2550
                 style="vertical-align: middle; margin-top: -1px"/></li>
 
2551
        <li><a href="https://www.python.org/">Python</a> &raquo;</li>
 
2552
        <li>
 
2553
          <span class="version_switcher_placeholder">3.5.2</span>
 
2554
          <a href="../index.html">Documentation </a> &raquo;
 
2555
        </li>
 
2556
 
 
2557
          <li class="nav-item nav-item-1"><a href="index.html" >Python HOWTOs</a> &raquo;</li>
 
2558
    <li class="right">
 
2559
        
 
2560
 
 
2561
    <div class="inline-search" style="display: none" role="search">
 
2562
        <form class="inline-search" action="../search.html" method="get">
 
2563
          <input placeholder="Quick search" type="text" name="q" />
 
2564
          <input type="submit" value="Go" />
 
2565
          <input type="hidden" name="check_keywords" value="yes" />
 
2566
          <input type="hidden" name="area" value="default" />
 
2567
        </form>
 
2568
    </div>
 
2569
    <script type="text/javascript">$('.inline-search').show(0);</script>
 
2570
         |
 
2571
    </li>
 
2572
 
 
2573
      </ul>
 
2574
    </div>  
 
2575
    <div class="footer">
 
2576
    &copy; <a href="../copyright.html">Copyright</a> 2001-2016, Python Software Foundation.
 
2577
    <br />
 
2578
    The Python Software Foundation is a non-profit corporation.
 
2579
    <a href="https://www.python.org/psf/donations/">Please donate.</a>
 
2580
    <br />
 
2581
    Last updated on Sep 23, 2016.
 
2582
    <a href="../bugs.html">Found a bug</a>?
 
2583
    <br />
 
2584
    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3.3.
 
2585
    </div>
 
2586
 
 
2587
  </body>
 
2588
</html>
 
 
b'\\ No newline at end of file'