blob: c6efbe01d2617dcae3f401569dbe858702aca172 [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
Alexandre Vassalottice261952008-05-12 02:31:37 +000039from socketserver import ThreadingTCPServer, StreamRequestHandler
Christian Heimes180510d2008-03-03 19:15:45 +000040import struct
41import sys
42import tempfile
Vinay Sajipe6c1eb92011-03-29 17:20:34 +010043from test.support import captured_stdout, run_with_locale, run_unittest, patch
Vinay Sajipe723e962011-04-15 22:27:17 +010044from test.support import TestHandler, Matcher
Christian Heimes180510d2008-03-03 19:15:45 +000045import textwrap
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
51except ImportError:
52 threading = None
Christian Heimes18c66892008-02-17 13:31:39 +000053
54
Christian Heimes180510d2008-03-03 19:15:45 +000055class BaseTest(unittest.TestCase):
56
57 """Base class for logging tests."""
58
59 log_format = "%(name)s -> %(levelname)s: %(message)s"
60 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
61 message_num = 0
62
63 def setUp(self):
64 """Setup the default logging stream to an internal StringIO instance,
65 so that we can examine log output as we want."""
66 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000067 logging._acquireLock()
68 try:
Christian Heimes180510d2008-03-03 19:15:45 +000069 self.saved_handlers = logging._handlers.copy()
70 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000071 self.saved_loggers = saved_loggers = logger_dict.copy()
Christian Heimes180510d2008-03-03 19:15:45 +000072 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000073 self.logger_states = logger_states = {}
74 for name in saved_loggers:
75 logger_states[name] = getattr(saved_loggers[name],
76 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000077 finally:
78 logging._releaseLock()
79
Benjamin Peterson22005fc2010-04-11 16:25:06 +000080 # Set two unused loggers: one non-ASCII and one Unicode.
81 # This is to test correct operation when sorting existing
82 # loggers in the configuration code. See issue 8201.
Vinay Sajipb4a08092010-09-20 09:55:00 +000083 self.logger1 = logging.getLogger("\xab\xd7\xbb")
84 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +000085
Christian Heimes180510d2008-03-03 19:15:45 +000086 self.root_logger = logging.getLogger("")
87 self.original_logging_level = self.root_logger.getEffectiveLevel()
88
89 self.stream = io.StringIO()
90 self.root_logger.setLevel(logging.DEBUG)
91 self.root_hdlr = logging.StreamHandler(self.stream)
92 self.root_formatter = logging.Formatter(self.log_format)
93 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +000094 if self.logger1.hasHandlers():
95 hlist = self.logger1.handlers + self.root_logger.handlers
96 raise AssertionError('Unexpected handlers: %s' % hlist)
97 if self.logger2.hasHandlers():
98 hlist = self.logger2.handlers + self.root_logger.handlers
99 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000100 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000101 self.assertTrue(self.logger1.hasHandlers())
102 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000103
104 def tearDown(self):
105 """Remove our logging stream, and restore the original logging
106 level."""
107 self.stream.close()
108 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000109 while self.root_logger.handlers:
110 h = self.root_logger.handlers[0]
111 self.root_logger.removeHandler(h)
112 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000113 self.root_logger.setLevel(self.original_logging_level)
114 logging._acquireLock()
115 try:
116 logging._levelNames.clear()
117 logging._levelNames.update(self.saved_level_names)
118 logging._handlers.clear()
119 logging._handlers.update(self.saved_handlers)
120 logging._handlerList[:] = self.saved_handler_list
121 loggerDict = logging.getLogger().manager.loggerDict
122 loggerDict.clear()
123 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000124 logger_states = self.logger_states
125 for name in self.logger_states:
126 if logger_states[name] is not None:
127 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000128 finally:
129 logging._releaseLock()
130
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000131 def assert_log_lines(self, expected_values, stream=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000132 """Match the collected log lines against the regular expression
133 self.expected_log_pat, and compare the extracted group values to
134 the expected_values list of tuples."""
135 stream = stream or self.stream
136 pat = re.compile(self.expected_log_pat)
137 try:
138 stream.reset()
139 actual_lines = stream.readlines()
140 except AttributeError:
141 # StringIO.StringIO lacks a reset() method.
142 actual_lines = stream.getvalue().splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000143 self.assertEqual(len(actual_lines), len(expected_values),
Vinay Sajip6fac8172010-10-19 20:44:14 +0000144 '%s vs. %s' % (actual_lines, expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000145 for actual, expected in zip(actual_lines, expected_values):
146 match = pat.search(actual)
147 if not match:
148 self.fail("Log line does not match expected pattern:\n" +
149 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000150 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000151 s = stream.read()
152 if s:
153 self.fail("Remaining output at end of log stream:\n" + s)
154
155 def next_message(self):
156 """Generate a message consisting solely of an auto-incrementing
157 integer."""
158 self.message_num += 1
159 return "%d" % self.message_num
160
161
162class BuiltinLevelsTest(BaseTest):
163 """Test builtin levels and their inheritance."""
164
165 def test_flat(self):
166 #Logging levels in a flat logger namespace.
167 m = self.next_message
168
169 ERR = logging.getLogger("ERR")
170 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000171 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000172 INF.setLevel(logging.INFO)
173 DEB = logging.getLogger("DEB")
174 DEB.setLevel(logging.DEBUG)
175
176 # These should log.
177 ERR.log(logging.CRITICAL, m())
178 ERR.error(m())
179
180 INF.log(logging.CRITICAL, m())
181 INF.error(m())
182 INF.warn(m())
183 INF.info(m())
184
185 DEB.log(logging.CRITICAL, m())
186 DEB.error(m())
187 DEB.warn (m())
188 DEB.info (m())
189 DEB.debug(m())
190
191 # These should not log.
192 ERR.warn(m())
193 ERR.info(m())
194 ERR.debug(m())
195
196 INF.debug(m())
197
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000198 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000199 ('ERR', 'CRITICAL', '1'),
200 ('ERR', 'ERROR', '2'),
201 ('INF', 'CRITICAL', '3'),
202 ('INF', 'ERROR', '4'),
203 ('INF', 'WARNING', '5'),
204 ('INF', 'INFO', '6'),
205 ('DEB', 'CRITICAL', '7'),
206 ('DEB', 'ERROR', '8'),
207 ('DEB', 'WARNING', '9'),
208 ('DEB', 'INFO', '10'),
209 ('DEB', 'DEBUG', '11'),
210 ])
211
212 def test_nested_explicit(self):
213 # Logging levels in a nested namespace, all explicitly set.
214 m = self.next_message
215
216 INF = logging.getLogger("INF")
217 INF.setLevel(logging.INFO)
218 INF_ERR = logging.getLogger("INF.ERR")
219 INF_ERR.setLevel(logging.ERROR)
220
221 # These should log.
222 INF_ERR.log(logging.CRITICAL, m())
223 INF_ERR.error(m())
224
225 # These should not log.
226 INF_ERR.warn(m())
227 INF_ERR.info(m())
228 INF_ERR.debug(m())
229
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000230 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000231 ('INF.ERR', 'CRITICAL', '1'),
232 ('INF.ERR', 'ERROR', '2'),
233 ])
234
235 def test_nested_inherited(self):
236 #Logging levels in a nested namespace, inherited from parent loggers.
237 m = self.next_message
238
239 INF = logging.getLogger("INF")
240 INF.setLevel(logging.INFO)
241 INF_ERR = logging.getLogger("INF.ERR")
242 INF_ERR.setLevel(logging.ERROR)
243 INF_UNDEF = logging.getLogger("INF.UNDEF")
244 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
245 UNDEF = logging.getLogger("UNDEF")
246
247 # These should log.
248 INF_UNDEF.log(logging.CRITICAL, m())
249 INF_UNDEF.error(m())
250 INF_UNDEF.warn(m())
251 INF_UNDEF.info(m())
252 INF_ERR_UNDEF.log(logging.CRITICAL, m())
253 INF_ERR_UNDEF.error(m())
254
255 # These should not log.
256 INF_UNDEF.debug(m())
257 INF_ERR_UNDEF.warn(m())
258 INF_ERR_UNDEF.info(m())
259 INF_ERR_UNDEF.debug(m())
260
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000261 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000262 ('INF.UNDEF', 'CRITICAL', '1'),
263 ('INF.UNDEF', 'ERROR', '2'),
264 ('INF.UNDEF', 'WARNING', '3'),
265 ('INF.UNDEF', 'INFO', '4'),
266 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
267 ('INF.ERR.UNDEF', 'ERROR', '6'),
268 ])
269
270 def test_nested_with_virtual_parent(self):
271 # Logging levels when some parent does not exist yet.
272 m = self.next_message
273
274 INF = logging.getLogger("INF")
275 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
276 CHILD = logging.getLogger("INF.BADPARENT")
277 INF.setLevel(logging.INFO)
278
279 # These should log.
280 GRANDCHILD.log(logging.FATAL, m())
281 GRANDCHILD.info(m())
282 CHILD.log(logging.FATAL, m())
283 CHILD.info(m())
284
285 # These should not log.
286 GRANDCHILD.debug(m())
287 CHILD.debug(m())
288
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000289 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000290 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
291 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
292 ('INF.BADPARENT', 'CRITICAL', '3'),
293 ('INF.BADPARENT', 'INFO', '4'),
294 ])
295
296
297class BasicFilterTest(BaseTest):
298
299 """Test the bundled Filter class."""
300
301 def test_filter(self):
302 # Only messages satisfying the specified criteria pass through the
303 # filter.
304 filter_ = logging.Filter("spam.eggs")
305 handler = self.root_logger.handlers[0]
306 try:
307 handler.addFilter(filter_)
308 spam = logging.getLogger("spam")
309 spam_eggs = logging.getLogger("spam.eggs")
310 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
311 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
312
313 spam.info(self.next_message())
314 spam_eggs.info(self.next_message()) # Good.
315 spam_eggs_fish.info(self.next_message()) # Good.
316 spam_bakedbeans.info(self.next_message())
317
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000318 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000319 ('spam.eggs', 'INFO', '2'),
320 ('spam.eggs.fish', 'INFO', '3'),
321 ])
322 finally:
323 handler.removeFilter(filter_)
324
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000325 def test_callable_filter(self):
326 # Only messages satisfying the specified criteria pass through the
327 # filter.
328
329 def filterfunc(record):
330 parts = record.name.split('.')
331 prefix = '.'.join(parts[:2])
332 return prefix == 'spam.eggs'
333
334 handler = self.root_logger.handlers[0]
335 try:
336 handler.addFilter(filterfunc)
337 spam = logging.getLogger("spam")
338 spam_eggs = logging.getLogger("spam.eggs")
339 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
340 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
341
342 spam.info(self.next_message())
343 spam_eggs.info(self.next_message()) # Good.
344 spam_eggs_fish.info(self.next_message()) # Good.
345 spam_bakedbeans.info(self.next_message())
346
347 self.assert_log_lines([
348 ('spam.eggs', 'INFO', '2'),
349 ('spam.eggs.fish', 'INFO', '3'),
350 ])
351 finally:
352 handler.removeFilter(filterfunc)
353
Christian Heimes180510d2008-03-03 19:15:45 +0000354
355#
356# First, we define our levels. There can be as many as you want - the only
357# limitations are that they should be integers, the lowest should be > 0 and
358# larger values mean less information being logged. If you need specific
359# level values which do not fit into these limitations, you can use a
360# mapping dictionary to convert between your application levels and the
361# logging system.
362#
363SILENT = 120
364TACITURN = 119
365TERSE = 118
366EFFUSIVE = 117
367SOCIABLE = 116
368VERBOSE = 115
369TALKATIVE = 114
370GARRULOUS = 113
371CHATTERBOX = 112
372BORING = 111
373
374LEVEL_RANGE = range(BORING, SILENT + 1)
375
376#
377# Next, we define names for our levels. You don't need to do this - in which
378# case the system will use "Level n" to denote the text for the level.
379#
380my_logging_levels = {
381 SILENT : 'Silent',
382 TACITURN : 'Taciturn',
383 TERSE : 'Terse',
384 EFFUSIVE : 'Effusive',
385 SOCIABLE : 'Sociable',
386 VERBOSE : 'Verbose',
387 TALKATIVE : 'Talkative',
388 GARRULOUS : 'Garrulous',
389 CHATTERBOX : 'Chatterbox',
390 BORING : 'Boring',
391}
392
393class GarrulousFilter(logging.Filter):
394
395 """A filter which blocks garrulous messages."""
396
397 def filter(self, record):
398 return record.levelno != GARRULOUS
399
400class VerySpecificFilter(logging.Filter):
401
402 """A filter which blocks sociable and taciturn messages."""
403
404 def filter(self, record):
405 return record.levelno not in [SOCIABLE, TACITURN]
406
407
408class CustomLevelsAndFiltersTest(BaseTest):
409
410 """Test various filtering possibilities with custom logging levels."""
411
412 # Skip the logger name group.
413 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
414
415 def setUp(self):
416 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000417 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000418 logging.addLevelName(k, v)
419
420 def log_at_all_levels(self, logger):
421 for lvl in LEVEL_RANGE:
422 logger.log(lvl, self.next_message())
423
424 def test_logger_filter(self):
425 # Filter at logger level.
426 self.root_logger.setLevel(VERBOSE)
427 # Levels >= 'Verbose' are good.
428 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000429 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000430 ('Verbose', '5'),
431 ('Sociable', '6'),
432 ('Effusive', '7'),
433 ('Terse', '8'),
434 ('Taciturn', '9'),
435 ('Silent', '10'),
436 ])
437
438 def test_handler_filter(self):
439 # Filter at handler level.
440 self.root_logger.handlers[0].setLevel(SOCIABLE)
441 try:
442 # Levels >= 'Sociable' are good.
443 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000444 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000445 ('Sociable', '6'),
446 ('Effusive', '7'),
447 ('Terse', '8'),
448 ('Taciturn', '9'),
449 ('Silent', '10'),
450 ])
451 finally:
452 self.root_logger.handlers[0].setLevel(logging.NOTSET)
453
454 def test_specific_filters(self):
455 # Set a specific filter object on the handler, and then add another
456 # filter object on the logger itself.
457 handler = self.root_logger.handlers[0]
458 specific_filter = None
459 garr = GarrulousFilter()
460 handler.addFilter(garr)
461 try:
462 self.log_at_all_levels(self.root_logger)
463 first_lines = [
464 # Notice how 'Garrulous' is missing
465 ('Boring', '1'),
466 ('Chatterbox', '2'),
467 ('Talkative', '4'),
468 ('Verbose', '5'),
469 ('Sociable', '6'),
470 ('Effusive', '7'),
471 ('Terse', '8'),
472 ('Taciturn', '9'),
473 ('Silent', '10'),
474 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000475 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000476
477 specific_filter = VerySpecificFilter()
478 self.root_logger.addFilter(specific_filter)
479 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000480 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000481 # Not only 'Garrulous' is still missing, but also 'Sociable'
482 # and 'Taciturn'
483 ('Boring', '11'),
484 ('Chatterbox', '12'),
485 ('Talkative', '14'),
486 ('Verbose', '15'),
487 ('Effusive', '17'),
488 ('Terse', '18'),
489 ('Silent', '20'),
490 ])
491 finally:
492 if specific_filter:
493 self.root_logger.removeFilter(specific_filter)
494 handler.removeFilter(garr)
495
496
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100497class HandlerTest(BaseTest):
498 def test_name(self):
499 h = logging.Handler()
500 h.name = 'generic'
501 self.assertEqual(h.name, 'generic')
502 h.name = 'anothergeneric'
503 self.assertEqual(h.name, 'anothergeneric')
504 self.assertRaises(NotImplementedError, h.emit, None)
505
506 def test_abc(self):
507 pass
508
509class BadStream(object):
510 def write(self, data):
511 raise RuntimeError('deliberate mistake')
512
513class TestStreamHandler(logging.StreamHandler):
514 def handleError(self, record):
515 self.error_record = record
516
517class StreamHandlerTest(BaseTest):
518 def test_error_handling(self):
519 h = TestStreamHandler(BadStream())
520 r = logging.makeLogRecord({})
521 old_raise = logging.raiseExceptions
522 try:
523 h.handle(r)
524 self.assertIs(h.error_record, r)
525 finally:
526 logging.raiseExceptions = old_raise
527
Christian Heimes180510d2008-03-03 19:15:45 +0000528class MemoryHandlerTest(BaseTest):
529
530 """Tests for the MemoryHandler."""
531
532 # Do not bother with a logger name group.
533 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
534
535 def setUp(self):
536 BaseTest.setUp(self)
537 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
538 self.root_hdlr)
539 self.mem_logger = logging.getLogger('mem')
540 self.mem_logger.propagate = 0
541 self.mem_logger.addHandler(self.mem_hdlr)
542
543 def tearDown(self):
544 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000545 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000546
547 def test_flush(self):
548 # The memory handler flushes to its target handler based on specific
549 # criteria (message count and message level).
550 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000551 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000552 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000553 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000554 # This will flush because the level is >= logging.WARNING
555 self.mem_logger.warn(self.next_message())
556 lines = [
557 ('DEBUG', '1'),
558 ('INFO', '2'),
559 ('WARNING', '3'),
560 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000561 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000562 for n in (4, 14):
563 for i in range(9):
564 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000565 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000566 # This will flush because it's the 10th message since the last
567 # flush.
568 self.mem_logger.debug(self.next_message())
569 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000570 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000571
572 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000573 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000574
575
576class ExceptionFormatter(logging.Formatter):
577 """A special exception formatter."""
578 def formatException(self, ei):
579 return "Got a [%s]" % ei[0].__name__
580
581
582class ConfigFileTest(BaseTest):
583
584 """Reading logging config from a .ini-style config file."""
585
586 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
587
588 # config0 is a standard configuration.
589 config0 = """
590 [loggers]
591 keys=root
592
593 [handlers]
594 keys=hand1
595
596 [formatters]
597 keys=form1
598
599 [logger_root]
600 level=WARNING
601 handlers=hand1
602
603 [handler_hand1]
604 class=StreamHandler
605 level=NOTSET
606 formatter=form1
607 args=(sys.stdout,)
608
609 [formatter_form1]
610 format=%(levelname)s ++ %(message)s
611 datefmt=
612 """
613
614 # config1 adds a little to the standard configuration.
615 config1 = """
616 [loggers]
617 keys=root,parser
618
619 [handlers]
620 keys=hand1
621
622 [formatters]
623 keys=form1
624
625 [logger_root]
626 level=WARNING
627 handlers=
628
629 [logger_parser]
630 level=DEBUG
631 handlers=hand1
632 propagate=1
633 qualname=compiler.parser
634
635 [handler_hand1]
636 class=StreamHandler
637 level=NOTSET
638 formatter=form1
639 args=(sys.stdout,)
640
641 [formatter_form1]
642 format=%(levelname)s ++ %(message)s
643 datefmt=
644 """
645
Vinay Sajip3f84b072011-03-07 17:49:33 +0000646 # config1a moves the handler to the root.
647 config1a = """
648 [loggers]
649 keys=root,parser
650
651 [handlers]
652 keys=hand1
653
654 [formatters]
655 keys=form1
656
657 [logger_root]
658 level=WARNING
659 handlers=hand1
660
661 [logger_parser]
662 level=DEBUG
663 handlers=
664 propagate=1
665 qualname=compiler.parser
666
667 [handler_hand1]
668 class=StreamHandler
669 level=NOTSET
670 formatter=form1
671 args=(sys.stdout,)
672
673 [formatter_form1]
674 format=%(levelname)s ++ %(message)s
675 datefmt=
676 """
677
Christian Heimes180510d2008-03-03 19:15:45 +0000678 # config2 has a subtle configuration error that should be reported
679 config2 = config1.replace("sys.stdout", "sys.stbout")
680
681 # config3 has a less subtle configuration error
682 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
683
684 # config4 specifies a custom formatter class to be loaded
685 config4 = """
686 [loggers]
687 keys=root
688
689 [handlers]
690 keys=hand1
691
692 [formatters]
693 keys=form1
694
695 [logger_root]
696 level=NOTSET
697 handlers=hand1
698
699 [handler_hand1]
700 class=StreamHandler
701 level=NOTSET
702 formatter=form1
703 args=(sys.stdout,)
704
705 [formatter_form1]
706 class=""" + __name__ + """.ExceptionFormatter
707 format=%(levelname)s:%(name)s:%(message)s
708 datefmt=
709 """
710
Georg Brandl3dbca812008-07-23 16:10:53 +0000711 # config5 specifies a custom handler class to be loaded
712 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
713
Benjamin Petersonae5360b2008-09-08 23:05:23 +0000714 # config6 uses ', ' delimiters in the handlers and formatters sections
715 config6 = """
716 [loggers]
717 keys=root,parser
718
719 [handlers]
720 keys=hand1, hand2
721
722 [formatters]
723 keys=form1, form2
724
725 [logger_root]
726 level=WARNING
727 handlers=
728
729 [logger_parser]
730 level=DEBUG
731 handlers=hand1
732 propagate=1
733 qualname=compiler.parser
734
735 [handler_hand1]
736 class=StreamHandler
737 level=NOTSET
738 formatter=form1
739 args=(sys.stdout,)
740
741 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +0000742 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +0000743 level=NOTSET
744 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +0000745 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +0000746
747 [formatter_form1]
748 format=%(levelname)s ++ %(message)s
749 datefmt=
750
751 [formatter_form2]
752 format=%(message)s
753 datefmt=
754 """
755
Vinay Sajip3f84b072011-03-07 17:49:33 +0000756 # config7 adds a compiler logger.
757 config7 = """
758 [loggers]
759 keys=root,parser,compiler
760
761 [handlers]
762 keys=hand1
763
764 [formatters]
765 keys=form1
766
767 [logger_root]
768 level=WARNING
769 handlers=hand1
770
771 [logger_compiler]
772 level=DEBUG
773 handlers=
774 propagate=1
775 qualname=compiler
776
777 [logger_parser]
778 level=DEBUG
779 handlers=
780 propagate=1
781 qualname=compiler.parser
782
783 [handler_hand1]
784 class=StreamHandler
785 level=NOTSET
786 formatter=form1
787 args=(sys.stdout,)
788
789 [formatter_form1]
790 format=%(levelname)s ++ %(message)s
791 datefmt=
792 """
793
Christian Heimes180510d2008-03-03 19:15:45 +0000794 def apply_config(self, conf):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000795 file = io.StringIO(textwrap.dedent(conf))
796 logging.config.fileConfig(file)
Christian Heimes180510d2008-03-03 19:15:45 +0000797
798 def test_config0_ok(self):
799 # A simple config file which overrides the default settings.
800 with captured_stdout() as output:
801 self.apply_config(self.config0)
802 logger = logging.getLogger()
803 # Won't output anything
804 logger.info(self.next_message())
805 # Outputs a message
806 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000807 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000808 ('ERROR', '2'),
809 ], stream=output)
810 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000811 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000812
Georg Brandl3dbca812008-07-23 16:10:53 +0000813 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +0000814 # A config file defining a sub-parser as well.
815 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +0000816 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +0000817 logger = logging.getLogger("compiler.parser")
818 # Both will output a message
819 logger.info(self.next_message())
820 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000821 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000822 ('INFO', '1'),
823 ('ERROR', '2'),
824 ], stream=output)
825 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000826 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000827
828 def test_config2_failure(self):
829 # A simple config file which overrides the default settings.
830 self.assertRaises(Exception, self.apply_config, self.config2)
831
832 def test_config3_failure(self):
833 # A simple config file which overrides the default settings.
834 self.assertRaises(Exception, self.apply_config, self.config3)
835
836 def test_config4_ok(self):
837 # A config file specifying a custom formatter class.
838 with captured_stdout() as output:
839 self.apply_config(self.config4)
840 logger = logging.getLogger()
841 try:
842 raise RuntimeError()
843 except RuntimeError:
844 logging.exception("just testing")
845 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000846 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +0000847 "ERROR:root:just testing\nGot a [RuntimeError]\n")
848 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000849 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000850
Georg Brandl3dbca812008-07-23 16:10:53 +0000851 def test_config5_ok(self):
852 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +0000853
Benjamin Petersonae5360b2008-09-08 23:05:23 +0000854 def test_config6_ok(self):
855 self.test_config1_ok(config=self.config6)
856
Vinay Sajip3f84b072011-03-07 17:49:33 +0000857 def test_config7_ok(self):
858 with captured_stdout() as output:
859 self.apply_config(self.config1a)
860 logger = logging.getLogger("compiler.parser")
861 # See issue #11424. compiler-hyphenated sorts
862 # between compiler and compiler.xyz and this
863 # was preventing compiler.xyz from being included
864 # in the child loggers of compiler because of an
865 # overzealous loop termination condition.
866 hyphenated = logging.getLogger('compiler-hyphenated')
867 # All will output a message
868 logger.info(self.next_message())
869 logger.error(self.next_message())
870 hyphenated.critical(self.next_message())
871 self.assert_log_lines([
872 ('INFO', '1'),
873 ('ERROR', '2'),
874 ('CRITICAL', '3'),
875 ], stream=output)
876 # Original logger output is empty.
877 self.assert_log_lines([])
878 with captured_stdout() as output:
879 self.apply_config(self.config7)
880 logger = logging.getLogger("compiler.parser")
881 self.assertFalse(logger.disabled)
882 # Both will output a message
883 logger.info(self.next_message())
884 logger.error(self.next_message())
885 logger = logging.getLogger("compiler.lexer")
886 # Both will output a message
887 logger.info(self.next_message())
888 logger.error(self.next_message())
889 # Will not appear
890 hyphenated.critical(self.next_message())
891 self.assert_log_lines([
892 ('INFO', '4'),
893 ('ERROR', '5'),
894 ('INFO', '6'),
895 ('ERROR', '7'),
896 ], stream=output)
897 # Original logger output is empty.
898 self.assert_log_lines([])
899
Christian Heimes180510d2008-03-03 19:15:45 +0000900class LogRecordStreamHandler(StreamRequestHandler):
901
902 """Handler for a streaming logging request. It saves the log message in the
903 TCP server's 'log_output' attribute."""
904
905 TCP_LOG_END = "!!!END!!!"
906
907 def handle(self):
908 """Handle multiple requests - each expected to be of 4-byte length,
909 followed by the LogRecord in pickle format. Logs the record
910 according to whatever policy is configured locally."""
911 while True:
912 chunk = self.connection.recv(4)
913 if len(chunk) < 4:
914 break
915 slen = struct.unpack(">L", chunk)[0]
916 chunk = self.connection.recv(slen)
917 while len(chunk) < slen:
918 chunk = chunk + self.connection.recv(slen - len(chunk))
919 obj = self.unpickle(chunk)
920 record = logging.makeLogRecord(obj)
921 self.handle_log_record(record)
922
923 def unpickle(self, data):
924 return pickle.loads(data)
925
926 def handle_log_record(self, record):
927 # If the end-of-messages sentinel is seen, tell the server to
928 # terminate.
929 if self.TCP_LOG_END in record.msg:
930 self.server.abort = 1
931 return
932 self.server.log_output += record.msg + "\n"
933
Guido van Rossum376e6362003-04-25 14:22:00 +0000934
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000935class LogRecordSocketReceiver(ThreadingTCPServer):
Christian Heimes180510d2008-03-03 19:15:45 +0000936
937 """A simple-minded TCP socket-based logging receiver suitable for test
938 purposes."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000939
940 allow_reuse_address = 1
Christian Heimes180510d2008-03-03 19:15:45 +0000941 log_output = ""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000942
943 def __init__(self, host='localhost',
944 port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
945 handler=LogRecordStreamHandler):
946 ThreadingTCPServer.__init__(self, (host, port), handler)
Christian Heimes8640e742008-02-23 16:23:06 +0000947 self.abort = False
Christian Heimes180510d2008-03-03 19:15:45 +0000948 self.timeout = 0.1
949 self.finished = threading.Event()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000950
951 def serve_until_stopped(self):
Neal Norwitz55cd82f2006-02-05 08:21:08 +0000952 while not self.abort:
Neal Norwitz5bab0f82006-03-05 02:16:12 +0000953 rd, wr, ex = select.select([self.socket.fileno()], [], [],
954 self.timeout)
955 if rd:
956 self.handle_request()
Christian Heimes180510d2008-03-03 19:15:45 +0000957 # Notify the main thread that we're about to exit
958 self.finished.set()
Martin v. Löwisf6848882006-01-29 19:55:18 +0000959 # close the listen socket
960 self.server_close()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000961
Guido van Rossum2a1d5162003-01-21 21:05:22 +0000962
Victor Stinner45df8202010-04-28 22:31:17 +0000963@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +0000964class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000965
Christian Heimes180510d2008-03-03 19:15:45 +0000966 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000967
Christian Heimes180510d2008-03-03 19:15:45 +0000968 def setUp(self):
969 """Set up a TCP server to receive log messages, and a SocketHandler
970 pointing to that server's address and port."""
971 BaseTest.setUp(self)
972 self.tcpserver = LogRecordSocketReceiver(port=0)
973 self.port = self.tcpserver.socket.getsockname()[1]
974 self.threads = [
975 threading.Thread(target=self.tcpserver.serve_until_stopped)]
976 for thread in self.threads:
977 thread.start()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000978
Christian Heimes180510d2008-03-03 19:15:45 +0000979 self.sock_hdlr = logging.handlers.SocketHandler('localhost', self.port)
980 self.sock_hdlr.setFormatter(self.root_formatter)
981 self.root_logger.removeHandler(self.root_logger.handlers[0])
982 self.root_logger.addHandler(self.sock_hdlr)
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000983
Christian Heimes180510d2008-03-03 19:15:45 +0000984 def tearDown(self):
985 """Shutdown the TCP server."""
986 try:
987 self.tcpserver.abort = True
988 del self.tcpserver
989 self.root_logger.removeHandler(self.sock_hdlr)
990 self.sock_hdlr.close()
991 for thread in self.threads:
992 thread.join(2.0)
993 finally:
994 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000995
Christian Heimes180510d2008-03-03 19:15:45 +0000996 def get_output(self):
997 """Get the log output as received by the TCP server."""
998 # Signal the TCP receiver and wait for it to terminate.
999 self.root_logger.critical(LogRecordStreamHandler.TCP_LOG_END)
1000 self.tcpserver.finished.wait(2.0)
1001 return self.tcpserver.log_output
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001002
Christian Heimes180510d2008-03-03 19:15:45 +00001003 def test_output(self):
1004 # The log message sent to the SocketHandler is properly received.
1005 logger = logging.getLogger("tcp")
1006 logger.error("spam")
1007 logger.debug("eggs")
Ezio Melottib3aedd42010-11-20 19:04:17 +00001008 self.assertEqual(self.get_output(), "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001009
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001010
Christian Heimes180510d2008-03-03 19:15:45 +00001011class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001012
Christian Heimes180510d2008-03-03 19:15:45 +00001013 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001014
Christian Heimes180510d2008-03-03 19:15:45 +00001015 def setUp(self):
1016 """Create a dict to remember potentially destroyed objects."""
1017 BaseTest.setUp(self)
1018 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001019
Christian Heimes180510d2008-03-03 19:15:45 +00001020 def _watch_for_survival(self, *args):
1021 """Watch the given objects for survival, by creating weakrefs to
1022 them."""
1023 for obj in args:
1024 key = id(obj), repr(obj)
1025 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001026
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001027 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001028 """Assert that all objects watched for survival have survived."""
1029 # Trigger cycle breaking.
1030 gc.collect()
1031 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001032 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001033 if ref() is None:
1034 dead.append(repr_)
1035 if dead:
1036 self.fail("%d objects should have survived "
1037 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001038
Christian Heimes180510d2008-03-03 19:15:45 +00001039 def test_persistent_loggers(self):
1040 # Logger objects are persistent and retain their configuration, even
1041 # if visible references are destroyed.
1042 self.root_logger.setLevel(logging.INFO)
1043 foo = logging.getLogger("foo")
1044 self._watch_for_survival(foo)
1045 foo.setLevel(logging.DEBUG)
1046 self.root_logger.debug(self.next_message())
1047 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001048 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001049 ('foo', 'DEBUG', '2'),
1050 ])
1051 del foo
1052 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001053 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001054 # foo has retained its settings.
1055 bar = logging.getLogger("foo")
1056 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001057 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001058 ('foo', 'DEBUG', '2'),
1059 ('foo', 'DEBUG', '3'),
1060 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001061
Benjamin Petersonf91df042009-02-13 02:50:59 +00001062
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001063class EncodingTest(BaseTest):
1064 def test_encoding_plain_file(self):
1065 # In Python 2.x, a plain file object is treated as having no encoding.
1066 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001067 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1068 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001069 # the non-ascii data we write to the log.
1070 data = "foo\x80"
1071 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001072 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001073 log.addHandler(handler)
1074 try:
1075 # write non-ascii data to the log.
1076 log.warning(data)
1077 finally:
1078 log.removeHandler(handler)
1079 handler.close()
1080 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001081 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001082 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001083 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001084 finally:
1085 f.close()
1086 finally:
1087 if os.path.isfile(fn):
1088 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001089
Benjamin Petersonf91df042009-02-13 02:50:59 +00001090 def test_encoding_cyrillic_unicode(self):
1091 log = logging.getLogger("test")
1092 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1093 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1094 #Ensure it's written in a Cyrillic encoding
1095 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001096 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001097 stream = io.BytesIO()
1098 writer = writer_class(stream, 'strict')
1099 handler = logging.StreamHandler(writer)
1100 log.addHandler(handler)
1101 try:
1102 log.warning(message)
1103 finally:
1104 log.removeHandler(handler)
1105 handler.close()
1106 # check we wrote exactly those bytes, ignoring trailing \n etc
1107 s = stream.getvalue()
1108 #Compare against what the data should be when encoded in CP-1251
1109 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1110
1111
Georg Brandlf9734072008-12-07 15:30:06 +00001112class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001113
Georg Brandlf9734072008-12-07 15:30:06 +00001114 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001115 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001116 logging.captureWarnings(True)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001117 self.addCleanup(lambda: logging.captureWarnings(False))
1118 warnings.filterwarnings("always", category=UserWarning)
1119 stream = io.StringIO()
1120 h = logging.StreamHandler(stream)
1121 logger = logging.getLogger("py.warnings")
1122 logger.addHandler(h)
1123 warnings.warn("I'm warning you...")
1124 logger.removeHandler(h)
1125 s = stream.getvalue()
1126 h.close()
1127 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001128
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001129 #See if an explicit file uses the original implementation
1130 a_file = io.StringIO()
1131 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1132 a_file, "Dummy line")
1133 s = a_file.getvalue()
1134 a_file.close()
1135 self.assertEqual(s,
1136 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1137
1138 def test_warnings_no_handlers(self):
1139 with warnings.catch_warnings():
1140 logging.captureWarnings(True)
1141 self.addCleanup(lambda: logging.captureWarnings(False))
1142
1143 # confirm our assumption: no loggers are set
1144 logger = logging.getLogger("py.warnings")
1145 assert logger.handlers == []
1146
1147 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
1148 self.assertTrue(len(logger.handlers) == 1)
1149 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001150
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001151
1152def formatFunc(format, datefmt=None):
1153 return logging.Formatter(format, datefmt)
1154
1155def handlerFunc():
1156 return logging.StreamHandler()
1157
1158class CustomHandler(logging.StreamHandler):
1159 pass
1160
1161class ConfigDictTest(BaseTest):
1162
1163 """Reading logging config from a dictionary."""
1164
1165 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1166
1167 # config0 is a standard configuration.
1168 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001169 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001170 'formatters': {
1171 'form1' : {
1172 'format' : '%(levelname)s ++ %(message)s',
1173 },
1174 },
1175 'handlers' : {
1176 'hand1' : {
1177 'class' : 'logging.StreamHandler',
1178 'formatter' : 'form1',
1179 'level' : 'NOTSET',
1180 'stream' : 'ext://sys.stdout',
1181 },
1182 },
1183 'root' : {
1184 'level' : 'WARNING',
1185 'handlers' : ['hand1'],
1186 },
1187 }
1188
1189 # config1 adds a little to the standard configuration.
1190 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001191 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001192 'formatters': {
1193 'form1' : {
1194 'format' : '%(levelname)s ++ %(message)s',
1195 },
1196 },
1197 'handlers' : {
1198 'hand1' : {
1199 'class' : 'logging.StreamHandler',
1200 'formatter' : 'form1',
1201 'level' : 'NOTSET',
1202 'stream' : 'ext://sys.stdout',
1203 },
1204 },
1205 'loggers' : {
1206 'compiler.parser' : {
1207 'level' : 'DEBUG',
1208 'handlers' : ['hand1'],
1209 },
1210 },
1211 'root' : {
1212 'level' : 'WARNING',
1213 },
1214 }
1215
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001216 # config1a moves the handler to the root. Used with config8a
1217 config1a = {
1218 'version': 1,
1219 'formatters': {
1220 'form1' : {
1221 'format' : '%(levelname)s ++ %(message)s',
1222 },
1223 },
1224 'handlers' : {
1225 'hand1' : {
1226 'class' : 'logging.StreamHandler',
1227 'formatter' : 'form1',
1228 'level' : 'NOTSET',
1229 'stream' : 'ext://sys.stdout',
1230 },
1231 },
1232 'loggers' : {
1233 'compiler.parser' : {
1234 'level' : 'DEBUG',
1235 },
1236 },
1237 'root' : {
1238 'level' : 'WARNING',
1239 'handlers' : ['hand1'],
1240 },
1241 }
1242
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001243 # config2 has a subtle configuration error that should be reported
1244 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001245 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001246 'formatters': {
1247 'form1' : {
1248 'format' : '%(levelname)s ++ %(message)s',
1249 },
1250 },
1251 'handlers' : {
1252 'hand1' : {
1253 'class' : 'logging.StreamHandler',
1254 'formatter' : 'form1',
1255 'level' : 'NOTSET',
1256 'stream' : 'ext://sys.stdbout',
1257 },
1258 },
1259 'loggers' : {
1260 'compiler.parser' : {
1261 'level' : 'DEBUG',
1262 'handlers' : ['hand1'],
1263 },
1264 },
1265 'root' : {
1266 'level' : 'WARNING',
1267 },
1268 }
1269
1270 #As config1 but with a misspelt level on a handler
1271 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001272 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001273 'formatters': {
1274 'form1' : {
1275 'format' : '%(levelname)s ++ %(message)s',
1276 },
1277 },
1278 'handlers' : {
1279 'hand1' : {
1280 'class' : 'logging.StreamHandler',
1281 'formatter' : 'form1',
1282 'level' : 'NTOSET',
1283 'stream' : 'ext://sys.stdout',
1284 },
1285 },
1286 'loggers' : {
1287 'compiler.parser' : {
1288 'level' : 'DEBUG',
1289 'handlers' : ['hand1'],
1290 },
1291 },
1292 'root' : {
1293 'level' : 'WARNING',
1294 },
1295 }
1296
1297
1298 #As config1 but with a misspelt level on a logger
1299 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001300 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001301 'formatters': {
1302 'form1' : {
1303 'format' : '%(levelname)s ++ %(message)s',
1304 },
1305 },
1306 'handlers' : {
1307 'hand1' : {
1308 'class' : 'logging.StreamHandler',
1309 'formatter' : 'form1',
1310 'level' : 'NOTSET',
1311 'stream' : 'ext://sys.stdout',
1312 },
1313 },
1314 'loggers' : {
1315 'compiler.parser' : {
1316 'level' : 'DEBUG',
1317 'handlers' : ['hand1'],
1318 },
1319 },
1320 'root' : {
1321 'level' : 'WRANING',
1322 },
1323 }
1324
1325 # config3 has a less subtle configuration error
1326 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001327 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001328 'formatters': {
1329 'form1' : {
1330 'format' : '%(levelname)s ++ %(message)s',
1331 },
1332 },
1333 'handlers' : {
1334 'hand1' : {
1335 'class' : 'logging.StreamHandler',
1336 'formatter' : 'misspelled_name',
1337 'level' : 'NOTSET',
1338 'stream' : 'ext://sys.stdout',
1339 },
1340 },
1341 'loggers' : {
1342 'compiler.parser' : {
1343 'level' : 'DEBUG',
1344 'handlers' : ['hand1'],
1345 },
1346 },
1347 'root' : {
1348 'level' : 'WARNING',
1349 },
1350 }
1351
1352 # config4 specifies a custom formatter class to be loaded
1353 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001354 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001355 'formatters': {
1356 'form1' : {
1357 '()' : __name__ + '.ExceptionFormatter',
1358 'format' : '%(levelname)s:%(name)s:%(message)s',
1359 },
1360 },
1361 'handlers' : {
1362 'hand1' : {
1363 'class' : 'logging.StreamHandler',
1364 'formatter' : 'form1',
1365 'level' : 'NOTSET',
1366 'stream' : 'ext://sys.stdout',
1367 },
1368 },
1369 'root' : {
1370 'level' : 'NOTSET',
1371 'handlers' : ['hand1'],
1372 },
1373 }
1374
1375 # As config4 but using an actual callable rather than a string
1376 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001377 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001378 'formatters': {
1379 'form1' : {
1380 '()' : ExceptionFormatter,
1381 'format' : '%(levelname)s:%(name)s:%(message)s',
1382 },
1383 'form2' : {
1384 '()' : __name__ + '.formatFunc',
1385 'format' : '%(levelname)s:%(name)s:%(message)s',
1386 },
1387 'form3' : {
1388 '()' : formatFunc,
1389 'format' : '%(levelname)s:%(name)s:%(message)s',
1390 },
1391 },
1392 'handlers' : {
1393 'hand1' : {
1394 'class' : 'logging.StreamHandler',
1395 'formatter' : 'form1',
1396 'level' : 'NOTSET',
1397 'stream' : 'ext://sys.stdout',
1398 },
1399 'hand2' : {
1400 '()' : handlerFunc,
1401 },
1402 },
1403 'root' : {
1404 'level' : 'NOTSET',
1405 'handlers' : ['hand1'],
1406 },
1407 }
1408
1409 # config5 specifies a custom handler class to be loaded
1410 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001411 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001412 'formatters': {
1413 'form1' : {
1414 'format' : '%(levelname)s ++ %(message)s',
1415 },
1416 },
1417 'handlers' : {
1418 'hand1' : {
1419 'class' : __name__ + '.CustomHandler',
1420 'formatter' : 'form1',
1421 'level' : 'NOTSET',
1422 'stream' : 'ext://sys.stdout',
1423 },
1424 },
1425 'loggers' : {
1426 'compiler.parser' : {
1427 'level' : 'DEBUG',
1428 'handlers' : ['hand1'],
1429 },
1430 },
1431 'root' : {
1432 'level' : 'WARNING',
1433 },
1434 }
1435
1436 # config6 specifies a custom handler class to be loaded
1437 # but has bad arguments
1438 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001439 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001440 'formatters': {
1441 'form1' : {
1442 'format' : '%(levelname)s ++ %(message)s',
1443 },
1444 },
1445 'handlers' : {
1446 'hand1' : {
1447 'class' : __name__ + '.CustomHandler',
1448 'formatter' : 'form1',
1449 'level' : 'NOTSET',
1450 'stream' : 'ext://sys.stdout',
1451 '9' : 'invalid parameter name',
1452 },
1453 },
1454 'loggers' : {
1455 'compiler.parser' : {
1456 'level' : 'DEBUG',
1457 'handlers' : ['hand1'],
1458 },
1459 },
1460 'root' : {
1461 'level' : 'WARNING',
1462 },
1463 }
1464
1465 #config 7 does not define compiler.parser but defines compiler.lexer
1466 #so compiler.parser should be disabled after applying it
1467 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001468 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001469 'formatters': {
1470 'form1' : {
1471 'format' : '%(levelname)s ++ %(message)s',
1472 },
1473 },
1474 'handlers' : {
1475 'hand1' : {
1476 'class' : 'logging.StreamHandler',
1477 'formatter' : 'form1',
1478 'level' : 'NOTSET',
1479 'stream' : 'ext://sys.stdout',
1480 },
1481 },
1482 'loggers' : {
1483 'compiler.lexer' : {
1484 'level' : 'DEBUG',
1485 'handlers' : ['hand1'],
1486 },
1487 },
1488 'root' : {
1489 'level' : 'WARNING',
1490 },
1491 }
1492
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001493 # config8 defines both compiler and compiler.lexer
1494 # so compiler.parser should not be disabled (since
1495 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001496 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001497 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001498 'disable_existing_loggers' : False,
1499 'formatters': {
1500 'form1' : {
1501 'format' : '%(levelname)s ++ %(message)s',
1502 },
1503 },
1504 'handlers' : {
1505 'hand1' : {
1506 'class' : 'logging.StreamHandler',
1507 'formatter' : 'form1',
1508 'level' : 'NOTSET',
1509 'stream' : 'ext://sys.stdout',
1510 },
1511 },
1512 'loggers' : {
1513 'compiler' : {
1514 'level' : 'DEBUG',
1515 'handlers' : ['hand1'],
1516 },
1517 'compiler.lexer' : {
1518 },
1519 },
1520 'root' : {
1521 'level' : 'WARNING',
1522 },
1523 }
1524
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001525 # config8a disables existing loggers
1526 config8a = {
1527 'version': 1,
1528 'disable_existing_loggers' : True,
1529 'formatters': {
1530 'form1' : {
1531 'format' : '%(levelname)s ++ %(message)s',
1532 },
1533 },
1534 'handlers' : {
1535 'hand1' : {
1536 'class' : 'logging.StreamHandler',
1537 'formatter' : 'form1',
1538 'level' : 'NOTSET',
1539 'stream' : 'ext://sys.stdout',
1540 },
1541 },
1542 'loggers' : {
1543 'compiler' : {
1544 'level' : 'DEBUG',
1545 'handlers' : ['hand1'],
1546 },
1547 'compiler.lexer' : {
1548 },
1549 },
1550 'root' : {
1551 'level' : 'WARNING',
1552 },
1553 }
1554
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001555 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001556 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001557 'formatters': {
1558 'form1' : {
1559 'format' : '%(levelname)s ++ %(message)s',
1560 },
1561 },
1562 'handlers' : {
1563 'hand1' : {
1564 'class' : 'logging.StreamHandler',
1565 'formatter' : 'form1',
1566 'level' : 'WARNING',
1567 'stream' : 'ext://sys.stdout',
1568 },
1569 },
1570 'loggers' : {
1571 'compiler.parser' : {
1572 'level' : 'WARNING',
1573 'handlers' : ['hand1'],
1574 },
1575 },
1576 'root' : {
1577 'level' : 'NOTSET',
1578 },
1579 }
1580
1581 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001582 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001583 'incremental' : True,
1584 'handlers' : {
1585 'hand1' : {
1586 'level' : 'WARNING',
1587 },
1588 },
1589 'loggers' : {
1590 'compiler.parser' : {
1591 'level' : 'INFO',
1592 },
1593 },
1594 }
1595
1596 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001597 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001598 'incremental' : True,
1599 'handlers' : {
1600 'hand1' : {
1601 'level' : 'INFO',
1602 },
1603 },
1604 'loggers' : {
1605 'compiler.parser' : {
1606 'level' : 'INFO',
1607 },
1608 },
1609 }
1610
1611 #As config1 but with a filter added
1612 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001613 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001614 'formatters': {
1615 'form1' : {
1616 'format' : '%(levelname)s ++ %(message)s',
1617 },
1618 },
1619 'filters' : {
1620 'filt1' : {
1621 'name' : 'compiler.parser',
1622 },
1623 },
1624 'handlers' : {
1625 'hand1' : {
1626 'class' : 'logging.StreamHandler',
1627 'formatter' : 'form1',
1628 'level' : 'NOTSET',
1629 'stream' : 'ext://sys.stdout',
1630 'filters' : ['filt1'],
1631 },
1632 },
1633 'loggers' : {
1634 'compiler.parser' : {
1635 'level' : 'DEBUG',
1636 'filters' : ['filt1'],
1637 },
1638 },
1639 'root' : {
1640 'level' : 'WARNING',
1641 'handlers' : ['hand1'],
1642 },
1643 }
1644
1645 #As config1 but using cfg:// references
1646 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001647 'version': 1,
1648 'true_formatters': {
1649 'form1' : {
1650 'format' : '%(levelname)s ++ %(message)s',
1651 },
1652 },
1653 'handler_configs': {
1654 'hand1' : {
1655 'class' : 'logging.StreamHandler',
1656 'formatter' : 'form1',
1657 'level' : 'NOTSET',
1658 'stream' : 'ext://sys.stdout',
1659 },
1660 },
1661 'formatters' : 'cfg://true_formatters',
1662 'handlers' : {
1663 'hand1' : 'cfg://handler_configs[hand1]',
1664 },
1665 'loggers' : {
1666 'compiler.parser' : {
1667 'level' : 'DEBUG',
1668 'handlers' : ['hand1'],
1669 },
1670 },
1671 'root' : {
1672 'level' : 'WARNING',
1673 },
1674 }
1675
1676 #As config11 but missing the version key
1677 config12 = {
1678 'true_formatters': {
1679 'form1' : {
1680 'format' : '%(levelname)s ++ %(message)s',
1681 },
1682 },
1683 'handler_configs': {
1684 'hand1' : {
1685 'class' : 'logging.StreamHandler',
1686 'formatter' : 'form1',
1687 'level' : 'NOTSET',
1688 'stream' : 'ext://sys.stdout',
1689 },
1690 },
1691 'formatters' : 'cfg://true_formatters',
1692 'handlers' : {
1693 'hand1' : 'cfg://handler_configs[hand1]',
1694 },
1695 'loggers' : {
1696 'compiler.parser' : {
1697 'level' : 'DEBUG',
1698 'handlers' : ['hand1'],
1699 },
1700 },
1701 'root' : {
1702 'level' : 'WARNING',
1703 },
1704 }
1705
1706 #As config11 but using an unsupported version
1707 config13 = {
1708 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001709 'true_formatters': {
1710 'form1' : {
1711 'format' : '%(levelname)s ++ %(message)s',
1712 },
1713 },
1714 'handler_configs': {
1715 'hand1' : {
1716 'class' : 'logging.StreamHandler',
1717 'formatter' : 'form1',
1718 'level' : 'NOTSET',
1719 'stream' : 'ext://sys.stdout',
1720 },
1721 },
1722 'formatters' : 'cfg://true_formatters',
1723 'handlers' : {
1724 'hand1' : 'cfg://handler_configs[hand1]',
1725 },
1726 'loggers' : {
1727 'compiler.parser' : {
1728 'level' : 'DEBUG',
1729 'handlers' : ['hand1'],
1730 },
1731 },
1732 'root' : {
1733 'level' : 'WARNING',
1734 },
1735 }
1736
1737 def apply_config(self, conf):
1738 logging.config.dictConfig(conf)
1739
1740 def test_config0_ok(self):
1741 # A simple config which overrides the default settings.
1742 with captured_stdout() as output:
1743 self.apply_config(self.config0)
1744 logger = logging.getLogger()
1745 # Won't output anything
1746 logger.info(self.next_message())
1747 # Outputs a message
1748 logger.error(self.next_message())
1749 self.assert_log_lines([
1750 ('ERROR', '2'),
1751 ], stream=output)
1752 # Original logger output is empty.
1753 self.assert_log_lines([])
1754
1755 def test_config1_ok(self, config=config1):
1756 # A config defining a sub-parser as well.
1757 with captured_stdout() as output:
1758 self.apply_config(config)
1759 logger = logging.getLogger("compiler.parser")
1760 # Both will output a message
1761 logger.info(self.next_message())
1762 logger.error(self.next_message())
1763 self.assert_log_lines([
1764 ('INFO', '1'),
1765 ('ERROR', '2'),
1766 ], stream=output)
1767 # Original logger output is empty.
1768 self.assert_log_lines([])
1769
1770 def test_config2_failure(self):
1771 # A simple config which overrides the default settings.
1772 self.assertRaises(Exception, self.apply_config, self.config2)
1773
1774 def test_config2a_failure(self):
1775 # A simple config which overrides the default settings.
1776 self.assertRaises(Exception, self.apply_config, self.config2a)
1777
1778 def test_config2b_failure(self):
1779 # A simple config which overrides the default settings.
1780 self.assertRaises(Exception, self.apply_config, self.config2b)
1781
1782 def test_config3_failure(self):
1783 # A simple config which overrides the default settings.
1784 self.assertRaises(Exception, self.apply_config, self.config3)
1785
1786 def test_config4_ok(self):
1787 # A config specifying a custom formatter class.
1788 with captured_stdout() as output:
1789 self.apply_config(self.config4)
1790 #logger = logging.getLogger()
1791 try:
1792 raise RuntimeError()
1793 except RuntimeError:
1794 logging.exception("just testing")
1795 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001796 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001797 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1798 # Original logger output is empty
1799 self.assert_log_lines([])
1800
1801 def test_config4a_ok(self):
1802 # A config specifying a custom formatter class.
1803 with captured_stdout() as output:
1804 self.apply_config(self.config4a)
1805 #logger = logging.getLogger()
1806 try:
1807 raise RuntimeError()
1808 except RuntimeError:
1809 logging.exception("just testing")
1810 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001811 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001812 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1813 # Original logger output is empty
1814 self.assert_log_lines([])
1815
1816 def test_config5_ok(self):
1817 self.test_config1_ok(config=self.config5)
1818
1819 def test_config6_failure(self):
1820 self.assertRaises(Exception, self.apply_config, self.config6)
1821
1822 def test_config7_ok(self):
1823 with captured_stdout() as output:
1824 self.apply_config(self.config1)
1825 logger = logging.getLogger("compiler.parser")
1826 # Both will output a message
1827 logger.info(self.next_message())
1828 logger.error(self.next_message())
1829 self.assert_log_lines([
1830 ('INFO', '1'),
1831 ('ERROR', '2'),
1832 ], stream=output)
1833 # Original logger output is empty.
1834 self.assert_log_lines([])
1835 with captured_stdout() as output:
1836 self.apply_config(self.config7)
1837 logger = logging.getLogger("compiler.parser")
1838 self.assertTrue(logger.disabled)
1839 logger = logging.getLogger("compiler.lexer")
1840 # Both will output a message
1841 logger.info(self.next_message())
1842 logger.error(self.next_message())
1843 self.assert_log_lines([
1844 ('INFO', '3'),
1845 ('ERROR', '4'),
1846 ], stream=output)
1847 # Original logger output is empty.
1848 self.assert_log_lines([])
1849
1850 #Same as test_config_7_ok but don't disable old loggers.
1851 def test_config_8_ok(self):
1852 with captured_stdout() as output:
1853 self.apply_config(self.config1)
1854 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001855 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001856 logger.info(self.next_message())
1857 logger.error(self.next_message())
1858 self.assert_log_lines([
1859 ('INFO', '1'),
1860 ('ERROR', '2'),
1861 ], stream=output)
1862 # Original logger output is empty.
1863 self.assert_log_lines([])
1864 with captured_stdout() as output:
1865 self.apply_config(self.config8)
1866 logger = logging.getLogger("compiler.parser")
1867 self.assertFalse(logger.disabled)
1868 # Both will output a message
1869 logger.info(self.next_message())
1870 logger.error(self.next_message())
1871 logger = logging.getLogger("compiler.lexer")
1872 # Both will output a message
1873 logger.info(self.next_message())
1874 logger.error(self.next_message())
1875 self.assert_log_lines([
1876 ('INFO', '3'),
1877 ('ERROR', '4'),
1878 ('INFO', '5'),
1879 ('ERROR', '6'),
1880 ], stream=output)
1881 # Original logger output is empty.
1882 self.assert_log_lines([])
1883
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001884 def test_config_8a_ok(self):
1885 with captured_stdout() as output:
1886 self.apply_config(self.config1a)
1887 logger = logging.getLogger("compiler.parser")
1888 # See issue #11424. compiler-hyphenated sorts
1889 # between compiler and compiler.xyz and this
1890 # was preventing compiler.xyz from being included
1891 # in the child loggers of compiler because of an
1892 # overzealous loop termination condition.
1893 hyphenated = logging.getLogger('compiler-hyphenated')
1894 # All will output a message
1895 logger.info(self.next_message())
1896 logger.error(self.next_message())
1897 hyphenated.critical(self.next_message())
1898 self.assert_log_lines([
1899 ('INFO', '1'),
1900 ('ERROR', '2'),
1901 ('CRITICAL', '3'),
1902 ], stream=output)
1903 # Original logger output is empty.
1904 self.assert_log_lines([])
1905 with captured_stdout() as output:
1906 self.apply_config(self.config8a)
1907 logger = logging.getLogger("compiler.parser")
1908 self.assertFalse(logger.disabled)
1909 # Both will output a message
1910 logger.info(self.next_message())
1911 logger.error(self.next_message())
1912 logger = logging.getLogger("compiler.lexer")
1913 # Both will output a message
1914 logger.info(self.next_message())
1915 logger.error(self.next_message())
1916 # Will not appear
1917 hyphenated.critical(self.next_message())
1918 self.assert_log_lines([
1919 ('INFO', '4'),
1920 ('ERROR', '5'),
1921 ('INFO', '6'),
1922 ('ERROR', '7'),
1923 ], stream=output)
1924 # Original logger output is empty.
1925 self.assert_log_lines([])
1926
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001927 def test_config_9_ok(self):
1928 with captured_stdout() as output:
1929 self.apply_config(self.config9)
1930 logger = logging.getLogger("compiler.parser")
1931 #Nothing will be output since both handler and logger are set to WARNING
1932 logger.info(self.next_message())
1933 self.assert_log_lines([], stream=output)
1934 self.apply_config(self.config9a)
1935 #Nothing will be output since both handler is still set to WARNING
1936 logger.info(self.next_message())
1937 self.assert_log_lines([], stream=output)
1938 self.apply_config(self.config9b)
1939 #Message should now be output
1940 logger.info(self.next_message())
1941 self.assert_log_lines([
1942 ('INFO', '3'),
1943 ], stream=output)
1944
1945 def test_config_10_ok(self):
1946 with captured_stdout() as output:
1947 self.apply_config(self.config10)
1948 logger = logging.getLogger("compiler.parser")
1949 logger.warning(self.next_message())
1950 logger = logging.getLogger('compiler')
1951 #Not output, because filtered
1952 logger.warning(self.next_message())
1953 logger = logging.getLogger('compiler.lexer')
1954 #Not output, because filtered
1955 logger.warning(self.next_message())
1956 logger = logging.getLogger("compiler.parser.codegen")
1957 #Output, as not filtered
1958 logger.error(self.next_message())
1959 self.assert_log_lines([
1960 ('WARNING', '1'),
1961 ('ERROR', '4'),
1962 ], stream=output)
1963
1964 def test_config11_ok(self):
1965 self.test_config1_ok(self.config11)
1966
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001967 def test_config12_failure(self):
1968 self.assertRaises(Exception, self.apply_config, self.config12)
1969
1970 def test_config13_failure(self):
1971 self.assertRaises(Exception, self.apply_config, self.config13)
1972
Victor Stinner45df8202010-04-28 22:31:17 +00001973 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001974 def setup_via_listener(self, text):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001975 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00001976 # Ask for a randomly assigned port (by using port 0)
1977 t = logging.config.listen(0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001978 t.start()
1979 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00001980 # Now get the port allocated
1981 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001982 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001983 try:
1984 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1985 sock.settimeout(2.0)
1986 sock.connect(('localhost', port))
1987
1988 slen = struct.pack('>L', len(text))
1989 s = slen + text
1990 sentsofar = 0
1991 left = len(s)
1992 while left > 0:
1993 sent = sock.send(s[sentsofar:])
1994 sentsofar += sent
1995 left -= sent
1996 sock.close()
1997 finally:
1998 t.ready.wait(2.0)
1999 logging.config.stopListening()
2000 t.join(2.0)
2001
2002 def test_listen_config_10_ok(self):
2003 with captured_stdout() as output:
2004 self.setup_via_listener(json.dumps(self.config10))
2005 logger = logging.getLogger("compiler.parser")
2006 logger.warning(self.next_message())
2007 logger = logging.getLogger('compiler')
2008 #Not output, because filtered
2009 logger.warning(self.next_message())
2010 logger = logging.getLogger('compiler.lexer')
2011 #Not output, because filtered
2012 logger.warning(self.next_message())
2013 logger = logging.getLogger("compiler.parser.codegen")
2014 #Output, as not filtered
2015 logger.error(self.next_message())
2016 self.assert_log_lines([
2017 ('WARNING', '1'),
2018 ('ERROR', '4'),
2019 ], stream=output)
2020
2021 def test_listen_config_1_ok(self):
2022 with captured_stdout() as output:
2023 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2024 logger = logging.getLogger("compiler.parser")
2025 # Both will output a message
2026 logger.info(self.next_message())
2027 logger.error(self.next_message())
2028 self.assert_log_lines([
2029 ('INFO', '1'),
2030 ('ERROR', '2'),
2031 ], stream=output)
2032 # Original logger output is empty.
2033 self.assert_log_lines([])
2034
2035
2036class ManagerTest(BaseTest):
2037 def test_manager_loggerclass(self):
2038 logged = []
2039
2040 class MyLogger(logging.Logger):
2041 def _log(self, level, msg, args, exc_info=None, extra=None):
2042 logged.append(msg)
2043
2044 man = logging.Manager(None)
2045 self.assertRaises(TypeError, man.setLoggerClass, int)
2046 man.setLoggerClass(MyLogger)
2047 logger = man.getLogger('test')
2048 logger.warning('should appear in logged')
2049 logging.warning('should not appear in logged')
2050
2051 self.assertEqual(logged, ['should appear in logged'])
2052
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002053 def test_set_log_record_factory(self):
2054 man = logging.Manager(None)
2055 expected = object()
2056 man.setLogRecordFactory(expected)
2057 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002058
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002059class ChildLoggerTest(BaseTest):
2060 def test_child_loggers(self):
2061 r = logging.getLogger()
2062 l1 = logging.getLogger('abc')
2063 l2 = logging.getLogger('def.ghi')
2064 c1 = r.getChild('xyz')
2065 c2 = r.getChild('uvw.xyz')
2066 self.assertTrue(c1 is logging.getLogger('xyz'))
2067 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
2068 c1 = l1.getChild('def')
2069 c2 = c1.getChild('ghi')
2070 c3 = l1.getChild('def.ghi')
2071 self.assertTrue(c1 is logging.getLogger('abc.def'))
2072 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
2073 self.assertTrue(c2 is c3)
2074
2075
Vinay Sajip6fac8172010-10-19 20:44:14 +00002076class DerivedLogRecord(logging.LogRecord):
2077 pass
2078
Vinay Sajip61561522010-12-03 11:50:38 +00002079class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002080
2081 def setUp(self):
2082 class CheckingFilter(logging.Filter):
2083 def __init__(self, cls):
2084 self.cls = cls
2085
2086 def filter(self, record):
2087 t = type(record)
2088 if t is not self.cls:
2089 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2090 self.cls)
2091 raise TypeError(msg)
2092 return True
2093
2094 BaseTest.setUp(self)
2095 self.filter = CheckingFilter(DerivedLogRecord)
2096 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002097 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002098
2099 def tearDown(self):
2100 self.root_logger.removeFilter(self.filter)
2101 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002102 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002103
2104 def test_logrecord_class(self):
2105 self.assertRaises(TypeError, self.root_logger.warning,
2106 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002107 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002108 self.root_logger.error(self.next_message())
2109 self.assert_log_lines([
2110 ('root', 'ERROR', '2'),
2111 ])
2112
2113
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002114class QueueHandlerTest(BaseTest):
2115 # Do not bother with a logger name group.
2116 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
2117
2118 def setUp(self):
2119 BaseTest.setUp(self)
2120 self.queue = queue.Queue(-1)
2121 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2122 self.que_logger = logging.getLogger('que')
2123 self.que_logger.propagate = False
2124 self.que_logger.setLevel(logging.WARNING)
2125 self.que_logger.addHandler(self.que_hdlr)
2126
2127 def tearDown(self):
2128 self.que_hdlr.close()
2129 BaseTest.tearDown(self)
2130
2131 def test_queue_handler(self):
2132 self.que_logger.debug(self.next_message())
2133 self.assertRaises(queue.Empty, self.queue.get_nowait)
2134 self.que_logger.info(self.next_message())
2135 self.assertRaises(queue.Empty, self.queue.get_nowait)
2136 msg = self.next_message()
2137 self.que_logger.warning(msg)
2138 data = self.queue.get_nowait()
2139 self.assertTrue(isinstance(data, logging.LogRecord))
2140 self.assertEqual(data.name, self.que_logger.name)
2141 self.assertEqual((data.msg, data.args), (msg, None))
2142
Vinay Sajipe723e962011-04-15 22:27:17 +01002143 def test_queue_listener(self):
2144 handler = TestHandler(Matcher())
2145 listener = logging.handlers.QueueListener(self.queue, handler)
2146 listener.start()
2147 try:
2148 self.que_logger.warning(self.next_message())
2149 self.que_logger.error(self.next_message())
2150 self.que_logger.critical(self.next_message())
2151 finally:
2152 listener.stop()
2153 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2154 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2155 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2156
2157
Vinay Sajipa39c5712010-10-25 13:57:39 +00002158class FormatterTest(unittest.TestCase):
2159 def setUp(self):
2160 self.common = {
2161 'name': 'formatter.test',
2162 'level': logging.DEBUG,
2163 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2164 'lineno': 42,
2165 'exc_info': None,
2166 'func': None,
2167 'msg': 'Message with %d %s',
2168 'args': (2, 'placeholders'),
2169 }
2170 self.variants = {
2171 }
2172
2173 def get_record(self, name=None):
2174 result = dict(self.common)
2175 if name is not None:
2176 result.update(self.variants[name])
2177 return logging.makeLogRecord(result)
2178
2179 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002180 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002181 r = self.get_record()
2182 f = logging.Formatter('${%(message)s}')
2183 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2184 f = logging.Formatter('%(random)s')
2185 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002186 self.assertFalse(f.usesTime())
2187 f = logging.Formatter('%(asctime)s')
2188 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002189 f = logging.Formatter('%(asctime)-15s')
2190 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002191 f = logging.Formatter('asctime')
2192 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002193
2194 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002195 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002196 r = self.get_record()
2197 f = logging.Formatter('$%{message}%$', style='{')
2198 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2199 f = logging.Formatter('{random}', style='{')
2200 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002201 self.assertFalse(f.usesTime())
2202 f = logging.Formatter('{asctime}', style='{')
2203 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002204 f = logging.Formatter('{asctime!s:15}', style='{')
2205 self.assertTrue(f.usesTime())
2206 f = logging.Formatter('{asctime:15}', style='{')
2207 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002208 f = logging.Formatter('asctime', style='{')
2209 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002210
2211 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002212 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002213 r = self.get_record()
2214 f = logging.Formatter('$message', style='$')
2215 self.assertEqual(f.format(r), 'Message with 2 placeholders')
2216 f = logging.Formatter('$$%${message}%$$', style='$')
2217 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2218 f = logging.Formatter('${random}', style='$')
2219 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002220 self.assertFalse(f.usesTime())
2221 f = logging.Formatter('${asctime}', style='$')
2222 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002223 f = logging.Formatter('${asctime', style='$')
2224 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002225 f = logging.Formatter('$asctime', style='$')
2226 self.assertTrue(f.usesTime())
2227 f = logging.Formatter('asctime', style='$')
2228 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002229
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002230 def test_invalid_style(self):
2231 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
2232
2233 def test_time(self):
2234 r = self.get_record()
2235 r.created = 735375780.0 # 21 April 1993 08:03:00
2236 r.msecs = 123
2237 f = logging.Formatter('%(asctime)s %(message)s')
2238 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
2239 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
2240
2241class ExceptionTest(BaseTest):
2242 def test_formatting(self):
2243 r = self.root_logger
2244 h = RecordingHandler()
2245 r.addHandler(h)
2246 try:
2247 raise RuntimeError('deliberate mistake')
2248 except:
2249 logging.exception('failed', stack_info=True)
2250 r.removeHandler(h)
2251 h.close()
2252 r = h.records[0]
2253 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
2254 'call last):\n'))
2255 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
2256 'deliberate mistake'))
2257 self.assertTrue(r.stack_info.startswith('Stack (most recent '
2258 'call last):\n'))
2259 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
2260 'stack_info=True)'))
2261
2262
Vinay Sajip5a27d402010-12-10 11:42:57 +00002263class LastResortTest(BaseTest):
2264 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002265 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00002266 root = self.root_logger
2267 root.removeHandler(self.root_hdlr)
2268 old_stderr = sys.stderr
2269 old_lastresort = logging.lastResort
2270 old_raise_exceptions = logging.raiseExceptions
2271 try:
2272 sys.stderr = sio = io.StringIO()
2273 root.warning('This is your final chance!')
2274 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
2275 #No handlers and no last resort, so 'No handlers' message
2276 logging.lastResort = None
2277 sys.stderr = sio = io.StringIO()
2278 root.warning('This is your final chance!')
2279 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
2280 # 'No handlers' message only printed once
2281 sys.stderr = sio = io.StringIO()
2282 root.warning('This is your final chance!')
2283 self.assertEqual(sio.getvalue(), '')
2284 root.manager.emittedNoHandlerWarning = False
2285 #If raiseExceptions is False, no message is printed
2286 logging.raiseExceptions = False
2287 sys.stderr = sio = io.StringIO()
2288 root.warning('This is your final chance!')
2289 self.assertEqual(sio.getvalue(), '')
2290 finally:
2291 sys.stderr = old_stderr
2292 root.addHandler(self.root_hdlr)
2293 logging.lastResort = old_lastresort
2294 logging.raiseExceptions = old_raise_exceptions
2295
2296
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002297class FakeHandler:
2298
2299 def __init__(self, identifier, called):
2300 for method in ('acquire', 'flush', 'close', 'release'):
2301 setattr(self, method, self.record_call(identifier, method, called))
2302
2303 def record_call(self, identifier, method_name, called):
2304 def inner():
2305 called.append('{} - {}'.format(identifier, method_name))
2306 return inner
2307
2308
2309class RecordingHandler(logging.NullHandler):
2310
2311 def __init__(self, *args, **kwargs):
2312 super(RecordingHandler, self).__init__(*args, **kwargs)
2313 self.records = []
2314
2315 def handle(self, record):
2316 """Keep track of all the emitted records."""
2317 self.records.append(record)
2318
2319
2320class ShutdownTest(BaseTest):
2321
Vinay Sajip5e66b162011-04-20 15:41:14 +01002322 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002323
2324 def setUp(self):
2325 super(ShutdownTest, self).setUp()
2326 self.called = []
2327
2328 raise_exceptions = logging.raiseExceptions
2329 self.addCleanup(lambda: setattr(logging, 'raiseExceptions', raise_exceptions))
2330
2331 def raise_error(self, error):
2332 def inner():
2333 raise error()
2334 return inner
2335
2336 def test_no_failure(self):
2337 # create some fake handlers
2338 handler0 = FakeHandler(0, self.called)
2339 handler1 = FakeHandler(1, self.called)
2340 handler2 = FakeHandler(2, self.called)
2341
2342 # create live weakref to those handlers
2343 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
2344
2345 logging.shutdown(handlerList=list(handlers))
2346
2347 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
2348 '1 - acquire', '1 - flush', '1 - close', '1 - release',
2349 '0 - acquire', '0 - flush', '0 - close', '0 - release']
2350 self.assertEqual(expected, self.called)
2351
2352 def _test_with_failure_in_method(self, method, error):
2353 handler = FakeHandler(0, self.called)
2354 setattr(handler, method, self.raise_error(error))
2355 handlers = [logging.weakref.ref(handler)]
2356
2357 logging.shutdown(handlerList=list(handlers))
2358
2359 self.assertEqual('0 - release', self.called[-1])
2360
2361 def test_with_ioerror_in_acquire(self):
2362 self._test_with_failure_in_method('acquire', IOError)
2363
2364 def test_with_ioerror_in_flush(self):
2365 self._test_with_failure_in_method('flush', IOError)
2366
2367 def test_with_ioerror_in_close(self):
2368 self._test_with_failure_in_method('close', IOError)
2369
2370 def test_with_valueerror_in_acquire(self):
2371 self._test_with_failure_in_method('acquire', ValueError)
2372
2373 def test_with_valueerror_in_flush(self):
2374 self._test_with_failure_in_method('flush', ValueError)
2375
2376 def test_with_valueerror_in_close(self):
2377 self._test_with_failure_in_method('close', ValueError)
2378
2379 def test_with_other_error_in_acquire_without_raise(self):
2380 logging.raiseExceptions = False
2381 self._test_with_failure_in_method('acquire', IndexError)
2382
2383 def test_with_other_error_in_flush_without_raise(self):
2384 logging.raiseExceptions = False
2385 self._test_with_failure_in_method('flush', IndexError)
2386
2387 def test_with_other_error_in_close_without_raise(self):
2388 logging.raiseExceptions = False
2389 self._test_with_failure_in_method('close', IndexError)
2390
2391 def test_with_other_error_in_acquire_with_raise(self):
2392 logging.raiseExceptions = True
2393 self.assertRaises(IndexError, self._test_with_failure_in_method,
2394 'acquire', IndexError)
2395
2396 def test_with_other_error_in_flush_with_raise(self):
2397 logging.raiseExceptions = True
2398 self.assertRaises(IndexError, self._test_with_failure_in_method,
2399 'flush', IndexError)
2400
2401 def test_with_other_error_in_close_with_raise(self):
2402 logging.raiseExceptions = True
2403 self.assertRaises(IndexError, self._test_with_failure_in_method,
2404 'close', IndexError)
2405
2406
2407class ModuleLevelMiscTest(BaseTest):
2408
Vinay Sajip5e66b162011-04-20 15:41:14 +01002409 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002410
2411 def test_disable(self):
2412 old_disable = logging.root.manager.disable
2413 # confirm our assumptions are correct
2414 assert old_disable == 0
2415 self.addCleanup(lambda: logging.disable(old_disable))
2416
2417 logging.disable(83)
2418 self.assertEqual(logging.root.manager.disable, 83)
2419
2420 def _test_log(self, method, level=None):
2421 called = []
2422 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01002423 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002424
2425 recording = RecordingHandler()
2426 logging.root.addHandler(recording)
2427
2428 log_method = getattr(logging, method)
2429 if level is not None:
2430 log_method(level, "test me: %r", recording)
2431 else:
2432 log_method("test me: %r", recording)
2433
2434 self.assertEqual(len(recording.records), 1)
2435 record = recording.records[0]
2436 self.assertEqual(record.getMessage(), "test me: %r" % recording)
2437
2438 expected_level = level if level is not None else getattr(logging, method.upper())
2439 self.assertEqual(record.levelno, expected_level)
2440
2441 # basicConfig was not called!
2442 self.assertEqual(called, [])
2443
2444 def test_log(self):
2445 self._test_log('log', logging.ERROR)
2446
2447 def test_debug(self):
2448 self._test_log('debug')
2449
2450 def test_info(self):
2451 self._test_log('info')
2452
2453 def test_warning(self):
2454 self._test_log('warning')
2455
2456 def test_error(self):
2457 self._test_log('error')
2458
2459 def test_critical(self):
2460 self._test_log('critical')
2461
2462 def test_set_logger_class(self):
2463 self.assertRaises(TypeError, logging.setLoggerClass, object)
2464
2465 class MyLogger(logging.Logger):
2466 pass
2467
2468 logging.setLoggerClass(MyLogger)
2469 self.assertEqual(logging.getLoggerClass(), MyLogger)
2470
2471 logging.setLoggerClass(logging.Logger)
2472 self.assertEqual(logging.getLoggerClass(), logging.Logger)
2473
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002474class LogRecordTest(BaseTest):
2475 def test_str_rep(self):
2476 r = logging.makeLogRecord({})
2477 s = str(r)
2478 self.assertTrue(s.startswith('<LogRecord: '))
2479 self.assertTrue(s.endswith('>'))
2480
2481 def test_dict_arg(self):
2482 h = RecordingHandler()
2483 r = logging.getLogger()
2484 r.addHandler(h)
2485 d = {'less' : 'more' }
2486 logging.warning('less is %(less)s', d)
2487 self.assertIs(h.records[0].args, d)
2488 self.assertEqual(h.records[0].message, 'less is more')
2489 r.removeHandler(h)
2490 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002491
2492class BasicConfigTest(unittest.TestCase):
2493
Vinay Sajip95bf5042011-04-20 11:50:56 +01002494 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002495
2496 def setUp(self):
2497 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01002498 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01002499 self.saved_handlers = logging._handlers.copy()
2500 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01002501 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01002502 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002503 logging.root.handlers = []
2504
2505 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01002506 for h in logging.root.handlers[:]:
2507 logging.root.removeHandler(h)
2508 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002509 super(BasicConfigTest, self).tearDown()
2510
Vinay Sajip3def7e02011-04-20 10:58:06 +01002511 def cleanup(self):
2512 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01002513 logging._handlers.clear()
2514 logging._handlers.update(self.saved_handlers)
2515 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01002516 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01002517
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002518 def test_no_kwargs(self):
2519 logging.basicConfig()
2520
2521 # handler defaults to a StreamHandler to sys.stderr
2522 self.assertEqual(len(logging.root.handlers), 1)
2523 handler = logging.root.handlers[0]
2524 self.assertIsInstance(handler, logging.StreamHandler)
2525 self.assertEqual(handler.stream, sys.stderr)
2526
2527 formatter = handler.formatter
2528 # format defaults to logging.BASIC_FORMAT
2529 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
2530 # datefmt defaults to None
2531 self.assertIsNone(formatter.datefmt)
2532 # style defaults to %
2533 self.assertIsInstance(formatter._style, logging.PercentStyle)
2534
2535 # level is not explicitely set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01002536 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002537
2538 def test_filename(self):
2539 logging.basicConfig(filename='test.log')
2540
2541 self.assertEqual(len(logging.root.handlers), 1)
2542 handler = logging.root.handlers[0]
2543 self.assertIsInstance(handler, logging.FileHandler)
2544
2545 expected = logging.FileHandler('test.log', 'a')
2546 self.addCleanup(expected.close)
2547 self.assertEqual(handler.stream.mode, expected.stream.mode)
2548 self.assertEqual(handler.stream.name, expected.stream.name)
2549
2550 def test_filemode(self):
2551 logging.basicConfig(filename='test.log', filemode='wb')
2552
2553 handler = logging.root.handlers[0]
2554 expected = logging.FileHandler('test.log', 'wb')
2555 self.addCleanup(expected.close)
2556 self.assertEqual(handler.stream.mode, expected.stream.mode)
2557
2558 def test_stream(self):
2559 stream = io.StringIO()
2560 self.addCleanup(stream.close)
2561 logging.basicConfig(stream=stream)
2562
2563 self.assertEqual(len(logging.root.handlers), 1)
2564 handler = logging.root.handlers[0]
2565 self.assertIsInstance(handler, logging.StreamHandler)
2566 self.assertEqual(handler.stream, stream)
2567
2568 def test_format(self):
2569 logging.basicConfig(format='foo')
2570
2571 formatter = logging.root.handlers[0].formatter
2572 self.assertEqual(formatter._style._fmt, 'foo')
2573
2574 def test_datefmt(self):
2575 logging.basicConfig(datefmt='bar')
2576
2577 formatter = logging.root.handlers[0].formatter
2578 self.assertEqual(formatter.datefmt, 'bar')
2579
2580 def test_style(self):
2581 logging.basicConfig(style='$')
2582
2583 formatter = logging.root.handlers[0].formatter
2584 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
2585
2586 def test_level(self):
2587 old_level = logging.root.level
2588 self.addCleanup(lambda: logging.root.setLevel(old_level))
2589
2590 logging.basicConfig(level=57)
2591 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002592 # Test that second call has no effect
2593 logging.basicConfig(level=58)
2594 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002595
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01002596 def test_incompatible(self):
2597 assertRaises = self.assertRaises
2598 handlers = [logging.StreamHandler()]
2599 stream = sys.stderr
2600 assertRaises(ValueError, logging.basicConfig, filename='test.log',
2601 stream=stream)
2602 assertRaises(ValueError, logging.basicConfig, filename='test.log',
2603 handlers=handlers)
2604 assertRaises(ValueError, logging.basicConfig, stream=stream,
2605 handlers=handlers)
2606
2607 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002608 handlers = [
2609 logging.StreamHandler(),
2610 logging.StreamHandler(sys.stdout),
2611 logging.StreamHandler(),
2612 ]
2613 f = logging.Formatter()
2614 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01002615 logging.basicConfig(handlers=handlers)
2616 self.assertIs(handlers[0], logging.root.handlers[0])
2617 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002618 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01002619 self.assertIsNotNone(handlers[0].formatter)
2620 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002621 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01002622 self.assertIs(handlers[0].formatter, handlers[1].formatter)
2623
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002624 def _test_log(self, method, level=None):
2625 # logging.root has no handlers so basicConfig should be called
2626 called = []
2627
2628 old_basic_config = logging.basicConfig
2629 def my_basic_config(*a, **kw):
2630 old_basic_config()
2631 old_level = logging.root.level
2632 logging.root.setLevel(100) # avoid having messages in stderr
2633 self.addCleanup(lambda: logging.root.setLevel(old_level))
2634 called.append((a, kw))
2635
2636 patch(self, logging, 'basicConfig', my_basic_config)
2637
2638 log_method = getattr(logging, method)
2639 if level is not None:
2640 log_method(level, "test me")
2641 else:
2642 log_method("test me")
2643
2644 # basicConfig was called with no arguments
2645 self.assertEqual(called, [((), {})])
2646
2647 def test_log(self):
2648 self._test_log('log', logging.WARNING)
2649
2650 def test_debug(self):
2651 self._test_log('debug')
2652
2653 def test_info(self):
2654 self._test_log('info')
2655
2656 def test_warning(self):
2657 self._test_log('warning')
2658
2659 def test_error(self):
2660 self._test_log('error')
2661
2662 def test_critical(self):
2663 self._test_log('critical')
2664
2665
2666class LoggerAdapterTest(unittest.TestCase):
2667
2668 def setUp(self):
2669 super(LoggerAdapterTest, self).setUp()
2670 old_handler_list = logging._handlerList[:]
2671
2672 self.recording = RecordingHandler()
2673 self.logger = logging.root
2674 self.logger.addHandler(self.recording)
2675 self.addCleanup(lambda: self.logger.removeHandler(self.recording))
2676 self.addCleanup(self.recording.close)
2677
2678 def cleanup():
2679 logging._handlerList[:] = old_handler_list
2680
2681 self.addCleanup(cleanup)
2682 self.addCleanup(logging.shutdown)
2683 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
2684
2685 def test_exception(self):
2686 msg = 'testing exception: %r'
2687 exc = None
2688 try:
2689 assert False
2690 except AssertionError as e:
2691 exc = e
2692 self.adapter.exception(msg, self.recording)
2693
2694 self.assertEqual(len(self.recording.records), 1)
2695 record = self.recording.records[0]
2696 self.assertEqual(record.levelno, logging.ERROR)
2697 self.assertEqual(record.msg, msg)
2698 self.assertEqual(record.args, (self.recording,))
2699 self.assertEqual(record.exc_info,
2700 (exc.__class__, exc, exc.__traceback__))
2701
2702 def test_critical(self):
2703 msg = 'critical test! %r'
2704 self.adapter.critical(msg, self.recording)
2705
2706 self.assertEqual(len(self.recording.records), 1)
2707 record = self.recording.records[0]
2708 self.assertEqual(record.levelno, logging.CRITICAL)
2709 self.assertEqual(record.msg, msg)
2710 self.assertEqual(record.args, (self.recording,))
2711
2712 def test_is_enabled_for(self):
2713 old_disable = self.adapter.logger.manager.disable
2714 self.adapter.logger.manager.disable = 33
2715 self.addCleanup(lambda: setattr(self.adapter.logger.manager,
2716 'disable', old_disable))
2717 self.assertFalse(self.adapter.isEnabledFor(32))
2718
2719 def test_has_handlers(self):
2720 self.assertTrue(self.adapter.hasHandlers())
2721
2722 for handler in self.logger.handlers:
2723 self.logger.removeHandler(handler)
2724 assert not self.logger.hasHandlers()
2725
2726 self.assertFalse(self.adapter.hasHandlers())
2727
2728
2729class LoggerTest(BaseTest):
2730
2731 def setUp(self):
2732 super(LoggerTest, self).setUp()
2733 self.recording = RecordingHandler()
2734 self.logger = logging.Logger(name='blah')
2735 self.logger.addHandler(self.recording)
2736 self.addCleanup(lambda: self.logger.removeHandler(self.recording))
2737 self.addCleanup(self.recording.close)
2738 self.addCleanup(logging.shutdown)
2739
2740 def test_set_invalid_level(self):
2741 self.assertRaises(TypeError, self.logger.setLevel, object())
2742
2743 def test_exception(self):
2744 msg = 'testing exception: %r'
2745 exc = None
2746 try:
2747 assert False
2748 except AssertionError as e:
2749 exc = e
2750 self.logger.exception(msg, self.recording)
2751
2752 self.assertEqual(len(self.recording.records), 1)
2753 record = self.recording.records[0]
2754 self.assertEqual(record.levelno, logging.ERROR)
2755 self.assertEqual(record.msg, msg)
2756 self.assertEqual(record.args, (self.recording,))
2757 self.assertEqual(record.exc_info,
2758 (exc.__class__, exc, exc.__traceback__))
2759
2760 def test_log_invalid_level_with_raise(self):
2761 old_raise = logging.raiseExceptions
2762 self.addCleanup(lambda: setattr(logging, 'raiseExecptions', old_raise))
2763
2764 logging.raiseExceptions = True
2765 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
2766
2767 def test_log_invalid_level_no_raise(self):
2768 old_raise = logging.raiseExceptions
2769 self.addCleanup(lambda: setattr(logging, 'raiseExecptions', old_raise))
2770
2771 logging.raiseExceptions = False
2772 self.logger.log('10', 'test message') # no exception happens
2773
2774 def test_find_caller_with_stack_info(self):
2775 called = []
2776 patch(self, logging.traceback, 'print_stack',
2777 lambda f, file: called.append(file.getvalue()))
2778
2779 self.logger.findCaller(stack_info=True)
2780
2781 self.assertEqual(len(called), 1)
2782 self.assertEqual('Stack (most recent call last):\n', called[0])
2783
2784 def test_make_record_with_extra_overwrite(self):
2785 name = 'my record'
2786 level = 13
2787 fn = lno = msg = args = exc_info = func = sinfo = None
2788 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
2789 exc_info, func, sinfo)
2790
2791 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
2792 extra = {key: 'some value'}
2793 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
2794 fn, lno, msg, args, exc_info,
2795 extra=extra, sinfo=sinfo)
2796
2797 def test_make_record_with_extra_no_overwrite(self):
2798 name = 'my record'
2799 level = 13
2800 fn = lno = msg = args = exc_info = func = sinfo = None
2801 extra = {'valid_key': 'some value'}
2802 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
2803 exc_info, extra=extra, sinfo=sinfo)
2804 self.assertIn('valid_key', result.__dict__)
2805
2806 def test_has_handlers(self):
2807 self.assertTrue(self.logger.hasHandlers())
2808
2809 for handler in self.logger.handlers:
2810 self.logger.removeHandler(handler)
2811 assert not self.logger.hasHandlers()
2812
2813 self.assertFalse(self.logger.hasHandlers())
2814
2815 def test_has_handlers_no_propagate(self):
2816 child_logger = logging.getLogger('blah.child')
2817 child_logger.propagate = False
2818 assert child_logger.handlers == []
2819
2820 self.assertFalse(child_logger.hasHandlers())
2821
2822 def test_is_enabled_for(self):
2823 old_disable = self.logger.manager.disable
2824 self.logger.manager.disable = 23
2825 self.addCleanup(lambda: setattr(self.logger.manager,
2826 'disable', old_disable))
2827 self.assertFalse(self.logger.isEnabledFor(22))
2828
2829
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002830class BaseFileTest(BaseTest):
2831 "Base class for handler tests that write log files"
2832
2833 def setUp(self):
2834 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00002835 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
2836 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002837 self.rmfiles = []
2838
2839 def tearDown(self):
2840 for fn in self.rmfiles:
2841 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00002842 if os.path.exists(self.fn):
2843 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00002844 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002845
2846 def assertLogFile(self, filename):
2847 "Assert a log file is there and register it for deletion"
2848 self.assertTrue(os.path.exists(filename),
2849 msg="Log file %r does not exist")
2850 self.rmfiles.append(filename)
2851
2852
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002853class FileHandlerTest(BaseFileTest):
2854 def test_delay(self):
2855 os.unlink(self.fn)
2856 fh = logging.FileHandler(self.fn, delay=True)
2857 self.assertIsNone(fh.stream)
2858 self.assertFalse(os.path.exists(self.fn))
2859 fh.handle(logging.makeLogRecord({}))
2860 self.assertIsNotNone(fh.stream)
2861 self.assertTrue(os.path.exists(self.fn))
2862 fh.close()
2863
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002864class RotatingFileHandlerTest(BaseFileTest):
2865 def next_rec(self):
2866 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
2867 self.next_message(), None, None, None)
2868
2869 def test_should_not_rollover(self):
2870 # If maxbytes is zero rollover never occurs
2871 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
2872 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00002873 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002874
2875 def test_should_rollover(self):
2876 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
2877 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00002878 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002879
2880 def test_file_created(self):
2881 # checks that the file is created and assumes it was created
2882 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002883 rh = logging.handlers.RotatingFileHandler(self.fn)
2884 rh.emit(self.next_rec())
2885 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00002886 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002887
2888 def test_rollover_filenames(self):
2889 rh = logging.handlers.RotatingFileHandler(
2890 self.fn, backupCount=2, maxBytes=1)
2891 rh.emit(self.next_rec())
2892 self.assertLogFile(self.fn)
2893 rh.emit(self.next_rec())
2894 self.assertLogFile(self.fn + ".1")
2895 rh.emit(self.next_rec())
2896 self.assertLogFile(self.fn + ".2")
2897 self.assertFalse(os.path.exists(self.fn + ".3"))
Vinay Sajipb046b802010-10-30 09:50:18 +00002898 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002899
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002900class TimedRotatingFileHandlerTest(BaseFileTest):
2901 # test methods added below
2902 pass
2903
2904def secs(**kw):
2905 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
2906
2907for when, exp in (('S', 1),
2908 ('M', 60),
2909 ('H', 60 * 60),
2910 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00002911 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002912 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00002913 ('W0', secs(days=4, hours=24)),
2914 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002915 def test_compute_rollover(self, when=when, exp=exp):
2916 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00002917 self.fn, when=when, interval=1, backupCount=0, utc=True)
2918 currentTime = 0.0
2919 actual = rh.computeRollover(currentTime)
2920 if exp != actual:
2921 # Failures occur on some systems for MIDNIGHT and W0.
2922 # Print detailed calculation for MIDNIGHT so we can try to see
2923 # what's going on
2924 import time
2925 if when == 'MIDNIGHT':
2926 try:
2927 if rh.utc:
2928 t = time.gmtime(currentTime)
2929 else:
2930 t = time.localtime(currentTime)
2931 currentHour = t[3]
2932 currentMinute = t[4]
2933 currentSecond = t[5]
2934 # r is the number of seconds left between now and midnight
2935 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
2936 currentMinute) * 60 +
2937 currentSecond)
2938 result = currentTime + r
2939 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
2940 print('currentHour: %s' % currentHour, file=sys.stderr)
2941 print('currentMinute: %s' % currentMinute, file=sys.stderr)
2942 print('currentSecond: %s' % currentSecond, file=sys.stderr)
2943 print('r: %s' % r, file=sys.stderr)
2944 print('result: %s' % result, file=sys.stderr)
2945 except Exception:
2946 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
2947 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00002948 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00002949 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
2950
Christian Heimes180510d2008-03-03 19:15:45 +00002951# Set the locale to the platform-dependent default. I have no idea
2952# why the test does this, but in any case we save the current locale
2953# first and restore it at the end.
2954@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00002955def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00002956 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002957 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002958 ConfigFileTest, SocketHandlerTest, MemoryTest,
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002959 EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002960 FormatterTest, StreamHandlerTest,
Vinay Sajip61561522010-12-03 11:50:38 +00002961 LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest,
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002962 ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
2963 LoggerAdapterTest, LoggerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002964 FileHandlerTest, RotatingFileHandlerTest,
2965 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00002966 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00002967 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00002968
Christian Heimes180510d2008-03-03 19:15:45 +00002969if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002970 test_main()