/usr/share/doc/python-logbook-doc/html/setups.html is in python-logbook-doc 0.7.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Common Logbook Setups — Logbook</title>
<link rel="stylesheet" href="_static/sheet.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.7.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Logbook" href="index.html" />
<link rel="next" title="Stacks in Logbook" href="stacks.html" />
<link rel="prev" title="Quickstart" href="quickstart.html" />
</head>
<body>
<div class="book">
<div class="banner">
<a href="index.html">
<!-- <img src="_static/" alt="Logbook logo"></img> -->
<h1>Logbook </h1>
</a>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="stacks.html" title="Stacks in Logbook"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="quickstart.html" title="Quickstart"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Logbook 0.7.0</a> »</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body">
<div class="section" id="common-logbook-setups">
<h1>Common Logbook Setups</h1>
<p>This part of the documentation shows how you can configure Logbook for
different kinds of setups.</p>
<div class="section" id="desktop-application-setup">
<h2>Desktop Application Setup</h2>
<p>If you develop a desktop application (command line or GUI), you probably have a line
like this in your code:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<p>This is what you should wrap with a <tt class="docutils literal"><span class="pre">with</span></tt> statement that sets up your log
handler:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook</span> <span class="kn">import</span> <span class="n">FileHandler</span>
<span class="n">log_handler</span> <span class="o">=</span> <span class="n">FileHandler</span><span class="p">(</span><span class="s">'application.log'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="k">with</span> <span class="n">log_handler</span><span class="o">.</span><span class="n">applicationbound</span><span class="p">():</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<p>Alternatively you can also just push a handler in there:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook</span> <span class="kn">import</span> <span class="n">FileHandler</span>
<span class="n">log_handler</span> <span class="o">=</span> <span class="n">FileHandler</span><span class="p">(</span><span class="s">'application.log'</span><span class="p">)</span>
<span class="n">log_handler</span><span class="o">.</span><span class="n">push_application</span><span class="p">()</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
<p>Please keep in mind that you will have to pop the handlers in reverse order if
you want to remove them from the stack, so it is recommended to use the context
manager API if you plan on reverting the handlers.</p>
</div>
<div class="section" id="web-application-setup">
<h2>Web Application Setup</h2>
<p>Typical modern web applications written in Python have two separate contexts
where code might be executed: when the code is imported, as well as when a
request is handled. The first case is easy to handle, just push a global file
handler that writes everything into a file.</p>
<p>But Logbook also gives you the ability to improve upon the logging. For
example, you can easily create yourself a log handler that is used for
request-bound logging that also injects additional information.</p>
<p>For this you can either subclass the logger or you can bind to the handler with
a function that is invoked before logging. The latter has the advantage that it
will also be triggered for other logger instances which might be used by a
different library.</p>
<p>Here is a simple WSGI example application that showcases sending error mails for
errors happened during a WSGI application:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook</span> <span class="kn">import</span> <span class="n">MailHandler</span>
<span class="n">mail_handler</span> <span class="o">=</span> <span class="n">MailHandler</span><span class="p">(</span><span class="s">'errors@example.com'</span><span class="p">,</span>
<span class="p">[</span><span class="s">'admin@example.com'</span><span class="p">],</span>
<span class="n">format_string</span><span class="o">=</span><span class="s">u'''</span><span class="se">\</span>
<span class="s">Subject: Application Error at {record.extra[url]}</span>
<span class="s">Message type: {record.level_name}</span>
<span class="s">Location: {record.filename}:{record.lineno}</span>
<span class="s">Module: {record.module}</span>
<span class="s">Function: {record.func_name}</span>
<span class="s">Time: {record.time:%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S}</span>
<span class="s">Remote IP: {record.extra[ip]}</span>
<span class="s">Request: {record.extra[url]} [{record.extra[method]}]</span>
<span class="s">Message:</span>
<span class="s">{record.message}</span>
<span class="s">'''</span><span class="p">,</span> <span class="n">bubble</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">application</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
<span class="n">request</span> <span class="o">=</span> <span class="n">Request</span><span class="p">(</span><span class="n">environ</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">inject_info</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">handler</span><span class="p">):</span>
<span class="n">record</span><span class="o">.</span><span class="n">extra</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
<span class="n">ip</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">remote_addr</span><span class="p">,</span>
<span class="n">method</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">method</span><span class="p">,</span>
<span class="n">url</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">url</span>
<span class="p">)</span>
<span class="k">with</span> <span class="n">mail_handler</span><span class="o">.</span><span class="n">threadbound</span><span class="p">(</span><span class="n">processor</span><span class="o">=</span><span class="n">inject_info</span><span class="p">):</span>
<span class="c"># standard WSGI processing happens here. If an error</span>
<span class="c"># is logged, a mail will be sent to the admin on</span>
<span class="c"># example.com</span>
<span class="o">...</span>
</pre></div>
</div>
</div>
<div class="section" id="deeply-nested-setups">
<h2>Deeply Nested Setups</h2>
<p>If you want deeply nested logger setups, you can use the
<a class="reference internal" href="api/handlers.html#logbook.NestedSetup" title="logbook.NestedSetup"><tt class="xref py py-class docutils literal"><span class="pre">NestedSetup</span></tt></a> class which simplifies that. This is best
explained using an example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">logbook</span> <span class="kn">import</span> <span class="n">NestedSetup</span><span class="p">,</span> <span class="n">NullHandler</span><span class="p">,</span> <span class="n">FileHandler</span><span class="p">,</span> \
<span class="n">MailHandler</span><span class="p">,</span> <span class="n">Processor</span>
<span class="k">def</span> <span class="nf">inject_information</span><span class="p">(</span><span class="n">record</span><span class="p">):</span>
<span class="n">record</span><span class="o">.</span><span class="n">extra</span><span class="p">[</span><span class="s">'cwd'</span><span class="p">]</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
<span class="c"># a nested handler setup can be used to configure more complex setups</span>
<span class="n">setup</span> <span class="o">=</span> <span class="n">NestedSetup</span><span class="p">([</span>
<span class="c"># make sure we never bubble up to the stderr handler</span>
<span class="c"># if we run out of setup handling</span>
<span class="n">NullHandler</span><span class="p">(),</span>
<span class="c"># then write messages that are at least warnings to to a logfile</span>
<span class="n">FileHandler</span><span class="p">(</span><span class="s">'application.log'</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="s">'WARNING'</span><span class="p">),</span>
<span class="c"># errors should then be delivered by mail and also be kept</span>
<span class="c"># in the application log, so we let them bubble up.</span>
<span class="n">MailHandler</span><span class="p">(</span><span class="s">'servererrors@example.com'</span><span class="p">,</span>
<span class="p">[</span><span class="s">'admin@example.com'</span><span class="p">],</span>
<span class="n">level</span><span class="o">=</span><span class="s">'ERROR'</span><span class="p">,</span> <span class="n">bubble</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="c"># while we're at it we can push a processor on its own stack to</span>
<span class="c"># record additional information. Because processors and handlers</span>
<span class="c"># go to different stacks it does not matter if the processor is</span>
<span class="c"># added here at the bottom or at the very beginning. Same would</span>
<span class="c"># be true for flags.</span>
<span class="n">Processor</span><span class="p">(</span><span class="n">inject_information</span><span class="p">)</span>
<span class="p">])</span>
</pre></div>
</div>
<p>Once such a complex setup is defined, the nested handler setup can be used as if
it was a single handler:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="n">setup</span><span class="o">.</span><span class="n">threadbound</span><span class="p">():</span>
<span class="c"># everything here is handled as specified by the rules above.</span>
<span class="o">...</span>
</pre></div>
</div>
</div>
<div class="section" id="distributed-logging">
<h2>Distributed Logging</h2>
<p>For applications that are spread over multiple processes or even machines
logging into a central system can be a pain. Logbook supports ZeroMQ to
deal with that. You can set up a <a class="reference internal" href="api/queues.html#logbook.queues.ZeroMQHandler" title="logbook.queues.ZeroMQHandler"><tt class="xref py py-class docutils literal"><span class="pre">ZeroMQHandler</span></tt></a>
that acts as ZeroMQ publisher and will send log records encoded as JSON
over the wire:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook.queues</span> <span class="kn">import</span> <span class="n">ZeroMQHandler</span>
<span class="n">handler</span> <span class="o">=</span> <span class="n">ZeroMQHandler</span><span class="p">(</span><span class="s">'tcp://127.0.0.1:5000'</span><span class="p">)</span>
</pre></div>
</div>
<p>Then you just need a separate process that can receive the log records and
hand it over to another log handler using the
<a class="reference internal" href="api/queues.html#logbook.queues.ZeroMQSubscriber" title="logbook.queues.ZeroMQSubscriber"><tt class="xref py py-class docutils literal"><span class="pre">ZeroMQSubscriber</span></tt></a>. The usual setup is this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook.queues</span> <span class="kn">import</span> <span class="n">ZeroMQSubscriber</span>
<span class="n">subscriber</span> <span class="o">=</span> <span class="n">ZeroMQSubscriber</span><span class="p">(</span><span class="s">'tcp://127.0.0.1:5000'</span><span class="p">)</span>
<span class="k">with</span> <span class="n">my_handler</span><span class="p">:</span>
<span class="n">subscriber</span><span class="o">.</span><span class="n">dispatch_forever</span><span class="p">()</span>
</pre></div>
</div>
<p>You can also run that loop in a background thread with
<a class="reference internal" href="api/queues.html#logbook.queues.ZeroMQSubscriber.dispatch_in_background" title="logbook.queues.ZeroMQSubscriber.dispatch_in_background"><tt class="xref py py-meth docutils literal"><span class="pre">dispatch_in_background()</span></tt></a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">logbook.queues</span> <span class="kn">import</span> <span class="n">ZeroMQSubscriber</span>
<span class="n">subscriber</span> <span class="o">=</span> <span class="n">ZeroMQSubscriber</span><span class="p">(</span><span class="s">'tcp://127.0.0.1:5000'</span><span class="p">)</span>
<span class="n">subscriber</span><span class="o">.</span><span class="n">dispatch_in_background</span><span class="p">(</span><span class="n">my_handler</span><span class="p">)</span>
</pre></div>
</div>
<p>If you just want to use this in a <a class="reference external" href="/usr/share/doc/python2.7/html/library/multiprocessing.html#module-multiprocessing" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal"><span class="pre">multiprocessing</span></tt></a> environment you
can use the <a class="reference internal" href="api/queues.html#logbook.queues.MultiProcessingHandler" title="logbook.queues.MultiProcessingHandler"><tt class="xref py py-class docutils literal"><span class="pre">MultiProcessingHandler</span></tt></a> and
<a class="reference internal" href="api/queues.html#logbook.queues.MultiProcessingSubscriber" title="logbook.queues.MultiProcessingSubscriber"><tt class="xref py py-class docutils literal"><span class="pre">MultiProcessingSubscriber</span></tt></a> instead. They work the
same way as the ZeroMQ equivalents but are connected through a
<a class="reference external" href="/usr/share/doc/python2.7/html/library/multiprocessing.html#multiprocessing.Queue" title="(in Python v2.7)"><tt class="xref py py-class docutils literal"><span class="pre">multiprocessing.Queue</span></tt></a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="kn">import</span> <span class="n">Queue</span>
<span class="kn">from</span> <span class="nn">logbook.queues</span> <span class="kn">import</span> <span class="n">MultiProcessingHandler</span><span class="p">,</span> \
<span class="n">MultiProcessingSubscriber</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="n">handler</span> <span class="o">=</span> <span class="n">MultiProcessingHandler</span><span class="p">(</span><span class="n">queue</span><span class="p">)</span>
<span class="n">subscriber</span> <span class="o">=</span> <span class="n">MultiProcessingSubscriber</span><span class="p">(</span><span class="n">queue</span><span class="p">)</span>
</pre></div>
</div>
<p>There is also the possibility to log into a Redis instance using the
<a class="reference internal" href="api/queues.html#logbook.queues.RedisHandler" title="logbook.queues.RedisHandler"><tt class="xref py py-class docutils literal"><span class="pre">RedisHandler</span></tt></a>. To do so, you just need to create an
instance of this handler as follows:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">logbook</span>
<span class="kn">from</span> <span class="nn">logbook.queues</span> <span class="kn">import</span> <span class="n">RedisHandler</span>
<span class="n">handler</span> <span class="o">=</span> <span class="n">RedisHandler</span><span class="p">()</span>
<span class="n">l</span> <span class="o">=</span> <span class="n">logbook</span><span class="o">.</span><span class="n">Logger</span><span class="p">()</span>
<span class="k">with</span> <span class="n">handler</span><span class="p">:</span>
<span class="n">l</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Your log message'</span><span class="p">)</span>
</pre></div>
</div>
<p>With the default parameters, this will send a message to redis under the key redis.</p>
</div>
<div class="section" id="redirecting-single-loggers">
<h2>Redirecting Single Loggers</h2>
<p>If you want to have a single logger go to another logfile you have two
options. First of all you can attach a handler to a specific record
dispatcher. So just import the logger and attach something:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication.yourmodule</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="n">logger</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MyHandler</span><span class="p">(</span><span class="o">...</span><span class="p">))</span>
</pre></div>
</div>
<p>Handlers attached directly to a record dispatcher will always take
precedence over the stack based handlers. The bubble flag works as
expected, so if you have a non-bubbling handler on your logger and it
always handles, it will never be passed to other handlers.</p>
<p>Secondly you can write a handler that looks at the logging channel and
only accepts loggers of a specific kind. You can also do that with a
filter function:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">handler</span> <span class="o">=</span> <span class="n">MyHandler</span><span class="p">(</span><span class="nb">filter</span><span class="o">=</span><span class="k">lambda</span> <span class="n">r</span><span class="p">:</span> <span class="n">r</span><span class="o">.</span><span class="n">channel</span> <span class="o">==</span> <span class="s">'app.database'</span><span class="p">)</span>
</pre></div>
</div>
<p>Keep in mind that the channel is intended to be a human readable string
and is not necessarily unique. If you really need to keep loggers apart
on a central point you might want to introduce some more meta information
into the extra dictionary.</p>
<p>You can also compare the dispatcher on the log record:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication.yourmodule</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="n">handler</span> <span class="o">=</span> <span class="n">MyHandler</span><span class="p">(</span><span class="nb">filter</span><span class="o">=</span><span class="k">lambda</span> <span class="n">r</span><span class="p">:</span> <span class="n">r</span><span class="o">.</span><span class="n">dispatcher</span> <span class="ow">is</span> <span class="n">logger</span><span class="p">)</span>
</pre></div>
</div>
<p>This however has the disadvantage that the dispatcher entry on the log
record is a weak reference and might go away unexpectedly and will not be
there if log records are sent to a different process.</p>
<p>Last but not least you can check if you can modify the stack around the
execution of the code that triggers that logger For instance if the
logger you are interested in is used by a specific subsystem, you can
modify the stacks before calling into the system.</p>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="stacks.html" title="Stacks in Logbook"
>next</a> |</li>
<li class="right" >
<a href="quickstart.html" title="Quickstart"
>previous</a> |</li>
<li><a href="index.html">Logbook 0.7.0</a> »</li>
</ul>
</div>
<div class="footer">
© Copyright 2010, Armin Ronacher, Georg Brandl.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
</div>
</div>
</body>
</html>
|