blob: 5e192d5df03e9b8771610d034ba64930f3473f70 [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
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asynchat
54 import asyncore
55 import errno
56 from http.server import HTTPServer, BaseHTTPRequestHandler
57 import smtpd
58 from urllib.parse import urlparse, parse_qs
59 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
60 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000061except ImportError:
62 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010063try:
64 import win32evtlog
65except ImportError:
66 win32evtlog = None
67try:
68 import win32evtlogutil
69except ImportError:
70 win32evtlogutil = None
71 win32evtlog = None
Christian Heimes18c66892008-02-17 13:31:39 +000072
73
Christian Heimes180510d2008-03-03 19:15:45 +000074class BaseTest(unittest.TestCase):
75
76 """Base class for logging tests."""
77
78 log_format = "%(name)s -> %(levelname)s: %(message)s"
79 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
80 message_num = 0
81
82 def setUp(self):
83 """Setup the default logging stream to an internal StringIO instance,
84 so that we can examine log output as we want."""
85 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000086 logging._acquireLock()
87 try:
Christian Heimes180510d2008-03-03 19:15:45 +000088 self.saved_handlers = logging._handlers.copy()
89 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.saved_loggers = saved_loggers = logger_dict.copy()
Christian Heimes180510d2008-03-03 19:15:45 +000091 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000092 self.logger_states = logger_states = {}
93 for name in saved_loggers:
94 logger_states[name] = getattr(saved_loggers[name],
95 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000096 finally:
97 logging._releaseLock()
98
Florent Xicluna5252f9f2011-11-07 19:43:05 +010099 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000100 self.logger1 = logging.getLogger("\xab\xd7\xbb")
101 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000102
Christian Heimes180510d2008-03-03 19:15:45 +0000103 self.root_logger = logging.getLogger("")
104 self.original_logging_level = self.root_logger.getEffectiveLevel()
105
106 self.stream = io.StringIO()
107 self.root_logger.setLevel(logging.DEBUG)
108 self.root_hdlr = logging.StreamHandler(self.stream)
109 self.root_formatter = logging.Formatter(self.log_format)
110 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000111 if self.logger1.hasHandlers():
112 hlist = self.logger1.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
114 if self.logger2.hasHandlers():
115 hlist = self.logger2.handlers + self.root_logger.handlers
116 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000117 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000118 self.assertTrue(self.logger1.hasHandlers())
119 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000120
121 def tearDown(self):
122 """Remove our logging stream, and restore the original logging
123 level."""
124 self.stream.close()
125 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000126 while self.root_logger.handlers:
127 h = self.root_logger.handlers[0]
128 self.root_logger.removeHandler(h)
129 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000130 self.root_logger.setLevel(self.original_logging_level)
131 logging._acquireLock()
132 try:
133 logging._levelNames.clear()
134 logging._levelNames.update(self.saved_level_names)
135 logging._handlers.clear()
136 logging._handlers.update(self.saved_handlers)
137 logging._handlerList[:] = self.saved_handler_list
138 loggerDict = logging.getLogger().manager.loggerDict
139 loggerDict.clear()
140 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000141 logger_states = self.logger_states
142 for name in self.logger_states:
143 if logger_states[name] is not None:
144 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000145 finally:
146 logging._releaseLock()
147
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000148 def assert_log_lines(self, expected_values, stream=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000149 """Match the collected log lines against the regular expression
150 self.expected_log_pat, and compare the extracted group values to
151 the expected_values list of tuples."""
152 stream = stream or self.stream
153 pat = re.compile(self.expected_log_pat)
154 try:
155 stream.reset()
156 actual_lines = stream.readlines()
157 except AttributeError:
158 # StringIO.StringIO lacks a reset() method.
159 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100160 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000161 for actual, expected in zip(actual_lines, expected_values):
162 match = pat.search(actual)
163 if not match:
164 self.fail("Log line does not match expected pattern:\n" +
165 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000166 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000167 s = stream.read()
168 if s:
169 self.fail("Remaining output at end of log stream:\n" + s)
170
171 def next_message(self):
172 """Generate a message consisting solely of an auto-incrementing
173 integer."""
174 self.message_num += 1
175 return "%d" % self.message_num
176
177
178class BuiltinLevelsTest(BaseTest):
179 """Test builtin levels and their inheritance."""
180
181 def test_flat(self):
182 #Logging levels in a flat logger namespace.
183 m = self.next_message
184
185 ERR = logging.getLogger("ERR")
186 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000187 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000188 INF.setLevel(logging.INFO)
189 DEB = logging.getLogger("DEB")
190 DEB.setLevel(logging.DEBUG)
191
192 # These should log.
193 ERR.log(logging.CRITICAL, m())
194 ERR.error(m())
195
196 INF.log(logging.CRITICAL, m())
197 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100198 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000199 INF.info(m())
200
201 DEB.log(logging.CRITICAL, m())
202 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100203 DEB.warning(m())
204 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000205 DEB.debug(m())
206
207 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100208 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000209 ERR.info(m())
210 ERR.debug(m())
211
212 INF.debug(m())
213
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000214 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000215 ('ERR', 'CRITICAL', '1'),
216 ('ERR', 'ERROR', '2'),
217 ('INF', 'CRITICAL', '3'),
218 ('INF', 'ERROR', '4'),
219 ('INF', 'WARNING', '5'),
220 ('INF', 'INFO', '6'),
221 ('DEB', 'CRITICAL', '7'),
222 ('DEB', 'ERROR', '8'),
223 ('DEB', 'WARNING', '9'),
224 ('DEB', 'INFO', '10'),
225 ('DEB', 'DEBUG', '11'),
226 ])
227
228 def test_nested_explicit(self):
229 # Logging levels in a nested namespace, all explicitly set.
230 m = self.next_message
231
232 INF = logging.getLogger("INF")
233 INF.setLevel(logging.INFO)
234 INF_ERR = logging.getLogger("INF.ERR")
235 INF_ERR.setLevel(logging.ERROR)
236
237 # These should log.
238 INF_ERR.log(logging.CRITICAL, m())
239 INF_ERR.error(m())
240
241 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100242 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000243 INF_ERR.info(m())
244 INF_ERR.debug(m())
245
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000246 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000247 ('INF.ERR', 'CRITICAL', '1'),
248 ('INF.ERR', 'ERROR', '2'),
249 ])
250
251 def test_nested_inherited(self):
252 #Logging levels in a nested namespace, inherited from parent loggers.
253 m = self.next_message
254
255 INF = logging.getLogger("INF")
256 INF.setLevel(logging.INFO)
257 INF_ERR = logging.getLogger("INF.ERR")
258 INF_ERR.setLevel(logging.ERROR)
259 INF_UNDEF = logging.getLogger("INF.UNDEF")
260 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
261 UNDEF = logging.getLogger("UNDEF")
262
263 # These should log.
264 INF_UNDEF.log(logging.CRITICAL, m())
265 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100266 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000267 INF_UNDEF.info(m())
268 INF_ERR_UNDEF.log(logging.CRITICAL, m())
269 INF_ERR_UNDEF.error(m())
270
271 # These should not log.
272 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100273 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000274 INF_ERR_UNDEF.info(m())
275 INF_ERR_UNDEF.debug(m())
276
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000277 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000278 ('INF.UNDEF', 'CRITICAL', '1'),
279 ('INF.UNDEF', 'ERROR', '2'),
280 ('INF.UNDEF', 'WARNING', '3'),
281 ('INF.UNDEF', 'INFO', '4'),
282 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
283 ('INF.ERR.UNDEF', 'ERROR', '6'),
284 ])
285
286 def test_nested_with_virtual_parent(self):
287 # Logging levels when some parent does not exist yet.
288 m = self.next_message
289
290 INF = logging.getLogger("INF")
291 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
292 CHILD = logging.getLogger("INF.BADPARENT")
293 INF.setLevel(logging.INFO)
294
295 # These should log.
296 GRANDCHILD.log(logging.FATAL, m())
297 GRANDCHILD.info(m())
298 CHILD.log(logging.FATAL, m())
299 CHILD.info(m())
300
301 # These should not log.
302 GRANDCHILD.debug(m())
303 CHILD.debug(m())
304
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000305 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000306 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
307 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
308 ('INF.BADPARENT', 'CRITICAL', '3'),
309 ('INF.BADPARENT', 'INFO', '4'),
310 ])
311
312
313class BasicFilterTest(BaseTest):
314
315 """Test the bundled Filter class."""
316
317 def test_filter(self):
318 # Only messages satisfying the specified criteria pass through the
319 # filter.
320 filter_ = logging.Filter("spam.eggs")
321 handler = self.root_logger.handlers[0]
322 try:
323 handler.addFilter(filter_)
324 spam = logging.getLogger("spam")
325 spam_eggs = logging.getLogger("spam.eggs")
326 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
327 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
328
329 spam.info(self.next_message())
330 spam_eggs.info(self.next_message()) # Good.
331 spam_eggs_fish.info(self.next_message()) # Good.
332 spam_bakedbeans.info(self.next_message())
333
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000334 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000335 ('spam.eggs', 'INFO', '2'),
336 ('spam.eggs.fish', 'INFO', '3'),
337 ])
338 finally:
339 handler.removeFilter(filter_)
340
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000341 def test_callable_filter(self):
342 # Only messages satisfying the specified criteria pass through the
343 # filter.
344
345 def filterfunc(record):
346 parts = record.name.split('.')
347 prefix = '.'.join(parts[:2])
348 return prefix == 'spam.eggs'
349
350 handler = self.root_logger.handlers[0]
351 try:
352 handler.addFilter(filterfunc)
353 spam = logging.getLogger("spam")
354 spam_eggs = logging.getLogger("spam.eggs")
355 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
356 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
357
358 spam.info(self.next_message())
359 spam_eggs.info(self.next_message()) # Good.
360 spam_eggs_fish.info(self.next_message()) # Good.
361 spam_bakedbeans.info(self.next_message())
362
363 self.assert_log_lines([
364 ('spam.eggs', 'INFO', '2'),
365 ('spam.eggs.fish', 'INFO', '3'),
366 ])
367 finally:
368 handler.removeFilter(filterfunc)
369
Vinay Sajip985ef872011-04-26 19:34:04 +0100370 def test_empty_filter(self):
371 f = logging.Filter()
372 r = logging.makeLogRecord({'name': 'spam.eggs'})
373 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000374
375#
376# First, we define our levels. There can be as many as you want - the only
377# limitations are that they should be integers, the lowest should be > 0 and
378# larger values mean less information being logged. If you need specific
379# level values which do not fit into these limitations, you can use a
380# mapping dictionary to convert between your application levels and the
381# logging system.
382#
383SILENT = 120
384TACITURN = 119
385TERSE = 118
386EFFUSIVE = 117
387SOCIABLE = 116
388VERBOSE = 115
389TALKATIVE = 114
390GARRULOUS = 113
391CHATTERBOX = 112
392BORING = 111
393
394LEVEL_RANGE = range(BORING, SILENT + 1)
395
396#
397# Next, we define names for our levels. You don't need to do this - in which
398# case the system will use "Level n" to denote the text for the level.
399#
400my_logging_levels = {
401 SILENT : 'Silent',
402 TACITURN : 'Taciturn',
403 TERSE : 'Terse',
404 EFFUSIVE : 'Effusive',
405 SOCIABLE : 'Sociable',
406 VERBOSE : 'Verbose',
407 TALKATIVE : 'Talkative',
408 GARRULOUS : 'Garrulous',
409 CHATTERBOX : 'Chatterbox',
410 BORING : 'Boring',
411}
412
413class GarrulousFilter(logging.Filter):
414
415 """A filter which blocks garrulous messages."""
416
417 def filter(self, record):
418 return record.levelno != GARRULOUS
419
420class VerySpecificFilter(logging.Filter):
421
422 """A filter which blocks sociable and taciturn messages."""
423
424 def filter(self, record):
425 return record.levelno not in [SOCIABLE, TACITURN]
426
427
428class CustomLevelsAndFiltersTest(BaseTest):
429
430 """Test various filtering possibilities with custom logging levels."""
431
432 # Skip the logger name group.
433 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
434
435 def setUp(self):
436 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000437 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000438 logging.addLevelName(k, v)
439
440 def log_at_all_levels(self, logger):
441 for lvl in LEVEL_RANGE:
442 logger.log(lvl, self.next_message())
443
444 def test_logger_filter(self):
445 # Filter at logger level.
446 self.root_logger.setLevel(VERBOSE)
447 # Levels >= 'Verbose' are good.
448 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000449 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000450 ('Verbose', '5'),
451 ('Sociable', '6'),
452 ('Effusive', '7'),
453 ('Terse', '8'),
454 ('Taciturn', '9'),
455 ('Silent', '10'),
456 ])
457
458 def test_handler_filter(self):
459 # Filter at handler level.
460 self.root_logger.handlers[0].setLevel(SOCIABLE)
461 try:
462 # Levels >= 'Sociable' are good.
463 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000464 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000465 ('Sociable', '6'),
466 ('Effusive', '7'),
467 ('Terse', '8'),
468 ('Taciturn', '9'),
469 ('Silent', '10'),
470 ])
471 finally:
472 self.root_logger.handlers[0].setLevel(logging.NOTSET)
473
474 def test_specific_filters(self):
475 # Set a specific filter object on the handler, and then add another
476 # filter object on the logger itself.
477 handler = self.root_logger.handlers[0]
478 specific_filter = None
479 garr = GarrulousFilter()
480 handler.addFilter(garr)
481 try:
482 self.log_at_all_levels(self.root_logger)
483 first_lines = [
484 # Notice how 'Garrulous' is missing
485 ('Boring', '1'),
486 ('Chatterbox', '2'),
487 ('Talkative', '4'),
488 ('Verbose', '5'),
489 ('Sociable', '6'),
490 ('Effusive', '7'),
491 ('Terse', '8'),
492 ('Taciturn', '9'),
493 ('Silent', '10'),
494 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000495 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000496
497 specific_filter = VerySpecificFilter()
498 self.root_logger.addFilter(specific_filter)
499 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000500 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000501 # Not only 'Garrulous' is still missing, but also 'Sociable'
502 # and 'Taciturn'
503 ('Boring', '11'),
504 ('Chatterbox', '12'),
505 ('Talkative', '14'),
506 ('Verbose', '15'),
507 ('Effusive', '17'),
508 ('Terse', '18'),
509 ('Silent', '20'),
510 ])
511 finally:
512 if specific_filter:
513 self.root_logger.removeFilter(specific_filter)
514 handler.removeFilter(garr)
515
516
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100517class HandlerTest(BaseTest):
518 def test_name(self):
519 h = logging.Handler()
520 h.name = 'generic'
521 self.assertEqual(h.name, 'generic')
522 h.name = 'anothergeneric'
523 self.assertEqual(h.name, 'anothergeneric')
524 self.assertRaises(NotImplementedError, h.emit, None)
525
Vinay Sajip5a35b062011-04-27 11:31:14 +0100526 def test_builtin_handlers(self):
527 # We can't actually *use* too many handlers in the tests,
528 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200529 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100530 for existing in (True, False):
531 fd, fn = tempfile.mkstemp()
532 os.close(fd)
533 if not existing:
534 os.unlink(fn)
535 h = logging.handlers.WatchedFileHandler(fn, delay=True)
536 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100537 dev, ino = h.dev, h.ino
538 self.assertNotEqual(dev, -1)
539 self.assertNotEqual(ino, -1)
540 r = logging.makeLogRecord({'msg': 'Test'})
541 h.handle(r)
542 # Now remove the file.
543 os.unlink(fn)
544 self.assertFalse(os.path.exists(fn))
545 # The next call should recreate the file.
546 h.handle(r)
547 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100548 else:
549 self.assertEqual(h.dev, -1)
550 self.assertEqual(h.ino, -1)
551 h.close()
552 if existing:
553 os.unlink(fn)
554 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100555 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100556 else:
557 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100558 try:
559 h = logging.handlers.SysLogHandler(sockname)
560 self.assertEqual(h.facility, h.LOG_USER)
561 self.assertTrue(h.unixsocket)
562 h.close()
563 except socket.error: # syslogd might not be available
564 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100565 for method in ('GET', 'POST', 'PUT'):
566 if method == 'PUT':
567 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
568 'localhost', '/log', method)
569 else:
570 h = logging.handlers.HTTPHandler('localhost', '/log', method)
571 h.close()
572 h = logging.handlers.BufferingHandler(0)
573 r = logging.makeLogRecord({})
574 self.assertTrue(h.shouldFlush(r))
575 h.close()
576 h = logging.handlers.BufferingHandler(1)
577 self.assertFalse(h.shouldFlush(r))
578 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100579
580class BadStream(object):
581 def write(self, data):
582 raise RuntimeError('deliberate mistake')
583
584class TestStreamHandler(logging.StreamHandler):
585 def handleError(self, record):
586 self.error_record = record
587
588class StreamHandlerTest(BaseTest):
589 def test_error_handling(self):
590 h = TestStreamHandler(BadStream())
591 r = logging.makeLogRecord({})
592 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100593 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100594 try:
595 h.handle(r)
596 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100597 h = logging.StreamHandler(BadStream())
598 sys.stderr = sio = io.StringIO()
599 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100600 self.assertIn('\nRuntimeError: deliberate mistake\n',
601 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100602 logging.raiseExceptions = False
603 sys.stderr = sio = io.StringIO()
604 h.handle(r)
605 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100606 finally:
607 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100608 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100609
Vinay Sajip7367d082011-05-02 13:17:27 +0100610# -- The following section could be moved into a server_helper.py module
611# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100612
Vinay Sajipce7c9782011-05-17 07:15:53 +0100613if threading:
614 class TestSMTPChannel(smtpd.SMTPChannel):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100615 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100616 This derived class has had to be created because smtpd does not
617 support use of custom channel maps, although they are allowed by
618 asyncore's design. Issue #11959 has been raised to address this,
619 and if resolved satisfactorily, some of this code can be removed.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100620 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100621 def __init__(self, server, conn, addr, sockmap):
622 asynchat.async_chat.__init__(self, conn, sockmap)
623 self.smtp_server = server
624 self.conn = conn
625 self.addr = addr
626 self.received_lines = []
627 self.smtp_state = self.COMMAND
628 self.seen_greeting = ''
629 self.mailfrom = None
630 self.rcpttos = []
631 self.received_data = ''
632 self.fqdn = socket.getfqdn()
633 self.num_bytes = 0
634 try:
635 self.peer = conn.getpeername()
636 except socket.error as err:
637 # a race condition may occur if the other end is closing
638 # before we can get the peername
639 self.close()
640 if err.args[0] != errno.ENOTCONN:
641 raise
642 return
643 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
644 self.set_terminator(b'\r\n')
Vinay Sajipa463d252011-04-30 21:52:48 +0100645
Vinay Sajip314b92b2011-05-02 14:31:16 +0100646
Vinay Sajipce7c9782011-05-17 07:15:53 +0100647 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100648 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100649 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100650
Vinay Sajipce7c9782011-05-17 07:15:53 +0100651 :param addr: A (host, port) tuple which the server listens on.
652 You can specify a port value of zero: the server's
653 *port* attribute will hold the actual port number
654 used, which can be used in client connections.
655 :param handler: A callable which will be called to process
656 incoming messages. The handler will be passed
657 the client address tuple, who the message is from,
658 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100659 :param poll_interval: The interval, in seconds, used in the underlying
660 :func:`select` or :func:`poll` call by
661 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100662 :param sockmap: A dictionary which will be used to hold
663 :class:`asyncore.dispatcher` instances used by
664 :func:`asyncore.loop`. This avoids changing the
665 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100666 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100667 channel_class = TestSMTPChannel
668
669 def __init__(self, addr, handler, poll_interval, sockmap):
670 self._localaddr = addr
671 self._remoteaddr = None
672 self.sockmap = sockmap
673 asyncore.dispatcher.__init__(self, map=sockmap)
674 try:
675 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
676 sock.setblocking(0)
677 self.set_socket(sock, map=sockmap)
678 # try to re-use a server port if possible
679 self.set_reuse_addr()
680 self.bind(addr)
681 self.port = sock.getsockname()[1]
682 self.listen(5)
683 except:
684 self.close()
Vinay Sajipe73afad2011-05-10 07:48:28 +0100685 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100686 self._handler = handler
687 self._thread = None
688 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100689
Vinay Sajipce7c9782011-05-17 07:15:53 +0100690 def handle_accepted(self, conn, addr):
691 """
692 Redefined only because the base class does not pass in a
693 map, forcing use of a global in :mod:`asyncore`.
694 """
695 channel = self.channel_class(self, conn, addr, self.sockmap)
Vinay Sajip314b92b2011-05-02 14:31:16 +0100696
Vinay Sajipce7c9782011-05-17 07:15:53 +0100697 def process_message(self, peer, mailfrom, rcpttos, data):
698 """
699 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701 Typically, this will be a test case method.
702 :param peer: The client (host, port) tuple.
703 :param mailfrom: The address of the sender.
704 :param rcpttos: The addresses of the recipients.
705 :param data: The message.
706 """
707 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100708
Vinay Sajipce7c9782011-05-17 07:15:53 +0100709 def start(self):
710 """
711 Start the server running on a separate daemon thread.
712 """
713 self._thread = t = threading.Thread(target=self.serve_forever,
714 args=(self.poll_interval,))
715 t.setDaemon(True)
716 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100717
Vinay Sajipce7c9782011-05-17 07:15:53 +0100718 def serve_forever(self, poll_interval):
719 """
720 Run the :mod:`asyncore` loop until normal termination
721 conditions arise.
722 :param poll_interval: The interval, in seconds, used in the underlying
723 :func:`select` or :func:`poll` call by
724 :func:`asyncore.loop`.
725 """
726 try:
727 asyncore.loop(poll_interval, map=self.sockmap)
728 except select.error:
729 # On FreeBSD 8, closing the server repeatably
730 # raises this error. We swallow it if the
731 # server has been closed.
732 if self.connected or self.accepting:
733 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100734
Vinay Sajipce7c9782011-05-17 07:15:53 +0100735 def stop(self, timeout=None):
736 """
737 Stop the thread by closing the server instance.
738 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100739
Vinay Sajipce7c9782011-05-17 07:15:53 +0100740 :param timeout: How long to wait for the server thread
741 to terminate.
742 """
743 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100744 self._thread.join(timeout)
745 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100746
Vinay Sajipce7c9782011-05-17 07:15:53 +0100747 class ControlMixin(object):
748 """
749 This mixin is used to start a server on a separate thread, and
750 shut it down programmatically. Request handling is simplified - instead
751 of needing to derive a suitable RequestHandler subclass, you just
752 provide a callable which will be passed each received request to be
753 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100754
Vinay Sajipce7c9782011-05-17 07:15:53 +0100755 :param handler: A handler callable which will be called with a
756 single parameter - the request - in order to
757 process the request. This handler is called on the
758 server thread, effectively meaning that requests are
759 processed serially. While not quite Web scale ;-),
760 this should be fine for testing applications.
761 :param poll_interval: The polling interval in seconds.
762 """
763 def __init__(self, handler, poll_interval):
764 self._thread = None
765 self.poll_interval = poll_interval
766 self._handler = handler
767 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100768
Vinay Sajipce7c9782011-05-17 07:15:53 +0100769 def start(self):
770 """
771 Create a daemon thread to run the server, and start it.
772 """
773 self._thread = t = threading.Thread(target=self.serve_forever,
774 args=(self.poll_interval,))
775 t.setDaemon(True)
776 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100777
Vinay Sajipce7c9782011-05-17 07:15:53 +0100778 def serve_forever(self, poll_interval):
779 """
780 Run the server. Set the ready flag before entering the
781 service loop.
782 """
783 self.ready.set()
784 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 def stop(self, timeout=None):
787 """
788 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100789
Vinay Sajipce7c9782011-05-17 07:15:53 +0100790 :param timeout: How long to wait for the server thread
791 to terminate.
792 """
793 self.shutdown()
794 if self._thread is not None:
795 self._thread.join(timeout)
796 self._thread = None
797 self.server_close()
798 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Vinay Sajipce7c9782011-05-17 07:15:53 +0100800 class TestHTTPServer(ControlMixin, HTTPServer):
801 """
802 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100803
Vinay Sajipce7c9782011-05-17 07:15:53 +0100804 :param addr: A tuple with the IP address and port to listen on.
805 :param handler: A handler callable which will be called with a
806 single parameter - the request - in order to
807 process the request.
808 :param poll_interval: The polling interval in seconds.
809 :param log: Pass ``True`` to enable log messages.
810 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100811 def __init__(self, addr, handler, poll_interval=0.5,
812 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100813 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
814 def __getattr__(self, name, default=None):
815 if name.startswith('do_'):
816 return self.process_request
817 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100818
Vinay Sajipce7c9782011-05-17 07:15:53 +0100819 def process_request(self):
820 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100821
Vinay Sajipce7c9782011-05-17 07:15:53 +0100822 def log_message(self, format, *args):
823 if log:
824 super(DelegatingHTTPRequestHandler,
825 self).log_message(format, *args)
826 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
827 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100828 self.sslctx = sslctx
829
830 def get_request(self):
831 try:
832 sock, addr = self.socket.accept()
833 if self.sslctx:
834 sock = self.sslctx.wrap_socket(sock, server_side=True)
835 except socket.error as e:
836 # socket errors are silenced by the caller, print them here
837 sys.stderr.write("Got an error:\n%s\n" % e)
838 raise
839 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 class TestTCPServer(ControlMixin, ThreadingTCPServer):
842 """
843 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100844
Vinay Sajipce7c9782011-05-17 07:15:53 +0100845 :param addr: A tuple with the IP address and port to listen on.
846 :param handler: A handler callable which will be called with a single
847 parameter - the request - in order to process the request.
848 :param poll_interval: The polling interval in seconds.
849 :bind_and_activate: If True (the default), binds the server and starts it
850 listening. If False, you need to call
851 :meth:`server_bind` and :meth:`server_activate` at
852 some later time before calling :meth:`start`, so that
853 the server will set up the socket and listen on it.
854 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100855
Vinay Sajipce7c9782011-05-17 07:15:53 +0100856 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100857
Vinay Sajipce7c9782011-05-17 07:15:53 +0100858 def __init__(self, addr, handler, poll_interval=0.5,
859 bind_and_activate=True):
860 class DelegatingTCPRequestHandler(StreamRequestHandler):
861
862 def handle(self):
863 self.server._handler(self)
864 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
865 bind_and_activate)
866 ControlMixin.__init__(self, handler, poll_interval)
867
868 def server_bind(self):
869 super(TestTCPServer, self).server_bind()
870 self.port = self.socket.getsockname()[1]
871
872 class TestUDPServer(ControlMixin, ThreadingUDPServer):
873 """
874 A UDP server which is controllable using :class:`ControlMixin`.
875
876 :param addr: A tuple with the IP address and port to listen on.
877 :param handler: A handler callable which will be called with a
878 single parameter - the request - in order to
879 process the request.
880 :param poll_interval: The polling interval for shutdown requests,
881 in seconds.
882 :bind_and_activate: If True (the default), binds the server and
883 starts it listening. If False, you need to
884 call :meth:`server_bind` and
885 :meth:`server_activate` at some later time
886 before calling :meth:`start`, so that the server will
887 set up the socket and listen on it.
888 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100889 def __init__(self, addr, handler, poll_interval=0.5,
890 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100891 class DelegatingUDPRequestHandler(DatagramRequestHandler):
892
893 def handle(self):
894 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100895
896 def finish(self):
897 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 if data:
899 try:
900 super(DelegatingUDPRequestHandler, self).finish()
901 except socket.error:
902 if not self.server._closed:
903 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100904
Vinay Sajip3ef12292011-05-23 23:00:42 +0100905 ThreadingUDPServer.__init__(self, addr,
906 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100907 bind_and_activate)
908 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100909 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100910
911 def server_bind(self):
912 super(TestUDPServer, self).server_bind()
913 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Vinay Sajipba980db2011-05-23 21:37:54 +0100915 def server_close(self):
916 super(TestUDPServer, self).server_close()
917 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100918
919# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100920
Vinay Sajipce7c9782011-05-17 07:15:53 +0100921@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100922class SMTPHandlerTest(BaseTest):
923 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100924 sockmap = {}
925 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
926 sockmap)
927 server.start()
928 addr = ('localhost', server.port)
Vinay Sajipa463d252011-04-30 21:52:48 +0100929 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
930 self.assertEqual(h.toaddrs, ['you'])
931 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100932 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100933 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100934 h.handle(r)
Vinay Sajip7367d082011-05-02 13:17:27 +0100935 self.handled.wait()
Vinay Sajipa463d252011-04-30 21:52:48 +0100936 server.stop()
937 self.assertEqual(len(self.messages), 1)
938 peer, mailfrom, rcpttos, data = self.messages[0]
939 self.assertEqual(mailfrom, 'me')
940 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100941 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100942 self.assertTrue(data.endswith('\n\nHello'))
943 h.close()
944
945 def process_message(self, *args):
946 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100947 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100948
Christian Heimes180510d2008-03-03 19:15:45 +0000949class MemoryHandlerTest(BaseTest):
950
951 """Tests for the MemoryHandler."""
952
953 # Do not bother with a logger name group.
954 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
955
956 def setUp(self):
957 BaseTest.setUp(self)
958 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
959 self.root_hdlr)
960 self.mem_logger = logging.getLogger('mem')
961 self.mem_logger.propagate = 0
962 self.mem_logger.addHandler(self.mem_hdlr)
963
964 def tearDown(self):
965 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000966 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000967
968 def test_flush(self):
969 # The memory handler flushes to its target handler based on specific
970 # criteria (message count and message level).
971 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000972 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000973 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000974 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000975 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100976 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000977 lines = [
978 ('DEBUG', '1'),
979 ('INFO', '2'),
980 ('WARNING', '3'),
981 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000982 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000983 for n in (4, 14):
984 for i in range(9):
985 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000986 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000987 # This will flush because it's the 10th message since the last
988 # flush.
989 self.mem_logger.debug(self.next_message())
990 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000991 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000992
993 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000994 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000995
996
997class ExceptionFormatter(logging.Formatter):
998 """A special exception formatter."""
999 def formatException(self, ei):
1000 return "Got a [%s]" % ei[0].__name__
1001
1002
1003class ConfigFileTest(BaseTest):
1004
1005 """Reading logging config from a .ini-style config file."""
1006
1007 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1008
1009 # config0 is a standard configuration.
1010 config0 = """
1011 [loggers]
1012 keys=root
1013
1014 [handlers]
1015 keys=hand1
1016
1017 [formatters]
1018 keys=form1
1019
1020 [logger_root]
1021 level=WARNING
1022 handlers=hand1
1023
1024 [handler_hand1]
1025 class=StreamHandler
1026 level=NOTSET
1027 formatter=form1
1028 args=(sys.stdout,)
1029
1030 [formatter_form1]
1031 format=%(levelname)s ++ %(message)s
1032 datefmt=
1033 """
1034
1035 # config1 adds a little to the standard configuration.
1036 config1 = """
1037 [loggers]
1038 keys=root,parser
1039
1040 [handlers]
1041 keys=hand1
1042
1043 [formatters]
1044 keys=form1
1045
1046 [logger_root]
1047 level=WARNING
1048 handlers=
1049
1050 [logger_parser]
1051 level=DEBUG
1052 handlers=hand1
1053 propagate=1
1054 qualname=compiler.parser
1055
1056 [handler_hand1]
1057 class=StreamHandler
1058 level=NOTSET
1059 formatter=form1
1060 args=(sys.stdout,)
1061
1062 [formatter_form1]
1063 format=%(levelname)s ++ %(message)s
1064 datefmt=
1065 """
1066
Vinay Sajip3f84b072011-03-07 17:49:33 +00001067 # config1a moves the handler to the root.
1068 config1a = """
1069 [loggers]
1070 keys=root,parser
1071
1072 [handlers]
1073 keys=hand1
1074
1075 [formatters]
1076 keys=form1
1077
1078 [logger_root]
1079 level=WARNING
1080 handlers=hand1
1081
1082 [logger_parser]
1083 level=DEBUG
1084 handlers=
1085 propagate=1
1086 qualname=compiler.parser
1087
1088 [handler_hand1]
1089 class=StreamHandler
1090 level=NOTSET
1091 formatter=form1
1092 args=(sys.stdout,)
1093
1094 [formatter_form1]
1095 format=%(levelname)s ++ %(message)s
1096 datefmt=
1097 """
1098
Christian Heimes180510d2008-03-03 19:15:45 +00001099 # config2 has a subtle configuration error that should be reported
1100 config2 = config1.replace("sys.stdout", "sys.stbout")
1101
1102 # config3 has a less subtle configuration error
1103 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1104
1105 # config4 specifies a custom formatter class to be loaded
1106 config4 = """
1107 [loggers]
1108 keys=root
1109
1110 [handlers]
1111 keys=hand1
1112
1113 [formatters]
1114 keys=form1
1115
1116 [logger_root]
1117 level=NOTSET
1118 handlers=hand1
1119
1120 [handler_hand1]
1121 class=StreamHandler
1122 level=NOTSET
1123 formatter=form1
1124 args=(sys.stdout,)
1125
1126 [formatter_form1]
1127 class=""" + __name__ + """.ExceptionFormatter
1128 format=%(levelname)s:%(name)s:%(message)s
1129 datefmt=
1130 """
1131
Georg Brandl3dbca812008-07-23 16:10:53 +00001132 # config5 specifies a custom handler class to be loaded
1133 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1134
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001135 # config6 uses ', ' delimiters in the handlers and formatters sections
1136 config6 = """
1137 [loggers]
1138 keys=root,parser
1139
1140 [handlers]
1141 keys=hand1, hand2
1142
1143 [formatters]
1144 keys=form1, form2
1145
1146 [logger_root]
1147 level=WARNING
1148 handlers=
1149
1150 [logger_parser]
1151 level=DEBUG
1152 handlers=hand1
1153 propagate=1
1154 qualname=compiler.parser
1155
1156 [handler_hand1]
1157 class=StreamHandler
1158 level=NOTSET
1159 formatter=form1
1160 args=(sys.stdout,)
1161
1162 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001163 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001164 level=NOTSET
1165 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001166 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001167
1168 [formatter_form1]
1169 format=%(levelname)s ++ %(message)s
1170 datefmt=
1171
1172 [formatter_form2]
1173 format=%(message)s
1174 datefmt=
1175 """
1176
Vinay Sajip3f84b072011-03-07 17:49:33 +00001177 # config7 adds a compiler logger.
1178 config7 = """
1179 [loggers]
1180 keys=root,parser,compiler
1181
1182 [handlers]
1183 keys=hand1
1184
1185 [formatters]
1186 keys=form1
1187
1188 [logger_root]
1189 level=WARNING
1190 handlers=hand1
1191
1192 [logger_compiler]
1193 level=DEBUG
1194 handlers=
1195 propagate=1
1196 qualname=compiler
1197
1198 [logger_parser]
1199 level=DEBUG
1200 handlers=
1201 propagate=1
1202 qualname=compiler.parser
1203
1204 [handler_hand1]
1205 class=StreamHandler
1206 level=NOTSET
1207 formatter=form1
1208 args=(sys.stdout,)
1209
1210 [formatter_form1]
1211 format=%(levelname)s ++ %(message)s
1212 datefmt=
1213 """
1214
Christian Heimes180510d2008-03-03 19:15:45 +00001215 def apply_config(self, conf):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001216 file = io.StringIO(textwrap.dedent(conf))
1217 logging.config.fileConfig(file)
Christian Heimes180510d2008-03-03 19:15:45 +00001218
1219 def test_config0_ok(self):
1220 # A simple config file which overrides the default settings.
1221 with captured_stdout() as output:
1222 self.apply_config(self.config0)
1223 logger = logging.getLogger()
1224 # Won't output anything
1225 logger.info(self.next_message())
1226 # Outputs a message
1227 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001228 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001229 ('ERROR', '2'),
1230 ], stream=output)
1231 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001232 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001233
Georg Brandl3dbca812008-07-23 16:10:53 +00001234 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001235 # A config file defining a sub-parser as well.
1236 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001237 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001238 logger = logging.getLogger("compiler.parser")
1239 # Both will output a message
1240 logger.info(self.next_message())
1241 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001242 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001243 ('INFO', '1'),
1244 ('ERROR', '2'),
1245 ], stream=output)
1246 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001247 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001248
1249 def test_config2_failure(self):
1250 # A simple config file which overrides the default settings.
1251 self.assertRaises(Exception, self.apply_config, self.config2)
1252
1253 def test_config3_failure(self):
1254 # A simple config file which overrides the default settings.
1255 self.assertRaises(Exception, self.apply_config, self.config3)
1256
1257 def test_config4_ok(self):
1258 # A config file specifying a custom formatter class.
1259 with captured_stdout() as output:
1260 self.apply_config(self.config4)
1261 logger = logging.getLogger()
1262 try:
1263 raise RuntimeError()
1264 except RuntimeError:
1265 logging.exception("just testing")
1266 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001267 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001268 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1269 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001270 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001271
Georg Brandl3dbca812008-07-23 16:10:53 +00001272 def test_config5_ok(self):
1273 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001274
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001275 def test_config6_ok(self):
1276 self.test_config1_ok(config=self.config6)
1277
Vinay Sajip3f84b072011-03-07 17:49:33 +00001278 def test_config7_ok(self):
1279 with captured_stdout() as output:
1280 self.apply_config(self.config1a)
1281 logger = logging.getLogger("compiler.parser")
1282 # See issue #11424. compiler-hyphenated sorts
1283 # between compiler and compiler.xyz and this
1284 # was preventing compiler.xyz from being included
1285 # in the child loggers of compiler because of an
1286 # overzealous loop termination condition.
1287 hyphenated = logging.getLogger('compiler-hyphenated')
1288 # All will output a message
1289 logger.info(self.next_message())
1290 logger.error(self.next_message())
1291 hyphenated.critical(self.next_message())
1292 self.assert_log_lines([
1293 ('INFO', '1'),
1294 ('ERROR', '2'),
1295 ('CRITICAL', '3'),
1296 ], stream=output)
1297 # Original logger output is empty.
1298 self.assert_log_lines([])
1299 with captured_stdout() as output:
1300 self.apply_config(self.config7)
1301 logger = logging.getLogger("compiler.parser")
1302 self.assertFalse(logger.disabled)
1303 # Both will output a message
1304 logger.info(self.next_message())
1305 logger.error(self.next_message())
1306 logger = logging.getLogger("compiler.lexer")
1307 # Both will output a message
1308 logger.info(self.next_message())
1309 logger.error(self.next_message())
1310 # Will not appear
1311 hyphenated.critical(self.next_message())
1312 self.assert_log_lines([
1313 ('INFO', '4'),
1314 ('ERROR', '5'),
1315 ('INFO', '6'),
1316 ('ERROR', '7'),
1317 ], stream=output)
1318 # Original logger output is empty.
1319 self.assert_log_lines([])
1320
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001321
Victor Stinner45df8202010-04-28 22:31:17 +00001322@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001323class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001324
Christian Heimes180510d2008-03-03 19:15:45 +00001325 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001326
Christian Heimes180510d2008-03-03 19:15:45 +00001327 def setUp(self):
1328 """Set up a TCP server to receive log messages, and a SocketHandler
1329 pointing to that server's address and port."""
1330 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001331 addr = ('localhost', 0)
1332 self.server = server = TestTCPServer(addr, self.handle_socket,
1333 0.01)
1334 server.start()
1335 server.ready.wait()
1336 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1337 server.port)
1338 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001339 self.root_logger.removeHandler(self.root_logger.handlers[0])
1340 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001341 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001342
Christian Heimes180510d2008-03-03 19:15:45 +00001343 def tearDown(self):
1344 """Shutdown the TCP server."""
1345 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001346 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001347 self.root_logger.removeHandler(self.sock_hdlr)
1348 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001349 finally:
1350 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001351
Vinay Sajip7367d082011-05-02 13:17:27 +01001352 def handle_socket(self, request):
1353 conn = request.connection
1354 while True:
1355 chunk = conn.recv(4)
1356 if len(chunk) < 4:
1357 break
1358 slen = struct.unpack(">L", chunk)[0]
1359 chunk = conn.recv(slen)
1360 while len(chunk) < slen:
1361 chunk = chunk + conn.recv(slen - len(chunk))
1362 obj = pickle.loads(chunk)
1363 record = logging.makeLogRecord(obj)
1364 self.log_output += record.msg + '\n'
1365 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001366
Christian Heimes180510d2008-03-03 19:15:45 +00001367 def test_output(self):
1368 # The log message sent to the SocketHandler is properly received.
1369 logger = logging.getLogger("tcp")
1370 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001371 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001372 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001373 self.handled.acquire()
1374 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001375
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001376 def test_noserver(self):
1377 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001378 self.server.stop(2.0)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001379 #The logging call should try to connect, which should fail
1380 try:
1381 raise RuntimeError('Deliberate mistake')
1382 except RuntimeError:
1383 self.root_logger.exception('Never sent')
1384 self.root_logger.error('Never sent, either')
1385 now = time.time()
1386 self.assertTrue(self.sock_hdlr.retryTime > now)
1387 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1388 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001389
Vinay Sajip7367d082011-05-02 13:17:27 +01001390
1391@unittest.skipUnless(threading, 'Threading required for this test.')
1392class DatagramHandlerTest(BaseTest):
1393
1394 """Test for DatagramHandler."""
1395
1396 def setUp(self):
1397 """Set up a UDP server to receive log messages, and a DatagramHandler
1398 pointing to that server's address and port."""
1399 BaseTest.setUp(self)
1400 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001401 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001402 server.start()
1403 server.ready.wait()
1404 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1405 server.port)
1406 self.log_output = ''
1407 self.root_logger.removeHandler(self.root_logger.handlers[0])
1408 self.root_logger.addHandler(self.sock_hdlr)
1409 self.handled = threading.Event()
1410
1411 def tearDown(self):
1412 """Shutdown the UDP server."""
1413 try:
1414 self.server.stop(2.0)
1415 self.root_logger.removeHandler(self.sock_hdlr)
1416 self.sock_hdlr.close()
1417 finally:
1418 BaseTest.tearDown(self)
1419
1420 def handle_datagram(self, request):
1421 slen = struct.pack('>L', 0) # length of prefix
1422 packet = request.packet[len(slen):]
1423 obj = pickle.loads(packet)
1424 record = logging.makeLogRecord(obj)
1425 self.log_output += record.msg + '\n'
1426 self.handled.set()
1427
1428 def test_output(self):
1429 # The log message sent to the DatagramHandler is properly received.
1430 logger = logging.getLogger("udp")
1431 logger.error("spam")
1432 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001433 self.handled.clear()
1434 logger.error("eggs")
1435 self.handled.wait()
1436 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001437
1438
1439@unittest.skipUnless(threading, 'Threading required for this test.')
1440class SysLogHandlerTest(BaseTest):
1441
1442 """Test for SysLogHandler using UDP."""
1443
1444 def setUp(self):
1445 """Set up a UDP server to receive log messages, and a SysLogHandler
1446 pointing to that server's address and port."""
1447 BaseTest.setUp(self)
1448 addr = ('localhost', 0)
1449 self.server = server = TestUDPServer(addr, self.handle_datagram,
1450 0.01)
1451 server.start()
1452 server.ready.wait()
1453 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1454 server.port))
1455 self.log_output = ''
1456 self.root_logger.removeHandler(self.root_logger.handlers[0])
1457 self.root_logger.addHandler(self.sl_hdlr)
1458 self.handled = threading.Event()
1459
1460 def tearDown(self):
1461 """Shutdown the UDP server."""
1462 try:
1463 self.server.stop(2.0)
1464 self.root_logger.removeHandler(self.sl_hdlr)
1465 self.sl_hdlr.close()
1466 finally:
1467 BaseTest.tearDown(self)
1468
1469 def handle_datagram(self, request):
1470 self.log_output = request.packet
1471 self.handled.set()
1472
1473 def test_output(self):
1474 # The log message sent to the SysLogHandler is properly received.
1475 logger = logging.getLogger("slh")
1476 logger.error("sp\xe4m")
1477 self.handled.wait()
1478 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001479 self.handled.clear()
1480 self.sl_hdlr.append_nul = False
1481 logger.error("sp\xe4m")
1482 self.handled.wait()
1483 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001484 self.handled.clear()
1485 self.sl_hdlr.ident = "h\xe4m-"
1486 logger.error("sp\xe4m")
1487 self.handled.wait()
1488 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfh\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001489
1490
1491@unittest.skipUnless(threading, 'Threading required for this test.')
1492class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001493 """Test for HTTPHandler."""
1494
Vinay Sajip9ba87612011-05-21 11:32:15 +01001495 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1496MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1497zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1498aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1499AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15000tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15015LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1502piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15032z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1504i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1505PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1506E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1507rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1508/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1509-----END RSA PRIVATE KEY-----
1510-----BEGIN CERTIFICATE-----
1511MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1512BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1513EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1514xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1515l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1516vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1517BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1518S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1519BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15204f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15211c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1522IRbTpvlHWPjsSvHz0ZOH
1523-----END CERTIFICATE-----"""
1524
Vinay Sajip7367d082011-05-02 13:17:27 +01001525 def setUp(self):
1526 """Set up an HTTP server to receive log messages, and a HTTPHandler
1527 pointing to that server's address and port."""
1528 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001529 self.handled = threading.Event()
1530
Vinay Sajip7367d082011-05-02 13:17:27 +01001531 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001532 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001533 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001534 if self.command == 'POST':
1535 try:
1536 rlen = int(request.headers['Content-Length'])
1537 self.post_data = request.rfile.read(rlen)
1538 except:
1539 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001540 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001541 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001542 self.handled.set()
1543
1544 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001545 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001546 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001547 root_logger = self.root_logger
1548 root_logger.removeHandler(self.root_logger.handlers[0])
1549 for secure in (False, True):
1550 addr = ('localhost', 0)
1551 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001552 try:
1553 import ssl
1554 fd, fn = tempfile.mkstemp()
1555 os.close(fd)
1556 with open(fn, 'w') as f:
1557 f.write(self.PEMFILE)
1558 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1559 sslctx.load_cert_chain(fn)
1560 os.unlink(fn)
1561 except ImportError:
1562 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001563 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001564 sslctx = None
1565 self.server = server = TestHTTPServer(addr, self.handle_request,
1566 0.01, sslctx=sslctx)
1567 server.start()
1568 server.ready.wait()
1569 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001570 secure_client = secure and sslctx
1571 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1572 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001573 self.log_data = None
1574 root_logger.addHandler(self.h_hdlr)
1575
1576 for method in ('GET', 'POST'):
1577 self.h_hdlr.method = method
1578 self.handled.clear()
1579 msg = "sp\xe4m"
1580 logger.error(msg)
1581 self.handled.wait()
1582 self.assertEqual(self.log_data.path, '/frob')
1583 self.assertEqual(self.command, method)
1584 if method == 'GET':
1585 d = parse_qs(self.log_data.query)
1586 else:
1587 d = parse_qs(self.post_data.decode('utf-8'))
1588 self.assertEqual(d['name'], ['http'])
1589 self.assertEqual(d['funcName'], ['test_output'])
1590 self.assertEqual(d['msg'], [msg])
1591
1592 self.server.stop(2.0)
1593 self.root_logger.removeHandler(self.h_hdlr)
1594 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001595
Christian Heimes180510d2008-03-03 19:15:45 +00001596class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001597
Christian Heimes180510d2008-03-03 19:15:45 +00001598 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001599
Christian Heimes180510d2008-03-03 19:15:45 +00001600 def setUp(self):
1601 """Create a dict to remember potentially destroyed objects."""
1602 BaseTest.setUp(self)
1603 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001604
Christian Heimes180510d2008-03-03 19:15:45 +00001605 def _watch_for_survival(self, *args):
1606 """Watch the given objects for survival, by creating weakrefs to
1607 them."""
1608 for obj in args:
1609 key = id(obj), repr(obj)
1610 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001611
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001612 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001613 """Assert that all objects watched for survival have survived."""
1614 # Trigger cycle breaking.
1615 gc.collect()
1616 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001617 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001618 if ref() is None:
1619 dead.append(repr_)
1620 if dead:
1621 self.fail("%d objects should have survived "
1622 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001623
Christian Heimes180510d2008-03-03 19:15:45 +00001624 def test_persistent_loggers(self):
1625 # Logger objects are persistent and retain their configuration, even
1626 # if visible references are destroyed.
1627 self.root_logger.setLevel(logging.INFO)
1628 foo = logging.getLogger("foo")
1629 self._watch_for_survival(foo)
1630 foo.setLevel(logging.DEBUG)
1631 self.root_logger.debug(self.next_message())
1632 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001633 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001634 ('foo', 'DEBUG', '2'),
1635 ])
1636 del foo
1637 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001638 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001639 # foo has retained its settings.
1640 bar = logging.getLogger("foo")
1641 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001642 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001643 ('foo', 'DEBUG', '2'),
1644 ('foo', 'DEBUG', '3'),
1645 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001646
Benjamin Petersonf91df042009-02-13 02:50:59 +00001647
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001648class EncodingTest(BaseTest):
1649 def test_encoding_plain_file(self):
1650 # In Python 2.x, a plain file object is treated as having no encoding.
1651 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001652 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1653 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001654 # the non-ascii data we write to the log.
1655 data = "foo\x80"
1656 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001657 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001658 log.addHandler(handler)
1659 try:
1660 # write non-ascii data to the log.
1661 log.warning(data)
1662 finally:
1663 log.removeHandler(handler)
1664 handler.close()
1665 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001666 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001667 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001668 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001669 finally:
1670 f.close()
1671 finally:
1672 if os.path.isfile(fn):
1673 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001674
Benjamin Petersonf91df042009-02-13 02:50:59 +00001675 def test_encoding_cyrillic_unicode(self):
1676 log = logging.getLogger("test")
1677 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1678 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1679 #Ensure it's written in a Cyrillic encoding
1680 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001681 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001682 stream = io.BytesIO()
1683 writer = writer_class(stream, 'strict')
1684 handler = logging.StreamHandler(writer)
1685 log.addHandler(handler)
1686 try:
1687 log.warning(message)
1688 finally:
1689 log.removeHandler(handler)
1690 handler.close()
1691 # check we wrote exactly those bytes, ignoring trailing \n etc
1692 s = stream.getvalue()
1693 #Compare against what the data should be when encoded in CP-1251
1694 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1695
1696
Georg Brandlf9734072008-12-07 15:30:06 +00001697class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001698
Georg Brandlf9734072008-12-07 15:30:06 +00001699 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001700 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001701 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001702 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001703 warnings.filterwarnings("always", category=UserWarning)
1704 stream = io.StringIO()
1705 h = logging.StreamHandler(stream)
1706 logger = logging.getLogger("py.warnings")
1707 logger.addHandler(h)
1708 warnings.warn("I'm warning you...")
1709 logger.removeHandler(h)
1710 s = stream.getvalue()
1711 h.close()
1712 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001713
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001714 #See if an explicit file uses the original implementation
1715 a_file = io.StringIO()
1716 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1717 a_file, "Dummy line")
1718 s = a_file.getvalue()
1719 a_file.close()
1720 self.assertEqual(s,
1721 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1722
1723 def test_warnings_no_handlers(self):
1724 with warnings.catch_warnings():
1725 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001726 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001727
1728 # confirm our assumption: no loggers are set
1729 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001730 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001731
1732 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001733 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001734 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001735
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001736
1737def formatFunc(format, datefmt=None):
1738 return logging.Formatter(format, datefmt)
1739
1740def handlerFunc():
1741 return logging.StreamHandler()
1742
1743class CustomHandler(logging.StreamHandler):
1744 pass
1745
1746class ConfigDictTest(BaseTest):
1747
1748 """Reading logging config from a dictionary."""
1749
1750 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1751
1752 # config0 is a standard configuration.
1753 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001754 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001755 'formatters': {
1756 'form1' : {
1757 'format' : '%(levelname)s ++ %(message)s',
1758 },
1759 },
1760 'handlers' : {
1761 'hand1' : {
1762 'class' : 'logging.StreamHandler',
1763 'formatter' : 'form1',
1764 'level' : 'NOTSET',
1765 'stream' : 'ext://sys.stdout',
1766 },
1767 },
1768 'root' : {
1769 'level' : 'WARNING',
1770 'handlers' : ['hand1'],
1771 },
1772 }
1773
1774 # config1 adds a little to the standard configuration.
1775 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001776 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001777 'formatters': {
1778 'form1' : {
1779 'format' : '%(levelname)s ++ %(message)s',
1780 },
1781 },
1782 'handlers' : {
1783 'hand1' : {
1784 'class' : 'logging.StreamHandler',
1785 'formatter' : 'form1',
1786 'level' : 'NOTSET',
1787 'stream' : 'ext://sys.stdout',
1788 },
1789 },
1790 'loggers' : {
1791 'compiler.parser' : {
1792 'level' : 'DEBUG',
1793 'handlers' : ['hand1'],
1794 },
1795 },
1796 'root' : {
1797 'level' : 'WARNING',
1798 },
1799 }
1800
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001801 # config1a moves the handler to the root. Used with config8a
1802 config1a = {
1803 'version': 1,
1804 'formatters': {
1805 'form1' : {
1806 'format' : '%(levelname)s ++ %(message)s',
1807 },
1808 },
1809 'handlers' : {
1810 'hand1' : {
1811 'class' : 'logging.StreamHandler',
1812 'formatter' : 'form1',
1813 'level' : 'NOTSET',
1814 'stream' : 'ext://sys.stdout',
1815 },
1816 },
1817 'loggers' : {
1818 'compiler.parser' : {
1819 'level' : 'DEBUG',
1820 },
1821 },
1822 'root' : {
1823 'level' : 'WARNING',
1824 'handlers' : ['hand1'],
1825 },
1826 }
1827
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001828 # config2 has a subtle configuration error that should be reported
1829 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001830 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001831 'formatters': {
1832 'form1' : {
1833 'format' : '%(levelname)s ++ %(message)s',
1834 },
1835 },
1836 'handlers' : {
1837 'hand1' : {
1838 'class' : 'logging.StreamHandler',
1839 'formatter' : 'form1',
1840 'level' : 'NOTSET',
1841 'stream' : 'ext://sys.stdbout',
1842 },
1843 },
1844 'loggers' : {
1845 'compiler.parser' : {
1846 'level' : 'DEBUG',
1847 'handlers' : ['hand1'],
1848 },
1849 },
1850 'root' : {
1851 'level' : 'WARNING',
1852 },
1853 }
1854
1855 #As config1 but with a misspelt level on a handler
1856 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001857 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001858 'formatters': {
1859 'form1' : {
1860 'format' : '%(levelname)s ++ %(message)s',
1861 },
1862 },
1863 'handlers' : {
1864 'hand1' : {
1865 'class' : 'logging.StreamHandler',
1866 'formatter' : 'form1',
1867 'level' : 'NTOSET',
1868 'stream' : 'ext://sys.stdout',
1869 },
1870 },
1871 'loggers' : {
1872 'compiler.parser' : {
1873 'level' : 'DEBUG',
1874 'handlers' : ['hand1'],
1875 },
1876 },
1877 'root' : {
1878 'level' : 'WARNING',
1879 },
1880 }
1881
1882
1883 #As config1 but with a misspelt level on a logger
1884 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001885 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001886 'formatters': {
1887 'form1' : {
1888 'format' : '%(levelname)s ++ %(message)s',
1889 },
1890 },
1891 'handlers' : {
1892 'hand1' : {
1893 'class' : 'logging.StreamHandler',
1894 'formatter' : 'form1',
1895 'level' : 'NOTSET',
1896 'stream' : 'ext://sys.stdout',
1897 },
1898 },
1899 'loggers' : {
1900 'compiler.parser' : {
1901 'level' : 'DEBUG',
1902 'handlers' : ['hand1'],
1903 },
1904 },
1905 'root' : {
1906 'level' : 'WRANING',
1907 },
1908 }
1909
1910 # config3 has a less subtle configuration error
1911 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001912 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001913 'formatters': {
1914 'form1' : {
1915 'format' : '%(levelname)s ++ %(message)s',
1916 },
1917 },
1918 'handlers' : {
1919 'hand1' : {
1920 'class' : 'logging.StreamHandler',
1921 'formatter' : 'misspelled_name',
1922 'level' : 'NOTSET',
1923 'stream' : 'ext://sys.stdout',
1924 },
1925 },
1926 'loggers' : {
1927 'compiler.parser' : {
1928 'level' : 'DEBUG',
1929 'handlers' : ['hand1'],
1930 },
1931 },
1932 'root' : {
1933 'level' : 'WARNING',
1934 },
1935 }
1936
1937 # config4 specifies a custom formatter class to be loaded
1938 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001939 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001940 'formatters': {
1941 'form1' : {
1942 '()' : __name__ + '.ExceptionFormatter',
1943 'format' : '%(levelname)s:%(name)s:%(message)s',
1944 },
1945 },
1946 'handlers' : {
1947 'hand1' : {
1948 'class' : 'logging.StreamHandler',
1949 'formatter' : 'form1',
1950 'level' : 'NOTSET',
1951 'stream' : 'ext://sys.stdout',
1952 },
1953 },
1954 'root' : {
1955 'level' : 'NOTSET',
1956 'handlers' : ['hand1'],
1957 },
1958 }
1959
1960 # As config4 but using an actual callable rather than a string
1961 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001962 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001963 'formatters': {
1964 'form1' : {
1965 '()' : ExceptionFormatter,
1966 'format' : '%(levelname)s:%(name)s:%(message)s',
1967 },
1968 'form2' : {
1969 '()' : __name__ + '.formatFunc',
1970 'format' : '%(levelname)s:%(name)s:%(message)s',
1971 },
1972 'form3' : {
1973 '()' : formatFunc,
1974 'format' : '%(levelname)s:%(name)s:%(message)s',
1975 },
1976 },
1977 'handlers' : {
1978 'hand1' : {
1979 'class' : 'logging.StreamHandler',
1980 'formatter' : 'form1',
1981 'level' : 'NOTSET',
1982 'stream' : 'ext://sys.stdout',
1983 },
1984 'hand2' : {
1985 '()' : handlerFunc,
1986 },
1987 },
1988 'root' : {
1989 'level' : 'NOTSET',
1990 'handlers' : ['hand1'],
1991 },
1992 }
1993
1994 # config5 specifies a custom handler class to be loaded
1995 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001996 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001997 'formatters': {
1998 'form1' : {
1999 'format' : '%(levelname)s ++ %(message)s',
2000 },
2001 },
2002 'handlers' : {
2003 'hand1' : {
2004 'class' : __name__ + '.CustomHandler',
2005 'formatter' : 'form1',
2006 'level' : 'NOTSET',
2007 'stream' : 'ext://sys.stdout',
2008 },
2009 },
2010 'loggers' : {
2011 'compiler.parser' : {
2012 'level' : 'DEBUG',
2013 'handlers' : ['hand1'],
2014 },
2015 },
2016 'root' : {
2017 'level' : 'WARNING',
2018 },
2019 }
2020
2021 # config6 specifies a custom handler class to be loaded
2022 # but has bad arguments
2023 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002024 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002025 'formatters': {
2026 'form1' : {
2027 'format' : '%(levelname)s ++ %(message)s',
2028 },
2029 },
2030 'handlers' : {
2031 'hand1' : {
2032 'class' : __name__ + '.CustomHandler',
2033 'formatter' : 'form1',
2034 'level' : 'NOTSET',
2035 'stream' : 'ext://sys.stdout',
2036 '9' : 'invalid parameter name',
2037 },
2038 },
2039 'loggers' : {
2040 'compiler.parser' : {
2041 'level' : 'DEBUG',
2042 'handlers' : ['hand1'],
2043 },
2044 },
2045 'root' : {
2046 'level' : 'WARNING',
2047 },
2048 }
2049
2050 #config 7 does not define compiler.parser but defines compiler.lexer
2051 #so compiler.parser should be disabled after applying it
2052 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002053 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002054 'formatters': {
2055 'form1' : {
2056 'format' : '%(levelname)s ++ %(message)s',
2057 },
2058 },
2059 'handlers' : {
2060 'hand1' : {
2061 'class' : 'logging.StreamHandler',
2062 'formatter' : 'form1',
2063 'level' : 'NOTSET',
2064 'stream' : 'ext://sys.stdout',
2065 },
2066 },
2067 'loggers' : {
2068 'compiler.lexer' : {
2069 'level' : 'DEBUG',
2070 'handlers' : ['hand1'],
2071 },
2072 },
2073 'root' : {
2074 'level' : 'WARNING',
2075 },
2076 }
2077
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002078 # config8 defines both compiler and compiler.lexer
2079 # so compiler.parser should not be disabled (since
2080 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002081 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002082 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002083 'disable_existing_loggers' : False,
2084 'formatters': {
2085 'form1' : {
2086 'format' : '%(levelname)s ++ %(message)s',
2087 },
2088 },
2089 'handlers' : {
2090 'hand1' : {
2091 'class' : 'logging.StreamHandler',
2092 'formatter' : 'form1',
2093 'level' : 'NOTSET',
2094 'stream' : 'ext://sys.stdout',
2095 },
2096 },
2097 'loggers' : {
2098 'compiler' : {
2099 'level' : 'DEBUG',
2100 'handlers' : ['hand1'],
2101 },
2102 'compiler.lexer' : {
2103 },
2104 },
2105 'root' : {
2106 'level' : 'WARNING',
2107 },
2108 }
2109
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002110 # config8a disables existing loggers
2111 config8a = {
2112 'version': 1,
2113 'disable_existing_loggers' : True,
2114 'formatters': {
2115 'form1' : {
2116 'format' : '%(levelname)s ++ %(message)s',
2117 },
2118 },
2119 'handlers' : {
2120 'hand1' : {
2121 'class' : 'logging.StreamHandler',
2122 'formatter' : 'form1',
2123 'level' : 'NOTSET',
2124 'stream' : 'ext://sys.stdout',
2125 },
2126 },
2127 'loggers' : {
2128 'compiler' : {
2129 'level' : 'DEBUG',
2130 'handlers' : ['hand1'],
2131 },
2132 'compiler.lexer' : {
2133 },
2134 },
2135 'root' : {
2136 'level' : 'WARNING',
2137 },
2138 }
2139
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002140 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002141 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002142 'formatters': {
2143 'form1' : {
2144 'format' : '%(levelname)s ++ %(message)s',
2145 },
2146 },
2147 'handlers' : {
2148 'hand1' : {
2149 'class' : 'logging.StreamHandler',
2150 'formatter' : 'form1',
2151 'level' : 'WARNING',
2152 'stream' : 'ext://sys.stdout',
2153 },
2154 },
2155 'loggers' : {
2156 'compiler.parser' : {
2157 'level' : 'WARNING',
2158 'handlers' : ['hand1'],
2159 },
2160 },
2161 'root' : {
2162 'level' : 'NOTSET',
2163 },
2164 }
2165
2166 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002167 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002168 'incremental' : True,
2169 'handlers' : {
2170 'hand1' : {
2171 'level' : 'WARNING',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.parser' : {
2176 'level' : 'INFO',
2177 },
2178 },
2179 }
2180
2181 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002182 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002183 'incremental' : True,
2184 'handlers' : {
2185 'hand1' : {
2186 'level' : 'INFO',
2187 },
2188 },
2189 'loggers' : {
2190 'compiler.parser' : {
2191 'level' : 'INFO',
2192 },
2193 },
2194 }
2195
2196 #As config1 but with a filter added
2197 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002198 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002199 'formatters': {
2200 'form1' : {
2201 'format' : '%(levelname)s ++ %(message)s',
2202 },
2203 },
2204 'filters' : {
2205 'filt1' : {
2206 'name' : 'compiler.parser',
2207 },
2208 },
2209 'handlers' : {
2210 'hand1' : {
2211 'class' : 'logging.StreamHandler',
2212 'formatter' : 'form1',
2213 'level' : 'NOTSET',
2214 'stream' : 'ext://sys.stdout',
2215 'filters' : ['filt1'],
2216 },
2217 },
2218 'loggers' : {
2219 'compiler.parser' : {
2220 'level' : 'DEBUG',
2221 'filters' : ['filt1'],
2222 },
2223 },
2224 'root' : {
2225 'level' : 'WARNING',
2226 'handlers' : ['hand1'],
2227 },
2228 }
2229
2230 #As config1 but using cfg:// references
2231 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002232 'version': 1,
2233 'true_formatters': {
2234 'form1' : {
2235 'format' : '%(levelname)s ++ %(message)s',
2236 },
2237 },
2238 'handler_configs': {
2239 'hand1' : {
2240 'class' : 'logging.StreamHandler',
2241 'formatter' : 'form1',
2242 'level' : 'NOTSET',
2243 'stream' : 'ext://sys.stdout',
2244 },
2245 },
2246 'formatters' : 'cfg://true_formatters',
2247 'handlers' : {
2248 'hand1' : 'cfg://handler_configs[hand1]',
2249 },
2250 'loggers' : {
2251 'compiler.parser' : {
2252 'level' : 'DEBUG',
2253 'handlers' : ['hand1'],
2254 },
2255 },
2256 'root' : {
2257 'level' : 'WARNING',
2258 },
2259 }
2260
2261 #As config11 but missing the version key
2262 config12 = {
2263 'true_formatters': {
2264 'form1' : {
2265 'format' : '%(levelname)s ++ %(message)s',
2266 },
2267 },
2268 'handler_configs': {
2269 'hand1' : {
2270 'class' : 'logging.StreamHandler',
2271 'formatter' : 'form1',
2272 'level' : 'NOTSET',
2273 'stream' : 'ext://sys.stdout',
2274 },
2275 },
2276 'formatters' : 'cfg://true_formatters',
2277 'handlers' : {
2278 'hand1' : 'cfg://handler_configs[hand1]',
2279 },
2280 'loggers' : {
2281 'compiler.parser' : {
2282 'level' : 'DEBUG',
2283 'handlers' : ['hand1'],
2284 },
2285 },
2286 'root' : {
2287 'level' : 'WARNING',
2288 },
2289 }
2290
2291 #As config11 but using an unsupported version
2292 config13 = {
2293 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002294 'true_formatters': {
2295 'form1' : {
2296 'format' : '%(levelname)s ++ %(message)s',
2297 },
2298 },
2299 'handler_configs': {
2300 'hand1' : {
2301 'class' : 'logging.StreamHandler',
2302 'formatter' : 'form1',
2303 'level' : 'NOTSET',
2304 'stream' : 'ext://sys.stdout',
2305 },
2306 },
2307 'formatters' : 'cfg://true_formatters',
2308 'handlers' : {
2309 'hand1' : 'cfg://handler_configs[hand1]',
2310 },
2311 'loggers' : {
2312 'compiler.parser' : {
2313 'level' : 'DEBUG',
2314 'handlers' : ['hand1'],
2315 },
2316 },
2317 'root' : {
2318 'level' : 'WARNING',
2319 },
2320 }
2321
2322 def apply_config(self, conf):
2323 logging.config.dictConfig(conf)
2324
2325 def test_config0_ok(self):
2326 # A simple config which overrides the default settings.
2327 with captured_stdout() as output:
2328 self.apply_config(self.config0)
2329 logger = logging.getLogger()
2330 # Won't output anything
2331 logger.info(self.next_message())
2332 # Outputs a message
2333 logger.error(self.next_message())
2334 self.assert_log_lines([
2335 ('ERROR', '2'),
2336 ], stream=output)
2337 # Original logger output is empty.
2338 self.assert_log_lines([])
2339
2340 def test_config1_ok(self, config=config1):
2341 # A config defining a sub-parser as well.
2342 with captured_stdout() as output:
2343 self.apply_config(config)
2344 logger = logging.getLogger("compiler.parser")
2345 # Both will output a message
2346 logger.info(self.next_message())
2347 logger.error(self.next_message())
2348 self.assert_log_lines([
2349 ('INFO', '1'),
2350 ('ERROR', '2'),
2351 ], stream=output)
2352 # Original logger output is empty.
2353 self.assert_log_lines([])
2354
2355 def test_config2_failure(self):
2356 # A simple config which overrides the default settings.
2357 self.assertRaises(Exception, self.apply_config, self.config2)
2358
2359 def test_config2a_failure(self):
2360 # A simple config which overrides the default settings.
2361 self.assertRaises(Exception, self.apply_config, self.config2a)
2362
2363 def test_config2b_failure(self):
2364 # A simple config which overrides the default settings.
2365 self.assertRaises(Exception, self.apply_config, self.config2b)
2366
2367 def test_config3_failure(self):
2368 # A simple config which overrides the default settings.
2369 self.assertRaises(Exception, self.apply_config, self.config3)
2370
2371 def test_config4_ok(self):
2372 # A config specifying a custom formatter class.
2373 with captured_stdout() as output:
2374 self.apply_config(self.config4)
2375 #logger = logging.getLogger()
2376 try:
2377 raise RuntimeError()
2378 except RuntimeError:
2379 logging.exception("just testing")
2380 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002381 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002382 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2383 # Original logger output is empty
2384 self.assert_log_lines([])
2385
2386 def test_config4a_ok(self):
2387 # A config specifying a custom formatter class.
2388 with captured_stdout() as output:
2389 self.apply_config(self.config4a)
2390 #logger = logging.getLogger()
2391 try:
2392 raise RuntimeError()
2393 except RuntimeError:
2394 logging.exception("just testing")
2395 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002396 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002397 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2398 # Original logger output is empty
2399 self.assert_log_lines([])
2400
2401 def test_config5_ok(self):
2402 self.test_config1_ok(config=self.config5)
2403
2404 def test_config6_failure(self):
2405 self.assertRaises(Exception, self.apply_config, self.config6)
2406
2407 def test_config7_ok(self):
2408 with captured_stdout() as output:
2409 self.apply_config(self.config1)
2410 logger = logging.getLogger("compiler.parser")
2411 # Both will output a message
2412 logger.info(self.next_message())
2413 logger.error(self.next_message())
2414 self.assert_log_lines([
2415 ('INFO', '1'),
2416 ('ERROR', '2'),
2417 ], stream=output)
2418 # Original logger output is empty.
2419 self.assert_log_lines([])
2420 with captured_stdout() as output:
2421 self.apply_config(self.config7)
2422 logger = logging.getLogger("compiler.parser")
2423 self.assertTrue(logger.disabled)
2424 logger = logging.getLogger("compiler.lexer")
2425 # Both will output a message
2426 logger.info(self.next_message())
2427 logger.error(self.next_message())
2428 self.assert_log_lines([
2429 ('INFO', '3'),
2430 ('ERROR', '4'),
2431 ], stream=output)
2432 # Original logger output is empty.
2433 self.assert_log_lines([])
2434
2435 #Same as test_config_7_ok but don't disable old loggers.
2436 def test_config_8_ok(self):
2437 with captured_stdout() as output:
2438 self.apply_config(self.config1)
2439 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002440 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002441 logger.info(self.next_message())
2442 logger.error(self.next_message())
2443 self.assert_log_lines([
2444 ('INFO', '1'),
2445 ('ERROR', '2'),
2446 ], stream=output)
2447 # Original logger output is empty.
2448 self.assert_log_lines([])
2449 with captured_stdout() as output:
2450 self.apply_config(self.config8)
2451 logger = logging.getLogger("compiler.parser")
2452 self.assertFalse(logger.disabled)
2453 # Both will output a message
2454 logger.info(self.next_message())
2455 logger.error(self.next_message())
2456 logger = logging.getLogger("compiler.lexer")
2457 # Both will output a message
2458 logger.info(self.next_message())
2459 logger.error(self.next_message())
2460 self.assert_log_lines([
2461 ('INFO', '3'),
2462 ('ERROR', '4'),
2463 ('INFO', '5'),
2464 ('ERROR', '6'),
2465 ], stream=output)
2466 # Original logger output is empty.
2467 self.assert_log_lines([])
2468
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002469 def test_config_8a_ok(self):
2470 with captured_stdout() as output:
2471 self.apply_config(self.config1a)
2472 logger = logging.getLogger("compiler.parser")
2473 # See issue #11424. compiler-hyphenated sorts
2474 # between compiler and compiler.xyz and this
2475 # was preventing compiler.xyz from being included
2476 # in the child loggers of compiler because of an
2477 # overzealous loop termination condition.
2478 hyphenated = logging.getLogger('compiler-hyphenated')
2479 # All will output a message
2480 logger.info(self.next_message())
2481 logger.error(self.next_message())
2482 hyphenated.critical(self.next_message())
2483 self.assert_log_lines([
2484 ('INFO', '1'),
2485 ('ERROR', '2'),
2486 ('CRITICAL', '3'),
2487 ], stream=output)
2488 # Original logger output is empty.
2489 self.assert_log_lines([])
2490 with captured_stdout() as output:
2491 self.apply_config(self.config8a)
2492 logger = logging.getLogger("compiler.parser")
2493 self.assertFalse(logger.disabled)
2494 # Both will output a message
2495 logger.info(self.next_message())
2496 logger.error(self.next_message())
2497 logger = logging.getLogger("compiler.lexer")
2498 # Both will output a message
2499 logger.info(self.next_message())
2500 logger.error(self.next_message())
2501 # Will not appear
2502 hyphenated.critical(self.next_message())
2503 self.assert_log_lines([
2504 ('INFO', '4'),
2505 ('ERROR', '5'),
2506 ('INFO', '6'),
2507 ('ERROR', '7'),
2508 ], stream=output)
2509 # Original logger output is empty.
2510 self.assert_log_lines([])
2511
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002512 def test_config_9_ok(self):
2513 with captured_stdout() as output:
2514 self.apply_config(self.config9)
2515 logger = logging.getLogger("compiler.parser")
2516 #Nothing will be output since both handler and logger are set to WARNING
2517 logger.info(self.next_message())
2518 self.assert_log_lines([], stream=output)
2519 self.apply_config(self.config9a)
2520 #Nothing will be output since both handler is still set to WARNING
2521 logger.info(self.next_message())
2522 self.assert_log_lines([], stream=output)
2523 self.apply_config(self.config9b)
2524 #Message should now be output
2525 logger.info(self.next_message())
2526 self.assert_log_lines([
2527 ('INFO', '3'),
2528 ], stream=output)
2529
2530 def test_config_10_ok(self):
2531 with captured_stdout() as output:
2532 self.apply_config(self.config10)
2533 logger = logging.getLogger("compiler.parser")
2534 logger.warning(self.next_message())
2535 logger = logging.getLogger('compiler')
2536 #Not output, because filtered
2537 logger.warning(self.next_message())
2538 logger = logging.getLogger('compiler.lexer')
2539 #Not output, because filtered
2540 logger.warning(self.next_message())
2541 logger = logging.getLogger("compiler.parser.codegen")
2542 #Output, as not filtered
2543 logger.error(self.next_message())
2544 self.assert_log_lines([
2545 ('WARNING', '1'),
2546 ('ERROR', '4'),
2547 ], stream=output)
2548
2549 def test_config11_ok(self):
2550 self.test_config1_ok(self.config11)
2551
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002552 def test_config12_failure(self):
2553 self.assertRaises(Exception, self.apply_config, self.config12)
2554
2555 def test_config13_failure(self):
2556 self.assertRaises(Exception, self.apply_config, self.config13)
2557
Victor Stinner45df8202010-04-28 22:31:17 +00002558 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002559 def setup_via_listener(self, text):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002560 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002561 # Ask for a randomly assigned port (by using port 0)
2562 t = logging.config.listen(0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002563 t.start()
2564 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002565 # Now get the port allocated
2566 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002567 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002568 try:
2569 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2570 sock.settimeout(2.0)
2571 sock.connect(('localhost', port))
2572
2573 slen = struct.pack('>L', len(text))
2574 s = slen + text
2575 sentsofar = 0
2576 left = len(s)
2577 while left > 0:
2578 sent = sock.send(s[sentsofar:])
2579 sentsofar += sent
2580 left -= sent
2581 sock.close()
2582 finally:
2583 t.ready.wait(2.0)
2584 logging.config.stopListening()
2585 t.join(2.0)
2586
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002587 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002588 def test_listen_config_10_ok(self):
2589 with captured_stdout() as output:
2590 self.setup_via_listener(json.dumps(self.config10))
2591 logger = logging.getLogger("compiler.parser")
2592 logger.warning(self.next_message())
2593 logger = logging.getLogger('compiler')
2594 #Not output, because filtered
2595 logger.warning(self.next_message())
2596 logger = logging.getLogger('compiler.lexer')
2597 #Not output, because filtered
2598 logger.warning(self.next_message())
2599 logger = logging.getLogger("compiler.parser.codegen")
2600 #Output, as not filtered
2601 logger.error(self.next_message())
2602 self.assert_log_lines([
2603 ('WARNING', '1'),
2604 ('ERROR', '4'),
2605 ], stream=output)
2606
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002607 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002608 def test_listen_config_1_ok(self):
2609 with captured_stdout() as output:
2610 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2611 logger = logging.getLogger("compiler.parser")
2612 # Both will output a message
2613 logger.info(self.next_message())
2614 logger.error(self.next_message())
2615 self.assert_log_lines([
2616 ('INFO', '1'),
2617 ('ERROR', '2'),
2618 ], stream=output)
2619 # Original logger output is empty.
2620 self.assert_log_lines([])
2621
Vinay Sajip373baef2011-04-26 20:05:24 +01002622 def test_baseconfig(self):
2623 d = {
2624 'atuple': (1, 2, 3),
2625 'alist': ['a', 'b', 'c'],
2626 'adict': {'d': 'e', 'f': 3 },
2627 'nest1': ('g', ('h', 'i'), 'j'),
2628 'nest2': ['k', ['l', 'm'], 'n'],
2629 'nest3': ['o', 'cfg://alist', 'p'],
2630 }
2631 bc = logging.config.BaseConfigurator(d)
2632 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2633 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2634 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2635 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2636 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2637 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2638 v = bc.convert('cfg://nest3')
2639 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2640 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2641 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2642 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002643
2644class ManagerTest(BaseTest):
2645 def test_manager_loggerclass(self):
2646 logged = []
2647
2648 class MyLogger(logging.Logger):
2649 def _log(self, level, msg, args, exc_info=None, extra=None):
2650 logged.append(msg)
2651
2652 man = logging.Manager(None)
2653 self.assertRaises(TypeError, man.setLoggerClass, int)
2654 man.setLoggerClass(MyLogger)
2655 logger = man.getLogger('test')
2656 logger.warning('should appear in logged')
2657 logging.warning('should not appear in logged')
2658
2659 self.assertEqual(logged, ['should appear in logged'])
2660
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002661 def test_set_log_record_factory(self):
2662 man = logging.Manager(None)
2663 expected = object()
2664 man.setLogRecordFactory(expected)
2665 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002666
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002667class ChildLoggerTest(BaseTest):
2668 def test_child_loggers(self):
2669 r = logging.getLogger()
2670 l1 = logging.getLogger('abc')
2671 l2 = logging.getLogger('def.ghi')
2672 c1 = r.getChild('xyz')
2673 c2 = r.getChild('uvw.xyz')
2674 self.assertTrue(c1 is logging.getLogger('xyz'))
2675 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
2676 c1 = l1.getChild('def')
2677 c2 = c1.getChild('ghi')
2678 c3 = l1.getChild('def.ghi')
2679 self.assertTrue(c1 is logging.getLogger('abc.def'))
2680 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
2681 self.assertTrue(c2 is c3)
2682
2683
Vinay Sajip6fac8172010-10-19 20:44:14 +00002684class DerivedLogRecord(logging.LogRecord):
2685 pass
2686
Vinay Sajip61561522010-12-03 11:50:38 +00002687class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002688
2689 def setUp(self):
2690 class CheckingFilter(logging.Filter):
2691 def __init__(self, cls):
2692 self.cls = cls
2693
2694 def filter(self, record):
2695 t = type(record)
2696 if t is not self.cls:
2697 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2698 self.cls)
2699 raise TypeError(msg)
2700 return True
2701
2702 BaseTest.setUp(self)
2703 self.filter = CheckingFilter(DerivedLogRecord)
2704 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002705 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002706
2707 def tearDown(self):
2708 self.root_logger.removeFilter(self.filter)
2709 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002710 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002711
2712 def test_logrecord_class(self):
2713 self.assertRaises(TypeError, self.root_logger.warning,
2714 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002715 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002716 self.root_logger.error(self.next_message())
2717 self.assert_log_lines([
2718 ('root', 'ERROR', '2'),
2719 ])
2720
2721
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002722class QueueHandlerTest(BaseTest):
2723 # Do not bother with a logger name group.
2724 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
2725
2726 def setUp(self):
2727 BaseTest.setUp(self)
2728 self.queue = queue.Queue(-1)
2729 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2730 self.que_logger = logging.getLogger('que')
2731 self.que_logger.propagate = False
2732 self.que_logger.setLevel(logging.WARNING)
2733 self.que_logger.addHandler(self.que_hdlr)
2734
2735 def tearDown(self):
2736 self.que_hdlr.close()
2737 BaseTest.tearDown(self)
2738
2739 def test_queue_handler(self):
2740 self.que_logger.debug(self.next_message())
2741 self.assertRaises(queue.Empty, self.queue.get_nowait)
2742 self.que_logger.info(self.next_message())
2743 self.assertRaises(queue.Empty, self.queue.get_nowait)
2744 msg = self.next_message()
2745 self.que_logger.warning(msg)
2746 data = self.queue.get_nowait()
2747 self.assertTrue(isinstance(data, logging.LogRecord))
2748 self.assertEqual(data.name, self.que_logger.name)
2749 self.assertEqual((data.msg, data.args), (msg, None))
2750
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002751 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2752 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002753 def test_queue_listener(self):
2754 handler = TestHandler(Matcher())
2755 listener = logging.handlers.QueueListener(self.queue, handler)
2756 listener.start()
2757 try:
2758 self.que_logger.warning(self.next_message())
2759 self.que_logger.error(self.next_message())
2760 self.que_logger.critical(self.next_message())
2761 finally:
2762 listener.stop()
2763 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2764 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2765 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2766
Vinay Sajip37eb3382011-04-26 20:26:41 +01002767ZERO = datetime.timedelta(0)
2768
2769class UTC(datetime.tzinfo):
2770 def utcoffset(self, dt):
2771 return ZERO
2772
2773 dst = utcoffset
2774
2775 def tzname(self, dt):
2776 return 'UTC'
2777
2778utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002779
Vinay Sajipa39c5712010-10-25 13:57:39 +00002780class FormatterTest(unittest.TestCase):
2781 def setUp(self):
2782 self.common = {
2783 'name': 'formatter.test',
2784 'level': logging.DEBUG,
2785 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2786 'lineno': 42,
2787 'exc_info': None,
2788 'func': None,
2789 'msg': 'Message with %d %s',
2790 'args': (2, 'placeholders'),
2791 }
2792 self.variants = {
2793 }
2794
2795 def get_record(self, name=None):
2796 result = dict(self.common)
2797 if name is not None:
2798 result.update(self.variants[name])
2799 return logging.makeLogRecord(result)
2800
2801 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002802 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002803 r = self.get_record()
2804 f = logging.Formatter('${%(message)s}')
2805 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2806 f = logging.Formatter('%(random)s')
2807 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002808 self.assertFalse(f.usesTime())
2809 f = logging.Formatter('%(asctime)s')
2810 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002811 f = logging.Formatter('%(asctime)-15s')
2812 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002813 f = logging.Formatter('asctime')
2814 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002815
2816 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002817 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002818 r = self.get_record()
2819 f = logging.Formatter('$%{message}%$', style='{')
2820 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2821 f = logging.Formatter('{random}', style='{')
2822 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002823 self.assertFalse(f.usesTime())
2824 f = logging.Formatter('{asctime}', style='{')
2825 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002826 f = logging.Formatter('{asctime!s:15}', style='{')
2827 self.assertTrue(f.usesTime())
2828 f = logging.Formatter('{asctime:15}', style='{')
2829 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002830 f = logging.Formatter('asctime', style='{')
2831 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002832
2833 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002834 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002835 r = self.get_record()
2836 f = logging.Formatter('$message', style='$')
2837 self.assertEqual(f.format(r), 'Message with 2 placeholders')
2838 f = logging.Formatter('$$%${message}%$$', style='$')
2839 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2840 f = logging.Formatter('${random}', style='$')
2841 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002842 self.assertFalse(f.usesTime())
2843 f = logging.Formatter('${asctime}', style='$')
2844 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002845 f = logging.Formatter('${asctime', style='$')
2846 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002847 f = logging.Formatter('$asctime', style='$')
2848 self.assertTrue(f.usesTime())
2849 f = logging.Formatter('asctime', style='$')
2850 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002851
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002852 def test_invalid_style(self):
2853 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
2854
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002855 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002856 r = self.get_record()
Vinay Sajip37eb3382011-04-26 20:26:41 +01002857 dt = datetime.datetime(1993,4,21,8,3,0,0,utc)
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002858 r.created = time.mktime(dt.timetuple()) - time.timezone
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002859 r.msecs = 123
2860 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01002861 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002862 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
2863 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01002864 f.format(r)
2865 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
2866
2867class TestBufferingFormatter(logging.BufferingFormatter):
2868 def formatHeader(self, records):
2869 return '[(%d)' % len(records)
2870
2871 def formatFooter(self, records):
2872 return '(%d)]' % len(records)
2873
2874class BufferingFormatterTest(unittest.TestCase):
2875 def setUp(self):
2876 self.records = [
2877 logging.makeLogRecord({'msg': 'one'}),
2878 logging.makeLogRecord({'msg': 'two'}),
2879 ]
2880
2881 def test_default(self):
2882 f = logging.BufferingFormatter()
2883 self.assertEqual('', f.format([]))
2884 self.assertEqual('onetwo', f.format(self.records))
2885
2886 def test_custom(self):
2887 f = TestBufferingFormatter()
2888 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
2889 lf = logging.Formatter('<%(message)s>')
2890 f = TestBufferingFormatter(lf)
2891 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002892
2893class ExceptionTest(BaseTest):
2894 def test_formatting(self):
2895 r = self.root_logger
2896 h = RecordingHandler()
2897 r.addHandler(h)
2898 try:
2899 raise RuntimeError('deliberate mistake')
2900 except:
2901 logging.exception('failed', stack_info=True)
2902 r.removeHandler(h)
2903 h.close()
2904 r = h.records[0]
2905 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
2906 'call last):\n'))
2907 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
2908 'deliberate mistake'))
2909 self.assertTrue(r.stack_info.startswith('Stack (most recent '
2910 'call last):\n'))
2911 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
2912 'stack_info=True)'))
2913
2914
Vinay Sajip5a27d402010-12-10 11:42:57 +00002915class LastResortTest(BaseTest):
2916 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002917 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00002918 root = self.root_logger
2919 root.removeHandler(self.root_hdlr)
2920 old_stderr = sys.stderr
2921 old_lastresort = logging.lastResort
2922 old_raise_exceptions = logging.raiseExceptions
2923 try:
2924 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01002925 root.debug('This should not appear')
2926 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00002927 root.warning('This is your final chance!')
2928 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
2929 #No handlers and no last resort, so 'No handlers' message
2930 logging.lastResort = None
2931 sys.stderr = sio = io.StringIO()
2932 root.warning('This is your final chance!')
2933 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
2934 # 'No handlers' message only printed once
2935 sys.stderr = sio = io.StringIO()
2936 root.warning('This is your final chance!')
2937 self.assertEqual(sio.getvalue(), '')
2938 root.manager.emittedNoHandlerWarning = False
2939 #If raiseExceptions is False, no message is printed
2940 logging.raiseExceptions = False
2941 sys.stderr = sio = io.StringIO()
2942 root.warning('This is your final chance!')
2943 self.assertEqual(sio.getvalue(), '')
2944 finally:
2945 sys.stderr = old_stderr
2946 root.addHandler(self.root_hdlr)
2947 logging.lastResort = old_lastresort
2948 logging.raiseExceptions = old_raise_exceptions
2949
2950
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002951class FakeHandler:
2952
2953 def __init__(self, identifier, called):
2954 for method in ('acquire', 'flush', 'close', 'release'):
2955 setattr(self, method, self.record_call(identifier, method, called))
2956
2957 def record_call(self, identifier, method_name, called):
2958 def inner():
2959 called.append('{} - {}'.format(identifier, method_name))
2960 return inner
2961
2962
2963class RecordingHandler(logging.NullHandler):
2964
2965 def __init__(self, *args, **kwargs):
2966 super(RecordingHandler, self).__init__(*args, **kwargs)
2967 self.records = []
2968
2969 def handle(self, record):
2970 """Keep track of all the emitted records."""
2971 self.records.append(record)
2972
2973
2974class ShutdownTest(BaseTest):
2975
Vinay Sajip5e66b162011-04-20 15:41:14 +01002976 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002977
2978 def setUp(self):
2979 super(ShutdownTest, self).setUp()
2980 self.called = []
2981
2982 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002983 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002984
2985 def raise_error(self, error):
2986 def inner():
2987 raise error()
2988 return inner
2989
2990 def test_no_failure(self):
2991 # create some fake handlers
2992 handler0 = FakeHandler(0, self.called)
2993 handler1 = FakeHandler(1, self.called)
2994 handler2 = FakeHandler(2, self.called)
2995
2996 # create live weakref to those handlers
2997 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
2998
2999 logging.shutdown(handlerList=list(handlers))
3000
3001 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3002 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3003 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3004 self.assertEqual(expected, self.called)
3005
3006 def _test_with_failure_in_method(self, method, error):
3007 handler = FakeHandler(0, self.called)
3008 setattr(handler, method, self.raise_error(error))
3009 handlers = [logging.weakref.ref(handler)]
3010
3011 logging.shutdown(handlerList=list(handlers))
3012
3013 self.assertEqual('0 - release', self.called[-1])
3014
3015 def test_with_ioerror_in_acquire(self):
3016 self._test_with_failure_in_method('acquire', IOError)
3017
3018 def test_with_ioerror_in_flush(self):
3019 self._test_with_failure_in_method('flush', IOError)
3020
3021 def test_with_ioerror_in_close(self):
3022 self._test_with_failure_in_method('close', IOError)
3023
3024 def test_with_valueerror_in_acquire(self):
3025 self._test_with_failure_in_method('acquire', ValueError)
3026
3027 def test_with_valueerror_in_flush(self):
3028 self._test_with_failure_in_method('flush', ValueError)
3029
3030 def test_with_valueerror_in_close(self):
3031 self._test_with_failure_in_method('close', ValueError)
3032
3033 def test_with_other_error_in_acquire_without_raise(self):
3034 logging.raiseExceptions = False
3035 self._test_with_failure_in_method('acquire', IndexError)
3036
3037 def test_with_other_error_in_flush_without_raise(self):
3038 logging.raiseExceptions = False
3039 self._test_with_failure_in_method('flush', IndexError)
3040
3041 def test_with_other_error_in_close_without_raise(self):
3042 logging.raiseExceptions = False
3043 self._test_with_failure_in_method('close', IndexError)
3044
3045 def test_with_other_error_in_acquire_with_raise(self):
3046 logging.raiseExceptions = True
3047 self.assertRaises(IndexError, self._test_with_failure_in_method,
3048 'acquire', IndexError)
3049
3050 def test_with_other_error_in_flush_with_raise(self):
3051 logging.raiseExceptions = True
3052 self.assertRaises(IndexError, self._test_with_failure_in_method,
3053 'flush', IndexError)
3054
3055 def test_with_other_error_in_close_with_raise(self):
3056 logging.raiseExceptions = True
3057 self.assertRaises(IndexError, self._test_with_failure_in_method,
3058 'close', IndexError)
3059
3060
3061class ModuleLevelMiscTest(BaseTest):
3062
Vinay Sajip5e66b162011-04-20 15:41:14 +01003063 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003064
3065 def test_disable(self):
3066 old_disable = logging.root.manager.disable
3067 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003068 self.assertEqual(old_disable, 0)
3069 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003070
3071 logging.disable(83)
3072 self.assertEqual(logging.root.manager.disable, 83)
3073
3074 def _test_log(self, method, level=None):
3075 called = []
3076 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003077 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003078
3079 recording = RecordingHandler()
3080 logging.root.addHandler(recording)
3081
3082 log_method = getattr(logging, method)
3083 if level is not None:
3084 log_method(level, "test me: %r", recording)
3085 else:
3086 log_method("test me: %r", recording)
3087
3088 self.assertEqual(len(recording.records), 1)
3089 record = recording.records[0]
3090 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3091
3092 expected_level = level if level is not None else getattr(logging, method.upper())
3093 self.assertEqual(record.levelno, expected_level)
3094
3095 # basicConfig was not called!
3096 self.assertEqual(called, [])
3097
3098 def test_log(self):
3099 self._test_log('log', logging.ERROR)
3100
3101 def test_debug(self):
3102 self._test_log('debug')
3103
3104 def test_info(self):
3105 self._test_log('info')
3106
3107 def test_warning(self):
3108 self._test_log('warning')
3109
3110 def test_error(self):
3111 self._test_log('error')
3112
3113 def test_critical(self):
3114 self._test_log('critical')
3115
3116 def test_set_logger_class(self):
3117 self.assertRaises(TypeError, logging.setLoggerClass, object)
3118
3119 class MyLogger(logging.Logger):
3120 pass
3121
3122 logging.setLoggerClass(MyLogger)
3123 self.assertEqual(logging.getLoggerClass(), MyLogger)
3124
3125 logging.setLoggerClass(logging.Logger)
3126 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3127
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003128class LogRecordTest(BaseTest):
3129 def test_str_rep(self):
3130 r = logging.makeLogRecord({})
3131 s = str(r)
3132 self.assertTrue(s.startswith('<LogRecord: '))
3133 self.assertTrue(s.endswith('>'))
3134
3135 def test_dict_arg(self):
3136 h = RecordingHandler()
3137 r = logging.getLogger()
3138 r.addHandler(h)
3139 d = {'less' : 'more' }
3140 logging.warning('less is %(less)s', d)
3141 self.assertIs(h.records[0].args, d)
3142 self.assertEqual(h.records[0].message, 'less is more')
3143 r.removeHandler(h)
3144 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003145
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003146 def test_multiprocessing(self):
3147 r = logging.makeLogRecord({})
3148 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003149 try:
3150 import multiprocessing as mp
3151 r = logging.makeLogRecord({})
3152 self.assertEqual(r.processName, mp.current_process().name)
3153 except ImportError:
3154 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003155
3156 def test_optional(self):
3157 r = logging.makeLogRecord({})
3158 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003159 if threading:
3160 NOT_NONE(r.thread)
3161 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003162 NOT_NONE(r.process)
3163 NOT_NONE(r.processName)
3164 log_threads = logging.logThreads
3165 log_processes = logging.logProcesses
3166 log_multiprocessing = logging.logMultiprocessing
3167 try:
3168 logging.logThreads = False
3169 logging.logProcesses = False
3170 logging.logMultiprocessing = False
3171 r = logging.makeLogRecord({})
3172 NONE = self.assertIsNone
3173 NONE(r.thread)
3174 NONE(r.threadName)
3175 NONE(r.process)
3176 NONE(r.processName)
3177 finally:
3178 logging.logThreads = log_threads
3179 logging.logProcesses = log_processes
3180 logging.logMultiprocessing = log_multiprocessing
3181
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003182class BasicConfigTest(unittest.TestCase):
3183
Vinay Sajip95bf5042011-04-20 11:50:56 +01003184 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003185
3186 def setUp(self):
3187 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003188 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003189 self.saved_handlers = logging._handlers.copy()
3190 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003191 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003192 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003193 logging.root.handlers = []
3194
3195 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003196 for h in logging.root.handlers[:]:
3197 logging.root.removeHandler(h)
3198 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003199 super(BasicConfigTest, self).tearDown()
3200
Vinay Sajip3def7e02011-04-20 10:58:06 +01003201 def cleanup(self):
3202 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003203 logging._handlers.clear()
3204 logging._handlers.update(self.saved_handlers)
3205 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003206 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003207
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003208 def test_no_kwargs(self):
3209 logging.basicConfig()
3210
3211 # handler defaults to a StreamHandler to sys.stderr
3212 self.assertEqual(len(logging.root.handlers), 1)
3213 handler = logging.root.handlers[0]
3214 self.assertIsInstance(handler, logging.StreamHandler)
3215 self.assertEqual(handler.stream, sys.stderr)
3216
3217 formatter = handler.formatter
3218 # format defaults to logging.BASIC_FORMAT
3219 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3220 # datefmt defaults to None
3221 self.assertIsNone(formatter.datefmt)
3222 # style defaults to %
3223 self.assertIsInstance(formatter._style, logging.PercentStyle)
3224
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003225 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003226 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003227
3228 def test_filename(self):
3229 logging.basicConfig(filename='test.log')
3230
3231 self.assertEqual(len(logging.root.handlers), 1)
3232 handler = logging.root.handlers[0]
3233 self.assertIsInstance(handler, logging.FileHandler)
3234
3235 expected = logging.FileHandler('test.log', 'a')
3236 self.addCleanup(expected.close)
3237 self.assertEqual(handler.stream.mode, expected.stream.mode)
3238 self.assertEqual(handler.stream.name, expected.stream.name)
3239
3240 def test_filemode(self):
3241 logging.basicConfig(filename='test.log', filemode='wb')
3242
3243 handler = logging.root.handlers[0]
3244 expected = logging.FileHandler('test.log', 'wb')
3245 self.addCleanup(expected.close)
3246 self.assertEqual(handler.stream.mode, expected.stream.mode)
3247
3248 def test_stream(self):
3249 stream = io.StringIO()
3250 self.addCleanup(stream.close)
3251 logging.basicConfig(stream=stream)
3252
3253 self.assertEqual(len(logging.root.handlers), 1)
3254 handler = logging.root.handlers[0]
3255 self.assertIsInstance(handler, logging.StreamHandler)
3256 self.assertEqual(handler.stream, stream)
3257
3258 def test_format(self):
3259 logging.basicConfig(format='foo')
3260
3261 formatter = logging.root.handlers[0].formatter
3262 self.assertEqual(formatter._style._fmt, 'foo')
3263
3264 def test_datefmt(self):
3265 logging.basicConfig(datefmt='bar')
3266
3267 formatter = logging.root.handlers[0].formatter
3268 self.assertEqual(formatter.datefmt, 'bar')
3269
3270 def test_style(self):
3271 logging.basicConfig(style='$')
3272
3273 formatter = logging.root.handlers[0].formatter
3274 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3275
3276 def test_level(self):
3277 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003278 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003279
3280 logging.basicConfig(level=57)
3281 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003282 # Test that second call has no effect
3283 logging.basicConfig(level=58)
3284 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003285
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003286 def test_incompatible(self):
3287 assertRaises = self.assertRaises
3288 handlers = [logging.StreamHandler()]
3289 stream = sys.stderr
3290 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3291 stream=stream)
3292 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3293 handlers=handlers)
3294 assertRaises(ValueError, logging.basicConfig, stream=stream,
3295 handlers=handlers)
3296
3297 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003298 handlers = [
3299 logging.StreamHandler(),
3300 logging.StreamHandler(sys.stdout),
3301 logging.StreamHandler(),
3302 ]
3303 f = logging.Formatter()
3304 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003305 logging.basicConfig(handlers=handlers)
3306 self.assertIs(handlers[0], logging.root.handlers[0])
3307 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003308 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003309 self.assertIsNotNone(handlers[0].formatter)
3310 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003311 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003312 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3313
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003314 def _test_log(self, method, level=None):
3315 # logging.root has no handlers so basicConfig should be called
3316 called = []
3317
3318 old_basic_config = logging.basicConfig
3319 def my_basic_config(*a, **kw):
3320 old_basic_config()
3321 old_level = logging.root.level
3322 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003323 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003324 called.append((a, kw))
3325
3326 patch(self, logging, 'basicConfig', my_basic_config)
3327
3328 log_method = getattr(logging, method)
3329 if level is not None:
3330 log_method(level, "test me")
3331 else:
3332 log_method("test me")
3333
3334 # basicConfig was called with no arguments
3335 self.assertEqual(called, [((), {})])
3336
3337 def test_log(self):
3338 self._test_log('log', logging.WARNING)
3339
3340 def test_debug(self):
3341 self._test_log('debug')
3342
3343 def test_info(self):
3344 self._test_log('info')
3345
3346 def test_warning(self):
3347 self._test_log('warning')
3348
3349 def test_error(self):
3350 self._test_log('error')
3351
3352 def test_critical(self):
3353 self._test_log('critical')
3354
3355
3356class LoggerAdapterTest(unittest.TestCase):
3357
3358 def setUp(self):
3359 super(LoggerAdapterTest, self).setUp()
3360 old_handler_list = logging._handlerList[:]
3361
3362 self.recording = RecordingHandler()
3363 self.logger = logging.root
3364 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003365 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003366 self.addCleanup(self.recording.close)
3367
3368 def cleanup():
3369 logging._handlerList[:] = old_handler_list
3370
3371 self.addCleanup(cleanup)
3372 self.addCleanup(logging.shutdown)
3373 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3374
3375 def test_exception(self):
3376 msg = 'testing exception: %r'
3377 exc = None
3378 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003379 1 / 0
3380 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003381 exc = e
3382 self.adapter.exception(msg, self.recording)
3383
3384 self.assertEqual(len(self.recording.records), 1)
3385 record = self.recording.records[0]
3386 self.assertEqual(record.levelno, logging.ERROR)
3387 self.assertEqual(record.msg, msg)
3388 self.assertEqual(record.args, (self.recording,))
3389 self.assertEqual(record.exc_info,
3390 (exc.__class__, exc, exc.__traceback__))
3391
3392 def test_critical(self):
3393 msg = 'critical test! %r'
3394 self.adapter.critical(msg, self.recording)
3395
3396 self.assertEqual(len(self.recording.records), 1)
3397 record = self.recording.records[0]
3398 self.assertEqual(record.levelno, logging.CRITICAL)
3399 self.assertEqual(record.msg, msg)
3400 self.assertEqual(record.args, (self.recording,))
3401
3402 def test_is_enabled_for(self):
3403 old_disable = self.adapter.logger.manager.disable
3404 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003405 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3406 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003407 self.assertFalse(self.adapter.isEnabledFor(32))
3408
3409 def test_has_handlers(self):
3410 self.assertTrue(self.adapter.hasHandlers())
3411
3412 for handler in self.logger.handlers:
3413 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003414
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003415 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003416 self.assertFalse(self.adapter.hasHandlers())
3417
3418
3419class LoggerTest(BaseTest):
3420
3421 def setUp(self):
3422 super(LoggerTest, self).setUp()
3423 self.recording = RecordingHandler()
3424 self.logger = logging.Logger(name='blah')
3425 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003426 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003427 self.addCleanup(self.recording.close)
3428 self.addCleanup(logging.shutdown)
3429
3430 def test_set_invalid_level(self):
3431 self.assertRaises(TypeError, self.logger.setLevel, object())
3432
3433 def test_exception(self):
3434 msg = 'testing exception: %r'
3435 exc = None
3436 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003437 1 / 0
3438 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003439 exc = e
3440 self.logger.exception(msg, self.recording)
3441
3442 self.assertEqual(len(self.recording.records), 1)
3443 record = self.recording.records[0]
3444 self.assertEqual(record.levelno, logging.ERROR)
3445 self.assertEqual(record.msg, msg)
3446 self.assertEqual(record.args, (self.recording,))
3447 self.assertEqual(record.exc_info,
3448 (exc.__class__, exc, exc.__traceback__))
3449
3450 def test_log_invalid_level_with_raise(self):
3451 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003452 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003453
3454 logging.raiseExceptions = True
3455 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3456
3457 def test_log_invalid_level_no_raise(self):
3458 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003459 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003460
3461 logging.raiseExceptions = False
3462 self.logger.log('10', 'test message') # no exception happens
3463
3464 def test_find_caller_with_stack_info(self):
3465 called = []
3466 patch(self, logging.traceback, 'print_stack',
3467 lambda f, file: called.append(file.getvalue()))
3468
3469 self.logger.findCaller(stack_info=True)
3470
3471 self.assertEqual(len(called), 1)
3472 self.assertEqual('Stack (most recent call last):\n', called[0])
3473
3474 def test_make_record_with_extra_overwrite(self):
3475 name = 'my record'
3476 level = 13
3477 fn = lno = msg = args = exc_info = func = sinfo = None
3478 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3479 exc_info, func, sinfo)
3480
3481 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3482 extra = {key: 'some value'}
3483 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3484 fn, lno, msg, args, exc_info,
3485 extra=extra, sinfo=sinfo)
3486
3487 def test_make_record_with_extra_no_overwrite(self):
3488 name = 'my record'
3489 level = 13
3490 fn = lno = msg = args = exc_info = func = sinfo = None
3491 extra = {'valid_key': 'some value'}
3492 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3493 exc_info, extra=extra, sinfo=sinfo)
3494 self.assertIn('valid_key', result.__dict__)
3495
3496 def test_has_handlers(self):
3497 self.assertTrue(self.logger.hasHandlers())
3498
3499 for handler in self.logger.handlers:
3500 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003501 self.assertFalse(self.logger.hasHandlers())
3502
3503 def test_has_handlers_no_propagate(self):
3504 child_logger = logging.getLogger('blah.child')
3505 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003506 self.assertFalse(child_logger.hasHandlers())
3507
3508 def test_is_enabled_for(self):
3509 old_disable = self.logger.manager.disable
3510 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003511 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003512 self.assertFalse(self.logger.isEnabledFor(22))
3513
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003514 def test_root_logger_aliases(self):
3515 root = logging.getLogger()
3516 self.assertIs(root, logging.root)
3517 self.assertIs(root, logging.getLogger(None))
3518 self.assertIs(root, logging.getLogger(''))
3519 self.assertIs(root, logging.getLogger('foo').root)
3520 self.assertIs(root, logging.getLogger('foo.bar').root)
3521 self.assertIs(root, logging.getLogger('foo').parent)
3522
3523 self.assertIsNot(root, logging.getLogger('\0'))
3524 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3525
3526 def test_invalid_names(self):
3527 self.assertRaises(TypeError, logging.getLogger, any)
3528 self.assertRaises(TypeError, logging.getLogger, b'foo')
3529
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003530
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003531class BaseFileTest(BaseTest):
3532 "Base class for handler tests that write log files"
3533
3534 def setUp(self):
3535 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003536 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3537 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003538 self.rmfiles = []
3539
3540 def tearDown(self):
3541 for fn in self.rmfiles:
3542 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003543 if os.path.exists(self.fn):
3544 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003545 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003546
3547 def assertLogFile(self, filename):
3548 "Assert a log file is there and register it for deletion"
3549 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003550 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003551 self.rmfiles.append(filename)
3552
3553
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003554class FileHandlerTest(BaseFileTest):
3555 def test_delay(self):
3556 os.unlink(self.fn)
3557 fh = logging.FileHandler(self.fn, delay=True)
3558 self.assertIsNone(fh.stream)
3559 self.assertFalse(os.path.exists(self.fn))
3560 fh.handle(logging.makeLogRecord({}))
3561 self.assertIsNotNone(fh.stream)
3562 self.assertTrue(os.path.exists(self.fn))
3563 fh.close()
3564
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003565class RotatingFileHandlerTest(BaseFileTest):
3566 def next_rec(self):
3567 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3568 self.next_message(), None, None, None)
3569
3570 def test_should_not_rollover(self):
3571 # If maxbytes is zero rollover never occurs
3572 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3573 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003574 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003575
3576 def test_should_rollover(self):
3577 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3578 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003579 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003580
3581 def test_file_created(self):
3582 # checks that the file is created and assumes it was created
3583 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003584 rh = logging.handlers.RotatingFileHandler(self.fn)
3585 rh.emit(self.next_rec())
3586 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003587 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003588
3589 def test_rollover_filenames(self):
3590 rh = logging.handlers.RotatingFileHandler(
3591 self.fn, backupCount=2, maxBytes=1)
3592 rh.emit(self.next_rec())
3593 self.assertLogFile(self.fn)
3594 rh.emit(self.next_rec())
3595 self.assertLogFile(self.fn + ".1")
3596 rh.emit(self.next_rec())
3597 self.assertLogFile(self.fn + ".2")
3598 self.assertFalse(os.path.exists(self.fn + ".3"))
Vinay Sajipb046b802010-10-30 09:50:18 +00003599 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003600
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003601class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003602 # other test methods added below
3603 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003604 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3605 backupCount=1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003606 r = logging.makeLogRecord({'msg': 'testing'})
3607 fh.emit(r)
3608 self.assertLogFile(self.fn)
Vinay Sajipb7b19302011-05-24 07:12:41 +01003609 time.sleep(1.01) # just a little over a second ...
Vinay Sajipfd285022011-05-07 17:01:22 +01003610 fh.emit(r)
3611 fh.close()
3612 # At this point, we should have a recent rotated file which we
3613 # can test for the existence of. However, in practice, on some
3614 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003615 # in time to go to look for the log file. So, we go back a fair
3616 # bit, and stop as soon as we see a rotated file. In theory this
3617 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003618 found = False
3619 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003620 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003621 for secs in range(GO_BACK):
3622 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003623 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3624 found = os.path.exists(fn)
3625 if found:
3626 self.rmfiles.append(fn)
3627 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003628 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3629 if not found:
3630 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003631 dn, fn = os.path.split(self.fn)
3632 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003633 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3634 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajipfd285022011-05-07 17:01:22 +01003635 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003636
Vinay Sajip0372e102011-05-05 12:59:14 +01003637 def test_invalid(self):
3638 assertRaises = self.assertRaises
3639 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003640 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003641 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003642 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003643 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003644 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003645
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003646def secs(**kw):
3647 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3648
3649for when, exp in (('S', 1),
3650 ('M', 60),
3651 ('H', 60 * 60),
3652 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003653 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003654 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003655 ('W0', secs(days=4, hours=24)),
3656 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003657 def test_compute_rollover(self, when=when, exp=exp):
3658 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003659 self.fn, when=when, interval=1, backupCount=0, utc=True)
3660 currentTime = 0.0
3661 actual = rh.computeRollover(currentTime)
3662 if exp != actual:
3663 # Failures occur on some systems for MIDNIGHT and W0.
3664 # Print detailed calculation for MIDNIGHT so we can try to see
3665 # what's going on
3666 import time
3667 if when == 'MIDNIGHT':
3668 try:
3669 if rh.utc:
3670 t = time.gmtime(currentTime)
3671 else:
3672 t = time.localtime(currentTime)
3673 currentHour = t[3]
3674 currentMinute = t[4]
3675 currentSecond = t[5]
3676 # r is the number of seconds left between now and midnight
3677 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3678 currentMinute) * 60 +
3679 currentSecond)
3680 result = currentTime + r
3681 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3682 print('currentHour: %s' % currentHour, file=sys.stderr)
3683 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3684 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3685 print('r: %s' % r, file=sys.stderr)
3686 print('result: %s' % result, file=sys.stderr)
3687 except Exception:
3688 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3689 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003690 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003691 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3692
Vinay Sajip60ccd822011-05-09 17:32:09 +01003693
3694@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
3695class NTEventLogHandlerTest(BaseTest):
3696 def test_basic(self):
3697 logtype = 'Application'
3698 elh = win32evtlog.OpenEventLog(None, logtype)
3699 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
3700 h = logging.handlers.NTEventLogHandler('test_logging')
3701 r = logging.makeLogRecord({'msg': 'Test Log Message'})
3702 h.handle(r)
3703 h.close()
3704 # Now see if the event is recorded
3705 self.assertTrue(num_recs < win32evtlog.GetNumberOfEventLogRecords(elh))
3706 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
3707 win32evtlog.EVENTLOG_SEQUENTIAL_READ
3708 found = False
3709 GO_BACK = 100
3710 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
3711 for e in events:
3712 if e.SourceName != 'test_logging':
3713 continue
3714 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
3715 if msg != 'Test Log Message\r\n':
3716 continue
3717 found = True
3718 break
3719 msg = 'Record not found in event log, went back %d records' % GO_BACK
3720 self.assertTrue(found, msg=msg)
3721
Christian Heimes180510d2008-03-03 19:15:45 +00003722# Set the locale to the platform-dependent default. I have no idea
3723# why the test does this, but in any case we save the current locale
3724# first and restore it at the end.
3725@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00003726def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00003727 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003728 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01003729 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
3730 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
3731 ManagerTest, FormatterTest, BufferingFormatterTest,
3732 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
3733 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
3734 BasicConfigTest, LoggerAdapterTest, LoggerTest,
3735 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003736 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01003737 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00003738 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00003739 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00003740
Christian Heimes180510d2008-03-03 19:15:45 +00003741if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00003742 test_main()