~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/python/logging/logging-0.4.9.2/python_logging.html

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
 
2
"http://www.w3.org/TR/REC-html40/loose.dtd">
 
3
<html>
 
4
 
 
5
<head>
 
6
<meta name="AUTHOR" content="Vinay Sajip">
 
7
<meta name="COPYRIGHT" content="ļæ½ 2002 Red Dove Consultants Limited">
 
8
<meta name="KEYWORDS" content="Red Dove Consultants, Python, logging, PEP 282">
 
9
<meta name="DESCRIPTION" content="A logging system for Python">
 
10
<meta name="summary" content="A logging system for Python">
 
11
<meta name="publisher" content="Red Dove Consultants Limited">
 
12
<meta name="identifier" content="http://www.red-dove.com">
 
13
<title>A Logging System for Python</title>
 
14
<link title="Default Style" rel="stylesheet" href="default.css" type="text/css">
 
15
</head>
 
16
 
 
17
<body style="margin: 5px" marginheight="0">
 
18
<table border="0" width="100%" cellspacing="0" cellpadding="0">
 
19
  <tr>
 
20
    <td class="bigtd">A Logging System for Python</td>
 
21
    <td rowspan="2" align="right" style="text-align: right; vertical-align: top"><a href="/index.html">Home</a><br>
 
22
    <a href="#download">Download</a><br>
 
23
    <a href="#license">Copyright &amp; License</a><br>
 
24
    <a href="#changes">Recent Changes</a><br>
 
25
    <!-- a href="logging_manual.html">Online Manual</a --></td>
 
26
  </tr>
 
27
  <tr>
 
28
  <td>"Oh, I'm a lumberjack and I'm okay..." <small>(Monty Python, <a href="http://www.montypython.net/scripts/lumberj.php">The Lumberjack Song</a>)</small></td>
 
29
  </tr>
 
30
</table>
 
31
 
 
32
<h4>Table of Contents</h4>
 
33
<a href="#abstract">Abstract</a><br>
 
34
<a href="#motivation">Motivation</a><br>
 
35
<a href="#influences">Influences</a><br>
 
36
<a href="#simplest">A Simple Example</a><br>
 
37
<a href="#ctrlflow">Control Flow</a><br>
 
38
<a href="#levels">Levels</a><br>
 
39
<a href="#loggers">Loggers</a><br>
 
40
<a href="#handlers">Handlers</a><br>
 
41
<a href="#formatters">Formatters</a><br>
 
42
<a href="#filters">Filters</a><br>
 
43
<a href="#config">Configuration</a><br>
 
44
<a href="#guiconf">The GUI Configurator</a><br>
 
45
<a href="#scenarios">Case Scenarios</a><br>
 
46
<a href="#threadsafe">Thread Safety</a><br>
 
47
<a href="#onthefly">On-The-Fly Reconfiguration</a><br>
 
48
<a href="#mlcf">Module-Level Convenience Functions</a><br>
 
49
<a href="#perf">Performance</a><br>
 
50
<a href="#impstatus">Implementation Status</a><br>
 
51
<a href="#acks">Acknowledgements</a><br>
 
52
<a href="#todo">Still To Do</a><br>
 
53
<a href="#download">Download and Installation</a><br>
 
54
<a href="#changes">Change History</a><br>
 
55
<a href="#license">Copyright and License</a><br>
 
56
 
 
57
<a name="abstract"></a><h4>Abstract</h4>
 
58
 
 
59
<p>There is a need for a standard logging system in Python, as comprehensively documented
 
60
in <a href="http://www.python.org/peps/pep-0282.html">PEP 282</a> and
 
61
enthusiastically endorsed by the BDFL in the <a
 
62
href="http://www.python.org/doc/essays/pepparade.html">Parade of the PEPs</a>. By a happy
 
63
coincidence, the package described here was already in development and fairly close in
 
64
intent and design to the description in the aforementioned PEP, borrowing as it did
 
65
heavily from JSR-47 (now JDK 1.4's java.util.logging package) and <a
 
66
href="http://jakarta.apache.org/log4j/">log4j</a>. This page describes it in more detail.
 
67
As I have tweaked the package to meet comments on PEP 282, I have structured this page in
 
68
the same way as the original PEP. </p>
 
69
 
 
70
<a name="motivation"></a><h4>Motivation</h4>
 
71
 
 
72
<p>The Python community has been incredibly helpful to me, a relative newcomer to the
 
73
language. Python and its community has certainly saved me much time and effort, and it
 
74
seems appropriate to give something back to the community by offering up this package for
 
75
people to try. Any <a href="mailto:vinay_sajip@red-dove.com">feedback</a> will be gratefully accepted. </p>
 
76
 
 
77
<a name="influences"></a><h4>Influences</h4>
 
78
 
 
79
<p>This package owes its greatest debt to Apache <a
 
80
href="http://jakarta.apache.org/log4j/">log4j</a>. Due notice was also taken of log4j's
 
81
comprehensive <a href="http://jakarta.apache.org/log4j/docs/critique.html">critique</a> of
 
82
JSR47. This package bears a close resemblance to log4j, but is not a close translation
 
83
(as, for example, <a href="http://log4p.sourceforge.net/">log4p</a> appears to be). I have
 
84
attempted to be more minimalist (and hopefully more Pythonic) in my approach. You be the
 
85
judge! </p>
 
86
 
 
87
<a name="simplest"></a><h4>A Simple Example</h4>
 
88
 
 
89
<p>Using the package doesn't get much simpler. It is packaged as a standard Python package called (unsurprisingly) <code>logging</code>. You just need to <code>import logging</code> and you're ready to go. Minimal example: </p>
 
90
 
 
91
<pre class="program">
 
92
# --- app.py --------------------------------------------------------------------
 
93
import logging
 
94
 
 
95
logging.warn(&quot;Hello&quot;)
 
96
logging.error(&quot;Still here...&quot;)
 
97
logging.warn(&quot;Goodbye&quot;)
 
98
</pre>
 
99
 
 
100
<p>When you run <code>app.py</code>, the results are: </p>
 
101
 
 
102
<pre class="output">
 
103
WARN:root:Hello
 
104
ERROR:root:Still here...
 
105
WARN:root:Goodbye
 
106
</pre>
 
107
 
 
108
<p>Don't worry about the format of the output - it's all configurable. Here's a slightly
 
109
more involved example; if you've just looked at PEP 282 you will probably get a feeling of
 
110
dejļæ½ vu. (This is intentional.)</p>
 
111
 
 
112
<a name="nextsimplest"></a><pre class="program">
 
113
# --- mymodule.py --------------------------------------------------------------------
 
114
import logging
 
115
log = logging.getLogger(&quot;MyModule&quot;)
 
116
 
 
117
def doIt():
 
118
    log.debug(&quot;doin' stuff&quot;)
 
119
    <span class="comment">#do stuff...but suppose an error occurs?</span>
 
120
    raise TypeError, &quot;bogus type error for testing&quot;
 
121
 
 
122
# --- myapp.py -----------------------------------------------------------------------
 
123
import logging, mymodule
 
124
 
 
125
logging.basicConfig()
 
126
 
 
127
log = logging.getLogger(&quot;MyApp&quot;)
 
128
log.setLevel(logging.DEBUG) <span class="comment">#set verbosity to show all messages of severity >= DEBUG</span>
 
129
log.info(&quot;Starting my app&quot;)
 
130
try:
 
131
    mymodule.doIt()
 
132
except Exception, e:
 
133
    log.exception(&quot;There was a problem.&quot;)
 
134
log.info(&quot;Ending my app&quot;)
 
135
</pre>
 
136
 
 
137
<p>When you run <code>myapp.py</code>, the results are: </p>
 
138
 
 
139
<pre class="output">
 
140
INFO:MyApp:Starting my app
 
141
ERROR:MyApp:There was a problem.
 
142
Traceback (most recent call last):
 
143
  File "myapp.py", line 9, in ?
 
144
    mymodule.doIt()
 
145
  File "mymodule.py", line 7, in doIt
 
146
    raise TypeError, "Bogus type error for testing"
 
147
TypeError: Bogus type error for testing
 
148
INFO:MyApp:Ending my app
 
149
</pre>
 
150
 
 
151
<p>But don't worry - the above output is not hardcoded into the package. It's just an
 
152
example of what you can do with very little work. As you can see, exceptions are handled
 
153
as one would expect. </p>
 
154
 
 
155
<a name="ctrlflow"></a><h4>Control Flow</h4>
 
156
 
 
157
<p>The package pretty much matches the PEP regarding control flow. The user of the package
 
158
makes logging calls on instances of <code>Logger</code>, which are organized into a
 
159
hierarchy based on a &quot;dotted name&quot; namespace. This hierarchy is embodied in an
 
160
encapsulated singleton <code>Manager</code> instance (which can be ignored by users of the
 
161
package, for most purposes). Based on the type of logging call and the logging
 
162
configuration (see below), the call may be passed through a set of <code>Filter</code>
 
163
instances to decide whether it should be dropped. If not, then the logger consults a set
 
164
of <code>Handler</code> instances which are associated with it, and asks each handler
 
165
instance to &quot;handle&quot; the logging event. By default, the system moves up the
 
166
namespace hierarchy and invokes handlers on all loggers at or above the level of the
 
167
logger on which the logging call was made. (You can override this by setting a logger's
 
168
&quot;propagate&quot; attribute to 0 - no traversal up the hierarchy is made from such a
 
169
logger. But I'm getting ahead of myself...) </p>
 
170
 
 
171
<p>Handlers are passed <code>LogRecord</code> instances which (should) contain all the
 
172
information we're interested in logging. Handlers, too, can invoke filters to determine
 
173
whether a record should be dropped. If not, then the handler takes a handler-specific
 
174
action to actually log the record to a file, the console or whatever.</p>
 
175
 
 
176
<a name="levels"></a><h4>Levels</h4>
 
177
 
 
178
<p>The following levels are implemented by default: </p>
 
179
 
 
180
<pre>
 
181
DEBUG
 
182
INFO
 
183
WARN
 
184
ERROR
 
185
CRITICAL
 
186
</pre>
 
187
 
 
188
<p>The <code>CRITICAL</code> level replaces the earlier <code>FATAL</code> level. You can use either (for now), but <code>CRITICAL</code> is preferred since <code>FATAL</code> implies that the application is about to terminate. This is not true for many systems which use logging - for example, a Web server application which encounters a <code>CRITICAL</code> condition (e.g. running out of resources) will still try to keep going as best it can.</p>
 
189
<p><code>FATAL</code> (and the corresponding <code>fatal()</code> methods) may be removed in future versions of the package. Currently, <code>CRITICAL</code> is synonymous with <code>FATAL</code> and <code>critical()</code> methods are synonymous with <code>fatal()</code>.</p>
 
190
<p>Exceptions logged via <code>exception()</code> use the <code>ERROR</code> level for logging. If it is desired to log exception information with arbitrary logging levels, this can be done by passing a keyword argument <code>exc_info</code> with a true value to the logging methods (see the pydoc for more details).</p>
 
191
<p>The levels are not deeply hardcoded into the package - the number of levels, their numeric values and their textual representation are all configurable. The above levels represent the experience of the log4j community and so are provided as the default levels for users who do not have very specific requirements in this area.</p>
 
192
<p>The example script <code>log_test4.py</code> shows the use of bespoke logging levels (as well as filtering by level at logger and handler, as well as use of filter classes).</p>
 
193
 
 
194
<a name="loggers"></a><h4>Loggers</h4>
 
195
 
 
196
<p>The package implements loggers pretty much as mentioned in the PEP, except that the manager class is called <code>Manager</code> rather than <code>LogManager</code>.</p>
 
197
<p>Each Logger instance represents "an area" of the application. This somewhat nebulous definition is needed because it's entirely up to each application developer to define an application's "areas".</p><p>For example, an application which reads and processes spreadsheet-type data in different formats might have an overall area "input", concerned with reading input files; and areas "input.csv", "input.xls" and "input.gnu", related to processing comma-separated-value, Excel and Gnumeric input files. Logging messages relating to the overall input function (e.g. deciding which files to process) might be logged used the logger named "input"; logging messages relating to reading individual files might be sent to any of "input.csv", "input.xls" or "input.gnu" depending on the type of file being read.</p><p>The advantage of the hierarchical structure is that logging verbosity may be controlled either at the high level or the low level. The levels are loosely coupled and new levels can easily be added at a later date, e.g."input.wks" for reading Lotus-123 format files. It's also possible to do things like routing messages relating to Excel file input to whoever is working on Excel imports, messages related to Gnumeric file processing to a different developer, and so on. Even if the same person works on both, they can at different times focus logging verbosity on particular areas of interest - for example, when debugging Excel imports, they can set the "input.xls" logger's verbosity to DEBUG and others to CRITICAL, and when moving to debug Gnumeric imports, they can reduce the "input.xls" verbosity by setting the level to CRITICAL, while increasing "input.gnu"'s verbosity by setting the level to DEBUG.</p>
 
198
 
 
199
<a name="handlers"></a><h4>Handlers</h4>
 
200
 
 
201
<p>The following handlers are implemented. I guess they could use more testing ;-)
 
202
 
 
203
<ul>
 
204
  <li>StreamHandler - logging to a stream, defaulting to sys.stderr.</li>
 
205
  <li>FileHandler - logging to disk files.</li>
 
206
  <li>RotatingFileHandler - logging to disk files with support for rollover, rotating files.</li>
 
207
  <li>SocketHandler - logging to a streaming socket.</li>
 
208
  <li>DatagramHandler - logging to a UDP socket.</li>
 
209
  <li>SMTPHandler - logging to an email address.</li>
 
210
  <li>SysLogHandler - logging to Unix syslog. Contributed by Nicolas Untz, based on <a href="http://www.nightmare.com/squirl/python-ext/misc/syslog.py
 
211
">Sam Rushing's syslog module</a>.</li>
 
212
  <li>MemoryHandler - buffering records in memory until a specific trigger occurs (or until the buffer gets full).</li>
 
213
  <li>NTEventLogHandler - writes events to the NT event log. For this to work, you need to have Mark Hammond's Win32 extensions installed. (Though of course you can still log to NT from other platforms - just use SocketHandler to redirect to an NT machine).</li>
 
214
  <li>HTTPHandler - sends events to a Web server using either GET or POST semantics.</li>
 
215
</ul>
 
216
<p>All of these except the first two are defined in a sub-module, handlers.py. (To use these handlers, you'll need to <code>import logging.handlers</code>. In addition to the above list, there are example implementations of <code>XMLHandler</code> (see <code>log_test9.py</code>), <code>BufferingSMTPHandler</code> (see <code>log_test11.py</code>) and <code>DBHandler</code> (see <code>log_test14.py</code>) in the test harnesses, on which you can base more specific classes. There is also a class called <code>SLHandler</code> (see <code>log_test1.py</code>) which implements an alternative SysLogHandler - one which uses the syslog module in the standard library (and which is therefore only available on Unix).</p>
 
217
<p>SOAPHandler, which sends events to a SOAP server, has moved (as of release 0.4.4) from the core to an example script (log_test13.py). The SOAP message is packaged as a function call to a single <code>log()</code> function on the remote server, which takes each relevant member of the  LogRecord as a positional parameter. This is perhaps not ideal - but then this SOAPHandler is just a proof-of-concept example to get you started ;-)</p>
 
218
<p>Note that the handlers are specifically intended <I>not</I> to raise exceptions when errors occur at runtime. This is to avoid error messages from the logging infrastructure polluting logging messages from the application being logged. If, for example, a SocketHandler sees a connection reset by the remote endpoint, it will silently drop all records passed to it (but it will try to connect each time). It may be that due to bugs there are some exceptions incorrectly raised by the logging system, I will try to rectify this kind of problem as soon as it is found and reported!</p>
 
219
 
 
220
<a name="formatters"></a><h4>Formatters</h4>
 
221
 
 
222
<p>A basic Formatter has been implemented, which should cater for most immediate
 
223
requirements. You basically initialize the Formatter with a format string which knows how the attribute dictionary of a LogRecord looks. For example, the output in the example above was produced
 
224
with a format string of <code>&quot;%(asctime)s %(name)-19s %(levelname)-5s -
 
225
%(message)s&quot;</code>. Note that the &quot;message&quot; attribute of the <code>LogRecord</code>
 
226
is derived from <code>&quot;msg % args&quot;</code> where <code>msg</code> and <code>args</code>
 
227
are passed by the the user in a logging call.</p>
 
228
 
 
229
<a name="filters"></a><h4>Filters</h4>
 
230
 
 
231
<p>Filters are used to refine logging output at either logger or handler level with a finer control than is available by just using logging levels. The basic Filter class takes an optional name argument and passes all logging records from loggers which are at or below the specified name.</p>
 
232
<p>For example, a <code>Filter</code> initialized with "A.B" will allow events logged by loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" but not "A.BB", "B.A.B".  If no name is specified, all events are passed by the filter.</p>
 
233
 
 
234
<a name="config"></a><h4>Configuration</h4>
 
235
 
 
236
<p>A basic configuration is provided via a module-level function, <code>basicConfig()</code>.
 
237
If you want to use very simple logging, you can just call the <a href="#mlcf">module-level
 
238
convenience functions</a> and they will call <code>basicConfig()</code> for you if
 
239
necessary. It (basically) adds a <code>StreamHandler</code> (which writes to <code>sys.stderr</code>)to the root <code>Logger</code>.</p>
 
240
 
 
241
<p>There are numerous examples of configuration in the test/example scripts included in the distribution. For example, <code>log_test8.py</code> has an example of using a file-based logger.</p>
 
242
<p>An alternative using ConfigParser-based configuration files is also available (the older, dict-based function is no more). To use this functionality, you'll need to <code>import logging.config</code>. Here is an example of such a config file - it's a bit long, but a full working example so bear with me. I've annotated it as best I can :-): </p>
 
243
<p>
 
244
In the listing below, some values are used by both the logging configuration API
 
245
and the GUI configurator, while others are used only by the GUI configurator. To
 
246
make it clearer which values you absolutely need to have in the .ini file for it to be useful even if you hand-code it, the values used by the configuration API are shown
 
247
<span class="program"><span class="strong">like this</span></span>. (The other ones are used by the GUI configurator, but ignored by the configuration API.)
 
248
</p>
 
249
<pre class="program">
 
250
# --- logconf.ini -----------------------------------------------------------
 
251
#The "loggers" section contains the key names for all the loggers in this
 
252
#configuration. These are not the actual channel names, but values used to
 
253
#identify where the parameters for each logger are found in this file.
 
254
#The section for an individual logger is named "logger_xxx" where the "key"
 
255
#for a logger is "xxx". So ... "logger_root", "logger_log02", etc. further
 
256
#down the file, indicate how the root logger is set up, logger "log_02" is set
 
257
#up, and so on.
 
258
#Logger key names can be any identifier, except "root" which is reserved for
 
259
#the root logger. (The names "lognn" are generated by the GUI configurator.)
 
260
 
 
261
<span class="strong">[loggers]
 
262
keys=root,log02,log03,log04,log05,log06,log07</span>
 
263
 
 
264
#The "handlers" section contains the key names for all the handlers in this
 
265
#configuration. Just as for loggers above, the key names are values used to
 
266
#identify where the parameters for each handler are found in this file.
 
267
#The section for an individual handler is named "handler_xxx" where the "key"
 
268
#for a handler is "xxx". So sections "handler_hand01", "handler_hand02", etc.
 
269
#further down the file, indicate how the handlers "hand01", "hand02" etc.
 
270
#are set up.
 
271
#Handler key names can be any identifier. (The names "handnn" are generated
 
272
#by the GUI configurator.)
 
273
 
 
274
<span class="strong">[handlers]
 
275
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09</span>
 
276
 
 
277
#The "formatters" section contains the key names for all the formatters in
 
278
#this configuration. Just as for loggers and handlers above, the key names
 
279
#are values used to identify where the parameters for each formatter are found
 
280
#in this file.
 
281
#The section for an individual formatter is named "formatter_xxx" where the
 
282
#"key" for a formatter is "xxx". So sections "formatter_form01",
 
283
#"formatter_form02", etc. further down the file indicate how the formatters
 
284
#"form01", "form02" etc. are set up.
 
285
#Formatter key names can be any identifier. (The names "formnn" are generated
 
286
#by the GUI configurator.)
 
287
 
 
288
<span class="strong">[formatters]
 
289
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09</span>
 
290
 
 
291
#The section below indicates the information relating to the root logger.
 
292
#
 
293
#The level value needs to be one of DEBUG, INFO, WARN, ERROR, CRITICAL or NOTSET.
 
294
#In the root logger, NOTSET indicates that all messages will be logged.
 
295
#Level values are eval()'d in the context of the logging package's namespace.
 
296
#
 
297
#The propagate value indicates whether or not parents of this loggers will
 
298
#be traversed when looking for handlers. It doesn't really make sense in the
 
299
#root logger - it's just there because a root logger is almost like any other
 
300
#logger.
 
301
#
 
302
#The channel value indicates the lowest portion of the channel name of the
 
303
#logger. For a logger called "a.b.c", this value would be "c".
 
304
#
 
305
#The parent value indicates the key name of the parent logger, except that
 
306
#root is shown as "(root)" rather than "root".
 
307
#
 
308
#The qualname value is the fully qualified channel name of the logger. For a
 
309
#logger called "a.b.c", this value would be "a.b.c".
 
310
#
 
311
#The handlers value is a comma-separated list of the key names of the handlers
 
312
#attached to this logger.
 
313
#
 
314
<span class="strong">[logger_root]
 
315
level=NOTSET
 
316
handlers=hand01</span>
 
317
qualname=(root) <span class="comment"># note - this is used in non-root loggers</span>
 
318
propagate=1 <span class="comment"># note - this is used in non-root loggers</span>
 
319
channel=
 
320
parent=
 
321
 
 
322
#
 
323
#The explanation for the values in this section is analogous to the above. The
 
324
#logger is named "log02" and coincidentally has a key name of "log02". It has
 
325
#a level of DEBUG and handler with key name "hand02". (See section
 
326
#"handler_hand02" for handler details.) If the level value were NOTSET, this tells
 
327
#the logging package to consult the parent (as long as propagate is 1) for the
 
328
#effective level of this logger. If propagate is 0, this level is treated as for
 
329
#the root logger - a value of NOTSET means "pass everything", and other values are
 
330
#interpreted at face value.
 
331
#
 
332
<span class="strong">[logger_log02]
 
333
level=DEBUG
 
334
propagate=1
 
335
qualname=log02
 
336
handlers=hand02</span>
 
337
channel=log02
 
338
parent=(root)
 
339
 
 
340
#
 
341
#The explanation for the values in this section is analogous to the above. The
 
342
#logger is named "log02.log03" and has a key name of "log03".
 
343
#It has a level of INFO and handler with key name "hand03".
 
344
#
 
345
<span class="strong">[logger_log03]
 
346
level=INFO
 
347
propagate=1
 
348
qualname=log02.log03
 
349
handlers=hand03</span>
 
350
channel=log03
 
351
parent=log02
 
352
 
 
353
#
 
354
#The explanations for the values in this section and subsequent logger sections
 
355
#are analogous to the above.
 
356
#
 
357
<span class="strong">[logger_log04]
 
358
level=WARN
 
359
propagate=0
 
360
qualname=log02.log03.log04
 
361
handlers=hand04</span>
 
362
channel=log04
 
363
parent=log03
 
364
 
 
365
<span class="strong">[logger_log05]
 
366
level=ERROR
 
367
propagate=1
 
368
qualname=log02.log03.log04.log05
 
369
handlers=hand05</span>
 
370
channel=log05
 
371
parent=log04
 
372
 
 
373
<span class="strong">[logger_log06]
 
374
level=CRITICAL
 
375
propagate=1
 
376
qualname=log02.log03.log04.log05.log06
 
377
handlers=hand06</span>
 
378
channel=log06
 
379
parent=log05
 
380
 
 
381
<span class="strong">[logger_log07]
 
382
level=WARN
 
383
propagate=1
 
384
qualname=log02.log03.log04.log05.log06.log07
 
385
handlers=hand07</span>
 
386
channel=log07
 
387
parent=log06
 
388
 
 
389
#The section below indicates the information relating to handler "hand01".
 
390
#The first three keys (class, level and formatter) are common to all handlers.
 
391
#Any other values are handler-specific, except that "args", when eval()'ed,
 
392
#is the list of arguments to the constructor for the handler class.
 
393
#
 
394
#The class value indicates the handler's class (as determined by eval() in
 
395
#the logging package's namespace).
 
396
#
 
397
#The level value needs to be one of DEBUG, INFO, WARN, ERROR, CRITICAL or NOTSET.
 
398
#NOTSET means "use the parent's level".
 
399
#
 
400
#The formatter value indicates the key name of the formatter for this handler.
 
401
#If blank, a default formatter (logging._defaultFormatter) is used.
 
402
#
 
403
#The stream value indicates the stream for this StreamHandler. It is computed
 
404
#by doing eval() on the string value in the context of the logging package's
 
405
#namespace.
 
406
#
 
407
#The args value is a tuple of arguments which is passed to the constructor for
 
408
#this handler's class in addition to the "self" argument.
 
409
#
 
410
<span class="strong">[handler_hand01]
 
411
class=StreamHandler
 
412
level=NOTSET
 
413
formatter=form01
 
414
args=(sys.stdout,)</span>
 
415
stream=sys.stdout
 
416
 
 
417
#The section below indicates the information relating to handler "hand02".
 
418
#The first three keys are common to all handlers.
 
419
#Any other values are handler-specific, except that "args", when eval()'ed,
 
420
#is the list of arguments to the constructor for the handler class.
 
421
#
 
422
#The filename value is the name of the file to write logging information to.
 
423
#The mode value is the mode used to open() the file. The maxsize and backcount
 
424
#values control rollover as described in the package's pydoc.
 
425
#
 
426
<span class="strong">[handler_hand02]
 
427
class=FileHandler
 
428
level=DEBUG
 
429
formatter=form02
 
430
args=('python.log', 'w')</span>
 
431
filename=python.log
 
432
mode=w
 
433
 
 
434
#The section below indicates the information relating to handler "hand03".
 
435
#The first three keys are common to all handlers.
 
436
#Any other values are handler-specific, except that "args", when eval()'ed,
 
437
#is the list of arguments to the constructor for the handler class.
 
438
#
 
439
#The host value is the name of the host to send logging information to.
 
440
#The port value is the port number to use for the socket connection.
 
441
#
 
442
<span class="strong">[handler_hand03]
 
443
class=handlers.SocketHandler
 
444
level=INFO
 
445
formatter=form03
 
446
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)</span>
 
447
host=localhost
 
448
port=DEFAULT_TCP_LOGGING_PORT
 
449
 
 
450
#The section below indicates the information relating to handler "hand04".
 
451
#The first three keys are common to all handlers.
 
452
#Any other values are handler-specific, except that "args", when eval()'ed,
 
453
#is the list of arguments to the constructor for the handler class.
 
454
#
 
455
#The host value is the name of the host to send logging information to.
 
456
#The port value is the port number to use for the socket connection.
 
457
#
 
458
<span class="strong">[handler_hand04]
 
459
class=handlers.DatagramHandler
 
460
level=WARN
 
461
formatter=form04
 
462
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)</span>
 
463
host=localhost
 
464
port=DEFAULT_UDP_LOGGING_PORT
 
465
 
 
466
#The section below indicates the information relating to handler "hand05".
 
467
#The first three keys are common to all handlers.
 
468
#Any other values are handler-specific, except that "args", when eval()'ed,
 
469
#is the list of arguments to the constructor for the handler class.
 
470
#
 
471
#The host value is the name of the host to send logging information to.
 
472
#The port value is the port number to use for the socket connection.
 
473
#The facility is the syslog facility to use for logging.
 
474
#
 
475
<span class="strong">[handler_hand05]
 
476
class=handlers.SysLogHandler
 
477
level=ERROR
 
478
formatter=form05
 
479
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)</span>
 
480
host=localhost
 
481
port=SYSLOG_UDP_PORT
 
482
facility=LOG_USER
 
483
 
 
484
#The section below indicates the information relating to handler "hand06".
 
485
#The first three keys are common to all handlers.
 
486
#Any other values are handler-specific, except that "args", when eval()'ed,
 
487
#is the list of arguments to the constructor for the handler class.
 
488
#
 
489
#The appname value is the name of the application which appears in the
 
490
#NT event log.
 
491
#The dllname value is the pathname of a DLL to use for message definitions.
 
492
#The logtype is the type of NT event log to write to - Application, Security
 
493
#or System.
 
494
#
 
495
<span class="strong">[handler_hand06]
 
496
class=NTEventLogHandler
 
497
level=CRITICAL
 
498
formatter=form06
 
499
args=('Python Application', '', 'Application')</span>
 
500
appname=Python Application
 
501
dllname=
 
502
logtype=Application
 
503
 
 
504
#The section below indicates the information relating to handler "hand07".
 
505
#The first three keys are common to all handlers.
 
506
#Any other values are handler-specific, except that "args", when eval()'ed,
 
507
#is the list of arguments to the constructor for the handler class.
 
508
#
 
509
#The host value is the name of the SMTP server to connect to.
 
510
#The port value is the port number to use for the SMTP connection.
 
511
#The from value is the "From" value in emails.
 
512
#The to value is a comma-separated list of email addresses.
 
513
#The subject value is the subject of the email.
 
514
#
 
515
<span class="strong">[handler_hand07]
 
516
class=SMTPHandler
 
517
level=WARN
 
518
formatter=form07
 
519
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')</span>
 
520
host=localhost
 
521
port=25
 
522
from=from@abc
 
523
to=user1@abc,user2@xyz
 
524
subject=Logger Subject
 
525
 
 
526
#The section below indicates the information relating to handler "hand08".
 
527
#The first three keys are common to all handlers.
 
528
#Any other values are handler-specific, except that "args", when eval()'ed,
 
529
#is the list of arguments to the constructor for the handler class.
 
530
#
 
531
#The capacity value is the size of this handler's buffer.
 
532
#The flushlevel value is the logging level at which the buffer is flushed.
 
533
#The from value is the "From" value in emails.
 
534
#The target value is the key name of the handler which messages are flushed
 
535
#to (i.e. sent to when flushing).
 
536
#
 
537
<span class="strong">[handler_hand08]
 
538
class=MemoryHandler
 
539
level=NOTSET
 
540
formatter=form08
 
541
target=
 
542
args=(10, ERROR)</span>
 
543
capacity=10
 
544
flushlevel=ERROR
 
545
 
 
546
#The section below indicates the information relating to handler "hand09".
 
547
#The first three keys are common to all handlers.
 
548
#Any other values are handler-specific, except that "args", when eval()'ed,
 
549
#is the list of arguments to the constructor for the handler class.
 
550
#
 
551
#The host value is the name of the HTTP server to connect to.
 
552
#The port value is the port number to use for the HTTP connection.
 
553
#The url value is the url to request from the server.
 
554
#The method value is the HTTP request type (GET or POST).
 
555
#
 
556
<span class="strong">[handler_hand09]
 
557
class=HTTPHandler
 
558
level=NOTSET
 
559
formatter=form09
 
560
args=('localhost:9022', '/log', 'GET')</span>
 
561
host=localhost
 
562
port=9022
 
563
url=/log
 
564
method=GET
 
565
 
 
566
#The sections below indicate the information relating to the various
 
567
#formatters. The format value is the overall format string, and the
 
568
#datefmt value is the strftime-compatible date/time format string. If
 
569
#empty, the logging package substitutes ISO8601 format date/times where
 
570
#needed. See the package pydoc for more details of the format string
 
571
#structure.
 
572
#
 
573
<span class="strong">[formatter_form01]
 
574
format=F1 %(asctime)s %(levelname)s %(message)s
 
575
datefmt=
 
576
 
 
577
[formatter_form02]
 
578
format=F2 %(asctime)s %(pathname)s(%(lineno)d): %(levelname)s %(message)s
 
579
datefmt=
 
580
 
 
581
[formatter_form03]
 
582
format=F3 %(asctime)s %(levelname)s %(message)s
 
583
datefmt=
 
584
 
 
585
[formatter_form04]
 
586
format=%(asctime)s %(levelname)s %(message)s
 
587
datefmt=
 
588
 
 
589
[formatter_form05]
 
590
format=F5 %(asctime)s %(levelname)s %(message)s
 
591
datefmt=
 
592
 
 
593
[formatter_form06]
 
594
format=F6 %(asctime)s %(levelname)s %(message)s
 
595
datefmt=
 
596
 
 
597
[formatter_form07]
 
598
format=F7 %(asctime)s %(levelname)s %(message)s
 
599
datefmt=
 
600
 
 
601
[formatter_form08]
 
602
format=F8 %(asctime)s %(levelname)s %(message)s
 
603
datefmt=
 
604
 
 
605
[formatter_form09]
 
606
format=F9 %(asctime)s %(levelname)s %(message)s
 
607
datefmt=</span>
 
608
 
 
609
# --- end of logconf.ini ----------------------------------------------------
 
610
</pre>
 
611
 
 
612
<p>To use a file like this, you would call <code>logging.config.fileConfig(&quot;logconf.ini&quot;)</code>
 
613
whereupon the file is read in and processed. Note that evaluation happens in the context of the logging package (hence the unqualified class names).
 
614
 
 
615
 
 
616
<a name="guiconf"></a><h4>The GUI Configurator</h4>
 
617
 
 
618
To create a file like the above, you can use the new GUI configurator, <code>logconf.py</code>, which is invoked either with no arguments or with a single argument giving the name of a configuration file to read. (Or, if you're a masochist/don't have Tk, you can do it by hand. The configurator is a quick hack, which I hope is reasonably intuitive - have a play with it and see what you think. I've used it with 1.5.2 and 2.1.2 on Windows and 1.5.2 on Linux/x86. There's no validation, rudimentary error checking and the usability could be better, but it's something to build on, hey?)</p>
 
619
 
 
620
<p>Here's a screenshot of the configurator:</p>
 
621
<img src="logconf.png" border="0"/>
 
622
<p>Here's a quick guide on how to use it:
 
623
<ul>
 
624
<li>The screen is laid out in three panels - for loggers, handlers and formatters (see the yellow rectangles in the screenshot).</li>
 
625
<li>Each panel consists of a listbox, New and Delete buttons and a "property editor" to set properties for each of the objects.</li>
 
626
<li>To create loggers, you need to first select the parent logger before clicking the New button. To create handlers and formatters, just click the appropriate New button.</li>
 
627
<li>To delete an item, just select it in the listbox and click the Delete button.</li>
 
628
<li>Whenever an item is selected in the listbox, its properties are displayed in the property editor section.</li>
 
629
<li>Whenever an item is deleted, the property editor section is cleared.</li>
 
630
<li>To edit a property, just click on the name or value. If the property is read-only, nothing happens. If it's a user-editable value, an entry field appears and you can type into it. If it's a user-selectable value (I mean selectable from a list), a button with ... appears. Clicking on it causes a pseudo-combobox to appear. All such boxes are single-selection, except for the "Handlers" property of loggers, for which several handlers can be selected.</li>
 
631
<li>To commit the changes, just click elsewhere in the property editor section, e.g. below the last property or on some other property.</li>
 
632
<li>Formatters are referred to by handlers, and handlers are referred to by loggers. Hence formatters and handlers have names generated for them automatically, for use in cross-referencing. The names of these cannot be changed. The name for loggers is, however, editable (except for the root logger), as it represents the position of the logger in the hierarchy.</li>
 
633
<li>The Load, Save, Save As and Reset buttons should be reasonably self-explanatory (except perhaps Reset, which just deletes all non-root loggers, handlers and formatters and starts with a clean slate).</li>
 
634
<li>Filters are not supported in this release, but will be as soon as time permits and if there is enough demand.</li>
 
635
</ul></p>
 
636
<a name="scenarios"></a><h4>Case Scenarios</h4>
 
637
 
 
638
<p>With reference to the <a href="http://www.python.org/peps/pep-0282.html">PEP</a>,
 
639
here are my comments on the current state of play.
 
640
 
 
641
<ol>
 
642
  <li>A short simple script. See the example <a href="#simplest"><code>app.py</code></a>
 
643
    above.</li>
 
644
  <li>Medium sized app with C extension module. I have not specifically considered C extension
 
645
    modules but I assume they can just use the standard Python C API to make logging calls.</li>
 
646
  <li>Distutils. I would welcome more specific comments on what kind of configuration people
 
647
    think would be useful. To a certain extent, controlling verbosity levels through setup.py
 
648
    options is, I think, the domain of the app developer rather than the logging package.</li>
 
649
  <li>Large applications. If users can restart a system after changing the logging settings
 
650
    (via some user-friendly or support-desk-friendly interface) then present functionality
 
651
    should cater for this. In the case where the logging behaviour of a (long-)running system needs
 
652
    to be changed, then the functionality (new in 0.4.3) described <a href="#onthefly">below</a> can be used.</li>
 
653
</ol>
 
654
 
 
655
<a name="threadsafe"></a><h4>Thread Safety</h4>
 
656
 
 
657
<p>The package is intended to be threadsafe. Although it makes no use of threads to provide its functionality (except for <a href="#onthefly">on-the-fly reconfiguration</a>), shared data in the package is protected by a thread lock which is acquired before, and released after, modifications to shared data. In addition, the Handler class creates a per-handler instance I/O lock which is acquired before, and released after, calling emit(). If you define your own handlers, in most situations you should not need to take any special precautions, as long as your I/O is called only from emit(). The thread locks impose a slight performance penalty, but it's no worse than for any other use of thread locks in Python applications.</p>
 
658
 
 
659
<a name="onthefly"></a><h4>On-The-Fly Reconfiguration</h4>
 
660
 
 
661
<p>The package also allows a program to permit changing of the logging configuration on the fly, i.e. <em>while the program is still running</em>. This should be a help for developers of long-running programs such as servers (e.g. Zope, Webware). At this stage, the on-the-fly configurability is fairly basic - to use it, two new module-level functions are provided (in the <code>logging.config</code> module).
 
662
<ul>
 
663
  <li><code>listen([port])</code> is used to create a thread which, when started, opens a socket server which listens on the specified port for configuration requests. The socket protocol is very basic - a two-byte length followed by a string of that length is sent to the listener. The string should be in the same format as logging configuration files, i.e. ConfigParser files conforming to the scheme described <a href="#config">above</a>.</li>
 
664
  <li><code>stopListening()</code> tells the thread created by listening to terminate.</li>
 
665
</ul>
 
666
Currently, you can't just change part of the logging configuration - the sent configuration completely replaces the existing configuration, and if previously existing loggers are not in the new configurations, they will be disabled after the new configuration takes effect. The script <code>log_test17.py</code> in the distribution illustrates the on-the-fly configuration feature.
 
667
</p>
 
668
 
 
669
<a name="mlcf"></a><h4>Module-Level Convenience Functions</h4>
 
670
 
 
671
<p>For the casual user, there are module-level convenience functions which operate on the
 
672
root logger. <a href="logging_pydoc.html#functions">Here</a> is the pydoc for them. </p>
 
673
 
 
674
<a name="perf"></a><h4>Performance</h4>
 
675
 
 
676
<p>The implementation has not been optimized for performance. This is planned to be done in a later phase, following feature stabilization and benchmarking.</p>
 
677
 
 
678
<a name="impstatus"></a><h4>Implementation Status</h4>
 
679
 
 
680
<p>The implementation is what I have termed alpha - mainly because it has not had very wide exposure or extensive testing in many environments. Please try to use it/break it and give me
 
681
any <a href="mailto:vinay_sajip@red-dove.com">feedback</a> you can! There is no reason I can see why this package should not be ready in time for the Python 2.3 release :-)</p>
 
682
 
 
683
 
 
684
<a name="#acks"></a><h4>Acknowledgements</h4>
 
685
<p>The biggest thank you goes to the <a href="http://jakarta.apache.org/log4j/">log4j</a> developers, whom I am attempting to flatter sincerely by imitation ;-) Thanks also to Trent Mick for <a href="http://www.python.org/peps/pep-0282.html">PEP 282</a>, which prompted me to offer this implementation.</p>
 
686
<p>I'd also like to thank all of the people who have given me feedback, patches and encouragement. In particular (but in no particular order):</p>
 
687
<ul>
 
688
<li>Ollie Rutherfurd - patches and suggestions.</li>
 
689
<li>Greg Ward - for nudging me in the direction of distutils.</li>
 
690
<li>Hunter Matthews - questions about user-defined logging levels.</li>
 
691
<li>Nicolas Untz - SysLogHandler implementation.</li>
 
692
<li>Jeremy Hylton - discussions about logging exceptions.</li>
 
693
<li>Kevin Butler - discussions about logging exceptions.</li>
 
694
<li>Richard Jones - lots of positive feedback and ideas.</li>
 
695
<li>David Goodger - suggestion about using CRITICAL rather than FATAL.</li>
 
696
<li>Denis S. Otkidach - suggestions on filters and feedback on performance.</li>
 
697
</ul>
 
698
<a name="todo"></a><h4>Still To Do</h4>
 
699
<p>No rest for the wicked...</p>
 
700
<ul>
 
701
<li>Improvements to the GUI configurator. Feedback, anyone?</li>
 
702
<li>Overview-type documentation? The pydoc is reasonably comprehensive (I like to think). Perhaps a slightly formalized version of the information on this page?</li>
 
703
<li>Testing, and more testing (you could help with this, too ...)</li>
 
704
</ul>
 
705
<p>If you can help with any of this, please <a href="mailto:vinay_sajip@red-dove.com">email me</a>.</p>
 
706
<a name="download"></a><h4>Download and Installation</h4>
 
707
<p>The current version is 0.4.7. <a href="logging-0.4.7.tar.gz">Here</a> is the latest tarball (also in <a href="logging-0.4.7.zip">zip</a> format or <a href="logging-0.4.7.win32.exe">Windows executable</a> - the latter includes the logging package only). The distribution contains the following files:
 
708
<hr>
 
709
<table border="0" cellpadding="0" cellspacing="0" width="100%">
 
710
<tr><th>Filename</th><th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th>Contents</th></tr>
 
711
<tr><td colspan="3">&nbsp;</td></tr>
 
712
<tr>
 
713
<td><code>README.txt</code></td><td>&nbsp;</td>
 
714
<td>Brief description and change history.</td>
 
715
</tr>
 
716
<tr>
 
717
<td><code>__init__.py</code></td><td>&nbsp;</td>
 
718
<td>The core logging package itself, including StreamHandler and FileHandler.</td>
 
719
</tr>
 
720
<tr>
 
721
<td><code>handlers.py</code></td><td>&nbsp;</td>
 
722
<td>The other handlers provided as part of the package.</td>
 
723
</tr>
 
724
<tr>
 
725
<td><code>config.py</code></td><td>&nbsp;</td>
 
726
<td>The code for configuring the package.</td>
 
727
</tr>
 
728
<tr>
 
729
<td><code>setup.py</code></td><td>&nbsp;</td>
 
730
<td>The distutils setup script.</td>
 
731
</tr>
 
732
<tr>
 
733
<td><code>logrecv.py</code></td><td>&nbsp;</td>
 
734
<td>A test server used for testing SocketHandler, DatagramHandler, HTTPHandler and SOAPHandler. Run it with an argument of one of "TCP", "UDP", "HTTP" or "SOAP" before running a test harness which logs to one of these handlers. Note that to use the SOAP handler, you need to have installed <a href="http://sourceforge.net/projects/pyxml">PyXML-0.6.6</a> and the <a href="http://www.zolera.com/opensrc/zsi/zsi.html">Zolera Soap Infrastructure</a>. This is needed for <code>logrecv.py</code> only, and not for the <code>logging</code> module itself. (Note that ZSI requires Python 2.x)</td>
 
735
</tr>
 
736
<tr>
 
737
<td><code>app.py</code></td><td>&nbsp;</td>
 
738
<td>The minimal example described <a href="#simplest">above</a>.</td>
 
739
</tr>
 
740
<tr>
 
741
<td><code>mymodule.py</code></td><td>&nbsp;</td>
 
742
<td>Another example described <a href="#nextsimplest">above</a>.</td>
 
743
</tr>
 
744
<tr>
 
745
<td><code>myapp.py</code></td><td>&nbsp;</td>
 
746
<td>From the second example described <a href="#nextsimplest">above</a>.</td>
 
747
</tr>
 
748
<tr>
 
749
<td><code>log_test.py</code></td><td>&nbsp;</td>
 
750
<td>A test script intended to work as a regression test harness. Runs a number of the other scripts and generates output to stdout.log and stderr.log.</td>
 
751
</tr>
 
752
<tr>
 
753
<td><code>log_test0.py</code></td><td>&nbsp;</td>
 
754
<td>A simple test script using <code>basicConfig()</code> only.</td>
 
755
</tr>
 
756
<tr>
 
757
<td><code>log_test1.py</code></td><td>&nbsp;</td>
 
758
<td>An example showing slightly more involved configuration and
 
759
    exception handling, as well as a Unix syslog handler which uses the standard library's syslog module.</td>
 
760
</tr>
 
761
<tr>
 
762
<td><code>log_test2.py</code></td><td>&nbsp;</td>
 
763
<td>A version of <code>log_test0.py</code> which only logs to
 
764
    a <code>SocketHandler</code>.</td>
 
765
</tr>
 
766
<tr>
 
767
<td><code>log_test3.py</code></td><td>&nbsp;</td>
 
768
<td>An example showing use of <code>fileConfig()</code> and
 
769
    logging to various loggers.</td>
 
770
</tr>
 
771
<tr>
 
772
<td><code>log_test4.py</code></td><td>&nbsp;</td>
 
773
<td>An example showing use of bespoke levels, filtering by level at logger and handler, and use of filter classes (descendants of <code>Filter</code>).</td>
 
774
</tr>
 
775
<tr>
 
776
<td><code>log_test5.py</code></td><td>&nbsp;</td>
 
777
<td>An example showing use of <code>SMTPHandler</code>. Before running this script, be sure to change the bogus addresses it contains to real ones which you have access to.</td>
 
778
</tr>
 
779
<tr>
 
780
<td><code>log_test6.py</code></td><td>&nbsp;</td>
 
781
<td>An example showing use of <code>NTEventLogHandler</code>. This script needs to be run on an NT system.</td>
 
782
</tr>
 
783
<tr>
 
784
<td><code>log_test7.py</code></td><td>&nbsp;</td>
 
785
<td>An example showing use of <code>MemoryHandler</code>.</td>
 
786
</tr>
 
787
<tr>
 
788
<td><code>log_test8.py</code></td><td>&nbsp;</td>
 
789
<td>An example showing use of <code>FileHandler</code> with rollover across multiple files.</td>
 
790
</tr>
 
791
<tr>
 
792
<td><code>log_test9.py</code></td><td>&nbsp;</td>
 
793
<td>An example showing use of <code>BufferingHandler</code> and <code>BufferingFormatter</code> through implementing simple <code>XMLFormatter</code> and <code>XMLHandler</code> classes.</td>
 
794
</tr>
 
795
<tr>
 
796
<td><code>log_test10.py</code></td><td>&nbsp;</td>
 
797
<td>An example showing how to get the logging module to create loggers of your own class (though it needs to be a subclass of <code>Logger</code>).</td>
 
798
</tr>
 
799
<tr>
 
800
<td><code>log_test11.py</code></td><td>&nbsp;</td>
 
801
<td>An example SMTP handler, called <code>BufferingSMTPHandler</code>, which buffers events and sends them via email in batches.</td>
 
802
</tr>
 
803
<tr>
 
804
<td><code>log_test12.py</code></td><td>&nbsp;</td>
 
805
<td>An example showing the use of <code>HTTPHandler</code>, for use with <code>logrecv.py</code>.</td>
 
806
</tr>
 
807
<tr>
 
808
<td><code>log_test13.py</code></td><td>&nbsp;</td>
 
809
<td>An example showing the use of <code>SOAPHandler</code>, for use with <code>logrecv.py</code>.</td>
 
810
</tr>
 
811
<tr>
 
812
<td><code>log_test14.py</code></td><td>&nbsp;</td>
 
813
<td>An example showing an implementation of <code>DBHandler</code>, showing how to log requests to RDBMS tables using the Python Database API 2.0.</td>
 
814
</tr>
 
815
<tr>
 
816
<td><code>log_test15.py</code></td><td>&nbsp;</td>
 
817
<td>An example showing the use of the <code>Filter</code> class with a string initializer.</td>
 
818
</tr>
 
819
<tr>
 
820
<td><code>log_test16.py</code></td><td>&nbsp;</td>
 
821
<td>An example showing the use of logging in a multi-threaded program.</td>
 
822
</tr>
 
823
<tr>
 
824
<td><code>log_test17.py</code></td><td>&nbsp;</td>
 
825
<td>An example showing the use of logging in a multi-threaded program, together with reconfiguring logging on the fly through the use of <code>listen()</code> and <code>stopListening()</code>. This script serves as both server and client, depending on the arguments it's called with.</td>
 
826
</tr>
 
827
<tr>
 
828
<td><code>log_test18.py</code></td><td>&nbsp;</td>
 
829
<td>An example showing the use of an example filter, MatchFilter, which offers flexible match-based
 
830
filtering of LogRecords.</td>
 
831
</tr>
 
832
<tr>
 
833
<td><code>log_test19.py</code></td><td>&nbsp;</td>
 
834
<td>A basic test of logger parents.</td>
 
835
</tr>
 
836
<tr>
 
837
<td><code>log_test20.py</code></td><td>&nbsp;</td>
 
838
<td>Demonstrates the use of custom class instances for messages and filtering based on classes.</td>
 
839
</tr>
 
840
<tr>
 
841
<td><code>log_test21.py</code></td><td>&nbsp;</td>
 
842
<td>Demonstrates the use of a wildcard name-space filter with and without custom message classes.</td>
 
843
</tr>
 
844
<tr>
 
845
<td><code>log_test22.py</code></td><td>&nbsp;</td>
 
846
<td>Demonstrates the use of either localtime or gmtime to do date/time formatting.</td>
 
847
</tr>
 
848
<tr>
 
849
<td><code>debug.ini</code></td><td>&nbsp;</td>
 
850
<td>An example configuration for use with log_test17.py.</td>
 
851
</tr>
 
852
<tr>
 
853
<td><code>warn.ini</code></td><td>&nbsp;</td>
 
854
<td>An example configuration for use with log_test17.py.</td>
 
855
</tr>
 
856
<tr>
 
857
<td><code>error.ini</code></td><td>&nbsp;</td>
 
858
<td>An example configuration for use with log_test17.py.</td>
 
859
</tr>
 
860
<tr>
 
861
<td><code>critical.ini</code></td><td>&nbsp;</td>
 
862
<td>An example configuration for use with log_test17.py.</td>
 
863
</tr>
 
864
<tr>
 
865
<td><code>log_test3.ini</code></td><td>&nbsp;</td>
 
866
<td>An example configuration for use with log_test3.py.</td>
 
867
</tr>
 
868
<tr>
 
869
<td><code>stdout.exp</code></td><td>&nbsp;</td>
 
870
<td>The expected results of stdout.log after running log_test.py.</td>
 
871
</tr>
 
872
<tr>
 
873
<td><code>stderr.exp</code></td><td>&nbsp;</td>
 
874
<td>The expected results of stderr.log after running log_test.py.</td>
 
875
</tr>
 
876
<tr>
 
877
<td><code>logconf.py</code></td><td>&nbsp;</td>
 
878
<td>A Tkinter-based GUI configurator.</td>
 
879
</tr>
 
880
<tr>
 
881
<td><code>logconf.ini</code></td><td>&nbsp;</td>
 
882
<td>Example configuration file, in ConfigParser format, for use with <code>logconf.py</code> and <code>log_test3.py</code>.</td>
 
883
</tr>
 
884
<tr>
 
885
<td><code>logging.dtd</code></td><td>&nbsp;</td>
 
886
<td>A simple example DTD for use with <code>log_test9.py</code>.</td>
 
887
</tr>
 
888
<tr>
 
889
<td><code>logging.xml</code></td><td>&nbsp;</td>
 
890
<td>An example XML file for use with <code>log_test9.py</code>. It references <code>events.xml</code> as external data.</td>
 
891
</tr>
 
892
<tr>
 
893
<td><code>events.xml</code></td><td>&nbsp;</td>
 
894
<td>An example XML file for use with <code>log_test9.py</code>. It holds the actual events in XML format.</td>
 
895
</tr>
 
896
<tr>
 
897
<td><code>python_logging.html</code></td><td>&nbsp;</td>
 
898
<td>The page you're reading now.</td>
 
899
</tr>
 
900
<td><code>default.css</code></td><td>&nbsp;</td>
 
901
<td>Stylesheet for use with the HTML pages.</td>
 
902
</tr>
 
903
<tr><td colspan="3">&nbsp;</td></tr>
 
904
</table>
 
905
<hr>
 
906
<p>To install, unpack the archive into any directory, and in that directory invoke the script <code>"setup.py install"</code> to install the module in the default location used by distutils.</p>
 
907
<p>To use, just put <code>logging.py</code> in your Python path, "<code>import logging</code>" and go. (The installation procedure described above will normally put the logging module in your Python path. If you want to use file-based configuration API, you'll also need to <code>import logging.config</code>. To use the more esoteric handlers, you'll also need to <code>import logging.handlers</code>.)</p>
 
908
 
 
909
<a name="changes"></a><h4>Change History</h4>
 
910
 
 
911
<p>The change history is as follows.</p>
 
912
 
 
913
<pre>
 
914
Version   Date        Description
 
915
=============================================================================
 
916
0.4.7     15 Nov 2002 Made into a package with three modules: __init__ (the
 
917
                      core code), handlers (all handlers other than
 
918
                      FileHandler and its bases) and config (all the config
 
919
                      stuff). Before doing this:
 
920
                      Updated docstrings to include a short line, then a
 
921
                      blank line, then more descriptive text.
 
922
                      Renamed 'lvl' to 'level' in various functions.
 
923
                      Changed FileHandler to use "a" and "w" instead of "a+"
 
924
                      and "w+".
 
925
                      Moved log file rotation functionality from FileHandler
 
926
                      to a new class RotatingFileHandler.
 
927
                      Improved docstring describing rollover.
 
928
                      Updated makePickle to use 4-byte length and struct
 
929
                      module, likewise logrecv.py. Also updated on-the-fly
 
930
                      config reader to use 4-byte length/struct module.
 
931
                      Altered ConfigParser test to look at 'readline' rather
 
932
                      than 'read'.
 
933
                      Added optional "defaults" argument to fileConfig, to
 
934
                      be passed to ConfigParser.
 
935
                      Renamed ALL to NOTSET to avoid confusion.
 
936
                      Commented out getRootLogger(), as obsolete.
 
937
                      To do regression testing, run log_test.py and compare
 
938
                      the created files stdout.log and stderr.log against
 
939
                      the files stdout.exp and stderr.exp. They should match
 
940
                      except fir a couple of exception messages which give
 
941
                      absolute file paths.
 
942
                      Updated python_logging.html to remove links to
 
943
                      logging_pydoc.html, which has been removed from the
 
944
                      distribution.
 
945
                      Changed default for raiseExceptions to 1.
 
946
-----------------------------------------------------------------------------
 
947
0.4.6     08 Jul 2002 Added raiseExceptions to allow conditional propagation
 
948
                      of exceptions which occur during handling.
 
949
                      Added converter to Formatter to allow use of any
 
950
                      function to convert time from seconds to a tuple. It
 
951
                      still defaults to time.localtime but now you can also
 
952
                      use time.gmtime.
 
953
                      Added log_test22.py to test the conversion feature.
 
954
                      Changed rootlogger default level to WARN - was DEBUG.
 
955
                      Updated some docstrings.
 
956
                      Moved import of threading to where thread is imported.
 
957
                      If either is unavailable, threading support is off.
 
958
                      Updated minor defects in python_logging.html.
 
959
                      Check to see if ConfigParser has readfp method; if it
 
960
                      does and an object with a 'read' method is passed in,
 
961
                      assumes a file-like object and uses readfp to read it
 
962
                      in.
 
963
-----------------------------------------------------------------------------
 
964
0.4.5     04 Jun 2002 Fixed bug which caused problem if no args to message
 
965
                      (suggested by Hye-Shik Chang).
 
966
                      Fixed bug in _fixupParents (thanks to Nicholas Veeser)
 
967
                      and added log_test19.py as a test case for this bug.
 
968
                      Added getMessage to LogRecord (code was moved here from
 
969
                      Formatter.format)
 
970
                      Applied str() to record.msg to allow arbitrary classes
 
971
                      to determine the formatting (as msg can now be a class
 
972
                      instance).
 
973
                      Table of Contents added to python_logging.html, the
 
974
                      section on Loggers updated, and the logconf.ini file
 
975
                      section annotated.
 
976
                      Added log_test20.py which demonstrates how to use
 
977
                      class instances to provide alternatives to numeric
 
978
                      severities as mechanisms for control of logging.
 
979
                      Added log_test21.py which builds on log_test20.py to
 
980
                      show how you can use a regular expression-based Filter
 
981
                      for flexible matching similar to e.g. Protomatter
 
982
                      Syslog, where you can filter on e.g. "a.*" or "*.b" or
 
983
                      "a.*.c".
 
984
                      _levelNames changed to contain reverse mappings as well
 
985
                      as forward mappings (leveltext->level as well as level
 
986
                      -> leveltext). The reverse mappings are used by
 
987
                      fileConfig().
 
988
                      fileConfig() now more forgiving of missing options in
 
989
                      .ini file - sensible defaults now used when some
 
990
                      options are absent. Also, eval() is used less when
 
991
                      interpreting .ini file contents - int() and dict lookup
 
992
                      are used in more places. Altered log_test3.py and added
 
993
                      log_test3.ini to show a hand-coded configuration file.
 
994
-----------------------------------------------------------------------------
 
995
0.4.4     02 May 2002 getEffectiveLevel() returns ALL instead of None when
 
996
                      nothing found. Modified references to level=0 to
 
997
                      level=ALL in a couple of places.
 
998
                      SocketHandler now inherits from Handler (it used to
 
999
                      inherit from StreamHandler, for no good reason).
 
1000
                      getLock() renamed to createLock().
 
1001
                      Docstring tidy-ups, and some tidying up of
 
1002
                      DatagramHandler.
 
1003
                      Factored out unpickling in logrecv.py.
 
1004
                      Added log_test18.py to illustrate MatchFilter, which is
 
1005
                      a general matching filter.
 
1006
                      Improved FileHandler.doRollover() so that the base
 
1007
                      file name is always the most recent, then .1, then .2
 
1008
                      etc. up to the maximum backup count. Renamed formal
 
1009
                      args and attributes used in rollover.
 
1010
                      Changed LogRecord attributes lvl -> levelno, level ->
 
1011
                      levelname (less ambiguity)
 
1012
                      Formatter.format searches for "%(asctime)" rather than
 
1013
                      "(asctime)"
 
1014
                      Renamed _start_time to _startTime
 
1015
                      Formatter.formatTime now returns the time
 
1016
                      Altered logrecv.py to support stopping servers
 
1017
                      programmatically
 
1018
                      Added log_test.py as overall test harness
 
1019
                      basicConfig() can now be safely called more than once
 
1020
                      Modified test scripts to make it easier to call them
 
1021
                      from log_test.py
 
1022
                      Moved SOAPHandler from core to log_test13.py. It's not
 
1023
                      general enough to be in the core; most production use
 
1024
                      will have differing RPC signatures.
 
1025
-----------------------------------------------------------------------------
 
1026
0.4.3     14 Apr 2002 Bug fix one-off error message to go to sys.stderr
 
1027
                      rather than sys.stdout.
 
1028
                      logrecv.py fix TCP for busy network.
 
1029
                      Thread safety - added locking to Handler and for shared
 
1030
                      data in module, and log_test16.py to test it.
 
1031
                      Added socket listener to allow on-the-fly configuration
 
1032
                      and added log_test17.py to test it.
 
1033
-----------------------------------------------------------------------------
 
1034
0.4.2     11 Apr 2002 Bug fix fileConfig() - setup of MemoryHandler target
 
1035
                      and errors when loggers have no handlers set or
 
1036
                      handlers have no formatters set
 
1037
                      logconf.py - seems to hang if window closed when combo
 
1038
                      dropdown is showing - added code to close popup on exit
 
1039
                      Some tweaks to _srcfile computation (normpath added)
 
1040
                      findCaller() optimized, now a lot faster!
 
1041
                      Logger.removeHandler now closes the handler before
 
1042
                      removing it
 
1043
                      fileConfig() removes existing handlers before adding
 
1044
                      the new set, to avoid memory leakage when repeated
 
1045
                      calls are made
 
1046
                      Fixed logrecv.py bug which hogged CPU time when TCP
 
1047
                      connection was closed from the client
 
1048
                      Added log_test14.py to demonstrate/test a DBHandler
 
1049
                      which writes logging records into an RDBMS using the
 
1050
                      Python Database API 2.0 (to run, you need something
 
1051
                      which supports this already installed - I tested with
 
1052
                      mxODBC)
 
1053
                      Made getLogger name argument optional - returns root
 
1054
                      logger if omitted
 
1055
                      Altered Filter to take a string initializer, filtering
 
1056
                      a sub-hierarchy rooted at a particular point (idea from
 
1057
                      Denis S. Otkidach).
 
1058
                      Added log_test15.py to test Filter initializer
 
1059
-----------------------------------------------------------------------------
 
1060
0.4.1     03 Apr 2002 Bug fix SMTPHandler - extra \r\n needed (Oleg Orlov)
 
1061
                      Added BufferingHandler, BufferingFormatter
 
1062
                      Renamed getChainedPriority to getEffectiveLevel
 
1063
                      Removed Logger.getRoot as it is redundant
 
1064
                      Added log_test9.py to test Buffering classes and
 
1065
                      to show an XMLFormatter example.
 
1066
                      Added setLoggerClass.
 
1067
                      Added log_test10.py to test setLoggerClass, using an
 
1068
                      example Logger-derived class which outputs exception
 
1069
                      info even for DEBUG level logging calls
 
1070
                      Added log_test11.py to test a buffering implementation
 
1071
                      of SMTPHandler
 
1072
                      Changed logging call implementation to allow keyword
 
1073
                      arguments (Kevin Butler and others)
 
1074
                      Changed default SysLogHandler implementation.
 
1075
                      Renamed "additive" to "propagate" as it better
 
1076
                      describes the attribute.
 
1077
                      Added HTTPHandler.
 
1078
                      Modified logrecv.py to remove "both" option and to add
 
1079
                      "HTTP" and "SOAP" options (SOAP option needs you to
 
1080
                      have PyXML-0.6.6 and ZSI installed - for logrecv.py
 
1081
                      only, and not for the core logging module itself).
 
1082
                      Added log_test12.py to test HTTPHandler.
 
1083
                      Added log_test13.py to test SOAPHandler.
 
1084
                      Formatted to Python source guidelines (spaces, indent
 
1085
                      of 4, within 80 columns).
 
1086
                      More method renamings (result of feedback) - _handle()
 
1087
                      renamed to emit(), _logRecord() renamed to handle().
 
1088
                      Renamed FATAL to CRITICAL (David Goodger), but left
 
1089
                      fatal() and FATAL in (until PEP is changed)
 
1090
                      Changed configuration file format to ConfigParser
 
1091
                      format.
 
1092
                      Factored filter application functionality out to a new
 
1093
                      Filterer class. The isLoggable() method is renamed to
 
1094
                      filter() in both Filter and Filterer classes.
 
1095
                      Altered SMTPHandler __init__ to accept (host, port)
 
1096
                      for the mail internet address.
 
1097
                      Added GUI configurator which uses Tkinter and the new
 
1098
                      configuration file format. (See logconf.py and an
 
1099
                      example configuration file in logconf.ini)
 
1100
                      Altered log_test3.py to test with the new file format.
 
1101
-----------------------------------------------------------------------------
 
1102
0.4       21 Mar 2002 Incorporated comments/patches from Ollie Rutherfurd:
 
1103
                      -Added level filtering for handlers.
 
1104
                      -Return root logger if no name specified in getLogger.
 
1105
                      Incorporated comments from Greg Ward:
 
1106
                      -Added distutils setup.py script.
 
1107
                      Added formatter initialization in Handler.__init__.
 
1108
                      Tidied up docstrings.
 
1109
                      Added removeHandler to Logger.
 
1110
                      Added removeFilter to Logger and Handler.
 
1111
                      logrecv.py modified to keep connection alive until
 
1112
                      client closes it.
 
1113
                      SocketHandler modified to not reset connection after
 
1114
                      each logging event.
 
1115
                      Added shutdown function which closes open sockets
 
1116
                      Renamed DEFAULT_LOGGING_PORT->DEFAULT_TCP_LOGGING_PORT
 
1117
                      Added DEFAULT_UDP_LOGGING_PORT
 
1118
                      Added log_test4.py (example of arbitrary levels)
 
1119
                      Added addLevelName, changed behaviour of getLevelName
 
1120
                      Fixed bugs in DatagramHandler
 
1121
                      Added SMTPHandler implementation
 
1122
                      Added log_test5.py to test SMTPHandler
 
1123
                      Added SysLogHandler (contribution from Nicolas Untz
 
1124
                      based on Sam Rushing's syslog.py)
 
1125
                      Modified log_test1.py to add a SysLogHandler
 
1126
                      Added rollover functionality to FileHandler
 
1127
                      Added NTEventLogHandler (based on Win32 extensions)
 
1128
                      Added MemoryHandler implementation
 
1129
                      Added log_test7.py to test MemoryHandler
 
1130
                      Added log_test8.py to test FileHandler rollover
 
1131
                      Added logException method to Logger
 
1132
                      Added formatException method to Formatter
 
1133
                      Added log_test6.py to test NTEventHandler and
 
1134
                      logException
 
1135
                      Numerous internal method renamings (sorry - but better
 
1136
                      to do this now, rather than when we enter beta status).
 
1137
-----------------------------------------------------------------------------
 
1138
0.3       14 Mar 2002 First public release, for early feedback
 
1139
-----------------------------------------------------------------------------
 
1140
0.2                   Consolidated into single file (for internal use only)
 
1141
-----------------------------------------------------------------------------
 
1142
0.1                   Initial implementation (for internal use only)
 
1143
-----------------------------------------------------------------------------
 
1144
</pre>
 
1145
 
 
1146
<a name="license"></a><h4>Copyright and License</h4>
 
1147
 
 
1148
<p>The copyright statement follows. </p>
 
1149
 
 
1150
<pre>
 
1151
Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
 
1152
 
 
1153
Permission to use, copy, modify, and distribute this software and its
 
1154
documentation for any purpose and without fee is hereby granted,
 
1155
provided that the above copyright notice appear in all copies and that
 
1156
both that copyright notice and this permission notice appear in
 
1157
supporting documentation, and that the name of Vinay Sajip
 
1158
not be used in advertising or publicity pertaining to distribution
 
1159
of the software without specific, written prior permission.
 
1160
VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 
1161
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 
1162
VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 
1163
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
1164
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 
1165
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
1166
 
 
1167
 
 
1168
 
 
1169
 
 
1170
 
 
1171
 
 
1172
 
 
1173
 
 
1174
 
 
1175
 
 
1176
 
 
1177
 
 
1178
 
 
1179
 
 
1180
 
 
1181
</pre>
 
1182
</body>
 
1183
</html>