blob: ed22d91f0cade10bb33636b51e651a058b6a45a5 [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajiped0473c2011-02-26 15:35:38 +00003# Copyright 2001-2011 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00004#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose and without fee is hereby granted,
7# provided that the above copyright notice appear in all copies and that
8# both that copyright notice and this permission notice appear in
9# supporting documentation, and that the name of Vinay Sajip
10# not be used in advertising or publicity pertaining to distribution
11# of the software without specific, written prior permission.
12# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
16# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19"""Test harness for the logging module. Run all tests.
20
Vinay Sajiped0473c2011-02-26 15:35:38 +000021Copyright (C) 2001-2011 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000022"""
23
Christian Heimes180510d2008-03-03 19:15:45 +000024import logging
25import logging.handlers
26import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000027
Benjamin Petersonf91df042009-02-13 02:50:59 +000028import codecs
Vinay Sajip19ec67a2010-09-17 18:57:36 +000029import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000037import select
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Vinay Sajipe6c1eb92011-03-29 17:20:34 +010042from test.support import captured_stdout, run_with_locale, run_unittest, patch
Vinay Sajipe723e962011-04-15 22:27:17 +010043from test.support import TestHandler, Matcher
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
52 import asynchat
53 import asyncore
54 import errno
55 from http.server import HTTPServer, BaseHTTPRequestHandler
56 import smtpd
57 from urllib.parse import urlparse, parse_qs
58 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
59 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000060except ImportError:
61 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010062try:
63 import win32evtlog
64except ImportError:
65 win32evtlog = None
66try:
67 import win32evtlogutil
68except ImportError:
69 win32evtlogutil = None
70 win32evtlog = None
Christian Heimes18c66892008-02-17 13:31:39 +000071
72
Christian Heimes180510d2008-03-03 19:15:45 +000073class BaseTest(unittest.TestCase):
74
75 """Base class for logging tests."""
76
77 log_format = "%(name)s -> %(levelname)s: %(message)s"
78 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
79 message_num = 0
80
81 def setUp(self):
82 """Setup the default logging stream to an internal StringIO instance,
83 so that we can examine log output as we want."""
84 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000085 logging._acquireLock()
86 try:
Christian Heimes180510d2008-03-03 19:15:45 +000087 self.saved_handlers = logging._handlers.copy()
88 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.saved_loggers = saved_loggers = logger_dict.copy()
Christian Heimes180510d2008-03-03 19:15:45 +000090 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000091 self.logger_states = logger_states = {}
92 for name in saved_loggers:
93 logger_states[name] = getattr(saved_loggers[name],
94 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000095 finally:
96 logging._releaseLock()
97
Benjamin Peterson22005fc2010-04-11 16:25:06 +000098 # Set two unused loggers: one non-ASCII and one Unicode.
99 # This is to test correct operation when sorting existing
100 # loggers in the configuration code. See issue 8201.
Vinay Sajipb4a08092010-09-20 09:55:00 +0000101 self.logger1 = logging.getLogger("\xab\xd7\xbb")
102 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000103
Christian Heimes180510d2008-03-03 19:15:45 +0000104 self.root_logger = logging.getLogger("")
105 self.original_logging_level = self.root_logger.getEffectiveLevel()
106
107 self.stream = io.StringIO()
108 self.root_logger.setLevel(logging.DEBUG)
109 self.root_hdlr = logging.StreamHandler(self.stream)
110 self.root_formatter = logging.Formatter(self.log_format)
111 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000112 if self.logger1.hasHandlers():
113 hlist = self.logger1.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
115 if self.logger2.hasHandlers():
116 hlist = self.logger2.handlers + self.root_logger.handlers
117 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000118 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000119 self.assertTrue(self.logger1.hasHandlers())
120 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000121
122 def tearDown(self):
123 """Remove our logging stream, and restore the original logging
124 level."""
125 self.stream.close()
126 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000127 while self.root_logger.handlers:
128 h = self.root_logger.handlers[0]
129 self.root_logger.removeHandler(h)
130 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000131 self.root_logger.setLevel(self.original_logging_level)
132 logging._acquireLock()
133 try:
134 logging._levelNames.clear()
135 logging._levelNames.update(self.saved_level_names)
136 logging._handlers.clear()
137 logging._handlers.update(self.saved_handlers)
138 logging._handlerList[:] = self.saved_handler_list
139 loggerDict = logging.getLogger().manager.loggerDict
140 loggerDict.clear()
141 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000142 logger_states = self.logger_states
143 for name in self.logger_states:
144 if logger_states[name] is not None:
145 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000146 finally:
147 logging._releaseLock()
148
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000149 def assert_log_lines(self, expected_values, stream=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000150 """Match the collected log lines against the regular expression
151 self.expected_log_pat, and compare the extracted group values to
152 the expected_values list of tuples."""
153 stream = stream or self.stream
154 pat = re.compile(self.expected_log_pat)
155 try:
156 stream.reset()
157 actual_lines = stream.readlines()
158 except AttributeError:
159 # StringIO.StringIO lacks a reset() method.
160 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100161 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000162 for actual, expected in zip(actual_lines, expected_values):
163 match = pat.search(actual)
164 if not match:
165 self.fail("Log line does not match expected pattern:\n" +
166 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000167 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000168 s = stream.read()
169 if s:
170 self.fail("Remaining output at end of log stream:\n" + s)
171
172 def next_message(self):
173 """Generate a message consisting solely of an auto-incrementing
174 integer."""
175 self.message_num += 1
176 return "%d" % self.message_num
177
178
179class BuiltinLevelsTest(BaseTest):
180 """Test builtin levels and their inheritance."""
181
182 def test_flat(self):
183 #Logging levels in a flat logger namespace.
184 m = self.next_message
185
186 ERR = logging.getLogger("ERR")
187 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000188 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000189 INF.setLevel(logging.INFO)
190 DEB = logging.getLogger("DEB")
191 DEB.setLevel(logging.DEBUG)
192
193 # These should log.
194 ERR.log(logging.CRITICAL, m())
195 ERR.error(m())
196
197 INF.log(logging.CRITICAL, m())
198 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100199 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 INF.info(m())
201
202 DEB.log(logging.CRITICAL, m())
203 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100204 DEB.warning(m())
205 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000206 DEB.debug(m())
207
208 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100209 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ERR.info(m())
211 ERR.debug(m())
212
213 INF.debug(m())
214
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000215 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000216 ('ERR', 'CRITICAL', '1'),
217 ('ERR', 'ERROR', '2'),
218 ('INF', 'CRITICAL', '3'),
219 ('INF', 'ERROR', '4'),
220 ('INF', 'WARNING', '5'),
221 ('INF', 'INFO', '6'),
222 ('DEB', 'CRITICAL', '7'),
223 ('DEB', 'ERROR', '8'),
224 ('DEB', 'WARNING', '9'),
225 ('DEB', 'INFO', '10'),
226 ('DEB', 'DEBUG', '11'),
227 ])
228
229 def test_nested_explicit(self):
230 # Logging levels in a nested namespace, all explicitly set.
231 m = self.next_message
232
233 INF = logging.getLogger("INF")
234 INF.setLevel(logging.INFO)
235 INF_ERR = logging.getLogger("INF.ERR")
236 INF_ERR.setLevel(logging.ERROR)
237
238 # These should log.
239 INF_ERR.log(logging.CRITICAL, m())
240 INF_ERR.error(m())
241
242 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100243 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000244 INF_ERR.info(m())
245 INF_ERR.debug(m())
246
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000247 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000248 ('INF.ERR', 'CRITICAL', '1'),
249 ('INF.ERR', 'ERROR', '2'),
250 ])
251
252 def test_nested_inherited(self):
253 #Logging levels in a nested namespace, inherited from parent loggers.
254 m = self.next_message
255
256 INF = logging.getLogger("INF")
257 INF.setLevel(logging.INFO)
258 INF_ERR = logging.getLogger("INF.ERR")
259 INF_ERR.setLevel(logging.ERROR)
260 INF_UNDEF = logging.getLogger("INF.UNDEF")
261 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
262 UNDEF = logging.getLogger("UNDEF")
263
264 # These should log.
265 INF_UNDEF.log(logging.CRITICAL, m())
266 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100267 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000268 INF_UNDEF.info(m())
269 INF_ERR_UNDEF.log(logging.CRITICAL, m())
270 INF_ERR_UNDEF.error(m())
271
272 # These should not log.
273 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100274 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000275 INF_ERR_UNDEF.info(m())
276 INF_ERR_UNDEF.debug(m())
277
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000278 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000279 ('INF.UNDEF', 'CRITICAL', '1'),
280 ('INF.UNDEF', 'ERROR', '2'),
281 ('INF.UNDEF', 'WARNING', '3'),
282 ('INF.UNDEF', 'INFO', '4'),
283 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
284 ('INF.ERR.UNDEF', 'ERROR', '6'),
285 ])
286
287 def test_nested_with_virtual_parent(self):
288 # Logging levels when some parent does not exist yet.
289 m = self.next_message
290
291 INF = logging.getLogger("INF")
292 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
293 CHILD = logging.getLogger("INF.BADPARENT")
294 INF.setLevel(logging.INFO)
295
296 # These should log.
297 GRANDCHILD.log(logging.FATAL, m())
298 GRANDCHILD.info(m())
299 CHILD.log(logging.FATAL, m())
300 CHILD.info(m())
301
302 # These should not log.
303 GRANDCHILD.debug(m())
304 CHILD.debug(m())
305
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000306 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000307 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
308 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
309 ('INF.BADPARENT', 'CRITICAL', '3'),
310 ('INF.BADPARENT', 'INFO', '4'),
311 ])
312
Vinay Sajip61b787e2011-11-07 08:53:03 +0000313 def test_invalid_name(self):
Vinay Sajip3bd56382011-11-07 10:15:08 +0000314 self.assertRaises(TypeError, logging.getLogger, any)
Christian Heimes180510d2008-03-03 19:15:45 +0000315
316class BasicFilterTest(BaseTest):
317
318 """Test the bundled Filter class."""
319
320 def test_filter(self):
321 # Only messages satisfying the specified criteria pass through the
322 # filter.
323 filter_ = logging.Filter("spam.eggs")
324 handler = self.root_logger.handlers[0]
325 try:
326 handler.addFilter(filter_)
327 spam = logging.getLogger("spam")
328 spam_eggs = logging.getLogger("spam.eggs")
329 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
330 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
331
332 spam.info(self.next_message())
333 spam_eggs.info(self.next_message()) # Good.
334 spam_eggs_fish.info(self.next_message()) # Good.
335 spam_bakedbeans.info(self.next_message())
336
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000337 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000338 ('spam.eggs', 'INFO', '2'),
339 ('spam.eggs.fish', 'INFO', '3'),
340 ])
341 finally:
342 handler.removeFilter(filter_)
343
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000344 def test_callable_filter(self):
345 # Only messages satisfying the specified criteria pass through the
346 # filter.
347
348 def filterfunc(record):
349 parts = record.name.split('.')
350 prefix = '.'.join(parts[:2])
351 return prefix == 'spam.eggs'
352
353 handler = self.root_logger.handlers[0]
354 try:
355 handler.addFilter(filterfunc)
356 spam = logging.getLogger("spam")
357 spam_eggs = logging.getLogger("spam.eggs")
358 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
359 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
360
361 spam.info(self.next_message())
362 spam_eggs.info(self.next_message()) # Good.
363 spam_eggs_fish.info(self.next_message()) # Good.
364 spam_bakedbeans.info(self.next_message())
365
366 self.assert_log_lines([
367 ('spam.eggs', 'INFO', '2'),
368 ('spam.eggs.fish', 'INFO', '3'),
369 ])
370 finally:
371 handler.removeFilter(filterfunc)
372
Vinay Sajip985ef872011-04-26 19:34:04 +0100373 def test_empty_filter(self):
374 f = logging.Filter()
375 r = logging.makeLogRecord({'name': 'spam.eggs'})
376 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000377
378#
379# First, we define our levels. There can be as many as you want - the only
380# limitations are that they should be integers, the lowest should be > 0 and
381# larger values mean less information being logged. If you need specific
382# level values which do not fit into these limitations, you can use a
383# mapping dictionary to convert between your application levels and the
384# logging system.
385#
386SILENT = 120
387TACITURN = 119
388TERSE = 118
389EFFUSIVE = 117
390SOCIABLE = 116
391VERBOSE = 115
392TALKATIVE = 114
393GARRULOUS = 113
394CHATTERBOX = 112
395BORING = 111
396
397LEVEL_RANGE = range(BORING, SILENT + 1)
398
399#
400# Next, we define names for our levels. You don't need to do this - in which
401# case the system will use "Level n" to denote the text for the level.
402#
403my_logging_levels = {
404 SILENT : 'Silent',
405 TACITURN : 'Taciturn',
406 TERSE : 'Terse',
407 EFFUSIVE : 'Effusive',
408 SOCIABLE : 'Sociable',
409 VERBOSE : 'Verbose',
410 TALKATIVE : 'Talkative',
411 GARRULOUS : 'Garrulous',
412 CHATTERBOX : 'Chatterbox',
413 BORING : 'Boring',
414}
415
416class GarrulousFilter(logging.Filter):
417
418 """A filter which blocks garrulous messages."""
419
420 def filter(self, record):
421 return record.levelno != GARRULOUS
422
423class VerySpecificFilter(logging.Filter):
424
425 """A filter which blocks sociable and taciturn messages."""
426
427 def filter(self, record):
428 return record.levelno not in [SOCIABLE, TACITURN]
429
430
431class CustomLevelsAndFiltersTest(BaseTest):
432
433 """Test various filtering possibilities with custom logging levels."""
434
435 # Skip the logger name group.
436 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
437
438 def setUp(self):
439 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000440 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000441 logging.addLevelName(k, v)
442
443 def log_at_all_levels(self, logger):
444 for lvl in LEVEL_RANGE:
445 logger.log(lvl, self.next_message())
446
447 def test_logger_filter(self):
448 # Filter at logger level.
449 self.root_logger.setLevel(VERBOSE)
450 # Levels >= 'Verbose' are good.
451 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000452 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000453 ('Verbose', '5'),
454 ('Sociable', '6'),
455 ('Effusive', '7'),
456 ('Terse', '8'),
457 ('Taciturn', '9'),
458 ('Silent', '10'),
459 ])
460
461 def test_handler_filter(self):
462 # Filter at handler level.
463 self.root_logger.handlers[0].setLevel(SOCIABLE)
464 try:
465 # Levels >= 'Sociable' are good.
466 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000467 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000468 ('Sociable', '6'),
469 ('Effusive', '7'),
470 ('Terse', '8'),
471 ('Taciturn', '9'),
472 ('Silent', '10'),
473 ])
474 finally:
475 self.root_logger.handlers[0].setLevel(logging.NOTSET)
476
477 def test_specific_filters(self):
478 # Set a specific filter object on the handler, and then add another
479 # filter object on the logger itself.
480 handler = self.root_logger.handlers[0]
481 specific_filter = None
482 garr = GarrulousFilter()
483 handler.addFilter(garr)
484 try:
485 self.log_at_all_levels(self.root_logger)
486 first_lines = [
487 # Notice how 'Garrulous' is missing
488 ('Boring', '1'),
489 ('Chatterbox', '2'),
490 ('Talkative', '4'),
491 ('Verbose', '5'),
492 ('Sociable', '6'),
493 ('Effusive', '7'),
494 ('Terse', '8'),
495 ('Taciturn', '9'),
496 ('Silent', '10'),
497 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000498 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000499
500 specific_filter = VerySpecificFilter()
501 self.root_logger.addFilter(specific_filter)
502 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000503 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000504 # Not only 'Garrulous' is still missing, but also 'Sociable'
505 # and 'Taciturn'
506 ('Boring', '11'),
507 ('Chatterbox', '12'),
508 ('Talkative', '14'),
509 ('Verbose', '15'),
510 ('Effusive', '17'),
511 ('Terse', '18'),
512 ('Silent', '20'),
513 ])
514 finally:
515 if specific_filter:
516 self.root_logger.removeFilter(specific_filter)
517 handler.removeFilter(garr)
518
519
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100520class HandlerTest(BaseTest):
521 def test_name(self):
522 h = logging.Handler()
523 h.name = 'generic'
524 self.assertEqual(h.name, 'generic')
525 h.name = 'anothergeneric'
526 self.assertEqual(h.name, 'anothergeneric')
527 self.assertRaises(NotImplementedError, h.emit, None)
528
Vinay Sajip5a35b062011-04-27 11:31:14 +0100529 def test_builtin_handlers(self):
530 # We can't actually *use* too many handlers in the tests,
531 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200532 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100533 for existing in (True, False):
534 fd, fn = tempfile.mkstemp()
535 os.close(fd)
536 if not existing:
537 os.unlink(fn)
538 h = logging.handlers.WatchedFileHandler(fn, delay=True)
539 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100540 dev, ino = h.dev, h.ino
541 self.assertNotEqual(dev, -1)
542 self.assertNotEqual(ino, -1)
543 r = logging.makeLogRecord({'msg': 'Test'})
544 h.handle(r)
545 # Now remove the file.
546 os.unlink(fn)
547 self.assertFalse(os.path.exists(fn))
548 # The next call should recreate the file.
549 h.handle(r)
550 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100551 else:
552 self.assertEqual(h.dev, -1)
553 self.assertEqual(h.ino, -1)
554 h.close()
555 if existing:
556 os.unlink(fn)
557 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100558 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100559 else:
560 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100561 try:
562 h = logging.handlers.SysLogHandler(sockname)
563 self.assertEqual(h.facility, h.LOG_USER)
564 self.assertTrue(h.unixsocket)
565 h.close()
566 except socket.error: # syslogd might not be available
567 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100568 for method in ('GET', 'POST', 'PUT'):
569 if method == 'PUT':
570 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
571 'localhost', '/log', method)
572 else:
573 h = logging.handlers.HTTPHandler('localhost', '/log', method)
574 h.close()
575 h = logging.handlers.BufferingHandler(0)
576 r = logging.makeLogRecord({})
577 self.assertTrue(h.shouldFlush(r))
578 h.close()
579 h = logging.handlers.BufferingHandler(1)
580 self.assertFalse(h.shouldFlush(r))
581 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100582
583class BadStream(object):
584 def write(self, data):
585 raise RuntimeError('deliberate mistake')
586
587class TestStreamHandler(logging.StreamHandler):
588 def handleError(self, record):
589 self.error_record = record
590
591class StreamHandlerTest(BaseTest):
592 def test_error_handling(self):
593 h = TestStreamHandler(BadStream())
594 r = logging.makeLogRecord({})
595 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100596 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100597 try:
598 h.handle(r)
599 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100600 h = logging.StreamHandler(BadStream())
601 sys.stderr = sio = io.StringIO()
602 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100603 self.assertIn('\nRuntimeError: deliberate mistake\n',
604 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100605 logging.raiseExceptions = False
606 sys.stderr = sio = io.StringIO()
607 h.handle(r)
608 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100609 finally:
610 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100611 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100612
Vinay Sajip7367d082011-05-02 13:17:27 +0100613# -- The following section could be moved into a server_helper.py module
614# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100615
Vinay Sajipce7c9782011-05-17 07:15:53 +0100616if threading:
617 class TestSMTPChannel(smtpd.SMTPChannel):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100618 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100619 This derived class has had to be created because smtpd does not
620 support use of custom channel maps, although they are allowed by
621 asyncore's design. Issue #11959 has been raised to address this,
622 and if resolved satisfactorily, some of this code can be removed.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100623 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100624 def __init__(self, server, conn, addr, sockmap):
625 asynchat.async_chat.__init__(self, conn, sockmap)
626 self.smtp_server = server
627 self.conn = conn
628 self.addr = addr
629 self.received_lines = []
630 self.smtp_state = self.COMMAND
631 self.seen_greeting = ''
632 self.mailfrom = None
633 self.rcpttos = []
634 self.received_data = ''
635 self.fqdn = socket.getfqdn()
636 self.num_bytes = 0
637 try:
638 self.peer = conn.getpeername()
639 except socket.error as err:
640 # a race condition may occur if the other end is closing
641 # before we can get the peername
642 self.close()
643 if err.args[0] != errno.ENOTCONN:
644 raise
645 return
646 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
647 self.set_terminator(b'\r\n')
Vinay Sajipa463d252011-04-30 21:52:48 +0100648
Vinay Sajip314b92b2011-05-02 14:31:16 +0100649
Vinay Sajipce7c9782011-05-17 07:15:53 +0100650 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100651 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100652 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100653
Vinay Sajipce7c9782011-05-17 07:15:53 +0100654 :param addr: A (host, port) tuple which the server listens on.
655 You can specify a port value of zero: the server's
656 *port* attribute will hold the actual port number
657 used, which can be used in client connections.
658 :param handler: A callable which will be called to process
659 incoming messages. The handler will be passed
660 the client address tuple, who the message is from,
661 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100662 :param poll_interval: The interval, in seconds, used in the underlying
663 :func:`select` or :func:`poll` call by
664 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100665 :param sockmap: A dictionary which will be used to hold
666 :class:`asyncore.dispatcher` instances used by
667 :func:`asyncore.loop`. This avoids changing the
668 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100669 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100670 channel_class = TestSMTPChannel
671
672 def __init__(self, addr, handler, poll_interval, sockmap):
673 self._localaddr = addr
674 self._remoteaddr = None
675 self.sockmap = sockmap
676 asyncore.dispatcher.__init__(self, map=sockmap)
677 try:
678 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
679 sock.setblocking(0)
680 self.set_socket(sock, map=sockmap)
681 # try to re-use a server port if possible
682 self.set_reuse_addr()
683 self.bind(addr)
684 self.port = sock.getsockname()[1]
685 self.listen(5)
686 except:
687 self.close()
Vinay Sajipe73afad2011-05-10 07:48:28 +0100688 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 self._handler = handler
690 self._thread = None
691 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 def handle_accepted(self, conn, addr):
694 """
695 Redefined only because the base class does not pass in a
696 map, forcing use of a global in :mod:`asyncore`.
697 """
698 channel = self.channel_class(self, conn, addr, self.sockmap)
Vinay Sajip314b92b2011-05-02 14:31:16 +0100699
Vinay Sajipce7c9782011-05-17 07:15:53 +0100700 def process_message(self, peer, mailfrom, rcpttos, data):
701 """
702 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100703
Vinay Sajipce7c9782011-05-17 07:15:53 +0100704 Typically, this will be a test case method.
705 :param peer: The client (host, port) tuple.
706 :param mailfrom: The address of the sender.
707 :param rcpttos: The addresses of the recipients.
708 :param data: The message.
709 """
710 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100711
Vinay Sajipce7c9782011-05-17 07:15:53 +0100712 def start(self):
713 """
714 Start the server running on a separate daemon thread.
715 """
716 self._thread = t = threading.Thread(target=self.serve_forever,
717 args=(self.poll_interval,))
718 t.setDaemon(True)
719 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100720
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 def serve_forever(self, poll_interval):
722 """
723 Run the :mod:`asyncore` loop until normal termination
724 conditions arise.
725 :param poll_interval: The interval, in seconds, used in the underlying
726 :func:`select` or :func:`poll` call by
727 :func:`asyncore.loop`.
728 """
729 try:
730 asyncore.loop(poll_interval, map=self.sockmap)
731 except select.error:
732 # On FreeBSD 8, closing the server repeatably
733 # raises this error. We swallow it if the
734 # server has been closed.
735 if self.connected or self.accepting:
736 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100737
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 def stop(self, timeout=None):
739 """
740 Stop the thread by closing the server instance.
741 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100742
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743 :param timeout: How long to wait for the server thread
744 to terminate.
745 """
746 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100747 self._thread.join(timeout)
748 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100749
Vinay Sajipce7c9782011-05-17 07:15:53 +0100750 class ControlMixin(object):
751 """
752 This mixin is used to start a server on a separate thread, and
753 shut it down programmatically. Request handling is simplified - instead
754 of needing to derive a suitable RequestHandler subclass, you just
755 provide a callable which will be passed each received request to be
756 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100757
Vinay Sajipce7c9782011-05-17 07:15:53 +0100758 :param handler: A handler callable which will be called with a
759 single parameter - the request - in order to
760 process the request. This handler is called on the
761 server thread, effectively meaning that requests are
762 processed serially. While not quite Web scale ;-),
763 this should be fine for testing applications.
764 :param poll_interval: The polling interval in seconds.
765 """
766 def __init__(self, handler, poll_interval):
767 self._thread = None
768 self.poll_interval = poll_interval
769 self._handler = handler
770 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100771
Vinay Sajipce7c9782011-05-17 07:15:53 +0100772 def start(self):
773 """
774 Create a daemon thread to run the server, and start it.
775 """
776 self._thread = t = threading.Thread(target=self.serve_forever,
777 args=(self.poll_interval,))
778 t.setDaemon(True)
779 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100780
Vinay Sajipce7c9782011-05-17 07:15:53 +0100781 def serve_forever(self, poll_interval):
782 """
783 Run the server. Set the ready flag before entering the
784 service loop.
785 """
786 self.ready.set()
787 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100788
Vinay Sajipce7c9782011-05-17 07:15:53 +0100789 def stop(self, timeout=None):
790 """
791 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100792
Vinay Sajipce7c9782011-05-17 07:15:53 +0100793 :param timeout: How long to wait for the server thread
794 to terminate.
795 """
796 self.shutdown()
797 if self._thread is not None:
798 self._thread.join(timeout)
799 self._thread = None
800 self.server_close()
801 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100802
Vinay Sajipce7c9782011-05-17 07:15:53 +0100803 class TestHTTPServer(ControlMixin, HTTPServer):
804 """
805 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Vinay Sajipce7c9782011-05-17 07:15:53 +0100807 :param addr: A tuple with the IP address and port to listen on.
808 :param handler: A handler callable which will be called with a
809 single parameter - the request - in order to
810 process the request.
811 :param poll_interval: The polling interval in seconds.
812 :param log: Pass ``True`` to enable log messages.
813 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100814 def __init__(self, addr, handler, poll_interval=0.5,
815 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100816 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
817 def __getattr__(self, name, default=None):
818 if name.startswith('do_'):
819 return self.process_request
820 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100821
Vinay Sajipce7c9782011-05-17 07:15:53 +0100822 def process_request(self):
823 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100824
Vinay Sajipce7c9782011-05-17 07:15:53 +0100825 def log_message(self, format, *args):
826 if log:
827 super(DelegatingHTTPRequestHandler,
828 self).log_message(format, *args)
829 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
830 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100831 self.sslctx = sslctx
832
833 def get_request(self):
834 try:
835 sock, addr = self.socket.accept()
836 if self.sslctx:
837 sock = self.sslctx.wrap_socket(sock, server_side=True)
838 except socket.error as e:
839 # socket errors are silenced by the caller, print them here
840 sys.stderr.write("Got an error:\n%s\n" % e)
841 raise
842 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100843
Vinay Sajipce7c9782011-05-17 07:15:53 +0100844 class TestTCPServer(ControlMixin, ThreadingTCPServer):
845 """
846 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 :param addr: A tuple with the IP address and port to listen on.
849 :param handler: A handler callable which will be called with a single
850 parameter - the request - in order to process the request.
851 :param poll_interval: The polling interval in seconds.
852 :bind_and_activate: If True (the default), binds the server and starts it
853 listening. If False, you need to call
854 :meth:`server_bind` and :meth:`server_activate` at
855 some later time before calling :meth:`start`, so that
856 the server will set up the socket and listen on it.
857 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100858
Vinay Sajipce7c9782011-05-17 07:15:53 +0100859 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 def __init__(self, addr, handler, poll_interval=0.5,
862 bind_and_activate=True):
863 class DelegatingTCPRequestHandler(StreamRequestHandler):
864
865 def handle(self):
866 self.server._handler(self)
867 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
868 bind_and_activate)
869 ControlMixin.__init__(self, handler, poll_interval)
870
871 def server_bind(self):
872 super(TestTCPServer, self).server_bind()
873 self.port = self.socket.getsockname()[1]
874
875 class TestUDPServer(ControlMixin, ThreadingUDPServer):
876 """
877 A UDP server which is controllable using :class:`ControlMixin`.
878
879 :param addr: A tuple with the IP address and port to listen on.
880 :param handler: A handler callable which will be called with a
881 single parameter - the request - in order to
882 process the request.
883 :param poll_interval: The polling interval for shutdown requests,
884 in seconds.
885 :bind_and_activate: If True (the default), binds the server and
886 starts it listening. If False, you need to
887 call :meth:`server_bind` and
888 :meth:`server_activate` at some later time
889 before calling :meth:`start`, so that the server will
890 set up the socket and listen on it.
891 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100892 def __init__(self, addr, handler, poll_interval=0.5,
893 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100894 class DelegatingUDPRequestHandler(DatagramRequestHandler):
895
896 def handle(self):
897 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100898
899 def finish(self):
900 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100901 if data:
902 try:
903 super(DelegatingUDPRequestHandler, self).finish()
904 except socket.error:
905 if not self.server._closed:
906 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100907
Vinay Sajip3ef12292011-05-23 23:00:42 +0100908 ThreadingUDPServer.__init__(self, addr,
909 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100910 bind_and_activate)
911 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100912 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100913
914 def server_bind(self):
915 super(TestUDPServer, self).server_bind()
916 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100917
Vinay Sajipba980db2011-05-23 21:37:54 +0100918 def server_close(self):
919 super(TestUDPServer, self).server_close()
920 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100921
922# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100923
Vinay Sajipce7c9782011-05-17 07:15:53 +0100924@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100925class SMTPHandlerTest(BaseTest):
926 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100927 sockmap = {}
928 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
929 sockmap)
930 server.start()
931 addr = ('localhost', server.port)
Vinay Sajipa463d252011-04-30 21:52:48 +0100932 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
933 self.assertEqual(h.toaddrs, ['you'])
934 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100936 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 h.handle(r)
Vinay Sajip7367d082011-05-02 13:17:27 +0100938 self.handled.wait()
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 server.stop()
940 self.assertEqual(len(self.messages), 1)
941 peer, mailfrom, rcpttos, data = self.messages[0]
942 self.assertEqual(mailfrom, 'me')
943 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100944 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100945 self.assertTrue(data.endswith('\n\nHello'))
946 h.close()
947
948 def process_message(self, *args):
949 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100950 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100951
Christian Heimes180510d2008-03-03 19:15:45 +0000952class MemoryHandlerTest(BaseTest):
953
954 """Tests for the MemoryHandler."""
955
956 # Do not bother with a logger name group.
957 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
958
959 def setUp(self):
960 BaseTest.setUp(self)
961 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
962 self.root_hdlr)
963 self.mem_logger = logging.getLogger('mem')
964 self.mem_logger.propagate = 0
965 self.mem_logger.addHandler(self.mem_hdlr)
966
967 def tearDown(self):
968 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000969 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000970
971 def test_flush(self):
972 # The memory handler flushes to its target handler based on specific
973 # criteria (message count and message level).
974 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000975 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000976 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000977 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000978 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100979 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000980 lines = [
981 ('DEBUG', '1'),
982 ('INFO', '2'),
983 ('WARNING', '3'),
984 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000985 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000986 for n in (4, 14):
987 for i in range(9):
988 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000989 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000990 # This will flush because it's the 10th message since the last
991 # flush.
992 self.mem_logger.debug(self.next_message())
993 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000994 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000995
996 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000997 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000998
999
1000class ExceptionFormatter(logging.Formatter):
1001 """A special exception formatter."""
1002 def formatException(self, ei):
1003 return "Got a [%s]" % ei[0].__name__
1004
1005
1006class ConfigFileTest(BaseTest):
1007
1008 """Reading logging config from a .ini-style config file."""
1009
1010 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1011
1012 # config0 is a standard configuration.
1013 config0 = """
1014 [loggers]
1015 keys=root
1016
1017 [handlers]
1018 keys=hand1
1019
1020 [formatters]
1021 keys=form1
1022
1023 [logger_root]
1024 level=WARNING
1025 handlers=hand1
1026
1027 [handler_hand1]
1028 class=StreamHandler
1029 level=NOTSET
1030 formatter=form1
1031 args=(sys.stdout,)
1032
1033 [formatter_form1]
1034 format=%(levelname)s ++ %(message)s
1035 datefmt=
1036 """
1037
1038 # config1 adds a little to the standard configuration.
1039 config1 = """
1040 [loggers]
1041 keys=root,parser
1042
1043 [handlers]
1044 keys=hand1
1045
1046 [formatters]
1047 keys=form1
1048
1049 [logger_root]
1050 level=WARNING
1051 handlers=
1052
1053 [logger_parser]
1054 level=DEBUG
1055 handlers=hand1
1056 propagate=1
1057 qualname=compiler.parser
1058
1059 [handler_hand1]
1060 class=StreamHandler
1061 level=NOTSET
1062 formatter=form1
1063 args=(sys.stdout,)
1064
1065 [formatter_form1]
1066 format=%(levelname)s ++ %(message)s
1067 datefmt=
1068 """
1069
Vinay Sajip3f84b072011-03-07 17:49:33 +00001070 # config1a moves the handler to the root.
1071 config1a = """
1072 [loggers]
1073 keys=root,parser
1074
1075 [handlers]
1076 keys=hand1
1077
1078 [formatters]
1079 keys=form1
1080
1081 [logger_root]
1082 level=WARNING
1083 handlers=hand1
1084
1085 [logger_parser]
1086 level=DEBUG
1087 handlers=
1088 propagate=1
1089 qualname=compiler.parser
1090
1091 [handler_hand1]
1092 class=StreamHandler
1093 level=NOTSET
1094 formatter=form1
1095 args=(sys.stdout,)
1096
1097 [formatter_form1]
1098 format=%(levelname)s ++ %(message)s
1099 datefmt=
1100 """
1101
Christian Heimes180510d2008-03-03 19:15:45 +00001102 # config2 has a subtle configuration error that should be reported
1103 config2 = config1.replace("sys.stdout", "sys.stbout")
1104
1105 # config3 has a less subtle configuration error
1106 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1107
1108 # config4 specifies a custom formatter class to be loaded
1109 config4 = """
1110 [loggers]
1111 keys=root
1112
1113 [handlers]
1114 keys=hand1
1115
1116 [formatters]
1117 keys=form1
1118
1119 [logger_root]
1120 level=NOTSET
1121 handlers=hand1
1122
1123 [handler_hand1]
1124 class=StreamHandler
1125 level=NOTSET
1126 formatter=form1
1127 args=(sys.stdout,)
1128
1129 [formatter_form1]
1130 class=""" + __name__ + """.ExceptionFormatter
1131 format=%(levelname)s:%(name)s:%(message)s
1132 datefmt=
1133 """
1134
Georg Brandl3dbca812008-07-23 16:10:53 +00001135 # config5 specifies a custom handler class to be loaded
1136 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1137
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001138 # config6 uses ', ' delimiters in the handlers and formatters sections
1139 config6 = """
1140 [loggers]
1141 keys=root,parser
1142
1143 [handlers]
1144 keys=hand1, hand2
1145
1146 [formatters]
1147 keys=form1, form2
1148
1149 [logger_root]
1150 level=WARNING
1151 handlers=
1152
1153 [logger_parser]
1154 level=DEBUG
1155 handlers=hand1
1156 propagate=1
1157 qualname=compiler.parser
1158
1159 [handler_hand1]
1160 class=StreamHandler
1161 level=NOTSET
1162 formatter=form1
1163 args=(sys.stdout,)
1164
1165 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001166 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001167 level=NOTSET
1168 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001169 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001170
1171 [formatter_form1]
1172 format=%(levelname)s ++ %(message)s
1173 datefmt=
1174
1175 [formatter_form2]
1176 format=%(message)s
1177 datefmt=
1178 """
1179
Vinay Sajip3f84b072011-03-07 17:49:33 +00001180 # config7 adds a compiler logger.
1181 config7 = """
1182 [loggers]
1183 keys=root,parser,compiler
1184
1185 [handlers]
1186 keys=hand1
1187
1188 [formatters]
1189 keys=form1
1190
1191 [logger_root]
1192 level=WARNING
1193 handlers=hand1
1194
1195 [logger_compiler]
1196 level=DEBUG
1197 handlers=
1198 propagate=1
1199 qualname=compiler
1200
1201 [logger_parser]
1202 level=DEBUG
1203 handlers=
1204 propagate=1
1205 qualname=compiler.parser
1206
1207 [handler_hand1]
1208 class=StreamHandler
1209 level=NOTSET
1210 formatter=form1
1211 args=(sys.stdout,)
1212
1213 [formatter_form1]
1214 format=%(levelname)s ++ %(message)s
1215 datefmt=
1216 """
1217
Christian Heimes180510d2008-03-03 19:15:45 +00001218 def apply_config(self, conf):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001219 file = io.StringIO(textwrap.dedent(conf))
1220 logging.config.fileConfig(file)
Christian Heimes180510d2008-03-03 19:15:45 +00001221
1222 def test_config0_ok(self):
1223 # A simple config file which overrides the default settings.
1224 with captured_stdout() as output:
1225 self.apply_config(self.config0)
1226 logger = logging.getLogger()
1227 # Won't output anything
1228 logger.info(self.next_message())
1229 # Outputs a message
1230 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001231 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001232 ('ERROR', '2'),
1233 ], stream=output)
1234 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001235 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001236
Georg Brandl3dbca812008-07-23 16:10:53 +00001237 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001238 # A config file defining a sub-parser as well.
1239 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001240 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001241 logger = logging.getLogger("compiler.parser")
1242 # Both will output a message
1243 logger.info(self.next_message())
1244 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001245 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001246 ('INFO', '1'),
1247 ('ERROR', '2'),
1248 ], stream=output)
1249 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001250 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001251
1252 def test_config2_failure(self):
1253 # A simple config file which overrides the default settings.
1254 self.assertRaises(Exception, self.apply_config, self.config2)
1255
1256 def test_config3_failure(self):
1257 # A simple config file which overrides the default settings.
1258 self.assertRaises(Exception, self.apply_config, self.config3)
1259
1260 def test_config4_ok(self):
1261 # A config file specifying a custom formatter class.
1262 with captured_stdout() as output:
1263 self.apply_config(self.config4)
1264 logger = logging.getLogger()
1265 try:
1266 raise RuntimeError()
1267 except RuntimeError:
1268 logging.exception("just testing")
1269 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001270 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001271 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1272 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001273 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001274
Georg Brandl3dbca812008-07-23 16:10:53 +00001275 def test_config5_ok(self):
1276 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001277
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001278 def test_config6_ok(self):
1279 self.test_config1_ok(config=self.config6)
1280
Vinay Sajip3f84b072011-03-07 17:49:33 +00001281 def test_config7_ok(self):
1282 with captured_stdout() as output:
1283 self.apply_config(self.config1a)
1284 logger = logging.getLogger("compiler.parser")
1285 # See issue #11424. compiler-hyphenated sorts
1286 # between compiler and compiler.xyz and this
1287 # was preventing compiler.xyz from being included
1288 # in the child loggers of compiler because of an
1289 # overzealous loop termination condition.
1290 hyphenated = logging.getLogger('compiler-hyphenated')
1291 # All will output a message
1292 logger.info(self.next_message())
1293 logger.error(self.next_message())
1294 hyphenated.critical(self.next_message())
1295 self.assert_log_lines([
1296 ('INFO', '1'),
1297 ('ERROR', '2'),
1298 ('CRITICAL', '3'),
1299 ], stream=output)
1300 # Original logger output is empty.
1301 self.assert_log_lines([])
1302 with captured_stdout() as output:
1303 self.apply_config(self.config7)
1304 logger = logging.getLogger("compiler.parser")
1305 self.assertFalse(logger.disabled)
1306 # Both will output a message
1307 logger.info(self.next_message())
1308 logger.error(self.next_message())
1309 logger = logging.getLogger("compiler.lexer")
1310 # Both will output a message
1311 logger.info(self.next_message())
1312 logger.error(self.next_message())
1313 # Will not appear
1314 hyphenated.critical(self.next_message())
1315 self.assert_log_lines([
1316 ('INFO', '4'),
1317 ('ERROR', '5'),
1318 ('INFO', '6'),
1319 ('ERROR', '7'),
1320 ], stream=output)
1321 # Original logger output is empty.
1322 self.assert_log_lines([])
1323
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001324
Victor Stinner45df8202010-04-28 22:31:17 +00001325@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001326class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001327
Christian Heimes180510d2008-03-03 19:15:45 +00001328 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001329
Christian Heimes180510d2008-03-03 19:15:45 +00001330 def setUp(self):
1331 """Set up a TCP server to receive log messages, and a SocketHandler
1332 pointing to that server's address and port."""
1333 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001334 addr = ('localhost', 0)
1335 self.server = server = TestTCPServer(addr, self.handle_socket,
1336 0.01)
1337 server.start()
1338 server.ready.wait()
1339 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1340 server.port)
1341 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001342 self.root_logger.removeHandler(self.root_logger.handlers[0])
1343 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001344 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001345
Christian Heimes180510d2008-03-03 19:15:45 +00001346 def tearDown(self):
1347 """Shutdown the TCP server."""
1348 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001349 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001350 self.root_logger.removeHandler(self.sock_hdlr)
1351 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001352 finally:
1353 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001354
Vinay Sajip7367d082011-05-02 13:17:27 +01001355 def handle_socket(self, request):
1356 conn = request.connection
1357 while True:
1358 chunk = conn.recv(4)
1359 if len(chunk) < 4:
1360 break
1361 slen = struct.unpack(">L", chunk)[0]
1362 chunk = conn.recv(slen)
1363 while len(chunk) < slen:
1364 chunk = chunk + conn.recv(slen - len(chunk))
1365 obj = pickle.loads(chunk)
1366 record = logging.makeLogRecord(obj)
1367 self.log_output += record.msg + '\n'
1368 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001369
Christian Heimes180510d2008-03-03 19:15:45 +00001370 def test_output(self):
1371 # The log message sent to the SocketHandler is properly received.
1372 logger = logging.getLogger("tcp")
1373 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001374 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001375 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001376 self.handled.acquire()
1377 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001378
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001379 def test_noserver(self):
1380 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001381 self.server.stop(2.0)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001382 #The logging call should try to connect, which should fail
1383 try:
1384 raise RuntimeError('Deliberate mistake')
1385 except RuntimeError:
1386 self.root_logger.exception('Never sent')
1387 self.root_logger.error('Never sent, either')
1388 now = time.time()
1389 self.assertTrue(self.sock_hdlr.retryTime > now)
1390 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1391 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001392
Vinay Sajip7367d082011-05-02 13:17:27 +01001393
1394@unittest.skipUnless(threading, 'Threading required for this test.')
1395class DatagramHandlerTest(BaseTest):
1396
1397 """Test for DatagramHandler."""
1398
1399 def setUp(self):
1400 """Set up a UDP server to receive log messages, and a DatagramHandler
1401 pointing to that server's address and port."""
1402 BaseTest.setUp(self)
1403 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001404 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001405 server.start()
1406 server.ready.wait()
1407 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1408 server.port)
1409 self.log_output = ''
1410 self.root_logger.removeHandler(self.root_logger.handlers[0])
1411 self.root_logger.addHandler(self.sock_hdlr)
1412 self.handled = threading.Event()
1413
1414 def tearDown(self):
1415 """Shutdown the UDP server."""
1416 try:
1417 self.server.stop(2.0)
1418 self.root_logger.removeHandler(self.sock_hdlr)
1419 self.sock_hdlr.close()
1420 finally:
1421 BaseTest.tearDown(self)
1422
1423 def handle_datagram(self, request):
1424 slen = struct.pack('>L', 0) # length of prefix
1425 packet = request.packet[len(slen):]
1426 obj = pickle.loads(packet)
1427 record = logging.makeLogRecord(obj)
1428 self.log_output += record.msg + '\n'
1429 self.handled.set()
1430
1431 def test_output(self):
1432 # The log message sent to the DatagramHandler is properly received.
1433 logger = logging.getLogger("udp")
1434 logger.error("spam")
1435 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001436 self.handled.clear()
1437 logger.error("eggs")
1438 self.handled.wait()
1439 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001440
1441
1442@unittest.skipUnless(threading, 'Threading required for this test.')
1443class SysLogHandlerTest(BaseTest):
1444
1445 """Test for SysLogHandler using UDP."""
1446
1447 def setUp(self):
1448 """Set up a UDP server to receive log messages, and a SysLogHandler
1449 pointing to that server's address and port."""
1450 BaseTest.setUp(self)
1451 addr = ('localhost', 0)
1452 self.server = server = TestUDPServer(addr, self.handle_datagram,
1453 0.01)
1454 server.start()
1455 server.ready.wait()
1456 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1457 server.port))
1458 self.log_output = ''
1459 self.root_logger.removeHandler(self.root_logger.handlers[0])
1460 self.root_logger.addHandler(self.sl_hdlr)
1461 self.handled = threading.Event()
1462
1463 def tearDown(self):
1464 """Shutdown the UDP server."""
1465 try:
1466 self.server.stop(2.0)
1467 self.root_logger.removeHandler(self.sl_hdlr)
1468 self.sl_hdlr.close()
1469 finally:
1470 BaseTest.tearDown(self)
1471
1472 def handle_datagram(self, request):
1473 self.log_output = request.packet
1474 self.handled.set()
1475
1476 def test_output(self):
1477 # The log message sent to the SysLogHandler is properly received.
1478 logger = logging.getLogger("slh")
1479 logger.error("sp\xe4m")
1480 self.handled.wait()
1481 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001482 self.handled.clear()
1483 self.sl_hdlr.append_nul = False
1484 logger.error("sp\xe4m")
1485 self.handled.wait()
1486 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001487 self.handled.clear()
1488 self.sl_hdlr.ident = "h\xe4m-"
1489 logger.error("sp\xe4m")
1490 self.handled.wait()
1491 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfh\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001492
1493
1494@unittest.skipUnless(threading, 'Threading required for this test.')
1495class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001496 """Test for HTTPHandler."""
1497
Vinay Sajip9ba87612011-05-21 11:32:15 +01001498 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1499MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1500zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1501aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1502AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15030tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15045LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1505piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15062z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1507i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1508PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1509E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1510rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1511/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1512-----END RSA PRIVATE KEY-----
1513-----BEGIN CERTIFICATE-----
1514MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1515BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1516EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1517xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1518l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1519vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1520BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1521S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1522BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15234f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15241c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1525IRbTpvlHWPjsSvHz0ZOH
1526-----END CERTIFICATE-----"""
1527
Vinay Sajip7367d082011-05-02 13:17:27 +01001528 def setUp(self):
1529 """Set up an HTTP server to receive log messages, and a HTTPHandler
1530 pointing to that server's address and port."""
1531 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001532 self.handled = threading.Event()
1533
Vinay Sajip7367d082011-05-02 13:17:27 +01001534 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001535 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001536 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001537 if self.command == 'POST':
1538 try:
1539 rlen = int(request.headers['Content-Length'])
1540 self.post_data = request.rfile.read(rlen)
1541 except:
1542 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001543 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001544 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001545 self.handled.set()
1546
1547 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001548 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001549 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001550 root_logger = self.root_logger
1551 root_logger.removeHandler(self.root_logger.handlers[0])
1552 for secure in (False, True):
1553 addr = ('localhost', 0)
1554 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001555 try:
1556 import ssl
1557 fd, fn = tempfile.mkstemp()
1558 os.close(fd)
1559 with open(fn, 'w') as f:
1560 f.write(self.PEMFILE)
1561 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1562 sslctx.load_cert_chain(fn)
1563 os.unlink(fn)
1564 except ImportError:
1565 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001566 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001567 sslctx = None
1568 self.server = server = TestHTTPServer(addr, self.handle_request,
1569 0.01, sslctx=sslctx)
1570 server.start()
1571 server.ready.wait()
1572 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001573 secure_client = secure and sslctx
1574 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1575 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001576 self.log_data = None
1577 root_logger.addHandler(self.h_hdlr)
1578
1579 for method in ('GET', 'POST'):
1580 self.h_hdlr.method = method
1581 self.handled.clear()
1582 msg = "sp\xe4m"
1583 logger.error(msg)
1584 self.handled.wait()
1585 self.assertEqual(self.log_data.path, '/frob')
1586 self.assertEqual(self.command, method)
1587 if method == 'GET':
1588 d = parse_qs(self.log_data.query)
1589 else:
1590 d = parse_qs(self.post_data.decode('utf-8'))
1591 self.assertEqual(d['name'], ['http'])
1592 self.assertEqual(d['funcName'], ['test_output'])
1593 self.assertEqual(d['msg'], [msg])
1594
1595 self.server.stop(2.0)
1596 self.root_logger.removeHandler(self.h_hdlr)
1597 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001598
Christian Heimes180510d2008-03-03 19:15:45 +00001599class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001600
Christian Heimes180510d2008-03-03 19:15:45 +00001601 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001602
Christian Heimes180510d2008-03-03 19:15:45 +00001603 def setUp(self):
1604 """Create a dict to remember potentially destroyed objects."""
1605 BaseTest.setUp(self)
1606 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001607
Christian Heimes180510d2008-03-03 19:15:45 +00001608 def _watch_for_survival(self, *args):
1609 """Watch the given objects for survival, by creating weakrefs to
1610 them."""
1611 for obj in args:
1612 key = id(obj), repr(obj)
1613 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001614
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001615 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001616 """Assert that all objects watched for survival have survived."""
1617 # Trigger cycle breaking.
1618 gc.collect()
1619 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001620 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001621 if ref() is None:
1622 dead.append(repr_)
1623 if dead:
1624 self.fail("%d objects should have survived "
1625 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001626
Christian Heimes180510d2008-03-03 19:15:45 +00001627 def test_persistent_loggers(self):
1628 # Logger objects are persistent and retain their configuration, even
1629 # if visible references are destroyed.
1630 self.root_logger.setLevel(logging.INFO)
1631 foo = logging.getLogger("foo")
1632 self._watch_for_survival(foo)
1633 foo.setLevel(logging.DEBUG)
1634 self.root_logger.debug(self.next_message())
1635 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001636 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001637 ('foo', 'DEBUG', '2'),
1638 ])
1639 del foo
1640 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001641 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001642 # foo has retained its settings.
1643 bar = logging.getLogger("foo")
1644 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001645 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001646 ('foo', 'DEBUG', '2'),
1647 ('foo', 'DEBUG', '3'),
1648 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001649
Benjamin Petersonf91df042009-02-13 02:50:59 +00001650
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001651class EncodingTest(BaseTest):
1652 def test_encoding_plain_file(self):
1653 # In Python 2.x, a plain file object is treated as having no encoding.
1654 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001655 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1656 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001657 # the non-ascii data we write to the log.
1658 data = "foo\x80"
1659 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001660 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001661 log.addHandler(handler)
1662 try:
1663 # write non-ascii data to the log.
1664 log.warning(data)
1665 finally:
1666 log.removeHandler(handler)
1667 handler.close()
1668 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001669 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001670 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001671 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001672 finally:
1673 f.close()
1674 finally:
1675 if os.path.isfile(fn):
1676 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001677
Benjamin Petersonf91df042009-02-13 02:50:59 +00001678 def test_encoding_cyrillic_unicode(self):
1679 log = logging.getLogger("test")
1680 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1681 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1682 #Ensure it's written in a Cyrillic encoding
1683 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001684 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001685 stream = io.BytesIO()
1686 writer = writer_class(stream, 'strict')
1687 handler = logging.StreamHandler(writer)
1688 log.addHandler(handler)
1689 try:
1690 log.warning(message)
1691 finally:
1692 log.removeHandler(handler)
1693 handler.close()
1694 # check we wrote exactly those bytes, ignoring trailing \n etc
1695 s = stream.getvalue()
1696 #Compare against what the data should be when encoded in CP-1251
1697 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1698
1699
Georg Brandlf9734072008-12-07 15:30:06 +00001700class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001701
Georg Brandlf9734072008-12-07 15:30:06 +00001702 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001703 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001704 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001705 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001706 warnings.filterwarnings("always", category=UserWarning)
1707 stream = io.StringIO()
1708 h = logging.StreamHandler(stream)
1709 logger = logging.getLogger("py.warnings")
1710 logger.addHandler(h)
1711 warnings.warn("I'm warning you...")
1712 logger.removeHandler(h)
1713 s = stream.getvalue()
1714 h.close()
1715 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001716
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001717 #See if an explicit file uses the original implementation
1718 a_file = io.StringIO()
1719 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1720 a_file, "Dummy line")
1721 s = a_file.getvalue()
1722 a_file.close()
1723 self.assertEqual(s,
1724 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1725
1726 def test_warnings_no_handlers(self):
1727 with warnings.catch_warnings():
1728 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001729 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001730
1731 # confirm our assumption: no loggers are set
1732 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001733 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001734
1735 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001736 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001737 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001738
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001739
1740def formatFunc(format, datefmt=None):
1741 return logging.Formatter(format, datefmt)
1742
1743def handlerFunc():
1744 return logging.StreamHandler()
1745
1746class CustomHandler(logging.StreamHandler):
1747 pass
1748
1749class ConfigDictTest(BaseTest):
1750
1751 """Reading logging config from a dictionary."""
1752
1753 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1754
1755 # config0 is a standard configuration.
1756 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001757 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001758 'formatters': {
1759 'form1' : {
1760 'format' : '%(levelname)s ++ %(message)s',
1761 },
1762 },
1763 'handlers' : {
1764 'hand1' : {
1765 'class' : 'logging.StreamHandler',
1766 'formatter' : 'form1',
1767 'level' : 'NOTSET',
1768 'stream' : 'ext://sys.stdout',
1769 },
1770 },
1771 'root' : {
1772 'level' : 'WARNING',
1773 'handlers' : ['hand1'],
1774 },
1775 }
1776
1777 # config1 adds a little to the standard configuration.
1778 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001779 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001780 'formatters': {
1781 'form1' : {
1782 'format' : '%(levelname)s ++ %(message)s',
1783 },
1784 },
1785 'handlers' : {
1786 'hand1' : {
1787 'class' : 'logging.StreamHandler',
1788 'formatter' : 'form1',
1789 'level' : 'NOTSET',
1790 'stream' : 'ext://sys.stdout',
1791 },
1792 },
1793 'loggers' : {
1794 'compiler.parser' : {
1795 'level' : 'DEBUG',
1796 'handlers' : ['hand1'],
1797 },
1798 },
1799 'root' : {
1800 'level' : 'WARNING',
1801 },
1802 }
1803
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001804 # config1a moves the handler to the root. Used with config8a
1805 config1a = {
1806 'version': 1,
1807 'formatters': {
1808 'form1' : {
1809 'format' : '%(levelname)s ++ %(message)s',
1810 },
1811 },
1812 'handlers' : {
1813 'hand1' : {
1814 'class' : 'logging.StreamHandler',
1815 'formatter' : 'form1',
1816 'level' : 'NOTSET',
1817 'stream' : 'ext://sys.stdout',
1818 },
1819 },
1820 'loggers' : {
1821 'compiler.parser' : {
1822 'level' : 'DEBUG',
1823 },
1824 },
1825 'root' : {
1826 'level' : 'WARNING',
1827 'handlers' : ['hand1'],
1828 },
1829 }
1830
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001831 # config2 has a subtle configuration error that should be reported
1832 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001833 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001834 'formatters': {
1835 'form1' : {
1836 'format' : '%(levelname)s ++ %(message)s',
1837 },
1838 },
1839 'handlers' : {
1840 'hand1' : {
1841 'class' : 'logging.StreamHandler',
1842 'formatter' : 'form1',
1843 'level' : 'NOTSET',
1844 'stream' : 'ext://sys.stdbout',
1845 },
1846 },
1847 'loggers' : {
1848 'compiler.parser' : {
1849 'level' : 'DEBUG',
1850 'handlers' : ['hand1'],
1851 },
1852 },
1853 'root' : {
1854 'level' : 'WARNING',
1855 },
1856 }
1857
1858 #As config1 but with a misspelt level on a handler
1859 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001860 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001861 'formatters': {
1862 'form1' : {
1863 'format' : '%(levelname)s ++ %(message)s',
1864 },
1865 },
1866 'handlers' : {
1867 'hand1' : {
1868 'class' : 'logging.StreamHandler',
1869 'formatter' : 'form1',
1870 'level' : 'NTOSET',
1871 'stream' : 'ext://sys.stdout',
1872 },
1873 },
1874 'loggers' : {
1875 'compiler.parser' : {
1876 'level' : 'DEBUG',
1877 'handlers' : ['hand1'],
1878 },
1879 },
1880 'root' : {
1881 'level' : 'WARNING',
1882 },
1883 }
1884
1885
1886 #As config1 but with a misspelt level on a logger
1887 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001888 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001889 'formatters': {
1890 'form1' : {
1891 'format' : '%(levelname)s ++ %(message)s',
1892 },
1893 },
1894 'handlers' : {
1895 'hand1' : {
1896 'class' : 'logging.StreamHandler',
1897 'formatter' : 'form1',
1898 'level' : 'NOTSET',
1899 'stream' : 'ext://sys.stdout',
1900 },
1901 },
1902 'loggers' : {
1903 'compiler.parser' : {
1904 'level' : 'DEBUG',
1905 'handlers' : ['hand1'],
1906 },
1907 },
1908 'root' : {
1909 'level' : 'WRANING',
1910 },
1911 }
1912
1913 # config3 has a less subtle configuration error
1914 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001915 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001916 'formatters': {
1917 'form1' : {
1918 'format' : '%(levelname)s ++ %(message)s',
1919 },
1920 },
1921 'handlers' : {
1922 'hand1' : {
1923 'class' : 'logging.StreamHandler',
1924 'formatter' : 'misspelled_name',
1925 'level' : 'NOTSET',
1926 'stream' : 'ext://sys.stdout',
1927 },
1928 },
1929 'loggers' : {
1930 'compiler.parser' : {
1931 'level' : 'DEBUG',
1932 'handlers' : ['hand1'],
1933 },
1934 },
1935 'root' : {
1936 'level' : 'WARNING',
1937 },
1938 }
1939
1940 # config4 specifies a custom formatter class to be loaded
1941 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001942 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001943 'formatters': {
1944 'form1' : {
1945 '()' : __name__ + '.ExceptionFormatter',
1946 'format' : '%(levelname)s:%(name)s:%(message)s',
1947 },
1948 },
1949 'handlers' : {
1950 'hand1' : {
1951 'class' : 'logging.StreamHandler',
1952 'formatter' : 'form1',
1953 'level' : 'NOTSET',
1954 'stream' : 'ext://sys.stdout',
1955 },
1956 },
1957 'root' : {
1958 'level' : 'NOTSET',
1959 'handlers' : ['hand1'],
1960 },
1961 }
1962
1963 # As config4 but using an actual callable rather than a string
1964 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001965 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001966 'formatters': {
1967 'form1' : {
1968 '()' : ExceptionFormatter,
1969 'format' : '%(levelname)s:%(name)s:%(message)s',
1970 },
1971 'form2' : {
1972 '()' : __name__ + '.formatFunc',
1973 'format' : '%(levelname)s:%(name)s:%(message)s',
1974 },
1975 'form3' : {
1976 '()' : formatFunc,
1977 'format' : '%(levelname)s:%(name)s:%(message)s',
1978 },
1979 },
1980 'handlers' : {
1981 'hand1' : {
1982 'class' : 'logging.StreamHandler',
1983 'formatter' : 'form1',
1984 'level' : 'NOTSET',
1985 'stream' : 'ext://sys.stdout',
1986 },
1987 'hand2' : {
1988 '()' : handlerFunc,
1989 },
1990 },
1991 'root' : {
1992 'level' : 'NOTSET',
1993 'handlers' : ['hand1'],
1994 },
1995 }
1996
1997 # config5 specifies a custom handler class to be loaded
1998 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001999 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002000 'formatters': {
2001 'form1' : {
2002 'format' : '%(levelname)s ++ %(message)s',
2003 },
2004 },
2005 'handlers' : {
2006 'hand1' : {
2007 'class' : __name__ + '.CustomHandler',
2008 'formatter' : 'form1',
2009 'level' : 'NOTSET',
2010 'stream' : 'ext://sys.stdout',
2011 },
2012 },
2013 'loggers' : {
2014 'compiler.parser' : {
2015 'level' : 'DEBUG',
2016 'handlers' : ['hand1'],
2017 },
2018 },
2019 'root' : {
2020 'level' : 'WARNING',
2021 },
2022 }
2023
2024 # config6 specifies a custom handler class to be loaded
2025 # but has bad arguments
2026 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002027 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002028 'formatters': {
2029 'form1' : {
2030 'format' : '%(levelname)s ++ %(message)s',
2031 },
2032 },
2033 'handlers' : {
2034 'hand1' : {
2035 'class' : __name__ + '.CustomHandler',
2036 'formatter' : 'form1',
2037 'level' : 'NOTSET',
2038 'stream' : 'ext://sys.stdout',
2039 '9' : 'invalid parameter name',
2040 },
2041 },
2042 'loggers' : {
2043 'compiler.parser' : {
2044 'level' : 'DEBUG',
2045 'handlers' : ['hand1'],
2046 },
2047 },
2048 'root' : {
2049 'level' : 'WARNING',
2050 },
2051 }
2052
2053 #config 7 does not define compiler.parser but defines compiler.lexer
2054 #so compiler.parser should be disabled after applying it
2055 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002056 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002057 'formatters': {
2058 'form1' : {
2059 'format' : '%(levelname)s ++ %(message)s',
2060 },
2061 },
2062 'handlers' : {
2063 'hand1' : {
2064 'class' : 'logging.StreamHandler',
2065 'formatter' : 'form1',
2066 'level' : 'NOTSET',
2067 'stream' : 'ext://sys.stdout',
2068 },
2069 },
2070 'loggers' : {
2071 'compiler.lexer' : {
2072 'level' : 'DEBUG',
2073 'handlers' : ['hand1'],
2074 },
2075 },
2076 'root' : {
2077 'level' : 'WARNING',
2078 },
2079 }
2080
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002081 # config8 defines both compiler and compiler.lexer
2082 # so compiler.parser should not be disabled (since
2083 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002084 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002085 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002086 'disable_existing_loggers' : False,
2087 'formatters': {
2088 'form1' : {
2089 'format' : '%(levelname)s ++ %(message)s',
2090 },
2091 },
2092 'handlers' : {
2093 'hand1' : {
2094 'class' : 'logging.StreamHandler',
2095 'formatter' : 'form1',
2096 'level' : 'NOTSET',
2097 'stream' : 'ext://sys.stdout',
2098 },
2099 },
2100 'loggers' : {
2101 'compiler' : {
2102 'level' : 'DEBUG',
2103 'handlers' : ['hand1'],
2104 },
2105 'compiler.lexer' : {
2106 },
2107 },
2108 'root' : {
2109 'level' : 'WARNING',
2110 },
2111 }
2112
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002113 # config8a disables existing loggers
2114 config8a = {
2115 'version': 1,
2116 'disable_existing_loggers' : True,
2117 'formatters': {
2118 'form1' : {
2119 'format' : '%(levelname)s ++ %(message)s',
2120 },
2121 },
2122 'handlers' : {
2123 'hand1' : {
2124 'class' : 'logging.StreamHandler',
2125 'formatter' : 'form1',
2126 'level' : 'NOTSET',
2127 'stream' : 'ext://sys.stdout',
2128 },
2129 },
2130 'loggers' : {
2131 'compiler' : {
2132 'level' : 'DEBUG',
2133 'handlers' : ['hand1'],
2134 },
2135 'compiler.lexer' : {
2136 },
2137 },
2138 'root' : {
2139 'level' : 'WARNING',
2140 },
2141 }
2142
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002143 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002144 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002145 'formatters': {
2146 'form1' : {
2147 'format' : '%(levelname)s ++ %(message)s',
2148 },
2149 },
2150 'handlers' : {
2151 'hand1' : {
2152 'class' : 'logging.StreamHandler',
2153 'formatter' : 'form1',
2154 'level' : 'WARNING',
2155 'stream' : 'ext://sys.stdout',
2156 },
2157 },
2158 'loggers' : {
2159 'compiler.parser' : {
2160 'level' : 'WARNING',
2161 'handlers' : ['hand1'],
2162 },
2163 },
2164 'root' : {
2165 'level' : 'NOTSET',
2166 },
2167 }
2168
2169 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002170 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002171 'incremental' : True,
2172 'handlers' : {
2173 'hand1' : {
2174 'level' : 'WARNING',
2175 },
2176 },
2177 'loggers' : {
2178 'compiler.parser' : {
2179 'level' : 'INFO',
2180 },
2181 },
2182 }
2183
2184 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002185 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002186 'incremental' : True,
2187 'handlers' : {
2188 'hand1' : {
2189 'level' : 'INFO',
2190 },
2191 },
2192 'loggers' : {
2193 'compiler.parser' : {
2194 'level' : 'INFO',
2195 },
2196 },
2197 }
2198
2199 #As config1 but with a filter added
2200 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002201 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002202 'formatters': {
2203 'form1' : {
2204 'format' : '%(levelname)s ++ %(message)s',
2205 },
2206 },
2207 'filters' : {
2208 'filt1' : {
2209 'name' : 'compiler.parser',
2210 },
2211 },
2212 'handlers' : {
2213 'hand1' : {
2214 'class' : 'logging.StreamHandler',
2215 'formatter' : 'form1',
2216 'level' : 'NOTSET',
2217 'stream' : 'ext://sys.stdout',
2218 'filters' : ['filt1'],
2219 },
2220 },
2221 'loggers' : {
2222 'compiler.parser' : {
2223 'level' : 'DEBUG',
2224 'filters' : ['filt1'],
2225 },
2226 },
2227 'root' : {
2228 'level' : 'WARNING',
2229 'handlers' : ['hand1'],
2230 },
2231 }
2232
2233 #As config1 but using cfg:// references
2234 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002235 'version': 1,
2236 'true_formatters': {
2237 'form1' : {
2238 'format' : '%(levelname)s ++ %(message)s',
2239 },
2240 },
2241 'handler_configs': {
2242 'hand1' : {
2243 'class' : 'logging.StreamHandler',
2244 'formatter' : 'form1',
2245 'level' : 'NOTSET',
2246 'stream' : 'ext://sys.stdout',
2247 },
2248 },
2249 'formatters' : 'cfg://true_formatters',
2250 'handlers' : {
2251 'hand1' : 'cfg://handler_configs[hand1]',
2252 },
2253 'loggers' : {
2254 'compiler.parser' : {
2255 'level' : 'DEBUG',
2256 'handlers' : ['hand1'],
2257 },
2258 },
2259 'root' : {
2260 'level' : 'WARNING',
2261 },
2262 }
2263
2264 #As config11 but missing the version key
2265 config12 = {
2266 'true_formatters': {
2267 'form1' : {
2268 'format' : '%(levelname)s ++ %(message)s',
2269 },
2270 },
2271 'handler_configs': {
2272 'hand1' : {
2273 'class' : 'logging.StreamHandler',
2274 'formatter' : 'form1',
2275 'level' : 'NOTSET',
2276 'stream' : 'ext://sys.stdout',
2277 },
2278 },
2279 'formatters' : 'cfg://true_formatters',
2280 'handlers' : {
2281 'hand1' : 'cfg://handler_configs[hand1]',
2282 },
2283 'loggers' : {
2284 'compiler.parser' : {
2285 'level' : 'DEBUG',
2286 'handlers' : ['hand1'],
2287 },
2288 },
2289 'root' : {
2290 'level' : 'WARNING',
2291 },
2292 }
2293
2294 #As config11 but using an unsupported version
2295 config13 = {
2296 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002297 'true_formatters': {
2298 'form1' : {
2299 'format' : '%(levelname)s ++ %(message)s',
2300 },
2301 },
2302 'handler_configs': {
2303 'hand1' : {
2304 'class' : 'logging.StreamHandler',
2305 'formatter' : 'form1',
2306 'level' : 'NOTSET',
2307 'stream' : 'ext://sys.stdout',
2308 },
2309 },
2310 'formatters' : 'cfg://true_formatters',
2311 'handlers' : {
2312 'hand1' : 'cfg://handler_configs[hand1]',
2313 },
2314 'loggers' : {
2315 'compiler.parser' : {
2316 'level' : 'DEBUG',
2317 'handlers' : ['hand1'],
2318 },
2319 },
2320 'root' : {
2321 'level' : 'WARNING',
2322 },
2323 }
2324
2325 def apply_config(self, conf):
2326 logging.config.dictConfig(conf)
2327
2328 def test_config0_ok(self):
2329 # A simple config which overrides the default settings.
2330 with captured_stdout() as output:
2331 self.apply_config(self.config0)
2332 logger = logging.getLogger()
2333 # Won't output anything
2334 logger.info(self.next_message())
2335 # Outputs a message
2336 logger.error(self.next_message())
2337 self.assert_log_lines([
2338 ('ERROR', '2'),
2339 ], stream=output)
2340 # Original logger output is empty.
2341 self.assert_log_lines([])
2342
2343 def test_config1_ok(self, config=config1):
2344 # A config defining a sub-parser as well.
2345 with captured_stdout() as output:
2346 self.apply_config(config)
2347 logger = logging.getLogger("compiler.parser")
2348 # Both will output a message
2349 logger.info(self.next_message())
2350 logger.error(self.next_message())
2351 self.assert_log_lines([
2352 ('INFO', '1'),
2353 ('ERROR', '2'),
2354 ], stream=output)
2355 # Original logger output is empty.
2356 self.assert_log_lines([])
2357
2358 def test_config2_failure(self):
2359 # A simple config which overrides the default settings.
2360 self.assertRaises(Exception, self.apply_config, self.config2)
2361
2362 def test_config2a_failure(self):
2363 # A simple config which overrides the default settings.
2364 self.assertRaises(Exception, self.apply_config, self.config2a)
2365
2366 def test_config2b_failure(self):
2367 # A simple config which overrides the default settings.
2368 self.assertRaises(Exception, self.apply_config, self.config2b)
2369
2370 def test_config3_failure(self):
2371 # A simple config which overrides the default settings.
2372 self.assertRaises(Exception, self.apply_config, self.config3)
2373
2374 def test_config4_ok(self):
2375 # A config specifying a custom formatter class.
2376 with captured_stdout() as output:
2377 self.apply_config(self.config4)
2378 #logger = logging.getLogger()
2379 try:
2380 raise RuntimeError()
2381 except RuntimeError:
2382 logging.exception("just testing")
2383 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002384 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002385 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2386 # Original logger output is empty
2387 self.assert_log_lines([])
2388
2389 def test_config4a_ok(self):
2390 # A config specifying a custom formatter class.
2391 with captured_stdout() as output:
2392 self.apply_config(self.config4a)
2393 #logger = logging.getLogger()
2394 try:
2395 raise RuntimeError()
2396 except RuntimeError:
2397 logging.exception("just testing")
2398 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002399 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002400 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2401 # Original logger output is empty
2402 self.assert_log_lines([])
2403
2404 def test_config5_ok(self):
2405 self.test_config1_ok(config=self.config5)
2406
2407 def test_config6_failure(self):
2408 self.assertRaises(Exception, self.apply_config, self.config6)
2409
2410 def test_config7_ok(self):
2411 with captured_stdout() as output:
2412 self.apply_config(self.config1)
2413 logger = logging.getLogger("compiler.parser")
2414 # Both will output a message
2415 logger.info(self.next_message())
2416 logger.error(self.next_message())
2417 self.assert_log_lines([
2418 ('INFO', '1'),
2419 ('ERROR', '2'),
2420 ], stream=output)
2421 # Original logger output is empty.
2422 self.assert_log_lines([])
2423 with captured_stdout() as output:
2424 self.apply_config(self.config7)
2425 logger = logging.getLogger("compiler.parser")
2426 self.assertTrue(logger.disabled)
2427 logger = logging.getLogger("compiler.lexer")
2428 # Both will output a message
2429 logger.info(self.next_message())
2430 logger.error(self.next_message())
2431 self.assert_log_lines([
2432 ('INFO', '3'),
2433 ('ERROR', '4'),
2434 ], stream=output)
2435 # Original logger output is empty.
2436 self.assert_log_lines([])
2437
2438 #Same as test_config_7_ok but don't disable old loggers.
2439 def test_config_8_ok(self):
2440 with captured_stdout() as output:
2441 self.apply_config(self.config1)
2442 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002443 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002444 logger.info(self.next_message())
2445 logger.error(self.next_message())
2446 self.assert_log_lines([
2447 ('INFO', '1'),
2448 ('ERROR', '2'),
2449 ], stream=output)
2450 # Original logger output is empty.
2451 self.assert_log_lines([])
2452 with captured_stdout() as output:
2453 self.apply_config(self.config8)
2454 logger = logging.getLogger("compiler.parser")
2455 self.assertFalse(logger.disabled)
2456 # Both will output a message
2457 logger.info(self.next_message())
2458 logger.error(self.next_message())
2459 logger = logging.getLogger("compiler.lexer")
2460 # Both will output a message
2461 logger.info(self.next_message())
2462 logger.error(self.next_message())
2463 self.assert_log_lines([
2464 ('INFO', '3'),
2465 ('ERROR', '4'),
2466 ('INFO', '5'),
2467 ('ERROR', '6'),
2468 ], stream=output)
2469 # Original logger output is empty.
2470 self.assert_log_lines([])
2471
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002472 def test_config_8a_ok(self):
2473 with captured_stdout() as output:
2474 self.apply_config(self.config1a)
2475 logger = logging.getLogger("compiler.parser")
2476 # See issue #11424. compiler-hyphenated sorts
2477 # between compiler and compiler.xyz and this
2478 # was preventing compiler.xyz from being included
2479 # in the child loggers of compiler because of an
2480 # overzealous loop termination condition.
2481 hyphenated = logging.getLogger('compiler-hyphenated')
2482 # All will output a message
2483 logger.info(self.next_message())
2484 logger.error(self.next_message())
2485 hyphenated.critical(self.next_message())
2486 self.assert_log_lines([
2487 ('INFO', '1'),
2488 ('ERROR', '2'),
2489 ('CRITICAL', '3'),
2490 ], stream=output)
2491 # Original logger output is empty.
2492 self.assert_log_lines([])
2493 with captured_stdout() as output:
2494 self.apply_config(self.config8a)
2495 logger = logging.getLogger("compiler.parser")
2496 self.assertFalse(logger.disabled)
2497 # Both will output a message
2498 logger.info(self.next_message())
2499 logger.error(self.next_message())
2500 logger = logging.getLogger("compiler.lexer")
2501 # Both will output a message
2502 logger.info(self.next_message())
2503 logger.error(self.next_message())
2504 # Will not appear
2505 hyphenated.critical(self.next_message())
2506 self.assert_log_lines([
2507 ('INFO', '4'),
2508 ('ERROR', '5'),
2509 ('INFO', '6'),
2510 ('ERROR', '7'),
2511 ], stream=output)
2512 # Original logger output is empty.
2513 self.assert_log_lines([])
2514
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002515 def test_config_9_ok(self):
2516 with captured_stdout() as output:
2517 self.apply_config(self.config9)
2518 logger = logging.getLogger("compiler.parser")
2519 #Nothing will be output since both handler and logger are set to WARNING
2520 logger.info(self.next_message())
2521 self.assert_log_lines([], stream=output)
2522 self.apply_config(self.config9a)
2523 #Nothing will be output since both handler is still set to WARNING
2524 logger.info(self.next_message())
2525 self.assert_log_lines([], stream=output)
2526 self.apply_config(self.config9b)
2527 #Message should now be output
2528 logger.info(self.next_message())
2529 self.assert_log_lines([
2530 ('INFO', '3'),
2531 ], stream=output)
2532
2533 def test_config_10_ok(self):
2534 with captured_stdout() as output:
2535 self.apply_config(self.config10)
2536 logger = logging.getLogger("compiler.parser")
2537 logger.warning(self.next_message())
2538 logger = logging.getLogger('compiler')
2539 #Not output, because filtered
2540 logger.warning(self.next_message())
2541 logger = logging.getLogger('compiler.lexer')
2542 #Not output, because filtered
2543 logger.warning(self.next_message())
2544 logger = logging.getLogger("compiler.parser.codegen")
2545 #Output, as not filtered
2546 logger.error(self.next_message())
2547 self.assert_log_lines([
2548 ('WARNING', '1'),
2549 ('ERROR', '4'),
2550 ], stream=output)
2551
2552 def test_config11_ok(self):
2553 self.test_config1_ok(self.config11)
2554
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002555 def test_config12_failure(self):
2556 self.assertRaises(Exception, self.apply_config, self.config12)
2557
2558 def test_config13_failure(self):
2559 self.assertRaises(Exception, self.apply_config, self.config13)
2560
Victor Stinner45df8202010-04-28 22:31:17 +00002561 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002562 def setup_via_listener(self, text):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002563 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002564 # Ask for a randomly assigned port (by using port 0)
2565 t = logging.config.listen(0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002566 t.start()
2567 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002568 # Now get the port allocated
2569 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002570 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002571 try:
2572 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2573 sock.settimeout(2.0)
2574 sock.connect(('localhost', port))
2575
2576 slen = struct.pack('>L', len(text))
2577 s = slen + text
2578 sentsofar = 0
2579 left = len(s)
2580 while left > 0:
2581 sent = sock.send(s[sentsofar:])
2582 sentsofar += sent
2583 left -= sent
2584 sock.close()
2585 finally:
2586 t.ready.wait(2.0)
2587 logging.config.stopListening()
2588 t.join(2.0)
2589
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002590 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002591 def test_listen_config_10_ok(self):
2592 with captured_stdout() as output:
2593 self.setup_via_listener(json.dumps(self.config10))
2594 logger = logging.getLogger("compiler.parser")
2595 logger.warning(self.next_message())
2596 logger = logging.getLogger('compiler')
2597 #Not output, because filtered
2598 logger.warning(self.next_message())
2599 logger = logging.getLogger('compiler.lexer')
2600 #Not output, because filtered
2601 logger.warning(self.next_message())
2602 logger = logging.getLogger("compiler.parser.codegen")
2603 #Output, as not filtered
2604 logger.error(self.next_message())
2605 self.assert_log_lines([
2606 ('WARNING', '1'),
2607 ('ERROR', '4'),
2608 ], stream=output)
2609
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002610 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002611 def test_listen_config_1_ok(self):
2612 with captured_stdout() as output:
2613 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2614 logger = logging.getLogger("compiler.parser")
2615 # Both will output a message
2616 logger.info(self.next_message())
2617 logger.error(self.next_message())
2618 self.assert_log_lines([
2619 ('INFO', '1'),
2620 ('ERROR', '2'),
2621 ], stream=output)
2622 # Original logger output is empty.
2623 self.assert_log_lines([])
2624
Vinay Sajip373baef2011-04-26 20:05:24 +01002625 def test_baseconfig(self):
2626 d = {
2627 'atuple': (1, 2, 3),
2628 'alist': ['a', 'b', 'c'],
2629 'adict': {'d': 'e', 'f': 3 },
2630 'nest1': ('g', ('h', 'i'), 'j'),
2631 'nest2': ['k', ['l', 'm'], 'n'],
2632 'nest3': ['o', 'cfg://alist', 'p'],
2633 }
2634 bc = logging.config.BaseConfigurator(d)
2635 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2636 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2637 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2638 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2639 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2640 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2641 v = bc.convert('cfg://nest3')
2642 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2643 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2644 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2645 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002646
2647class ManagerTest(BaseTest):
2648 def test_manager_loggerclass(self):
2649 logged = []
2650
2651 class MyLogger(logging.Logger):
2652 def _log(self, level, msg, args, exc_info=None, extra=None):
2653 logged.append(msg)
2654
2655 man = logging.Manager(None)
2656 self.assertRaises(TypeError, man.setLoggerClass, int)
2657 man.setLoggerClass(MyLogger)
2658 logger = man.getLogger('test')
2659 logger.warning('should appear in logged')
2660 logging.warning('should not appear in logged')
2661
2662 self.assertEqual(logged, ['should appear in logged'])
2663
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002664 def test_set_log_record_factory(self):
2665 man = logging.Manager(None)
2666 expected = object()
2667 man.setLogRecordFactory(expected)
2668 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002669
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002670class ChildLoggerTest(BaseTest):
2671 def test_child_loggers(self):
2672 r = logging.getLogger()
2673 l1 = logging.getLogger('abc')
2674 l2 = logging.getLogger('def.ghi')
2675 c1 = r.getChild('xyz')
2676 c2 = r.getChild('uvw.xyz')
2677 self.assertTrue(c1 is logging.getLogger('xyz'))
2678 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
2679 c1 = l1.getChild('def')
2680 c2 = c1.getChild('ghi')
2681 c3 = l1.getChild('def.ghi')
2682 self.assertTrue(c1 is logging.getLogger('abc.def'))
2683 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
2684 self.assertTrue(c2 is c3)
2685
2686
Vinay Sajip6fac8172010-10-19 20:44:14 +00002687class DerivedLogRecord(logging.LogRecord):
2688 pass
2689
Vinay Sajip61561522010-12-03 11:50:38 +00002690class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002691
2692 def setUp(self):
2693 class CheckingFilter(logging.Filter):
2694 def __init__(self, cls):
2695 self.cls = cls
2696
2697 def filter(self, record):
2698 t = type(record)
2699 if t is not self.cls:
2700 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2701 self.cls)
2702 raise TypeError(msg)
2703 return True
2704
2705 BaseTest.setUp(self)
2706 self.filter = CheckingFilter(DerivedLogRecord)
2707 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002708 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002709
2710 def tearDown(self):
2711 self.root_logger.removeFilter(self.filter)
2712 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002713 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002714
2715 def test_logrecord_class(self):
2716 self.assertRaises(TypeError, self.root_logger.warning,
2717 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002718 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002719 self.root_logger.error(self.next_message())
2720 self.assert_log_lines([
2721 ('root', 'ERROR', '2'),
2722 ])
2723
2724
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002725class QueueHandlerTest(BaseTest):
2726 # Do not bother with a logger name group.
2727 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
2728
2729 def setUp(self):
2730 BaseTest.setUp(self)
2731 self.queue = queue.Queue(-1)
2732 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2733 self.que_logger = logging.getLogger('que')
2734 self.que_logger.propagate = False
2735 self.que_logger.setLevel(logging.WARNING)
2736 self.que_logger.addHandler(self.que_hdlr)
2737
2738 def tearDown(self):
2739 self.que_hdlr.close()
2740 BaseTest.tearDown(self)
2741
2742 def test_queue_handler(self):
2743 self.que_logger.debug(self.next_message())
2744 self.assertRaises(queue.Empty, self.queue.get_nowait)
2745 self.que_logger.info(self.next_message())
2746 self.assertRaises(queue.Empty, self.queue.get_nowait)
2747 msg = self.next_message()
2748 self.que_logger.warning(msg)
2749 data = self.queue.get_nowait()
2750 self.assertTrue(isinstance(data, logging.LogRecord))
2751 self.assertEqual(data.name, self.que_logger.name)
2752 self.assertEqual((data.msg, data.args), (msg, None))
2753
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002754 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2755 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002756 def test_queue_listener(self):
2757 handler = TestHandler(Matcher())
2758 listener = logging.handlers.QueueListener(self.queue, handler)
2759 listener.start()
2760 try:
2761 self.que_logger.warning(self.next_message())
2762 self.que_logger.error(self.next_message())
2763 self.que_logger.critical(self.next_message())
2764 finally:
2765 listener.stop()
2766 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2767 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2768 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2769
Vinay Sajip37eb3382011-04-26 20:26:41 +01002770ZERO = datetime.timedelta(0)
2771
2772class UTC(datetime.tzinfo):
2773 def utcoffset(self, dt):
2774 return ZERO
2775
2776 dst = utcoffset
2777
2778 def tzname(self, dt):
2779 return 'UTC'
2780
2781utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002782
Vinay Sajipa39c5712010-10-25 13:57:39 +00002783class FormatterTest(unittest.TestCase):
2784 def setUp(self):
2785 self.common = {
2786 'name': 'formatter.test',
2787 'level': logging.DEBUG,
2788 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2789 'lineno': 42,
2790 'exc_info': None,
2791 'func': None,
2792 'msg': 'Message with %d %s',
2793 'args': (2, 'placeholders'),
2794 }
2795 self.variants = {
2796 }
2797
2798 def get_record(self, name=None):
2799 result = dict(self.common)
2800 if name is not None:
2801 result.update(self.variants[name])
2802 return logging.makeLogRecord(result)
2803
2804 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002805 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002806 r = self.get_record()
2807 f = logging.Formatter('${%(message)s}')
2808 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2809 f = logging.Formatter('%(random)s')
2810 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002811 self.assertFalse(f.usesTime())
2812 f = logging.Formatter('%(asctime)s')
2813 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002814 f = logging.Formatter('%(asctime)-15s')
2815 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002816 f = logging.Formatter('asctime')
2817 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002818
2819 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002820 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002821 r = self.get_record()
2822 f = logging.Formatter('$%{message}%$', style='{')
2823 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2824 f = logging.Formatter('{random}', style='{')
2825 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002826 self.assertFalse(f.usesTime())
2827 f = logging.Formatter('{asctime}', style='{')
2828 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002829 f = logging.Formatter('{asctime!s:15}', style='{')
2830 self.assertTrue(f.usesTime())
2831 f = logging.Formatter('{asctime:15}', style='{')
2832 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002833 f = logging.Formatter('asctime', style='{')
2834 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002835
2836 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002837 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002838 r = self.get_record()
2839 f = logging.Formatter('$message', style='$')
2840 self.assertEqual(f.format(r), 'Message with 2 placeholders')
2841 f = logging.Formatter('$$%${message}%$$', style='$')
2842 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2843 f = logging.Formatter('${random}', style='$')
2844 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002845 self.assertFalse(f.usesTime())
2846 f = logging.Formatter('${asctime}', style='$')
2847 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002848 f = logging.Formatter('${asctime', style='$')
2849 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002850 f = logging.Formatter('$asctime', style='$')
2851 self.assertTrue(f.usesTime())
2852 f = logging.Formatter('asctime', style='$')
2853 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002854
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002855 def test_invalid_style(self):
2856 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
2857
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002858 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002859 r = self.get_record()
Vinay Sajip37eb3382011-04-26 20:26:41 +01002860 dt = datetime.datetime(1993,4,21,8,3,0,0,utc)
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002861 r.created = time.mktime(dt.timetuple()) - time.timezone
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002862 r.msecs = 123
2863 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01002864 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002865 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
2866 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01002867 f.format(r)
2868 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
2869
2870class TestBufferingFormatter(logging.BufferingFormatter):
2871 def formatHeader(self, records):
2872 return '[(%d)' % len(records)
2873
2874 def formatFooter(self, records):
2875 return '(%d)]' % len(records)
2876
2877class BufferingFormatterTest(unittest.TestCase):
2878 def setUp(self):
2879 self.records = [
2880 logging.makeLogRecord({'msg': 'one'}),
2881 logging.makeLogRecord({'msg': 'two'}),
2882 ]
2883
2884 def test_default(self):
2885 f = logging.BufferingFormatter()
2886 self.assertEqual('', f.format([]))
2887 self.assertEqual('onetwo', f.format(self.records))
2888
2889 def test_custom(self):
2890 f = TestBufferingFormatter()
2891 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
2892 lf = logging.Formatter('<%(message)s>')
2893 f = TestBufferingFormatter(lf)
2894 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002895
2896class ExceptionTest(BaseTest):
2897 def test_formatting(self):
2898 r = self.root_logger
2899 h = RecordingHandler()
2900 r.addHandler(h)
2901 try:
2902 raise RuntimeError('deliberate mistake')
2903 except:
2904 logging.exception('failed', stack_info=True)
2905 r.removeHandler(h)
2906 h.close()
2907 r = h.records[0]
2908 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
2909 'call last):\n'))
2910 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
2911 'deliberate mistake'))
2912 self.assertTrue(r.stack_info.startswith('Stack (most recent '
2913 'call last):\n'))
2914 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
2915 'stack_info=True)'))
2916
2917
Vinay Sajip5a27d402010-12-10 11:42:57 +00002918class LastResortTest(BaseTest):
2919 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002920 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00002921 root = self.root_logger
2922 root.removeHandler(self.root_hdlr)
2923 old_stderr = sys.stderr
2924 old_lastresort = logging.lastResort
2925 old_raise_exceptions = logging.raiseExceptions
2926 try:
2927 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01002928 root.debug('This should not appear')
2929 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00002930 root.warning('This is your final chance!')
2931 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
2932 #No handlers and no last resort, so 'No handlers' message
2933 logging.lastResort = None
2934 sys.stderr = sio = io.StringIO()
2935 root.warning('This is your final chance!')
2936 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
2937 # 'No handlers' message only printed once
2938 sys.stderr = sio = io.StringIO()
2939 root.warning('This is your final chance!')
2940 self.assertEqual(sio.getvalue(), '')
2941 root.manager.emittedNoHandlerWarning = False
2942 #If raiseExceptions is False, no message is printed
2943 logging.raiseExceptions = False
2944 sys.stderr = sio = io.StringIO()
2945 root.warning('This is your final chance!')
2946 self.assertEqual(sio.getvalue(), '')
2947 finally:
2948 sys.stderr = old_stderr
2949 root.addHandler(self.root_hdlr)
2950 logging.lastResort = old_lastresort
2951 logging.raiseExceptions = old_raise_exceptions
2952
2953
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002954class FakeHandler:
2955
2956 def __init__(self, identifier, called):
2957 for method in ('acquire', 'flush', 'close', 'release'):
2958 setattr(self, method, self.record_call(identifier, method, called))
2959
2960 def record_call(self, identifier, method_name, called):
2961 def inner():
2962 called.append('{} - {}'.format(identifier, method_name))
2963 return inner
2964
2965
2966class RecordingHandler(logging.NullHandler):
2967
2968 def __init__(self, *args, **kwargs):
2969 super(RecordingHandler, self).__init__(*args, **kwargs)
2970 self.records = []
2971
2972 def handle(self, record):
2973 """Keep track of all the emitted records."""
2974 self.records.append(record)
2975
2976
2977class ShutdownTest(BaseTest):
2978
Vinay Sajip5e66b162011-04-20 15:41:14 +01002979 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002980
2981 def setUp(self):
2982 super(ShutdownTest, self).setUp()
2983 self.called = []
2984
2985 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002986 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002987
2988 def raise_error(self, error):
2989 def inner():
2990 raise error()
2991 return inner
2992
2993 def test_no_failure(self):
2994 # create some fake handlers
2995 handler0 = FakeHandler(0, self.called)
2996 handler1 = FakeHandler(1, self.called)
2997 handler2 = FakeHandler(2, self.called)
2998
2999 # create live weakref to those handlers
3000 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3001
3002 logging.shutdown(handlerList=list(handlers))
3003
3004 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3005 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3006 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3007 self.assertEqual(expected, self.called)
3008
3009 def _test_with_failure_in_method(self, method, error):
3010 handler = FakeHandler(0, self.called)
3011 setattr(handler, method, self.raise_error(error))
3012 handlers = [logging.weakref.ref(handler)]
3013
3014 logging.shutdown(handlerList=list(handlers))
3015
3016 self.assertEqual('0 - release', self.called[-1])
3017
3018 def test_with_ioerror_in_acquire(self):
3019 self._test_with_failure_in_method('acquire', IOError)
3020
3021 def test_with_ioerror_in_flush(self):
3022 self._test_with_failure_in_method('flush', IOError)
3023
3024 def test_with_ioerror_in_close(self):
3025 self._test_with_failure_in_method('close', IOError)
3026
3027 def test_with_valueerror_in_acquire(self):
3028 self._test_with_failure_in_method('acquire', ValueError)
3029
3030 def test_with_valueerror_in_flush(self):
3031 self._test_with_failure_in_method('flush', ValueError)
3032
3033 def test_with_valueerror_in_close(self):
3034 self._test_with_failure_in_method('close', ValueError)
3035
3036 def test_with_other_error_in_acquire_without_raise(self):
3037 logging.raiseExceptions = False
3038 self._test_with_failure_in_method('acquire', IndexError)
3039
3040 def test_with_other_error_in_flush_without_raise(self):
3041 logging.raiseExceptions = False
3042 self._test_with_failure_in_method('flush', IndexError)
3043
3044 def test_with_other_error_in_close_without_raise(self):
3045 logging.raiseExceptions = False
3046 self._test_with_failure_in_method('close', IndexError)
3047
3048 def test_with_other_error_in_acquire_with_raise(self):
3049 logging.raiseExceptions = True
3050 self.assertRaises(IndexError, self._test_with_failure_in_method,
3051 'acquire', IndexError)
3052
3053 def test_with_other_error_in_flush_with_raise(self):
3054 logging.raiseExceptions = True
3055 self.assertRaises(IndexError, self._test_with_failure_in_method,
3056 'flush', IndexError)
3057
3058 def test_with_other_error_in_close_with_raise(self):
3059 logging.raiseExceptions = True
3060 self.assertRaises(IndexError, self._test_with_failure_in_method,
3061 'close', IndexError)
3062
3063
3064class ModuleLevelMiscTest(BaseTest):
3065
Vinay Sajip5e66b162011-04-20 15:41:14 +01003066 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003067
3068 def test_disable(self):
3069 old_disable = logging.root.manager.disable
3070 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003071 self.assertEqual(old_disable, 0)
3072 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003073
3074 logging.disable(83)
3075 self.assertEqual(logging.root.manager.disable, 83)
3076
3077 def _test_log(self, method, level=None):
3078 called = []
3079 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003080 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003081
3082 recording = RecordingHandler()
3083 logging.root.addHandler(recording)
3084
3085 log_method = getattr(logging, method)
3086 if level is not None:
3087 log_method(level, "test me: %r", recording)
3088 else:
3089 log_method("test me: %r", recording)
3090
3091 self.assertEqual(len(recording.records), 1)
3092 record = recording.records[0]
3093 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3094
3095 expected_level = level if level is not None else getattr(logging, method.upper())
3096 self.assertEqual(record.levelno, expected_level)
3097
3098 # basicConfig was not called!
3099 self.assertEqual(called, [])
3100
3101 def test_log(self):
3102 self._test_log('log', logging.ERROR)
3103
3104 def test_debug(self):
3105 self._test_log('debug')
3106
3107 def test_info(self):
3108 self._test_log('info')
3109
3110 def test_warning(self):
3111 self._test_log('warning')
3112
3113 def test_error(self):
3114 self._test_log('error')
3115
3116 def test_critical(self):
3117 self._test_log('critical')
3118
3119 def test_set_logger_class(self):
3120 self.assertRaises(TypeError, logging.setLoggerClass, object)
3121
3122 class MyLogger(logging.Logger):
3123 pass
3124
3125 logging.setLoggerClass(MyLogger)
3126 self.assertEqual(logging.getLoggerClass(), MyLogger)
3127
3128 logging.setLoggerClass(logging.Logger)
3129 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3130
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003131class LogRecordTest(BaseTest):
3132 def test_str_rep(self):
3133 r = logging.makeLogRecord({})
3134 s = str(r)
3135 self.assertTrue(s.startswith('<LogRecord: '))
3136 self.assertTrue(s.endswith('>'))
3137
3138 def test_dict_arg(self):
3139 h = RecordingHandler()
3140 r = logging.getLogger()
3141 r.addHandler(h)
3142 d = {'less' : 'more' }
3143 logging.warning('less is %(less)s', d)
3144 self.assertIs(h.records[0].args, d)
3145 self.assertEqual(h.records[0].message, 'less is more')
3146 r.removeHandler(h)
3147 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003148
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003149 def test_multiprocessing(self):
3150 r = logging.makeLogRecord({})
3151 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003152 try:
3153 import multiprocessing as mp
3154 r = logging.makeLogRecord({})
3155 self.assertEqual(r.processName, mp.current_process().name)
3156 except ImportError:
3157 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003158
3159 def test_optional(self):
3160 r = logging.makeLogRecord({})
3161 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003162 if threading:
3163 NOT_NONE(r.thread)
3164 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003165 NOT_NONE(r.process)
3166 NOT_NONE(r.processName)
3167 log_threads = logging.logThreads
3168 log_processes = logging.logProcesses
3169 log_multiprocessing = logging.logMultiprocessing
3170 try:
3171 logging.logThreads = False
3172 logging.logProcesses = False
3173 logging.logMultiprocessing = False
3174 r = logging.makeLogRecord({})
3175 NONE = self.assertIsNone
3176 NONE(r.thread)
3177 NONE(r.threadName)
3178 NONE(r.process)
3179 NONE(r.processName)
3180 finally:
3181 logging.logThreads = log_threads
3182 logging.logProcesses = log_processes
3183 logging.logMultiprocessing = log_multiprocessing
3184
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003185class BasicConfigTest(unittest.TestCase):
3186
Vinay Sajip95bf5042011-04-20 11:50:56 +01003187 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003188
3189 def setUp(self):
3190 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003191 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003192 self.saved_handlers = logging._handlers.copy()
3193 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003194 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003195 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003196 logging.root.handlers = []
3197
3198 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003199 for h in logging.root.handlers[:]:
3200 logging.root.removeHandler(h)
3201 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003202 super(BasicConfigTest, self).tearDown()
3203
Vinay Sajip3def7e02011-04-20 10:58:06 +01003204 def cleanup(self):
3205 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003206 logging._handlers.clear()
3207 logging._handlers.update(self.saved_handlers)
3208 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003209 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003210
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003211 def test_no_kwargs(self):
3212 logging.basicConfig()
3213
3214 # handler defaults to a StreamHandler to sys.stderr
3215 self.assertEqual(len(logging.root.handlers), 1)
3216 handler = logging.root.handlers[0]
3217 self.assertIsInstance(handler, logging.StreamHandler)
3218 self.assertEqual(handler.stream, sys.stderr)
3219
3220 formatter = handler.formatter
3221 # format defaults to logging.BASIC_FORMAT
3222 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3223 # datefmt defaults to None
3224 self.assertIsNone(formatter.datefmt)
3225 # style defaults to %
3226 self.assertIsInstance(formatter._style, logging.PercentStyle)
3227
3228 # level is not explicitely set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003229 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003230
3231 def test_filename(self):
3232 logging.basicConfig(filename='test.log')
3233
3234 self.assertEqual(len(logging.root.handlers), 1)
3235 handler = logging.root.handlers[0]
3236 self.assertIsInstance(handler, logging.FileHandler)
3237
3238 expected = logging.FileHandler('test.log', 'a')
3239 self.addCleanup(expected.close)
3240 self.assertEqual(handler.stream.mode, expected.stream.mode)
3241 self.assertEqual(handler.stream.name, expected.stream.name)
3242
3243 def test_filemode(self):
3244 logging.basicConfig(filename='test.log', filemode='wb')
3245
3246 handler = logging.root.handlers[0]
3247 expected = logging.FileHandler('test.log', 'wb')
3248 self.addCleanup(expected.close)
3249 self.assertEqual(handler.stream.mode, expected.stream.mode)
3250
3251 def test_stream(self):
3252 stream = io.StringIO()
3253 self.addCleanup(stream.close)
3254 logging.basicConfig(stream=stream)
3255
3256 self.assertEqual(len(logging.root.handlers), 1)
3257 handler = logging.root.handlers[0]
3258 self.assertIsInstance(handler, logging.StreamHandler)
3259 self.assertEqual(handler.stream, stream)
3260
3261 def test_format(self):
3262 logging.basicConfig(format='foo')
3263
3264 formatter = logging.root.handlers[0].formatter
3265 self.assertEqual(formatter._style._fmt, 'foo')
3266
3267 def test_datefmt(self):
3268 logging.basicConfig(datefmt='bar')
3269
3270 formatter = logging.root.handlers[0].formatter
3271 self.assertEqual(formatter.datefmt, 'bar')
3272
3273 def test_style(self):
3274 logging.basicConfig(style='$')
3275
3276 formatter = logging.root.handlers[0].formatter
3277 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3278
3279 def test_level(self):
3280 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003281 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003282
3283 logging.basicConfig(level=57)
3284 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003285 # Test that second call has no effect
3286 logging.basicConfig(level=58)
3287 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003288
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003289 def test_incompatible(self):
3290 assertRaises = self.assertRaises
3291 handlers = [logging.StreamHandler()]
3292 stream = sys.stderr
3293 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3294 stream=stream)
3295 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3296 handlers=handlers)
3297 assertRaises(ValueError, logging.basicConfig, stream=stream,
3298 handlers=handlers)
3299
3300 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003301 handlers = [
3302 logging.StreamHandler(),
3303 logging.StreamHandler(sys.stdout),
3304 logging.StreamHandler(),
3305 ]
3306 f = logging.Formatter()
3307 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003308 logging.basicConfig(handlers=handlers)
3309 self.assertIs(handlers[0], logging.root.handlers[0])
3310 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003311 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003312 self.assertIsNotNone(handlers[0].formatter)
3313 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003314 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003315 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3316
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003317 def _test_log(self, method, level=None):
3318 # logging.root has no handlers so basicConfig should be called
3319 called = []
3320
3321 old_basic_config = logging.basicConfig
3322 def my_basic_config(*a, **kw):
3323 old_basic_config()
3324 old_level = logging.root.level
3325 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003326 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003327 called.append((a, kw))
3328
3329 patch(self, logging, 'basicConfig', my_basic_config)
3330
3331 log_method = getattr(logging, method)
3332 if level is not None:
3333 log_method(level, "test me")
3334 else:
3335 log_method("test me")
3336
3337 # basicConfig was called with no arguments
3338 self.assertEqual(called, [((), {})])
3339
3340 def test_log(self):
3341 self._test_log('log', logging.WARNING)
3342
3343 def test_debug(self):
3344 self._test_log('debug')
3345
3346 def test_info(self):
3347 self._test_log('info')
3348
3349 def test_warning(self):
3350 self._test_log('warning')
3351
3352 def test_error(self):
3353 self._test_log('error')
3354
3355 def test_critical(self):
3356 self._test_log('critical')
3357
3358
3359class LoggerAdapterTest(unittest.TestCase):
3360
3361 def setUp(self):
3362 super(LoggerAdapterTest, self).setUp()
3363 old_handler_list = logging._handlerList[:]
3364
3365 self.recording = RecordingHandler()
3366 self.logger = logging.root
3367 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003368 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003369 self.addCleanup(self.recording.close)
3370
3371 def cleanup():
3372 logging._handlerList[:] = old_handler_list
3373
3374 self.addCleanup(cleanup)
3375 self.addCleanup(logging.shutdown)
3376 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3377
3378 def test_exception(self):
3379 msg = 'testing exception: %r'
3380 exc = None
3381 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003382 1 / 0
3383 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003384 exc = e
3385 self.adapter.exception(msg, self.recording)
3386
3387 self.assertEqual(len(self.recording.records), 1)
3388 record = self.recording.records[0]
3389 self.assertEqual(record.levelno, logging.ERROR)
3390 self.assertEqual(record.msg, msg)
3391 self.assertEqual(record.args, (self.recording,))
3392 self.assertEqual(record.exc_info,
3393 (exc.__class__, exc, exc.__traceback__))
3394
3395 def test_critical(self):
3396 msg = 'critical test! %r'
3397 self.adapter.critical(msg, self.recording)
3398
3399 self.assertEqual(len(self.recording.records), 1)
3400 record = self.recording.records[0]
3401 self.assertEqual(record.levelno, logging.CRITICAL)
3402 self.assertEqual(record.msg, msg)
3403 self.assertEqual(record.args, (self.recording,))
3404
3405 def test_is_enabled_for(self):
3406 old_disable = self.adapter.logger.manager.disable
3407 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003408 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3409 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003410 self.assertFalse(self.adapter.isEnabledFor(32))
3411
3412 def test_has_handlers(self):
3413 self.assertTrue(self.adapter.hasHandlers())
3414
3415 for handler in self.logger.handlers:
3416 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003417
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003418 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003419 self.assertFalse(self.adapter.hasHandlers())
3420
3421
3422class LoggerTest(BaseTest):
3423
3424 def setUp(self):
3425 super(LoggerTest, self).setUp()
3426 self.recording = RecordingHandler()
3427 self.logger = logging.Logger(name='blah')
3428 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003429 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003430 self.addCleanup(self.recording.close)
3431 self.addCleanup(logging.shutdown)
3432
3433 def test_set_invalid_level(self):
3434 self.assertRaises(TypeError, self.logger.setLevel, object())
3435
3436 def test_exception(self):
3437 msg = 'testing exception: %r'
3438 exc = None
3439 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003440 1 / 0
3441 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003442 exc = e
3443 self.logger.exception(msg, self.recording)
3444
3445 self.assertEqual(len(self.recording.records), 1)
3446 record = self.recording.records[0]
3447 self.assertEqual(record.levelno, logging.ERROR)
3448 self.assertEqual(record.msg, msg)
3449 self.assertEqual(record.args, (self.recording,))
3450 self.assertEqual(record.exc_info,
3451 (exc.__class__, exc, exc.__traceback__))
3452
3453 def test_log_invalid_level_with_raise(self):
3454 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003455 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003456
3457 logging.raiseExceptions = True
3458 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3459
3460 def test_log_invalid_level_no_raise(self):
3461 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003462 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003463
3464 logging.raiseExceptions = False
3465 self.logger.log('10', 'test message') # no exception happens
3466
3467 def test_find_caller_with_stack_info(self):
3468 called = []
3469 patch(self, logging.traceback, 'print_stack',
3470 lambda f, file: called.append(file.getvalue()))
3471
3472 self.logger.findCaller(stack_info=True)
3473
3474 self.assertEqual(len(called), 1)
3475 self.assertEqual('Stack (most recent call last):\n', called[0])
3476
3477 def test_make_record_with_extra_overwrite(self):
3478 name = 'my record'
3479 level = 13
3480 fn = lno = msg = args = exc_info = func = sinfo = None
3481 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3482 exc_info, func, sinfo)
3483
3484 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3485 extra = {key: 'some value'}
3486 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3487 fn, lno, msg, args, exc_info,
3488 extra=extra, sinfo=sinfo)
3489
3490 def test_make_record_with_extra_no_overwrite(self):
3491 name = 'my record'
3492 level = 13
3493 fn = lno = msg = args = exc_info = func = sinfo = None
3494 extra = {'valid_key': 'some value'}
3495 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3496 exc_info, extra=extra, sinfo=sinfo)
3497 self.assertIn('valid_key', result.__dict__)
3498
3499 def test_has_handlers(self):
3500 self.assertTrue(self.logger.hasHandlers())
3501
3502 for handler in self.logger.handlers:
3503 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003504 self.assertFalse(self.logger.hasHandlers())
3505
3506 def test_has_handlers_no_propagate(self):
3507 child_logger = logging.getLogger('blah.child')
3508 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003509 self.assertFalse(child_logger.hasHandlers())
3510
3511 def test_is_enabled_for(self):
3512 old_disable = self.logger.manager.disable
3513 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003514 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003515 self.assertFalse(self.logger.isEnabledFor(22))
3516
3517
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003518class BaseFileTest(BaseTest):
3519 "Base class for handler tests that write log files"
3520
3521 def setUp(self):
3522 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003523 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3524 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003525 self.rmfiles = []
3526
3527 def tearDown(self):
3528 for fn in self.rmfiles:
3529 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003530 if os.path.exists(self.fn):
3531 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003532 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003533
3534 def assertLogFile(self, filename):
3535 "Assert a log file is there and register it for deletion"
3536 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003537 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003538 self.rmfiles.append(filename)
3539
3540
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003541class FileHandlerTest(BaseFileTest):
3542 def test_delay(self):
3543 os.unlink(self.fn)
3544 fh = logging.FileHandler(self.fn, delay=True)
3545 self.assertIsNone(fh.stream)
3546 self.assertFalse(os.path.exists(self.fn))
3547 fh.handle(logging.makeLogRecord({}))
3548 self.assertIsNotNone(fh.stream)
3549 self.assertTrue(os.path.exists(self.fn))
3550 fh.close()
3551
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003552class RotatingFileHandlerTest(BaseFileTest):
3553 def next_rec(self):
3554 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3555 self.next_message(), None, None, None)
3556
3557 def test_should_not_rollover(self):
3558 # If maxbytes is zero rollover never occurs
3559 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3560 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003561 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003562
3563 def test_should_rollover(self):
3564 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3565 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003566 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003567
3568 def test_file_created(self):
3569 # checks that the file is created and assumes it was created
3570 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003571 rh = logging.handlers.RotatingFileHandler(self.fn)
3572 rh.emit(self.next_rec())
3573 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003574 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003575
3576 def test_rollover_filenames(self):
3577 rh = logging.handlers.RotatingFileHandler(
3578 self.fn, backupCount=2, maxBytes=1)
3579 rh.emit(self.next_rec())
3580 self.assertLogFile(self.fn)
3581 rh.emit(self.next_rec())
3582 self.assertLogFile(self.fn + ".1")
3583 rh.emit(self.next_rec())
3584 self.assertLogFile(self.fn + ".2")
3585 self.assertFalse(os.path.exists(self.fn + ".3"))
Vinay Sajipb046b802010-10-30 09:50:18 +00003586 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003587
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003588class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003589 # other test methods added below
3590 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003591 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3592 backupCount=1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003593 r = logging.makeLogRecord({'msg': 'testing'})
3594 fh.emit(r)
3595 self.assertLogFile(self.fn)
Vinay Sajipb7b19302011-05-24 07:12:41 +01003596 time.sleep(1.01) # just a little over a second ...
Vinay Sajipfd285022011-05-07 17:01:22 +01003597 fh.emit(r)
3598 fh.close()
3599 # At this point, we should have a recent rotated file which we
3600 # can test for the existence of. However, in practice, on some
3601 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003602 # in time to go to look for the log file. So, we go back a fair
3603 # bit, and stop as soon as we see a rotated file. In theory this
3604 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003605 found = False
3606 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003607 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003608 for secs in range(GO_BACK):
3609 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003610 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3611 found = os.path.exists(fn)
3612 if found:
3613 self.rmfiles.append(fn)
3614 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003615 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3616 if not found:
3617 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003618 dn, fn = os.path.split(self.fn)
3619 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003620 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3621 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajipfd285022011-05-07 17:01:22 +01003622 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003623
Vinay Sajip0372e102011-05-05 12:59:14 +01003624 def test_invalid(self):
3625 assertRaises = self.assertRaises
3626 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003627 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003628 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003629 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003630 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003631 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003632
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003633def secs(**kw):
3634 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3635
3636for when, exp in (('S', 1),
3637 ('M', 60),
3638 ('H', 60 * 60),
3639 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003640 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003641 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003642 ('W0', secs(days=4, hours=24)),
3643 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003644 def test_compute_rollover(self, when=when, exp=exp):
3645 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003646 self.fn, when=when, interval=1, backupCount=0, utc=True)
3647 currentTime = 0.0
3648 actual = rh.computeRollover(currentTime)
3649 if exp != actual:
3650 # Failures occur on some systems for MIDNIGHT and W0.
3651 # Print detailed calculation for MIDNIGHT so we can try to see
3652 # what's going on
3653 import time
3654 if when == 'MIDNIGHT':
3655 try:
3656 if rh.utc:
3657 t = time.gmtime(currentTime)
3658 else:
3659 t = time.localtime(currentTime)
3660 currentHour = t[3]
3661 currentMinute = t[4]
3662 currentSecond = t[5]
3663 # r is the number of seconds left between now and midnight
3664 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3665 currentMinute) * 60 +
3666 currentSecond)
3667 result = currentTime + r
3668 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3669 print('currentHour: %s' % currentHour, file=sys.stderr)
3670 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3671 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3672 print('r: %s' % r, file=sys.stderr)
3673 print('result: %s' % result, file=sys.stderr)
3674 except Exception:
3675 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3676 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003677 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003678 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3679
Vinay Sajip60ccd822011-05-09 17:32:09 +01003680
3681@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
3682class NTEventLogHandlerTest(BaseTest):
3683 def test_basic(self):
3684 logtype = 'Application'
3685 elh = win32evtlog.OpenEventLog(None, logtype)
3686 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
3687 h = logging.handlers.NTEventLogHandler('test_logging')
3688 r = logging.makeLogRecord({'msg': 'Test Log Message'})
3689 h.handle(r)
3690 h.close()
3691 # Now see if the event is recorded
3692 self.assertTrue(num_recs < win32evtlog.GetNumberOfEventLogRecords(elh))
3693 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
3694 win32evtlog.EVENTLOG_SEQUENTIAL_READ
3695 found = False
3696 GO_BACK = 100
3697 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
3698 for e in events:
3699 if e.SourceName != 'test_logging':
3700 continue
3701 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
3702 if msg != 'Test Log Message\r\n':
3703 continue
3704 found = True
3705 break
3706 msg = 'Record not found in event log, went back %d records' % GO_BACK
3707 self.assertTrue(found, msg=msg)
3708
Christian Heimes180510d2008-03-03 19:15:45 +00003709# Set the locale to the platform-dependent default. I have no idea
3710# why the test does this, but in any case we save the current locale
3711# first and restore it at the end.
3712@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00003713def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00003714 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003715 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01003716 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
3717 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
3718 ManagerTest, FormatterTest, BufferingFormatterTest,
3719 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
3720 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
3721 BasicConfigTest, LoggerAdapterTest, LoggerTest,
3722 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003723 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01003724 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00003725 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00003726 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00003727
Christian Heimes180510d2008-03-03 19:15:45 +00003728if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00003729 test_main()