blob: 63d49fe5c77dbb32f1bb26fb52fe5678a1de95aa [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajip3f885b52013-03-22 15:19:54 +00003# Copyright 2001-2013 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 Sajip3f885b52013-03-22 15:19:54 +000021Copyright (C) 2001-2013 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 Sajipcf9e2f22012-10-09 09:06:03 +010029import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000030import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000031import pickle
32import io
33import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000034import json
Christian Heimes180510d2008-03-03 19:15:45 +000035import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000036import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010037import random
Christian Heimes180510d2008-03-03 19:15:45 +000038import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000039import select
Christian Heimes180510d2008-03-03 19:15:45 +000040import socket
Christian Heimes180510d2008-03-03 19:15:45 +000041import struct
42import sys
43import tempfile
Eric V. Smith851cad72012-03-11 22:46:04 -070044from test.support import (captured_stdout, run_with_locale, run_unittest,
45 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000046import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010047import time
Christian Heimes180510d2008-03-03 19:15:45 +000048import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000049import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000050import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000051try:
52 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010054 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010055 import asynchat
56 import asyncore
57 import errno
58 from http.server import HTTPServer, BaseHTTPRequestHandler
59 import smtpd
60 from urllib.parse import urlparse, parse_qs
61 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
62 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000063except ImportError:
64 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010065try:
66 import win32evtlog
67except ImportError:
68 win32evtlog = None
69try:
70 import win32evtlogutil
71except ImportError:
72 win32evtlogutil = None
73 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070074try:
75 import zlib
76except ImportError:
77 pass
Christian Heimes18c66892008-02-17 13:31:39 +000078
79
Christian Heimes180510d2008-03-03 19:15:45 +000080class BaseTest(unittest.TestCase):
81
82 """Base class for logging tests."""
83
84 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030085 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000086 message_num = 0
87
88 def setUp(self):
89 """Setup the default logging stream to an internal StringIO instance,
90 so that we can examine log output as we want."""
91 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000092 logging._acquireLock()
93 try:
Christian Heimes180510d2008-03-03 19:15:45 +000094 self.saved_handlers = logging._handlers.copy()
95 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000096 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070097 self.saved_name_to_level = logging._nameToLevel.copy()
98 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000099 self.logger_states = logger_states = {}
100 for name in saved_loggers:
101 logger_states[name] = getattr(saved_loggers[name],
102 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000103 finally:
104 logging._releaseLock()
105
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100106 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000107 self.logger1 = logging.getLogger("\xab\xd7\xbb")
108 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000109
Christian Heimes180510d2008-03-03 19:15:45 +0000110 self.root_logger = logging.getLogger("")
111 self.original_logging_level = self.root_logger.getEffectiveLevel()
112
113 self.stream = io.StringIO()
114 self.root_logger.setLevel(logging.DEBUG)
115 self.root_hdlr = logging.StreamHandler(self.stream)
116 self.root_formatter = logging.Formatter(self.log_format)
117 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000118 if self.logger1.hasHandlers():
119 hlist = self.logger1.handlers + self.root_logger.handlers
120 raise AssertionError('Unexpected handlers: %s' % hlist)
121 if self.logger2.hasHandlers():
122 hlist = self.logger2.handlers + self.root_logger.handlers
123 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000124 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000125 self.assertTrue(self.logger1.hasHandlers())
126 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000127
128 def tearDown(self):
129 """Remove our logging stream, and restore the original logging
130 level."""
131 self.stream.close()
132 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000133 while self.root_logger.handlers:
134 h = self.root_logger.handlers[0]
135 self.root_logger.removeHandler(h)
136 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000137 self.root_logger.setLevel(self.original_logging_level)
138 logging._acquireLock()
139 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700140 logging._levelToName.clear()
141 logging._levelToName.update(self.saved_level_to_name)
142 logging._nameToLevel.clear()
143 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000144 logging._handlers.clear()
145 logging._handlers.update(self.saved_handlers)
146 logging._handlerList[:] = self.saved_handler_list
147 loggerDict = logging.getLogger().manager.loggerDict
148 loggerDict.clear()
149 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000150 logger_states = self.logger_states
151 for name in self.logger_states:
152 if logger_states[name] is not None:
153 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000154 finally:
155 logging._releaseLock()
156
Vinay Sajip4ded5512012-10-02 15:56:16 +0100157 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000158 """Match the collected log lines against the regular expression
159 self.expected_log_pat, and compare the extracted group values to
160 the expected_values list of tuples."""
161 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100162 pat = re.compile(pat or self.expected_log_pat)
Christian Heimes180510d2008-03-03 19:15:45 +0000163 try:
Vinay Sajip4ded5512012-10-02 15:56:16 +0100164 if hasattr(stream, 'reset'):
165 stream.reset()
166 elif hasattr(stream, 'seek'):
167 stream.seek(0)
Christian Heimes180510d2008-03-03 19:15:45 +0000168 actual_lines = stream.readlines()
169 except AttributeError:
170 # StringIO.StringIO lacks a reset() method.
171 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100172 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000173 for actual, expected in zip(actual_lines, expected_values):
174 match = pat.search(actual)
175 if not match:
176 self.fail("Log line does not match expected pattern:\n" +
177 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000178 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000179 s = stream.read()
180 if s:
181 self.fail("Remaining output at end of log stream:\n" + s)
182
183 def next_message(self):
184 """Generate a message consisting solely of an auto-incrementing
185 integer."""
186 self.message_num += 1
187 return "%d" % self.message_num
188
189
190class BuiltinLevelsTest(BaseTest):
191 """Test builtin levels and their inheritance."""
192
193 def test_flat(self):
194 #Logging levels in a flat logger namespace.
195 m = self.next_message
196
197 ERR = logging.getLogger("ERR")
198 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000199 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000200 INF.setLevel(logging.INFO)
201 DEB = logging.getLogger("DEB")
202 DEB.setLevel(logging.DEBUG)
203
204 # These should log.
205 ERR.log(logging.CRITICAL, m())
206 ERR.error(m())
207
208 INF.log(logging.CRITICAL, m())
209 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100210 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000211 INF.info(m())
212
213 DEB.log(logging.CRITICAL, m())
214 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100215 DEB.warning(m())
216 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000217 DEB.debug(m())
218
219 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100220 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000221 ERR.info(m())
222 ERR.debug(m())
223
224 INF.debug(m())
225
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000226 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000227 ('ERR', 'CRITICAL', '1'),
228 ('ERR', 'ERROR', '2'),
229 ('INF', 'CRITICAL', '3'),
230 ('INF', 'ERROR', '4'),
231 ('INF', 'WARNING', '5'),
232 ('INF', 'INFO', '6'),
233 ('DEB', 'CRITICAL', '7'),
234 ('DEB', 'ERROR', '8'),
235 ('DEB', 'WARNING', '9'),
236 ('DEB', 'INFO', '10'),
237 ('DEB', 'DEBUG', '11'),
238 ])
239
240 def test_nested_explicit(self):
241 # Logging levels in a nested namespace, all explicitly set.
242 m = self.next_message
243
244 INF = logging.getLogger("INF")
245 INF.setLevel(logging.INFO)
246 INF_ERR = logging.getLogger("INF.ERR")
247 INF_ERR.setLevel(logging.ERROR)
248
249 # These should log.
250 INF_ERR.log(logging.CRITICAL, m())
251 INF_ERR.error(m())
252
253 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100254 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000255 INF_ERR.info(m())
256 INF_ERR.debug(m())
257
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000258 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000259 ('INF.ERR', 'CRITICAL', '1'),
260 ('INF.ERR', 'ERROR', '2'),
261 ])
262
263 def test_nested_inherited(self):
264 #Logging levels in a nested namespace, inherited from parent loggers.
265 m = self.next_message
266
267 INF = logging.getLogger("INF")
268 INF.setLevel(logging.INFO)
269 INF_ERR = logging.getLogger("INF.ERR")
270 INF_ERR.setLevel(logging.ERROR)
271 INF_UNDEF = logging.getLogger("INF.UNDEF")
272 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
273 UNDEF = logging.getLogger("UNDEF")
274
275 # These should log.
276 INF_UNDEF.log(logging.CRITICAL, m())
277 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100278 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000279 INF_UNDEF.info(m())
280 INF_ERR_UNDEF.log(logging.CRITICAL, m())
281 INF_ERR_UNDEF.error(m())
282
283 # These should not log.
284 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100285 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000286 INF_ERR_UNDEF.info(m())
287 INF_ERR_UNDEF.debug(m())
288
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000289 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000290 ('INF.UNDEF', 'CRITICAL', '1'),
291 ('INF.UNDEF', 'ERROR', '2'),
292 ('INF.UNDEF', 'WARNING', '3'),
293 ('INF.UNDEF', 'INFO', '4'),
294 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
295 ('INF.ERR.UNDEF', 'ERROR', '6'),
296 ])
297
298 def test_nested_with_virtual_parent(self):
299 # Logging levels when some parent does not exist yet.
300 m = self.next_message
301
302 INF = logging.getLogger("INF")
303 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
304 CHILD = logging.getLogger("INF.BADPARENT")
305 INF.setLevel(logging.INFO)
306
307 # These should log.
308 GRANDCHILD.log(logging.FATAL, m())
309 GRANDCHILD.info(m())
310 CHILD.log(logging.FATAL, m())
311 CHILD.info(m())
312
313 # These should not log.
314 GRANDCHILD.debug(m())
315 CHILD.debug(m())
316
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000317 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000318 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
319 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
320 ('INF.BADPARENT', 'CRITICAL', '3'),
321 ('INF.BADPARENT', 'INFO', '4'),
322 ])
323
324
325class BasicFilterTest(BaseTest):
326
327 """Test the bundled Filter class."""
328
329 def test_filter(self):
330 # Only messages satisfying the specified criteria pass through the
331 # filter.
332 filter_ = logging.Filter("spam.eggs")
333 handler = self.root_logger.handlers[0]
334 try:
335 handler.addFilter(filter_)
336 spam = logging.getLogger("spam")
337 spam_eggs = logging.getLogger("spam.eggs")
338 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
339 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
340
341 spam.info(self.next_message())
342 spam_eggs.info(self.next_message()) # Good.
343 spam_eggs_fish.info(self.next_message()) # Good.
344 spam_bakedbeans.info(self.next_message())
345
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000346 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000347 ('spam.eggs', 'INFO', '2'),
348 ('spam.eggs.fish', 'INFO', '3'),
349 ])
350 finally:
351 handler.removeFilter(filter_)
352
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000353 def test_callable_filter(self):
354 # Only messages satisfying the specified criteria pass through the
355 # filter.
356
357 def filterfunc(record):
358 parts = record.name.split('.')
359 prefix = '.'.join(parts[:2])
360 return prefix == 'spam.eggs'
361
362 handler = self.root_logger.handlers[0]
363 try:
364 handler.addFilter(filterfunc)
365 spam = logging.getLogger("spam")
366 spam_eggs = logging.getLogger("spam.eggs")
367 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
368 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
369
370 spam.info(self.next_message())
371 spam_eggs.info(self.next_message()) # Good.
372 spam_eggs_fish.info(self.next_message()) # Good.
373 spam_bakedbeans.info(self.next_message())
374
375 self.assert_log_lines([
376 ('spam.eggs', 'INFO', '2'),
377 ('spam.eggs.fish', 'INFO', '3'),
378 ])
379 finally:
380 handler.removeFilter(filterfunc)
381
Vinay Sajip985ef872011-04-26 19:34:04 +0100382 def test_empty_filter(self):
383 f = logging.Filter()
384 r = logging.makeLogRecord({'name': 'spam.eggs'})
385 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000386
387#
388# First, we define our levels. There can be as many as you want - the only
389# limitations are that they should be integers, the lowest should be > 0 and
390# larger values mean less information being logged. If you need specific
391# level values which do not fit into these limitations, you can use a
392# mapping dictionary to convert between your application levels and the
393# logging system.
394#
395SILENT = 120
396TACITURN = 119
397TERSE = 118
398EFFUSIVE = 117
399SOCIABLE = 116
400VERBOSE = 115
401TALKATIVE = 114
402GARRULOUS = 113
403CHATTERBOX = 112
404BORING = 111
405
406LEVEL_RANGE = range(BORING, SILENT + 1)
407
408#
409# Next, we define names for our levels. You don't need to do this - in which
410# case the system will use "Level n" to denote the text for the level.
411#
412my_logging_levels = {
413 SILENT : 'Silent',
414 TACITURN : 'Taciturn',
415 TERSE : 'Terse',
416 EFFUSIVE : 'Effusive',
417 SOCIABLE : 'Sociable',
418 VERBOSE : 'Verbose',
419 TALKATIVE : 'Talkative',
420 GARRULOUS : 'Garrulous',
421 CHATTERBOX : 'Chatterbox',
422 BORING : 'Boring',
423}
424
425class GarrulousFilter(logging.Filter):
426
427 """A filter which blocks garrulous messages."""
428
429 def filter(self, record):
430 return record.levelno != GARRULOUS
431
432class VerySpecificFilter(logging.Filter):
433
434 """A filter which blocks sociable and taciturn messages."""
435
436 def filter(self, record):
437 return record.levelno not in [SOCIABLE, TACITURN]
438
439
440class CustomLevelsAndFiltersTest(BaseTest):
441
442 """Test various filtering possibilities with custom logging levels."""
443
444 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300445 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000446
447 def setUp(self):
448 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000449 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000450 logging.addLevelName(k, v)
451
452 def log_at_all_levels(self, logger):
453 for lvl in LEVEL_RANGE:
454 logger.log(lvl, self.next_message())
455
456 def test_logger_filter(self):
457 # Filter at logger level.
458 self.root_logger.setLevel(VERBOSE)
459 # Levels >= 'Verbose' are good.
460 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000461 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000462 ('Verbose', '5'),
463 ('Sociable', '6'),
464 ('Effusive', '7'),
465 ('Terse', '8'),
466 ('Taciturn', '9'),
467 ('Silent', '10'),
468 ])
469
470 def test_handler_filter(self):
471 # Filter at handler level.
472 self.root_logger.handlers[0].setLevel(SOCIABLE)
473 try:
474 # Levels >= 'Sociable' are good.
475 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000476 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000477 ('Sociable', '6'),
478 ('Effusive', '7'),
479 ('Terse', '8'),
480 ('Taciturn', '9'),
481 ('Silent', '10'),
482 ])
483 finally:
484 self.root_logger.handlers[0].setLevel(logging.NOTSET)
485
486 def test_specific_filters(self):
487 # Set a specific filter object on the handler, and then add another
488 # filter object on the logger itself.
489 handler = self.root_logger.handlers[0]
490 specific_filter = None
491 garr = GarrulousFilter()
492 handler.addFilter(garr)
493 try:
494 self.log_at_all_levels(self.root_logger)
495 first_lines = [
496 # Notice how 'Garrulous' is missing
497 ('Boring', '1'),
498 ('Chatterbox', '2'),
499 ('Talkative', '4'),
500 ('Verbose', '5'),
501 ('Sociable', '6'),
502 ('Effusive', '7'),
503 ('Terse', '8'),
504 ('Taciturn', '9'),
505 ('Silent', '10'),
506 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000507 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000508
509 specific_filter = VerySpecificFilter()
510 self.root_logger.addFilter(specific_filter)
511 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000512 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000513 # Not only 'Garrulous' is still missing, but also 'Sociable'
514 # and 'Taciturn'
515 ('Boring', '11'),
516 ('Chatterbox', '12'),
517 ('Talkative', '14'),
518 ('Verbose', '15'),
519 ('Effusive', '17'),
520 ('Terse', '18'),
521 ('Silent', '20'),
522 ])
523 finally:
524 if specific_filter:
525 self.root_logger.removeFilter(specific_filter)
526 handler.removeFilter(garr)
527
528
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100529class HandlerTest(BaseTest):
530 def test_name(self):
531 h = logging.Handler()
532 h.name = 'generic'
533 self.assertEqual(h.name, 'generic')
534 h.name = 'anothergeneric'
535 self.assertEqual(h.name, 'anothergeneric')
536 self.assertRaises(NotImplementedError, h.emit, None)
537
Vinay Sajip5a35b062011-04-27 11:31:14 +0100538 def test_builtin_handlers(self):
539 # We can't actually *use* too many handlers in the tests,
540 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200541 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100542 for existing in (True, False):
543 fd, fn = tempfile.mkstemp()
544 os.close(fd)
545 if not existing:
546 os.unlink(fn)
547 h = logging.handlers.WatchedFileHandler(fn, delay=True)
548 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100549 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100550 self.assertEqual(dev, -1)
551 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100552 r = logging.makeLogRecord({'msg': 'Test'})
553 h.handle(r)
554 # Now remove the file.
555 os.unlink(fn)
556 self.assertFalse(os.path.exists(fn))
557 # The next call should recreate the file.
558 h.handle(r)
559 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100560 else:
561 self.assertEqual(h.dev, -1)
562 self.assertEqual(h.ino, -1)
563 h.close()
564 if existing:
565 os.unlink(fn)
566 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100567 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100568 else:
569 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100570 try:
571 h = logging.handlers.SysLogHandler(sockname)
572 self.assertEqual(h.facility, h.LOG_USER)
573 self.assertTrue(h.unixsocket)
574 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200575 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100576 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100577 for method in ('GET', 'POST', 'PUT'):
578 if method == 'PUT':
579 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
580 'localhost', '/log', method)
581 else:
582 h = logging.handlers.HTTPHandler('localhost', '/log', method)
583 h.close()
584 h = logging.handlers.BufferingHandler(0)
585 r = logging.makeLogRecord({})
586 self.assertTrue(h.shouldFlush(r))
587 h.close()
588 h = logging.handlers.BufferingHandler(1)
589 self.assertFalse(h.shouldFlush(r))
590 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100591
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100592 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100593 @unittest.skipUnless(threading, 'Threading required for this test.')
594 def test_race(self):
595 # Issue #14632 refers.
596 def remove_loop(fname, tries):
597 for _ in range(tries):
598 try:
599 os.unlink(fname)
600 except OSError:
601 pass
602 time.sleep(0.004 * random.randint(0, 4))
603
Vinay Sajipc94871a2012-04-25 10:51:35 +0100604 del_count = 500
605 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100606
Vinay Sajipa5798de2012-04-24 23:33:33 +0100607 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100608 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
609 os.close(fd)
610 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
611 remover.daemon = True
612 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100613 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100614 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
615 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100616 try:
617 for _ in range(log_count):
618 time.sleep(0.005)
619 r = logging.makeLogRecord({'msg': 'testing' })
620 h.handle(r)
621 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100622 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100623 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100624 if os.path.exists(fn):
625 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100626
627
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100628class BadStream(object):
629 def write(self, data):
630 raise RuntimeError('deliberate mistake')
631
632class TestStreamHandler(logging.StreamHandler):
633 def handleError(self, record):
634 self.error_record = record
635
636class StreamHandlerTest(BaseTest):
637 def test_error_handling(self):
638 h = TestStreamHandler(BadStream())
639 r = logging.makeLogRecord({})
640 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100641 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100642 try:
643 h.handle(r)
644 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100645 h = logging.StreamHandler(BadStream())
646 sys.stderr = sio = io.StringIO()
647 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100648 self.assertIn('\nRuntimeError: deliberate mistake\n',
649 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100650 logging.raiseExceptions = False
651 sys.stderr = sio = io.StringIO()
652 h.handle(r)
653 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100654 finally:
655 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100656 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100657
Vinay Sajip7367d082011-05-02 13:17:27 +0100658# -- The following section could be moved into a server_helper.py module
659# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100660
Vinay Sajipce7c9782011-05-17 07:15:53 +0100661if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100662 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100663 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100665
Vinay Sajipce7c9782011-05-17 07:15:53 +0100666 :param addr: A (host, port) tuple which the server listens on.
667 You can specify a port value of zero: the server's
668 *port* attribute will hold the actual port number
669 used, which can be used in client connections.
670 :param handler: A callable which will be called to process
671 incoming messages. The handler will be passed
672 the client address tuple, who the message is from,
673 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100674 :param poll_interval: The interval, in seconds, used in the underlying
675 :func:`select` or :func:`poll` call by
676 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100677 :param sockmap: A dictionary which will be used to hold
678 :class:`asyncore.dispatcher` instances used by
679 :func:`asyncore.loop`. This avoids changing the
680 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100681 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100682
683 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100684 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
685 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100686 self._handler = handler
687 self._thread = None
688 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100689
Vinay Sajipce7c9782011-05-17 07:15:53 +0100690 def process_message(self, peer, mailfrom, rcpttos, data):
691 """
692 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100693
Vinay Sajipce7c9782011-05-17 07:15:53 +0100694 Typically, this will be a test case method.
695 :param peer: The client (host, port) tuple.
696 :param mailfrom: The address of the sender.
697 :param rcpttos: The addresses of the recipients.
698 :param data: The message.
699 """
700 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100701
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702 def start(self):
703 """
704 Start the server running on a separate daemon thread.
705 """
706 self._thread = t = threading.Thread(target=self.serve_forever,
707 args=(self.poll_interval,))
708 t.setDaemon(True)
709 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100710
Vinay Sajipce7c9782011-05-17 07:15:53 +0100711 def serve_forever(self, poll_interval):
712 """
713 Run the :mod:`asyncore` loop until normal termination
714 conditions arise.
715 :param poll_interval: The interval, in seconds, used in the underlying
716 :func:`select` or :func:`poll` call by
717 :func:`asyncore.loop`.
718 """
719 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100720 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200721 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100722 # On FreeBSD 8, closing the server repeatably
723 # raises this error. We swallow it if the
724 # server has been closed.
725 if self.connected or self.accepting:
726 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100727
Vinay Sajipce7c9782011-05-17 07:15:53 +0100728 def stop(self, timeout=None):
729 """
730 Stop the thread by closing the server instance.
731 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100732
Vinay Sajipce7c9782011-05-17 07:15:53 +0100733 :param timeout: How long to wait for the server thread
734 to terminate.
735 """
736 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100737 self._thread.join(timeout)
738 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100739
Vinay Sajipce7c9782011-05-17 07:15:53 +0100740 class ControlMixin(object):
741 """
742 This mixin is used to start a server on a separate thread, and
743 shut it down programmatically. Request handling is simplified - instead
744 of needing to derive a suitable RequestHandler subclass, you just
745 provide a callable which will be passed each received request to be
746 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100747
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 :param handler: A handler callable which will be called with a
749 single parameter - the request - in order to
750 process the request. This handler is called on the
751 server thread, effectively meaning that requests are
752 processed serially. While not quite Web scale ;-),
753 this should be fine for testing applications.
754 :param poll_interval: The polling interval in seconds.
755 """
756 def __init__(self, handler, poll_interval):
757 self._thread = None
758 self.poll_interval = poll_interval
759 self._handler = handler
760 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100761
Vinay Sajipce7c9782011-05-17 07:15:53 +0100762 def start(self):
763 """
764 Create a daemon thread to run the server, and start it.
765 """
766 self._thread = t = threading.Thread(target=self.serve_forever,
767 args=(self.poll_interval,))
768 t.setDaemon(True)
769 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100770
Vinay Sajipce7c9782011-05-17 07:15:53 +0100771 def serve_forever(self, poll_interval):
772 """
773 Run the server. Set the ready flag before entering the
774 service loop.
775 """
776 self.ready.set()
777 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100778
Vinay Sajipce7c9782011-05-17 07:15:53 +0100779 def stop(self, timeout=None):
780 """
781 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100782
Vinay Sajipce7c9782011-05-17 07:15:53 +0100783 :param timeout: How long to wait for the server thread
784 to terminate.
785 """
786 self.shutdown()
787 if self._thread is not None:
788 self._thread.join(timeout)
789 self._thread = None
790 self.server_close()
791 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100792
Vinay Sajipce7c9782011-05-17 07:15:53 +0100793 class TestHTTPServer(ControlMixin, HTTPServer):
794 """
795 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100796
Vinay Sajipce7c9782011-05-17 07:15:53 +0100797 :param addr: A tuple with the IP address and port to listen on.
798 :param handler: A handler callable which will be called with a
799 single parameter - the request - in order to
800 process the request.
801 :param poll_interval: The polling interval in seconds.
802 :param log: Pass ``True`` to enable log messages.
803 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100804 def __init__(self, addr, handler, poll_interval=0.5,
805 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100806 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
807 def __getattr__(self, name, default=None):
808 if name.startswith('do_'):
809 return self.process_request
810 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100811
Vinay Sajipce7c9782011-05-17 07:15:53 +0100812 def process_request(self):
813 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100814
Vinay Sajipce7c9782011-05-17 07:15:53 +0100815 def log_message(self, format, *args):
816 if log:
817 super(DelegatingHTTPRequestHandler,
818 self).log_message(format, *args)
819 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
820 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100821 self.sslctx = sslctx
822
823 def get_request(self):
824 try:
825 sock, addr = self.socket.accept()
826 if self.sslctx:
827 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200828 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100829 # socket errors are silenced by the caller, print them here
830 sys.stderr.write("Got an error:\n%s\n" % e)
831 raise
832 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100833
Vinay Sajipce7c9782011-05-17 07:15:53 +0100834 class TestTCPServer(ControlMixin, ThreadingTCPServer):
835 """
836 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100837
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 :param addr: A tuple with the IP address and port to listen on.
839 :param handler: A handler callable which will be called with a single
840 parameter - the request - in order to process the request.
841 :param poll_interval: The polling interval in seconds.
842 :bind_and_activate: If True (the default), binds the server and starts it
843 listening. If False, you need to call
844 :meth:`server_bind` and :meth:`server_activate` at
845 some later time before calling :meth:`start`, so that
846 the server will set up the socket and listen on it.
847 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100848
Vinay Sajipce7c9782011-05-17 07:15:53 +0100849 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100850
Vinay Sajipce7c9782011-05-17 07:15:53 +0100851 def __init__(self, addr, handler, poll_interval=0.5,
852 bind_and_activate=True):
853 class DelegatingTCPRequestHandler(StreamRequestHandler):
854
855 def handle(self):
856 self.server._handler(self)
857 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
858 bind_and_activate)
859 ControlMixin.__init__(self, handler, poll_interval)
860
861 def server_bind(self):
862 super(TestTCPServer, self).server_bind()
863 self.port = self.socket.getsockname()[1]
864
865 class TestUDPServer(ControlMixin, ThreadingUDPServer):
866 """
867 A UDP server which is controllable using :class:`ControlMixin`.
868
869 :param addr: A tuple with the IP address and port to listen on.
870 :param handler: A handler callable which will be called with a
871 single parameter - the request - in order to
872 process the request.
873 :param poll_interval: The polling interval for shutdown requests,
874 in seconds.
875 :bind_and_activate: If True (the default), binds the server and
876 starts it listening. If False, you need to
877 call :meth:`server_bind` and
878 :meth:`server_activate` at some later time
879 before calling :meth:`start`, so that the server will
880 set up the socket and listen on it.
881 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100882 def __init__(self, addr, handler, poll_interval=0.5,
883 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100884 class DelegatingUDPRequestHandler(DatagramRequestHandler):
885
886 def handle(self):
887 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100888
889 def finish(self):
890 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100891 if data:
892 try:
893 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200894 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100895 if not self.server._closed:
896 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100897
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 ThreadingUDPServer.__init__(self, addr,
899 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100900 bind_and_activate)
901 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100902 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100903
904 def server_bind(self):
905 super(TestUDPServer, self).server_bind()
906 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Vinay Sajipba980db2011-05-23 21:37:54 +0100908 def server_close(self):
909 super(TestUDPServer, self).server_close()
910 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100911
912# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100913
Vinay Sajipce7c9782011-05-17 07:15:53 +0100914@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100915class SMTPHandlerTest(BaseTest):
916 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100917 sockmap = {}
918 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
919 sockmap)
920 server.start()
921 addr = ('localhost', server.port)
Vinay Sajip4c3f4782012-04-22 18:19:50 +0100922 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
Vinay Sajipa463d252011-04-30 21:52:48 +0100923 self.assertEqual(h.toaddrs, ['you'])
924 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100925 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100926 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100927 h.handle(r)
Vinay Sajip17160fd2012-03-15 12:02:08 +0000928 self.handled.wait(5.0) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100929 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000930 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 self.assertEqual(len(self.messages), 1)
932 peer, mailfrom, rcpttos, data = self.messages[0]
933 self.assertEqual(mailfrom, 'me')
934 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100935 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100936 self.assertTrue(data.endswith('\n\nHello'))
937 h.close()
938
939 def process_message(self, *args):
940 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100941 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100942
Christian Heimes180510d2008-03-03 19:15:45 +0000943class MemoryHandlerTest(BaseTest):
944
945 """Tests for the MemoryHandler."""
946
947 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300948 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000949
950 def setUp(self):
951 BaseTest.setUp(self)
952 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
953 self.root_hdlr)
954 self.mem_logger = logging.getLogger('mem')
955 self.mem_logger.propagate = 0
956 self.mem_logger.addHandler(self.mem_hdlr)
957
958 def tearDown(self):
959 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000960 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000961
962 def test_flush(self):
963 # The memory handler flushes to its target handler based on specific
964 # criteria (message count and message level).
965 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000966 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000967 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000968 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000969 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100970 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000971 lines = [
972 ('DEBUG', '1'),
973 ('INFO', '2'),
974 ('WARNING', '3'),
975 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000976 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000977 for n in (4, 14):
978 for i in range(9):
979 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000980 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000981 # This will flush because it's the 10th message since the last
982 # flush.
983 self.mem_logger.debug(self.next_message())
984 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000985 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000986
987 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989
990
991class ExceptionFormatter(logging.Formatter):
992 """A special exception formatter."""
993 def formatException(self, ei):
994 return "Got a [%s]" % ei[0].__name__
995
996
997class ConfigFileTest(BaseTest):
998
999 """Reading logging config from a .ini-style config file."""
1000
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001001 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001002
1003 # config0 is a standard configuration.
1004 config0 = """
1005 [loggers]
1006 keys=root
1007
1008 [handlers]
1009 keys=hand1
1010
1011 [formatters]
1012 keys=form1
1013
1014 [logger_root]
1015 level=WARNING
1016 handlers=hand1
1017
1018 [handler_hand1]
1019 class=StreamHandler
1020 level=NOTSET
1021 formatter=form1
1022 args=(sys.stdout,)
1023
1024 [formatter_form1]
1025 format=%(levelname)s ++ %(message)s
1026 datefmt=
1027 """
1028
1029 # config1 adds a little to the standard configuration.
1030 config1 = """
1031 [loggers]
1032 keys=root,parser
1033
1034 [handlers]
1035 keys=hand1
1036
1037 [formatters]
1038 keys=form1
1039
1040 [logger_root]
1041 level=WARNING
1042 handlers=
1043
1044 [logger_parser]
1045 level=DEBUG
1046 handlers=hand1
1047 propagate=1
1048 qualname=compiler.parser
1049
1050 [handler_hand1]
1051 class=StreamHandler
1052 level=NOTSET
1053 formatter=form1
1054 args=(sys.stdout,)
1055
1056 [formatter_form1]
1057 format=%(levelname)s ++ %(message)s
1058 datefmt=
1059 """
1060
Vinay Sajip3f84b072011-03-07 17:49:33 +00001061 # config1a moves the handler to the root.
1062 config1a = """
1063 [loggers]
1064 keys=root,parser
1065
1066 [handlers]
1067 keys=hand1
1068
1069 [formatters]
1070 keys=form1
1071
1072 [logger_root]
1073 level=WARNING
1074 handlers=hand1
1075
1076 [logger_parser]
1077 level=DEBUG
1078 handlers=
1079 propagate=1
1080 qualname=compiler.parser
1081
1082 [handler_hand1]
1083 class=StreamHandler
1084 level=NOTSET
1085 formatter=form1
1086 args=(sys.stdout,)
1087
1088 [formatter_form1]
1089 format=%(levelname)s ++ %(message)s
1090 datefmt=
1091 """
1092
Christian Heimes180510d2008-03-03 19:15:45 +00001093 # config2 has a subtle configuration error that should be reported
1094 config2 = config1.replace("sys.stdout", "sys.stbout")
1095
1096 # config3 has a less subtle configuration error
1097 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1098
1099 # config4 specifies a custom formatter class to be loaded
1100 config4 = """
1101 [loggers]
1102 keys=root
1103
1104 [handlers]
1105 keys=hand1
1106
1107 [formatters]
1108 keys=form1
1109
1110 [logger_root]
1111 level=NOTSET
1112 handlers=hand1
1113
1114 [handler_hand1]
1115 class=StreamHandler
1116 level=NOTSET
1117 formatter=form1
1118 args=(sys.stdout,)
1119
1120 [formatter_form1]
1121 class=""" + __name__ + """.ExceptionFormatter
1122 format=%(levelname)s:%(name)s:%(message)s
1123 datefmt=
1124 """
1125
Georg Brandl3dbca812008-07-23 16:10:53 +00001126 # config5 specifies a custom handler class to be loaded
1127 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1128
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001129 # config6 uses ', ' delimiters in the handlers and formatters sections
1130 config6 = """
1131 [loggers]
1132 keys=root,parser
1133
1134 [handlers]
1135 keys=hand1, hand2
1136
1137 [formatters]
1138 keys=form1, form2
1139
1140 [logger_root]
1141 level=WARNING
1142 handlers=
1143
1144 [logger_parser]
1145 level=DEBUG
1146 handlers=hand1
1147 propagate=1
1148 qualname=compiler.parser
1149
1150 [handler_hand1]
1151 class=StreamHandler
1152 level=NOTSET
1153 formatter=form1
1154 args=(sys.stdout,)
1155
1156 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001157 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001158 level=NOTSET
1159 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001160 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001161
1162 [formatter_form1]
1163 format=%(levelname)s ++ %(message)s
1164 datefmt=
1165
1166 [formatter_form2]
1167 format=%(message)s
1168 datefmt=
1169 """
1170
Vinay Sajip3f84b072011-03-07 17:49:33 +00001171 # config7 adds a compiler logger.
1172 config7 = """
1173 [loggers]
1174 keys=root,parser,compiler
1175
1176 [handlers]
1177 keys=hand1
1178
1179 [formatters]
1180 keys=form1
1181
1182 [logger_root]
1183 level=WARNING
1184 handlers=hand1
1185
1186 [logger_compiler]
1187 level=DEBUG
1188 handlers=
1189 propagate=1
1190 qualname=compiler
1191
1192 [logger_parser]
1193 level=DEBUG
1194 handlers=
1195 propagate=1
1196 qualname=compiler.parser
1197
1198 [handler_hand1]
1199 class=StreamHandler
1200 level=NOTSET
1201 formatter=form1
1202 args=(sys.stdout,)
1203
1204 [formatter_form1]
1205 format=%(levelname)s ++ %(message)s
1206 datefmt=
1207 """
1208
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001209 disable_test = """
1210 [loggers]
1211 keys=root
1212
1213 [handlers]
1214 keys=screen
1215
1216 [formatters]
1217 keys=
1218
1219 [logger_root]
1220 level=DEBUG
1221 handlers=screen
1222
1223 [handler_screen]
1224 level=DEBUG
1225 class=StreamHandler
1226 args=(sys.stdout,)
1227 formatter=
1228 """
1229
1230 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001231 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001232 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001233
1234 def test_config0_ok(self):
1235 # A simple config file which overrides the default settings.
1236 with captured_stdout() as output:
1237 self.apply_config(self.config0)
1238 logger = logging.getLogger()
1239 # Won't output anything
1240 logger.info(self.next_message())
1241 # Outputs a message
1242 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001243 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001244 ('ERROR', '2'),
1245 ], stream=output)
1246 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001247 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001248
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001249 def test_config0_using_cp_ok(self):
1250 # A simple config file which overrides the default settings.
1251 with captured_stdout() as output:
1252 file = io.StringIO(textwrap.dedent(self.config0))
1253 cp = configparser.ConfigParser()
1254 cp.read_file(file)
1255 logging.config.fileConfig(cp)
1256 logger = logging.getLogger()
1257 # Won't output anything
1258 logger.info(self.next_message())
1259 # Outputs a message
1260 logger.error(self.next_message())
1261 self.assert_log_lines([
1262 ('ERROR', '2'),
1263 ], stream=output)
1264 # Original logger output is empty.
1265 self.assert_log_lines([])
1266
Georg Brandl3dbca812008-07-23 16:10:53 +00001267 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001268 # A config file defining a sub-parser as well.
1269 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001270 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001271 logger = logging.getLogger("compiler.parser")
1272 # Both will output a message
1273 logger.info(self.next_message())
1274 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001275 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001276 ('INFO', '1'),
1277 ('ERROR', '2'),
1278 ], stream=output)
1279 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001280 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001281
1282 def test_config2_failure(self):
1283 # A simple config file which overrides the default settings.
1284 self.assertRaises(Exception, self.apply_config, self.config2)
1285
1286 def test_config3_failure(self):
1287 # A simple config file which overrides the default settings.
1288 self.assertRaises(Exception, self.apply_config, self.config3)
1289
1290 def test_config4_ok(self):
1291 # A config file specifying a custom formatter class.
1292 with captured_stdout() as output:
1293 self.apply_config(self.config4)
1294 logger = logging.getLogger()
1295 try:
1296 raise RuntimeError()
1297 except RuntimeError:
1298 logging.exception("just testing")
1299 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001300 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001301 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1302 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001303 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001304
Georg Brandl3dbca812008-07-23 16:10:53 +00001305 def test_config5_ok(self):
1306 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001307
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001308 def test_config6_ok(self):
1309 self.test_config1_ok(config=self.config6)
1310
Vinay Sajip3f84b072011-03-07 17:49:33 +00001311 def test_config7_ok(self):
1312 with captured_stdout() as output:
1313 self.apply_config(self.config1a)
1314 logger = logging.getLogger("compiler.parser")
1315 # See issue #11424. compiler-hyphenated sorts
1316 # between compiler and compiler.xyz and this
1317 # was preventing compiler.xyz from being included
1318 # in the child loggers of compiler because of an
1319 # overzealous loop termination condition.
1320 hyphenated = logging.getLogger('compiler-hyphenated')
1321 # All will output a message
1322 logger.info(self.next_message())
1323 logger.error(self.next_message())
1324 hyphenated.critical(self.next_message())
1325 self.assert_log_lines([
1326 ('INFO', '1'),
1327 ('ERROR', '2'),
1328 ('CRITICAL', '3'),
1329 ], stream=output)
1330 # Original logger output is empty.
1331 self.assert_log_lines([])
1332 with captured_stdout() as output:
1333 self.apply_config(self.config7)
1334 logger = logging.getLogger("compiler.parser")
1335 self.assertFalse(logger.disabled)
1336 # Both will output a message
1337 logger.info(self.next_message())
1338 logger.error(self.next_message())
1339 logger = logging.getLogger("compiler.lexer")
1340 # Both will output a message
1341 logger.info(self.next_message())
1342 logger.error(self.next_message())
1343 # Will not appear
1344 hyphenated.critical(self.next_message())
1345 self.assert_log_lines([
1346 ('INFO', '4'),
1347 ('ERROR', '5'),
1348 ('INFO', '6'),
1349 ('ERROR', '7'),
1350 ], stream=output)
1351 # Original logger output is empty.
1352 self.assert_log_lines([])
1353
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001354 def test_logger_disabling(self):
1355 self.apply_config(self.disable_test)
1356 logger = logging.getLogger('foo')
1357 self.assertFalse(logger.disabled)
1358 self.apply_config(self.disable_test)
1359 self.assertTrue(logger.disabled)
1360 self.apply_config(self.disable_test, disable_existing_loggers=False)
1361 self.assertFalse(logger.disabled)
1362
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001363
Victor Stinner45df8202010-04-28 22:31:17 +00001364@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001365class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001366
Christian Heimes180510d2008-03-03 19:15:45 +00001367 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001368
Christian Heimes180510d2008-03-03 19:15:45 +00001369 def setUp(self):
1370 """Set up a TCP server to receive log messages, and a SocketHandler
1371 pointing to that server's address and port."""
1372 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001373 addr = ('localhost', 0)
1374 self.server = server = TestTCPServer(addr, self.handle_socket,
1375 0.01)
1376 server.start()
1377 server.ready.wait()
1378 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1379 server.port)
1380 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001381 self.root_logger.removeHandler(self.root_logger.handlers[0])
1382 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001383 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001384
Christian Heimes180510d2008-03-03 19:15:45 +00001385 def tearDown(self):
1386 """Shutdown the TCP server."""
1387 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001388 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001389 self.root_logger.removeHandler(self.sock_hdlr)
1390 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001391 finally:
1392 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001393
Vinay Sajip7367d082011-05-02 13:17:27 +01001394 def handle_socket(self, request):
1395 conn = request.connection
1396 while True:
1397 chunk = conn.recv(4)
1398 if len(chunk) < 4:
1399 break
1400 slen = struct.unpack(">L", chunk)[0]
1401 chunk = conn.recv(slen)
1402 while len(chunk) < slen:
1403 chunk = chunk + conn.recv(slen - len(chunk))
1404 obj = pickle.loads(chunk)
1405 record = logging.makeLogRecord(obj)
1406 self.log_output += record.msg + '\n'
1407 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001408
Christian Heimes180510d2008-03-03 19:15:45 +00001409 def test_output(self):
1410 # The log message sent to the SocketHandler is properly received.
1411 logger = logging.getLogger("tcp")
1412 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001413 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001414 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001415 self.handled.acquire()
1416 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001417
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001418 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001419 # Avoid timing-related failures due to SocketHandler's own hard-wired
1420 # one-second timeout on socket.create_connection() (issue #16264).
1421 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001422 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001423 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001424 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001425 try:
1426 raise RuntimeError('Deliberate mistake')
1427 except RuntimeError:
1428 self.root_logger.exception('Never sent')
1429 self.root_logger.error('Never sent, either')
1430 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001431 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001432 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1433 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001434
Vinay Sajip7367d082011-05-02 13:17:27 +01001435
1436@unittest.skipUnless(threading, 'Threading required for this test.')
1437class DatagramHandlerTest(BaseTest):
1438
1439 """Test for DatagramHandler."""
1440
1441 def setUp(self):
1442 """Set up a UDP server to receive log messages, and a DatagramHandler
1443 pointing to that server's address and port."""
1444 BaseTest.setUp(self)
1445 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001446 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001447 server.start()
1448 server.ready.wait()
1449 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1450 server.port)
1451 self.log_output = ''
1452 self.root_logger.removeHandler(self.root_logger.handlers[0])
1453 self.root_logger.addHandler(self.sock_hdlr)
1454 self.handled = threading.Event()
1455
1456 def tearDown(self):
1457 """Shutdown the UDP server."""
1458 try:
1459 self.server.stop(2.0)
1460 self.root_logger.removeHandler(self.sock_hdlr)
1461 self.sock_hdlr.close()
1462 finally:
1463 BaseTest.tearDown(self)
1464
1465 def handle_datagram(self, request):
1466 slen = struct.pack('>L', 0) # length of prefix
1467 packet = request.packet[len(slen):]
1468 obj = pickle.loads(packet)
1469 record = logging.makeLogRecord(obj)
1470 self.log_output += record.msg + '\n'
1471 self.handled.set()
1472
1473 def test_output(self):
1474 # The log message sent to the DatagramHandler is properly received.
1475 logger = logging.getLogger("udp")
1476 logger.error("spam")
1477 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001478 self.handled.clear()
1479 logger.error("eggs")
1480 self.handled.wait()
1481 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001482
1483
1484@unittest.skipUnless(threading, 'Threading required for this test.')
1485class SysLogHandlerTest(BaseTest):
1486
1487 """Test for SysLogHandler using UDP."""
1488
1489 def setUp(self):
1490 """Set up a UDP server to receive log messages, and a SysLogHandler
1491 pointing to that server's address and port."""
1492 BaseTest.setUp(self)
1493 addr = ('localhost', 0)
1494 self.server = server = TestUDPServer(addr, self.handle_datagram,
1495 0.01)
1496 server.start()
1497 server.ready.wait()
1498 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1499 server.port))
1500 self.log_output = ''
1501 self.root_logger.removeHandler(self.root_logger.handlers[0])
1502 self.root_logger.addHandler(self.sl_hdlr)
1503 self.handled = threading.Event()
1504
1505 def tearDown(self):
1506 """Shutdown the UDP server."""
1507 try:
1508 self.server.stop(2.0)
1509 self.root_logger.removeHandler(self.sl_hdlr)
1510 self.sl_hdlr.close()
1511 finally:
1512 BaseTest.tearDown(self)
1513
1514 def handle_datagram(self, request):
1515 self.log_output = request.packet
1516 self.handled.set()
1517
1518 def test_output(self):
1519 # The log message sent to the SysLogHandler is properly received.
1520 logger = logging.getLogger("slh")
1521 logger.error("sp\xe4m")
1522 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001523 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001524 self.handled.clear()
1525 self.sl_hdlr.append_nul = False
1526 logger.error("sp\xe4m")
1527 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001528 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001529 self.handled.clear()
1530 self.sl_hdlr.ident = "h\xe4m-"
1531 logger.error("sp\xe4m")
1532 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001533 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001534
1535
1536@unittest.skipUnless(threading, 'Threading required for this test.')
1537class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001538 """Test for HTTPHandler."""
1539
Vinay Sajip9ba87612011-05-21 11:32:15 +01001540 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1541MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1542zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1543aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1544AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15450tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15465LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1547piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15482z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1549i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1550PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1551E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1552rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1553/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1554-----END RSA PRIVATE KEY-----
1555-----BEGIN CERTIFICATE-----
1556MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1557BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1558EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1559xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1560l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1561vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1562BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1563S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1564BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15654f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15661c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1567IRbTpvlHWPjsSvHz0ZOH
1568-----END CERTIFICATE-----"""
1569
Vinay Sajip7367d082011-05-02 13:17:27 +01001570 def setUp(self):
1571 """Set up an HTTP server to receive log messages, and a HTTPHandler
1572 pointing to that server's address and port."""
1573 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001574 self.handled = threading.Event()
1575
Vinay Sajip7367d082011-05-02 13:17:27 +01001576 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001577 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001578 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001579 if self.command == 'POST':
1580 try:
1581 rlen = int(request.headers['Content-Length'])
1582 self.post_data = request.rfile.read(rlen)
1583 except:
1584 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001585 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001586 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001587 self.handled.set()
1588
1589 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001590 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001591 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001592 root_logger = self.root_logger
1593 root_logger.removeHandler(self.root_logger.handlers[0])
1594 for secure in (False, True):
1595 addr = ('localhost', 0)
1596 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001597 try:
1598 import ssl
1599 fd, fn = tempfile.mkstemp()
1600 os.close(fd)
1601 with open(fn, 'w') as f:
1602 f.write(self.PEMFILE)
1603 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1604 sslctx.load_cert_chain(fn)
1605 os.unlink(fn)
1606 except ImportError:
1607 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001608 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001609 sslctx = None
1610 self.server = server = TestHTTPServer(addr, self.handle_request,
1611 0.01, sslctx=sslctx)
1612 server.start()
1613 server.ready.wait()
1614 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001615 secure_client = secure and sslctx
1616 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1617 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001618 self.log_data = None
1619 root_logger.addHandler(self.h_hdlr)
1620
1621 for method in ('GET', 'POST'):
1622 self.h_hdlr.method = method
1623 self.handled.clear()
1624 msg = "sp\xe4m"
1625 logger.error(msg)
1626 self.handled.wait()
1627 self.assertEqual(self.log_data.path, '/frob')
1628 self.assertEqual(self.command, method)
1629 if method == 'GET':
1630 d = parse_qs(self.log_data.query)
1631 else:
1632 d = parse_qs(self.post_data.decode('utf-8'))
1633 self.assertEqual(d['name'], ['http'])
1634 self.assertEqual(d['funcName'], ['test_output'])
1635 self.assertEqual(d['msg'], [msg])
1636
1637 self.server.stop(2.0)
1638 self.root_logger.removeHandler(self.h_hdlr)
1639 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001640
Christian Heimes180510d2008-03-03 19:15:45 +00001641class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001642
Christian Heimes180510d2008-03-03 19:15:45 +00001643 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001644
Christian Heimes180510d2008-03-03 19:15:45 +00001645 def setUp(self):
1646 """Create a dict to remember potentially destroyed objects."""
1647 BaseTest.setUp(self)
1648 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001649
Christian Heimes180510d2008-03-03 19:15:45 +00001650 def _watch_for_survival(self, *args):
1651 """Watch the given objects for survival, by creating weakrefs to
1652 them."""
1653 for obj in args:
1654 key = id(obj), repr(obj)
1655 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001656
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001657 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001658 """Assert that all objects watched for survival have survived."""
1659 # Trigger cycle breaking.
1660 gc.collect()
1661 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001662 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001663 if ref() is None:
1664 dead.append(repr_)
1665 if dead:
1666 self.fail("%d objects should have survived "
1667 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001668
Christian Heimes180510d2008-03-03 19:15:45 +00001669 def test_persistent_loggers(self):
1670 # Logger objects are persistent and retain their configuration, even
1671 # if visible references are destroyed.
1672 self.root_logger.setLevel(logging.INFO)
1673 foo = logging.getLogger("foo")
1674 self._watch_for_survival(foo)
1675 foo.setLevel(logging.DEBUG)
1676 self.root_logger.debug(self.next_message())
1677 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001678 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001679 ('foo', 'DEBUG', '2'),
1680 ])
1681 del foo
1682 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001683 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001684 # foo has retained its settings.
1685 bar = logging.getLogger("foo")
1686 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001687 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001688 ('foo', 'DEBUG', '2'),
1689 ('foo', 'DEBUG', '3'),
1690 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001691
Benjamin Petersonf91df042009-02-13 02:50:59 +00001692
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001693class EncodingTest(BaseTest):
1694 def test_encoding_plain_file(self):
1695 # In Python 2.x, a plain file object is treated as having no encoding.
1696 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001697 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1698 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001699 # the non-ascii data we write to the log.
1700 data = "foo\x80"
1701 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001702 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001703 log.addHandler(handler)
1704 try:
1705 # write non-ascii data to the log.
1706 log.warning(data)
1707 finally:
1708 log.removeHandler(handler)
1709 handler.close()
1710 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001711 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001712 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001713 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001714 finally:
1715 f.close()
1716 finally:
1717 if os.path.isfile(fn):
1718 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001719
Benjamin Petersonf91df042009-02-13 02:50:59 +00001720 def test_encoding_cyrillic_unicode(self):
1721 log = logging.getLogger("test")
1722 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1723 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1724 #Ensure it's written in a Cyrillic encoding
1725 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001726 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001727 stream = io.BytesIO()
1728 writer = writer_class(stream, 'strict')
1729 handler = logging.StreamHandler(writer)
1730 log.addHandler(handler)
1731 try:
1732 log.warning(message)
1733 finally:
1734 log.removeHandler(handler)
1735 handler.close()
1736 # check we wrote exactly those bytes, ignoring trailing \n etc
1737 s = stream.getvalue()
1738 #Compare against what the data should be when encoded in CP-1251
1739 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1740
1741
Georg Brandlf9734072008-12-07 15:30:06 +00001742class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001743
Georg Brandlf9734072008-12-07 15:30:06 +00001744 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001745 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001746 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001747 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001748 warnings.filterwarnings("always", category=UserWarning)
1749 stream = io.StringIO()
1750 h = logging.StreamHandler(stream)
1751 logger = logging.getLogger("py.warnings")
1752 logger.addHandler(h)
1753 warnings.warn("I'm warning you...")
1754 logger.removeHandler(h)
1755 s = stream.getvalue()
1756 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001757 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001758
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001759 #See if an explicit file uses the original implementation
1760 a_file = io.StringIO()
1761 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1762 a_file, "Dummy line")
1763 s = a_file.getvalue()
1764 a_file.close()
1765 self.assertEqual(s,
1766 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1767
1768 def test_warnings_no_handlers(self):
1769 with warnings.catch_warnings():
1770 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001771 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001772
1773 # confirm our assumption: no loggers are set
1774 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001775 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001776
1777 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001778 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001779 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001780
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001781
1782def formatFunc(format, datefmt=None):
1783 return logging.Formatter(format, datefmt)
1784
1785def handlerFunc():
1786 return logging.StreamHandler()
1787
1788class CustomHandler(logging.StreamHandler):
1789 pass
1790
1791class ConfigDictTest(BaseTest):
1792
1793 """Reading logging config from a dictionary."""
1794
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001795 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001796
1797 # config0 is a standard configuration.
1798 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001799 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001800 'formatters': {
1801 'form1' : {
1802 'format' : '%(levelname)s ++ %(message)s',
1803 },
1804 },
1805 'handlers' : {
1806 'hand1' : {
1807 'class' : 'logging.StreamHandler',
1808 'formatter' : 'form1',
1809 'level' : 'NOTSET',
1810 'stream' : 'ext://sys.stdout',
1811 },
1812 },
1813 'root' : {
1814 'level' : 'WARNING',
1815 'handlers' : ['hand1'],
1816 },
1817 }
1818
1819 # config1 adds a little to the standard configuration.
1820 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001821 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001822 'formatters': {
1823 'form1' : {
1824 'format' : '%(levelname)s ++ %(message)s',
1825 },
1826 },
1827 'handlers' : {
1828 'hand1' : {
1829 'class' : 'logging.StreamHandler',
1830 'formatter' : 'form1',
1831 'level' : 'NOTSET',
1832 'stream' : 'ext://sys.stdout',
1833 },
1834 },
1835 'loggers' : {
1836 'compiler.parser' : {
1837 'level' : 'DEBUG',
1838 'handlers' : ['hand1'],
1839 },
1840 },
1841 'root' : {
1842 'level' : 'WARNING',
1843 },
1844 }
1845
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001846 # config1a moves the handler to the root. Used with config8a
1847 config1a = {
1848 'version': 1,
1849 'formatters': {
1850 'form1' : {
1851 'format' : '%(levelname)s ++ %(message)s',
1852 },
1853 },
1854 'handlers' : {
1855 'hand1' : {
1856 'class' : 'logging.StreamHandler',
1857 'formatter' : 'form1',
1858 'level' : 'NOTSET',
1859 'stream' : 'ext://sys.stdout',
1860 },
1861 },
1862 'loggers' : {
1863 'compiler.parser' : {
1864 'level' : 'DEBUG',
1865 },
1866 },
1867 'root' : {
1868 'level' : 'WARNING',
1869 'handlers' : ['hand1'],
1870 },
1871 }
1872
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001873 # config2 has a subtle configuration error that should be reported
1874 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001875 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001876 'formatters': {
1877 'form1' : {
1878 'format' : '%(levelname)s ++ %(message)s',
1879 },
1880 },
1881 'handlers' : {
1882 'hand1' : {
1883 'class' : 'logging.StreamHandler',
1884 'formatter' : 'form1',
1885 'level' : 'NOTSET',
1886 'stream' : 'ext://sys.stdbout',
1887 },
1888 },
1889 'loggers' : {
1890 'compiler.parser' : {
1891 'level' : 'DEBUG',
1892 'handlers' : ['hand1'],
1893 },
1894 },
1895 'root' : {
1896 'level' : 'WARNING',
1897 },
1898 }
1899
1900 #As config1 but with a misspelt level on a handler
1901 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001902 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001903 'formatters': {
1904 'form1' : {
1905 'format' : '%(levelname)s ++ %(message)s',
1906 },
1907 },
1908 'handlers' : {
1909 'hand1' : {
1910 'class' : 'logging.StreamHandler',
1911 'formatter' : 'form1',
1912 'level' : 'NTOSET',
1913 'stream' : 'ext://sys.stdout',
1914 },
1915 },
1916 'loggers' : {
1917 'compiler.parser' : {
1918 'level' : 'DEBUG',
1919 'handlers' : ['hand1'],
1920 },
1921 },
1922 'root' : {
1923 'level' : 'WARNING',
1924 },
1925 }
1926
1927
1928 #As config1 but with a misspelt level on a logger
1929 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001930 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001931 'formatters': {
1932 'form1' : {
1933 'format' : '%(levelname)s ++ %(message)s',
1934 },
1935 },
1936 'handlers' : {
1937 'hand1' : {
1938 'class' : 'logging.StreamHandler',
1939 'formatter' : 'form1',
1940 'level' : 'NOTSET',
1941 'stream' : 'ext://sys.stdout',
1942 },
1943 },
1944 'loggers' : {
1945 'compiler.parser' : {
1946 'level' : 'DEBUG',
1947 'handlers' : ['hand1'],
1948 },
1949 },
1950 'root' : {
1951 'level' : 'WRANING',
1952 },
1953 }
1954
1955 # config3 has a less subtle configuration error
1956 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001957 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001958 'formatters': {
1959 'form1' : {
1960 'format' : '%(levelname)s ++ %(message)s',
1961 },
1962 },
1963 'handlers' : {
1964 'hand1' : {
1965 'class' : 'logging.StreamHandler',
1966 'formatter' : 'misspelled_name',
1967 'level' : 'NOTSET',
1968 'stream' : 'ext://sys.stdout',
1969 },
1970 },
1971 'loggers' : {
1972 'compiler.parser' : {
1973 'level' : 'DEBUG',
1974 'handlers' : ['hand1'],
1975 },
1976 },
1977 'root' : {
1978 'level' : 'WARNING',
1979 },
1980 }
1981
1982 # config4 specifies a custom formatter class to be loaded
1983 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001984 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001985 'formatters': {
1986 'form1' : {
1987 '()' : __name__ + '.ExceptionFormatter',
1988 'format' : '%(levelname)s:%(name)s:%(message)s',
1989 },
1990 },
1991 'handlers' : {
1992 'hand1' : {
1993 'class' : 'logging.StreamHandler',
1994 'formatter' : 'form1',
1995 'level' : 'NOTSET',
1996 'stream' : 'ext://sys.stdout',
1997 },
1998 },
1999 'root' : {
2000 'level' : 'NOTSET',
2001 'handlers' : ['hand1'],
2002 },
2003 }
2004
2005 # As config4 but using an actual callable rather than a string
2006 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002007 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002008 'formatters': {
2009 'form1' : {
2010 '()' : ExceptionFormatter,
2011 'format' : '%(levelname)s:%(name)s:%(message)s',
2012 },
2013 'form2' : {
2014 '()' : __name__ + '.formatFunc',
2015 'format' : '%(levelname)s:%(name)s:%(message)s',
2016 },
2017 'form3' : {
2018 '()' : formatFunc,
2019 'format' : '%(levelname)s:%(name)s:%(message)s',
2020 },
2021 },
2022 'handlers' : {
2023 'hand1' : {
2024 'class' : 'logging.StreamHandler',
2025 'formatter' : 'form1',
2026 'level' : 'NOTSET',
2027 'stream' : 'ext://sys.stdout',
2028 },
2029 'hand2' : {
2030 '()' : handlerFunc,
2031 },
2032 },
2033 'root' : {
2034 'level' : 'NOTSET',
2035 'handlers' : ['hand1'],
2036 },
2037 }
2038
2039 # config5 specifies a custom handler class to be loaded
2040 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002041 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002042 'formatters': {
2043 'form1' : {
2044 'format' : '%(levelname)s ++ %(message)s',
2045 },
2046 },
2047 'handlers' : {
2048 'hand1' : {
2049 'class' : __name__ + '.CustomHandler',
2050 'formatter' : 'form1',
2051 'level' : 'NOTSET',
2052 'stream' : 'ext://sys.stdout',
2053 },
2054 },
2055 'loggers' : {
2056 'compiler.parser' : {
2057 'level' : 'DEBUG',
2058 'handlers' : ['hand1'],
2059 },
2060 },
2061 'root' : {
2062 'level' : 'WARNING',
2063 },
2064 }
2065
2066 # config6 specifies a custom handler class to be loaded
2067 # but has bad arguments
2068 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002069 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002070 'formatters': {
2071 'form1' : {
2072 'format' : '%(levelname)s ++ %(message)s',
2073 },
2074 },
2075 'handlers' : {
2076 'hand1' : {
2077 'class' : __name__ + '.CustomHandler',
2078 'formatter' : 'form1',
2079 'level' : 'NOTSET',
2080 'stream' : 'ext://sys.stdout',
2081 '9' : 'invalid parameter name',
2082 },
2083 },
2084 'loggers' : {
2085 'compiler.parser' : {
2086 'level' : 'DEBUG',
2087 'handlers' : ['hand1'],
2088 },
2089 },
2090 'root' : {
2091 'level' : 'WARNING',
2092 },
2093 }
2094
2095 #config 7 does not define compiler.parser but defines compiler.lexer
2096 #so compiler.parser should be disabled after applying it
2097 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002098 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002099 'formatters': {
2100 'form1' : {
2101 'format' : '%(levelname)s ++ %(message)s',
2102 },
2103 },
2104 'handlers' : {
2105 'hand1' : {
2106 'class' : 'logging.StreamHandler',
2107 'formatter' : 'form1',
2108 'level' : 'NOTSET',
2109 'stream' : 'ext://sys.stdout',
2110 },
2111 },
2112 'loggers' : {
2113 'compiler.lexer' : {
2114 'level' : 'DEBUG',
2115 'handlers' : ['hand1'],
2116 },
2117 },
2118 'root' : {
2119 'level' : 'WARNING',
2120 },
2121 }
2122
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002123 # config8 defines both compiler and compiler.lexer
2124 # so compiler.parser should not be disabled (since
2125 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002126 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002127 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002128 'disable_existing_loggers' : False,
2129 'formatters': {
2130 'form1' : {
2131 'format' : '%(levelname)s ++ %(message)s',
2132 },
2133 },
2134 'handlers' : {
2135 'hand1' : {
2136 'class' : 'logging.StreamHandler',
2137 'formatter' : 'form1',
2138 'level' : 'NOTSET',
2139 'stream' : 'ext://sys.stdout',
2140 },
2141 },
2142 'loggers' : {
2143 'compiler' : {
2144 'level' : 'DEBUG',
2145 'handlers' : ['hand1'],
2146 },
2147 'compiler.lexer' : {
2148 },
2149 },
2150 'root' : {
2151 'level' : 'WARNING',
2152 },
2153 }
2154
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002155 # config8a disables existing loggers
2156 config8a = {
2157 'version': 1,
2158 'disable_existing_loggers' : True,
2159 'formatters': {
2160 'form1' : {
2161 'format' : '%(levelname)s ++ %(message)s',
2162 },
2163 },
2164 'handlers' : {
2165 'hand1' : {
2166 'class' : 'logging.StreamHandler',
2167 'formatter' : 'form1',
2168 'level' : 'NOTSET',
2169 'stream' : 'ext://sys.stdout',
2170 },
2171 },
2172 'loggers' : {
2173 'compiler' : {
2174 'level' : 'DEBUG',
2175 'handlers' : ['hand1'],
2176 },
2177 'compiler.lexer' : {
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WARNING',
2182 },
2183 }
2184
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002185 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002186 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002187 'formatters': {
2188 'form1' : {
2189 'format' : '%(levelname)s ++ %(message)s',
2190 },
2191 },
2192 'handlers' : {
2193 'hand1' : {
2194 'class' : 'logging.StreamHandler',
2195 'formatter' : 'form1',
2196 'level' : 'WARNING',
2197 'stream' : 'ext://sys.stdout',
2198 },
2199 },
2200 'loggers' : {
2201 'compiler.parser' : {
2202 'level' : 'WARNING',
2203 'handlers' : ['hand1'],
2204 },
2205 },
2206 'root' : {
2207 'level' : 'NOTSET',
2208 },
2209 }
2210
2211 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002212 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002213 'incremental' : True,
2214 'handlers' : {
2215 'hand1' : {
2216 'level' : 'WARNING',
2217 },
2218 },
2219 'loggers' : {
2220 'compiler.parser' : {
2221 'level' : 'INFO',
2222 },
2223 },
2224 }
2225
2226 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002227 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002228 'incremental' : True,
2229 'handlers' : {
2230 'hand1' : {
2231 'level' : 'INFO',
2232 },
2233 },
2234 'loggers' : {
2235 'compiler.parser' : {
2236 'level' : 'INFO',
2237 },
2238 },
2239 }
2240
2241 #As config1 but with a filter added
2242 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002243 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002244 'formatters': {
2245 'form1' : {
2246 'format' : '%(levelname)s ++ %(message)s',
2247 },
2248 },
2249 'filters' : {
2250 'filt1' : {
2251 'name' : 'compiler.parser',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : 'logging.StreamHandler',
2257 'formatter' : 'form1',
2258 'level' : 'NOTSET',
2259 'stream' : 'ext://sys.stdout',
2260 'filters' : ['filt1'],
2261 },
2262 },
2263 'loggers' : {
2264 'compiler.parser' : {
2265 'level' : 'DEBUG',
2266 'filters' : ['filt1'],
2267 },
2268 },
2269 'root' : {
2270 'level' : 'WARNING',
2271 'handlers' : ['hand1'],
2272 },
2273 }
2274
2275 #As config1 but using cfg:// references
2276 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002277 'version': 1,
2278 'true_formatters': {
2279 'form1' : {
2280 'format' : '%(levelname)s ++ %(message)s',
2281 },
2282 },
2283 'handler_configs': {
2284 'hand1' : {
2285 'class' : 'logging.StreamHandler',
2286 'formatter' : 'form1',
2287 'level' : 'NOTSET',
2288 'stream' : 'ext://sys.stdout',
2289 },
2290 },
2291 'formatters' : 'cfg://true_formatters',
2292 'handlers' : {
2293 'hand1' : 'cfg://handler_configs[hand1]',
2294 },
2295 'loggers' : {
2296 'compiler.parser' : {
2297 'level' : 'DEBUG',
2298 'handlers' : ['hand1'],
2299 },
2300 },
2301 'root' : {
2302 'level' : 'WARNING',
2303 },
2304 }
2305
2306 #As config11 but missing the version key
2307 config12 = {
2308 'true_formatters': {
2309 'form1' : {
2310 'format' : '%(levelname)s ++ %(message)s',
2311 },
2312 },
2313 'handler_configs': {
2314 'hand1' : {
2315 'class' : 'logging.StreamHandler',
2316 'formatter' : 'form1',
2317 'level' : 'NOTSET',
2318 'stream' : 'ext://sys.stdout',
2319 },
2320 },
2321 'formatters' : 'cfg://true_formatters',
2322 'handlers' : {
2323 'hand1' : 'cfg://handler_configs[hand1]',
2324 },
2325 'loggers' : {
2326 'compiler.parser' : {
2327 'level' : 'DEBUG',
2328 'handlers' : ['hand1'],
2329 },
2330 },
2331 'root' : {
2332 'level' : 'WARNING',
2333 },
2334 }
2335
2336 #As config11 but using an unsupported version
2337 config13 = {
2338 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002339 'true_formatters': {
2340 'form1' : {
2341 'format' : '%(levelname)s ++ %(message)s',
2342 },
2343 },
2344 'handler_configs': {
2345 'hand1' : {
2346 'class' : 'logging.StreamHandler',
2347 'formatter' : 'form1',
2348 'level' : 'NOTSET',
2349 'stream' : 'ext://sys.stdout',
2350 },
2351 },
2352 'formatters' : 'cfg://true_formatters',
2353 'handlers' : {
2354 'hand1' : 'cfg://handler_configs[hand1]',
2355 },
2356 'loggers' : {
2357 'compiler.parser' : {
2358 'level' : 'DEBUG',
2359 'handlers' : ['hand1'],
2360 },
2361 },
2362 'root' : {
2363 'level' : 'WARNING',
2364 },
2365 }
2366
Vinay Sajip8d270232012-11-15 14:20:18 +00002367 # As config0, but with properties
2368 config14 = {
2369 'version': 1,
2370 'formatters': {
2371 'form1' : {
2372 'format' : '%(levelname)s ++ %(message)s',
2373 },
2374 },
2375 'handlers' : {
2376 'hand1' : {
2377 'class' : 'logging.StreamHandler',
2378 'formatter' : 'form1',
2379 'level' : 'NOTSET',
2380 'stream' : 'ext://sys.stdout',
2381 '.': {
2382 'foo': 'bar',
2383 'terminator': '!\n',
2384 }
2385 },
2386 },
2387 'root' : {
2388 'level' : 'WARNING',
2389 'handlers' : ['hand1'],
2390 },
2391 }
2392
Vinay Sajip3f885b52013-03-22 15:19:54 +00002393 out_of_order = {
2394 "version": 1,
2395 "formatters": {
2396 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002397 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2398 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002399 }
2400 },
2401 "handlers": {
2402 "fileGlobal": {
2403 "class": "logging.StreamHandler",
2404 "level": "DEBUG",
2405 "formatter": "mySimpleFormatter"
2406 },
2407 "bufferGlobal": {
2408 "class": "logging.handlers.MemoryHandler",
2409 "capacity": 5,
2410 "formatter": "mySimpleFormatter",
2411 "target": "fileGlobal",
2412 "level": "DEBUG"
2413 }
2414 },
2415 "loggers": {
2416 "mymodule": {
2417 "level": "DEBUG",
2418 "handlers": ["bufferGlobal"],
2419 "propagate": "true"
2420 }
2421 }
2422 }
2423
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002424 def apply_config(self, conf):
2425 logging.config.dictConfig(conf)
2426
2427 def test_config0_ok(self):
2428 # A simple config which overrides the default settings.
2429 with captured_stdout() as output:
2430 self.apply_config(self.config0)
2431 logger = logging.getLogger()
2432 # Won't output anything
2433 logger.info(self.next_message())
2434 # Outputs a message
2435 logger.error(self.next_message())
2436 self.assert_log_lines([
2437 ('ERROR', '2'),
2438 ], stream=output)
2439 # Original logger output is empty.
2440 self.assert_log_lines([])
2441
2442 def test_config1_ok(self, config=config1):
2443 # A config defining a sub-parser as well.
2444 with captured_stdout() as output:
2445 self.apply_config(config)
2446 logger = logging.getLogger("compiler.parser")
2447 # Both will output a message
2448 logger.info(self.next_message())
2449 logger.error(self.next_message())
2450 self.assert_log_lines([
2451 ('INFO', '1'),
2452 ('ERROR', '2'),
2453 ], stream=output)
2454 # Original logger output is empty.
2455 self.assert_log_lines([])
2456
2457 def test_config2_failure(self):
2458 # A simple config which overrides the default settings.
2459 self.assertRaises(Exception, self.apply_config, self.config2)
2460
2461 def test_config2a_failure(self):
2462 # A simple config which overrides the default settings.
2463 self.assertRaises(Exception, self.apply_config, self.config2a)
2464
2465 def test_config2b_failure(self):
2466 # A simple config which overrides the default settings.
2467 self.assertRaises(Exception, self.apply_config, self.config2b)
2468
2469 def test_config3_failure(self):
2470 # A simple config which overrides the default settings.
2471 self.assertRaises(Exception, self.apply_config, self.config3)
2472
2473 def test_config4_ok(self):
2474 # A config specifying a custom formatter class.
2475 with captured_stdout() as output:
2476 self.apply_config(self.config4)
2477 #logger = logging.getLogger()
2478 try:
2479 raise RuntimeError()
2480 except RuntimeError:
2481 logging.exception("just testing")
2482 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002483 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002484 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2485 # Original logger output is empty
2486 self.assert_log_lines([])
2487
2488 def test_config4a_ok(self):
2489 # A config specifying a custom formatter class.
2490 with captured_stdout() as output:
2491 self.apply_config(self.config4a)
2492 #logger = logging.getLogger()
2493 try:
2494 raise RuntimeError()
2495 except RuntimeError:
2496 logging.exception("just testing")
2497 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002498 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002499 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2500 # Original logger output is empty
2501 self.assert_log_lines([])
2502
2503 def test_config5_ok(self):
2504 self.test_config1_ok(config=self.config5)
2505
2506 def test_config6_failure(self):
2507 self.assertRaises(Exception, self.apply_config, self.config6)
2508
2509 def test_config7_ok(self):
2510 with captured_stdout() as output:
2511 self.apply_config(self.config1)
2512 logger = logging.getLogger("compiler.parser")
2513 # Both will output a message
2514 logger.info(self.next_message())
2515 logger.error(self.next_message())
2516 self.assert_log_lines([
2517 ('INFO', '1'),
2518 ('ERROR', '2'),
2519 ], stream=output)
2520 # Original logger output is empty.
2521 self.assert_log_lines([])
2522 with captured_stdout() as output:
2523 self.apply_config(self.config7)
2524 logger = logging.getLogger("compiler.parser")
2525 self.assertTrue(logger.disabled)
2526 logger = logging.getLogger("compiler.lexer")
2527 # Both will output a message
2528 logger.info(self.next_message())
2529 logger.error(self.next_message())
2530 self.assert_log_lines([
2531 ('INFO', '3'),
2532 ('ERROR', '4'),
2533 ], stream=output)
2534 # Original logger output is empty.
2535 self.assert_log_lines([])
2536
2537 #Same as test_config_7_ok but don't disable old loggers.
2538 def test_config_8_ok(self):
2539 with captured_stdout() as output:
2540 self.apply_config(self.config1)
2541 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002542 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002543 logger.info(self.next_message())
2544 logger.error(self.next_message())
2545 self.assert_log_lines([
2546 ('INFO', '1'),
2547 ('ERROR', '2'),
2548 ], stream=output)
2549 # Original logger output is empty.
2550 self.assert_log_lines([])
2551 with captured_stdout() as output:
2552 self.apply_config(self.config8)
2553 logger = logging.getLogger("compiler.parser")
2554 self.assertFalse(logger.disabled)
2555 # Both will output a message
2556 logger.info(self.next_message())
2557 logger.error(self.next_message())
2558 logger = logging.getLogger("compiler.lexer")
2559 # Both will output a message
2560 logger.info(self.next_message())
2561 logger.error(self.next_message())
2562 self.assert_log_lines([
2563 ('INFO', '3'),
2564 ('ERROR', '4'),
2565 ('INFO', '5'),
2566 ('ERROR', '6'),
2567 ], stream=output)
2568 # Original logger output is empty.
2569 self.assert_log_lines([])
2570
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002571 def test_config_8a_ok(self):
2572 with captured_stdout() as output:
2573 self.apply_config(self.config1a)
2574 logger = logging.getLogger("compiler.parser")
2575 # See issue #11424. compiler-hyphenated sorts
2576 # between compiler and compiler.xyz and this
2577 # was preventing compiler.xyz from being included
2578 # in the child loggers of compiler because of an
2579 # overzealous loop termination condition.
2580 hyphenated = logging.getLogger('compiler-hyphenated')
2581 # All will output a message
2582 logger.info(self.next_message())
2583 logger.error(self.next_message())
2584 hyphenated.critical(self.next_message())
2585 self.assert_log_lines([
2586 ('INFO', '1'),
2587 ('ERROR', '2'),
2588 ('CRITICAL', '3'),
2589 ], stream=output)
2590 # Original logger output is empty.
2591 self.assert_log_lines([])
2592 with captured_stdout() as output:
2593 self.apply_config(self.config8a)
2594 logger = logging.getLogger("compiler.parser")
2595 self.assertFalse(logger.disabled)
2596 # Both will output a message
2597 logger.info(self.next_message())
2598 logger.error(self.next_message())
2599 logger = logging.getLogger("compiler.lexer")
2600 # Both will output a message
2601 logger.info(self.next_message())
2602 logger.error(self.next_message())
2603 # Will not appear
2604 hyphenated.critical(self.next_message())
2605 self.assert_log_lines([
2606 ('INFO', '4'),
2607 ('ERROR', '5'),
2608 ('INFO', '6'),
2609 ('ERROR', '7'),
2610 ], stream=output)
2611 # Original logger output is empty.
2612 self.assert_log_lines([])
2613
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002614 def test_config_9_ok(self):
2615 with captured_stdout() as output:
2616 self.apply_config(self.config9)
2617 logger = logging.getLogger("compiler.parser")
2618 #Nothing will be output since both handler and logger are set to WARNING
2619 logger.info(self.next_message())
2620 self.assert_log_lines([], stream=output)
2621 self.apply_config(self.config9a)
2622 #Nothing will be output since both handler is still set to WARNING
2623 logger.info(self.next_message())
2624 self.assert_log_lines([], stream=output)
2625 self.apply_config(self.config9b)
2626 #Message should now be output
2627 logger.info(self.next_message())
2628 self.assert_log_lines([
2629 ('INFO', '3'),
2630 ], stream=output)
2631
2632 def test_config_10_ok(self):
2633 with captured_stdout() as output:
2634 self.apply_config(self.config10)
2635 logger = logging.getLogger("compiler.parser")
2636 logger.warning(self.next_message())
2637 logger = logging.getLogger('compiler')
2638 #Not output, because filtered
2639 logger.warning(self.next_message())
2640 logger = logging.getLogger('compiler.lexer')
2641 #Not output, because filtered
2642 logger.warning(self.next_message())
2643 logger = logging.getLogger("compiler.parser.codegen")
2644 #Output, as not filtered
2645 logger.error(self.next_message())
2646 self.assert_log_lines([
2647 ('WARNING', '1'),
2648 ('ERROR', '4'),
2649 ], stream=output)
2650
2651 def test_config11_ok(self):
2652 self.test_config1_ok(self.config11)
2653
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002654 def test_config12_failure(self):
2655 self.assertRaises(Exception, self.apply_config, self.config12)
2656
2657 def test_config13_failure(self):
2658 self.assertRaises(Exception, self.apply_config, self.config13)
2659
Vinay Sajip8d270232012-11-15 14:20:18 +00002660 def test_config14_ok(self):
2661 with captured_stdout() as output:
2662 self.apply_config(self.config14)
2663 h = logging._handlers['hand1']
2664 self.assertEqual(h.foo, 'bar')
2665 self.assertEqual(h.terminator, '!\n')
2666 logging.warning('Exclamation')
2667 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2668
Victor Stinner45df8202010-04-28 22:31:17 +00002669 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002670 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002671 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002672 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002673 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002674 t.start()
2675 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002676 # Now get the port allocated
2677 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002679 try:
2680 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2681 sock.settimeout(2.0)
2682 sock.connect(('localhost', port))
2683
2684 slen = struct.pack('>L', len(text))
2685 s = slen + text
2686 sentsofar = 0
2687 left = len(s)
2688 while left > 0:
2689 sent = sock.send(s[sentsofar:])
2690 sentsofar += sent
2691 left -= sent
2692 sock.close()
2693 finally:
2694 t.ready.wait(2.0)
2695 logging.config.stopListening()
2696 t.join(2.0)
2697
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002698 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002699 def test_listen_config_10_ok(self):
2700 with captured_stdout() as output:
2701 self.setup_via_listener(json.dumps(self.config10))
2702 logger = logging.getLogger("compiler.parser")
2703 logger.warning(self.next_message())
2704 logger = logging.getLogger('compiler')
2705 #Not output, because filtered
2706 logger.warning(self.next_message())
2707 logger = logging.getLogger('compiler.lexer')
2708 #Not output, because filtered
2709 logger.warning(self.next_message())
2710 logger = logging.getLogger("compiler.parser.codegen")
2711 #Output, as not filtered
2712 logger.error(self.next_message())
2713 self.assert_log_lines([
2714 ('WARNING', '1'),
2715 ('ERROR', '4'),
2716 ], stream=output)
2717
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002718 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002719 def test_listen_config_1_ok(self):
2720 with captured_stdout() as output:
2721 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2722 logger = logging.getLogger("compiler.parser")
2723 # Both will output a message
2724 logger.info(self.next_message())
2725 logger.error(self.next_message())
2726 self.assert_log_lines([
2727 ('INFO', '1'),
2728 ('ERROR', '2'),
2729 ], stream=output)
2730 # Original logger output is empty.
2731 self.assert_log_lines([])
2732
Vinay Sajip4ded5512012-10-02 15:56:16 +01002733 @unittest.skipUnless(threading, 'Threading required for this test.')
2734 def test_listen_verify(self):
2735
2736 def verify_fail(stuff):
2737 return None
2738
2739 def verify_reverse(stuff):
2740 return stuff[::-1]
2741
2742 logger = logging.getLogger("compiler.parser")
2743 to_send = textwrap.dedent(ConfigFileTest.config1)
2744 # First, specify a verification function that will fail.
2745 # We expect to see no output, since our configuration
2746 # never took effect.
2747 with captured_stdout() as output:
2748 self.setup_via_listener(to_send, verify_fail)
2749 # Both will output a message
2750 logger.info(self.next_message())
2751 logger.error(self.next_message())
2752 self.assert_log_lines([], stream=output)
2753 # Original logger output has the stuff we logged.
2754 self.assert_log_lines([
2755 ('INFO', '1'),
2756 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002757 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002758
2759 # Now, perform no verification. Our configuration
2760 # should take effect.
2761
2762 with captured_stdout() as output:
2763 self.setup_via_listener(to_send) # no verify callable specified
2764 logger = logging.getLogger("compiler.parser")
2765 # Both will output a message
2766 logger.info(self.next_message())
2767 logger.error(self.next_message())
2768 self.assert_log_lines([
2769 ('INFO', '3'),
2770 ('ERROR', '4'),
2771 ], stream=output)
2772 # Original logger output still has the stuff we logged before.
2773 self.assert_log_lines([
2774 ('INFO', '1'),
2775 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002776 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002777
2778 # Now, perform verification which transforms the bytes.
2779
2780 with captured_stdout() as output:
2781 self.setup_via_listener(to_send[::-1], verify_reverse)
2782 logger = logging.getLogger("compiler.parser")
2783 # Both will output a message
2784 logger.info(self.next_message())
2785 logger.error(self.next_message())
2786 self.assert_log_lines([
2787 ('INFO', '5'),
2788 ('ERROR', '6'),
2789 ], stream=output)
2790 # Original logger output still has the stuff we logged before.
2791 self.assert_log_lines([
2792 ('INFO', '1'),
2793 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002794 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002795
Vinay Sajip3f885b52013-03-22 15:19:54 +00002796 def test_out_of_order(self):
2797 self.apply_config(self.out_of_order)
2798 handler = logging.getLogger('mymodule').handlers[0]
2799 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002800 self.assertIsInstance(handler.formatter._style,
2801 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002802
Vinay Sajip373baef2011-04-26 20:05:24 +01002803 def test_baseconfig(self):
2804 d = {
2805 'atuple': (1, 2, 3),
2806 'alist': ['a', 'b', 'c'],
2807 'adict': {'d': 'e', 'f': 3 },
2808 'nest1': ('g', ('h', 'i'), 'j'),
2809 'nest2': ['k', ['l', 'm'], 'n'],
2810 'nest3': ['o', 'cfg://alist', 'p'],
2811 }
2812 bc = logging.config.BaseConfigurator(d)
2813 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2814 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2815 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2816 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2817 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2818 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2819 v = bc.convert('cfg://nest3')
2820 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2821 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2822 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2823 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002824
2825class ManagerTest(BaseTest):
2826 def test_manager_loggerclass(self):
2827 logged = []
2828
2829 class MyLogger(logging.Logger):
2830 def _log(self, level, msg, args, exc_info=None, extra=None):
2831 logged.append(msg)
2832
2833 man = logging.Manager(None)
2834 self.assertRaises(TypeError, man.setLoggerClass, int)
2835 man.setLoggerClass(MyLogger)
2836 logger = man.getLogger('test')
2837 logger.warning('should appear in logged')
2838 logging.warning('should not appear in logged')
2839
2840 self.assertEqual(logged, ['should appear in logged'])
2841
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002842 def test_set_log_record_factory(self):
2843 man = logging.Manager(None)
2844 expected = object()
2845 man.setLogRecordFactory(expected)
2846 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002847
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002848class ChildLoggerTest(BaseTest):
2849 def test_child_loggers(self):
2850 r = logging.getLogger()
2851 l1 = logging.getLogger('abc')
2852 l2 = logging.getLogger('def.ghi')
2853 c1 = r.getChild('xyz')
2854 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002855 self.assertIs(c1, logging.getLogger('xyz'))
2856 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002857 c1 = l1.getChild('def')
2858 c2 = c1.getChild('ghi')
2859 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002860 self.assertIs(c1, logging.getLogger('abc.def'))
2861 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2862 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002863
2864
Vinay Sajip6fac8172010-10-19 20:44:14 +00002865class DerivedLogRecord(logging.LogRecord):
2866 pass
2867
Vinay Sajip61561522010-12-03 11:50:38 +00002868class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002869
2870 def setUp(self):
2871 class CheckingFilter(logging.Filter):
2872 def __init__(self, cls):
2873 self.cls = cls
2874
2875 def filter(self, record):
2876 t = type(record)
2877 if t is not self.cls:
2878 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2879 self.cls)
2880 raise TypeError(msg)
2881 return True
2882
2883 BaseTest.setUp(self)
2884 self.filter = CheckingFilter(DerivedLogRecord)
2885 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002886 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002887
2888 def tearDown(self):
2889 self.root_logger.removeFilter(self.filter)
2890 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002891 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002892
2893 def test_logrecord_class(self):
2894 self.assertRaises(TypeError, self.root_logger.warning,
2895 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002896 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002897 self.root_logger.error(self.next_message())
2898 self.assert_log_lines([
2899 ('root', 'ERROR', '2'),
2900 ])
2901
2902
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002903class QueueHandlerTest(BaseTest):
2904 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002905 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002906
2907 def setUp(self):
2908 BaseTest.setUp(self)
2909 self.queue = queue.Queue(-1)
2910 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2911 self.que_logger = logging.getLogger('que')
2912 self.que_logger.propagate = False
2913 self.que_logger.setLevel(logging.WARNING)
2914 self.que_logger.addHandler(self.que_hdlr)
2915
2916 def tearDown(self):
2917 self.que_hdlr.close()
2918 BaseTest.tearDown(self)
2919
2920 def test_queue_handler(self):
2921 self.que_logger.debug(self.next_message())
2922 self.assertRaises(queue.Empty, self.queue.get_nowait)
2923 self.que_logger.info(self.next_message())
2924 self.assertRaises(queue.Empty, self.queue.get_nowait)
2925 msg = self.next_message()
2926 self.que_logger.warning(msg)
2927 data = self.queue.get_nowait()
2928 self.assertTrue(isinstance(data, logging.LogRecord))
2929 self.assertEqual(data.name, self.que_logger.name)
2930 self.assertEqual((data.msg, data.args), (msg, None))
2931
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002932 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2933 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002934 def test_queue_listener(self):
2935 handler = TestHandler(Matcher())
2936 listener = logging.handlers.QueueListener(self.queue, handler)
2937 listener.start()
2938 try:
2939 self.que_logger.warning(self.next_message())
2940 self.que_logger.error(self.next_message())
2941 self.que_logger.critical(self.next_message())
2942 finally:
2943 listener.stop()
2944 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2945 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2946 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2947
Vinay Sajip37eb3382011-04-26 20:26:41 +01002948ZERO = datetime.timedelta(0)
2949
2950class UTC(datetime.tzinfo):
2951 def utcoffset(self, dt):
2952 return ZERO
2953
2954 dst = utcoffset
2955
2956 def tzname(self, dt):
2957 return 'UTC'
2958
2959utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002960
Vinay Sajipa39c5712010-10-25 13:57:39 +00002961class FormatterTest(unittest.TestCase):
2962 def setUp(self):
2963 self.common = {
2964 'name': 'formatter.test',
2965 'level': logging.DEBUG,
2966 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2967 'lineno': 42,
2968 'exc_info': None,
2969 'func': None,
2970 'msg': 'Message with %d %s',
2971 'args': (2, 'placeholders'),
2972 }
2973 self.variants = {
2974 }
2975
2976 def get_record(self, name=None):
2977 result = dict(self.common)
2978 if name is not None:
2979 result.update(self.variants[name])
2980 return logging.makeLogRecord(result)
2981
2982 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002983 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002984 r = self.get_record()
2985 f = logging.Formatter('${%(message)s}')
2986 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2987 f = logging.Formatter('%(random)s')
2988 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002989 self.assertFalse(f.usesTime())
2990 f = logging.Formatter('%(asctime)s')
2991 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002992 f = logging.Formatter('%(asctime)-15s')
2993 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002994 f = logging.Formatter('asctime')
2995 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002996
2997 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002998 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002999 r = self.get_record()
3000 f = logging.Formatter('$%{message}%$', style='{')
3001 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3002 f = logging.Formatter('{random}', style='{')
3003 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003004 self.assertFalse(f.usesTime())
3005 f = logging.Formatter('{asctime}', style='{')
3006 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003007 f = logging.Formatter('{asctime!s:15}', style='{')
3008 self.assertTrue(f.usesTime())
3009 f = logging.Formatter('{asctime:15}', style='{')
3010 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003011 f = logging.Formatter('asctime', style='{')
3012 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003013
3014 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003015 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003016 r = self.get_record()
3017 f = logging.Formatter('$message', style='$')
3018 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3019 f = logging.Formatter('$$%${message}%$$', style='$')
3020 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3021 f = logging.Formatter('${random}', style='$')
3022 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003023 self.assertFalse(f.usesTime())
3024 f = logging.Formatter('${asctime}', style='$')
3025 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003026 f = logging.Formatter('${asctime', style='$')
3027 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003028 f = logging.Formatter('$asctime', style='$')
3029 self.assertTrue(f.usesTime())
3030 f = logging.Formatter('asctime', style='$')
3031 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003032
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003033 def test_invalid_style(self):
3034 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3035
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003036 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003037 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003038 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3039 # We use None to indicate we want the local timezone
3040 # We're essentially converting a UTC time to local time
3041 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003042 r.msecs = 123
3043 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003044 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003045 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3046 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003047 f.format(r)
3048 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3049
3050class TestBufferingFormatter(logging.BufferingFormatter):
3051 def formatHeader(self, records):
3052 return '[(%d)' % len(records)
3053
3054 def formatFooter(self, records):
3055 return '(%d)]' % len(records)
3056
3057class BufferingFormatterTest(unittest.TestCase):
3058 def setUp(self):
3059 self.records = [
3060 logging.makeLogRecord({'msg': 'one'}),
3061 logging.makeLogRecord({'msg': 'two'}),
3062 ]
3063
3064 def test_default(self):
3065 f = logging.BufferingFormatter()
3066 self.assertEqual('', f.format([]))
3067 self.assertEqual('onetwo', f.format(self.records))
3068
3069 def test_custom(self):
3070 f = TestBufferingFormatter()
3071 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3072 lf = logging.Formatter('<%(message)s>')
3073 f = TestBufferingFormatter(lf)
3074 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003075
3076class ExceptionTest(BaseTest):
3077 def test_formatting(self):
3078 r = self.root_logger
3079 h = RecordingHandler()
3080 r.addHandler(h)
3081 try:
3082 raise RuntimeError('deliberate mistake')
3083 except:
3084 logging.exception('failed', stack_info=True)
3085 r.removeHandler(h)
3086 h.close()
3087 r = h.records[0]
3088 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3089 'call last):\n'))
3090 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3091 'deliberate mistake'))
3092 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3093 'call last):\n'))
3094 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3095 'stack_info=True)'))
3096
3097
Vinay Sajip5a27d402010-12-10 11:42:57 +00003098class LastResortTest(BaseTest):
3099 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003100 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003101 root = self.root_logger
3102 root.removeHandler(self.root_hdlr)
3103 old_stderr = sys.stderr
3104 old_lastresort = logging.lastResort
3105 old_raise_exceptions = logging.raiseExceptions
3106 try:
3107 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003108 root.debug('This should not appear')
3109 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003110 root.warning('This is your final chance!')
3111 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3112 #No handlers and no last resort, so 'No handlers' message
3113 logging.lastResort = None
3114 sys.stderr = sio = io.StringIO()
3115 root.warning('This is your final chance!')
3116 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3117 # 'No handlers' message only printed once
3118 sys.stderr = sio = io.StringIO()
3119 root.warning('This is your final chance!')
3120 self.assertEqual(sio.getvalue(), '')
3121 root.manager.emittedNoHandlerWarning = False
3122 #If raiseExceptions is False, no message is printed
3123 logging.raiseExceptions = False
3124 sys.stderr = sio = io.StringIO()
3125 root.warning('This is your final chance!')
3126 self.assertEqual(sio.getvalue(), '')
3127 finally:
3128 sys.stderr = old_stderr
3129 root.addHandler(self.root_hdlr)
3130 logging.lastResort = old_lastresort
3131 logging.raiseExceptions = old_raise_exceptions
3132
3133
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003134class FakeHandler:
3135
3136 def __init__(self, identifier, called):
3137 for method in ('acquire', 'flush', 'close', 'release'):
3138 setattr(self, method, self.record_call(identifier, method, called))
3139
3140 def record_call(self, identifier, method_name, called):
3141 def inner():
3142 called.append('{} - {}'.format(identifier, method_name))
3143 return inner
3144
3145
3146class RecordingHandler(logging.NullHandler):
3147
3148 def __init__(self, *args, **kwargs):
3149 super(RecordingHandler, self).__init__(*args, **kwargs)
3150 self.records = []
3151
3152 def handle(self, record):
3153 """Keep track of all the emitted records."""
3154 self.records.append(record)
3155
3156
3157class ShutdownTest(BaseTest):
3158
Vinay Sajip5e66b162011-04-20 15:41:14 +01003159 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003160
3161 def setUp(self):
3162 super(ShutdownTest, self).setUp()
3163 self.called = []
3164
3165 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003166 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003167
3168 def raise_error(self, error):
3169 def inner():
3170 raise error()
3171 return inner
3172
3173 def test_no_failure(self):
3174 # create some fake handlers
3175 handler0 = FakeHandler(0, self.called)
3176 handler1 = FakeHandler(1, self.called)
3177 handler2 = FakeHandler(2, self.called)
3178
3179 # create live weakref to those handlers
3180 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3181
3182 logging.shutdown(handlerList=list(handlers))
3183
3184 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3185 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3186 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3187 self.assertEqual(expected, self.called)
3188
3189 def _test_with_failure_in_method(self, method, error):
3190 handler = FakeHandler(0, self.called)
3191 setattr(handler, method, self.raise_error(error))
3192 handlers = [logging.weakref.ref(handler)]
3193
3194 logging.shutdown(handlerList=list(handlers))
3195
3196 self.assertEqual('0 - release', self.called[-1])
3197
3198 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003199 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003200
3201 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003202 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003203
3204 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003205 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003206
3207 def test_with_valueerror_in_acquire(self):
3208 self._test_with_failure_in_method('acquire', ValueError)
3209
3210 def test_with_valueerror_in_flush(self):
3211 self._test_with_failure_in_method('flush', ValueError)
3212
3213 def test_with_valueerror_in_close(self):
3214 self._test_with_failure_in_method('close', ValueError)
3215
3216 def test_with_other_error_in_acquire_without_raise(self):
3217 logging.raiseExceptions = False
3218 self._test_with_failure_in_method('acquire', IndexError)
3219
3220 def test_with_other_error_in_flush_without_raise(self):
3221 logging.raiseExceptions = False
3222 self._test_with_failure_in_method('flush', IndexError)
3223
3224 def test_with_other_error_in_close_without_raise(self):
3225 logging.raiseExceptions = False
3226 self._test_with_failure_in_method('close', IndexError)
3227
3228 def test_with_other_error_in_acquire_with_raise(self):
3229 logging.raiseExceptions = True
3230 self.assertRaises(IndexError, self._test_with_failure_in_method,
3231 'acquire', IndexError)
3232
3233 def test_with_other_error_in_flush_with_raise(self):
3234 logging.raiseExceptions = True
3235 self.assertRaises(IndexError, self._test_with_failure_in_method,
3236 'flush', IndexError)
3237
3238 def test_with_other_error_in_close_with_raise(self):
3239 logging.raiseExceptions = True
3240 self.assertRaises(IndexError, self._test_with_failure_in_method,
3241 'close', IndexError)
3242
3243
3244class ModuleLevelMiscTest(BaseTest):
3245
Vinay Sajip5e66b162011-04-20 15:41:14 +01003246 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003247
3248 def test_disable(self):
3249 old_disable = logging.root.manager.disable
3250 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003251 self.assertEqual(old_disable, 0)
3252 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003253
3254 logging.disable(83)
3255 self.assertEqual(logging.root.manager.disable, 83)
3256
3257 def _test_log(self, method, level=None):
3258 called = []
3259 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003260 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003261
3262 recording = RecordingHandler()
3263 logging.root.addHandler(recording)
3264
3265 log_method = getattr(logging, method)
3266 if level is not None:
3267 log_method(level, "test me: %r", recording)
3268 else:
3269 log_method("test me: %r", recording)
3270
3271 self.assertEqual(len(recording.records), 1)
3272 record = recording.records[0]
3273 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3274
3275 expected_level = level if level is not None else getattr(logging, method.upper())
3276 self.assertEqual(record.levelno, expected_level)
3277
3278 # basicConfig was not called!
3279 self.assertEqual(called, [])
3280
3281 def test_log(self):
3282 self._test_log('log', logging.ERROR)
3283
3284 def test_debug(self):
3285 self._test_log('debug')
3286
3287 def test_info(self):
3288 self._test_log('info')
3289
3290 def test_warning(self):
3291 self._test_log('warning')
3292
3293 def test_error(self):
3294 self._test_log('error')
3295
3296 def test_critical(self):
3297 self._test_log('critical')
3298
3299 def test_set_logger_class(self):
3300 self.assertRaises(TypeError, logging.setLoggerClass, object)
3301
3302 class MyLogger(logging.Logger):
3303 pass
3304
3305 logging.setLoggerClass(MyLogger)
3306 self.assertEqual(logging.getLoggerClass(), MyLogger)
3307
3308 logging.setLoggerClass(logging.Logger)
3309 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3310
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003311class LogRecordTest(BaseTest):
3312 def test_str_rep(self):
3313 r = logging.makeLogRecord({})
3314 s = str(r)
3315 self.assertTrue(s.startswith('<LogRecord: '))
3316 self.assertTrue(s.endswith('>'))
3317
3318 def test_dict_arg(self):
3319 h = RecordingHandler()
3320 r = logging.getLogger()
3321 r.addHandler(h)
3322 d = {'less' : 'more' }
3323 logging.warning('less is %(less)s', d)
3324 self.assertIs(h.records[0].args, d)
3325 self.assertEqual(h.records[0].message, 'less is more')
3326 r.removeHandler(h)
3327 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003328
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003329 def test_multiprocessing(self):
3330 r = logging.makeLogRecord({})
3331 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003332 try:
3333 import multiprocessing as mp
3334 r = logging.makeLogRecord({})
3335 self.assertEqual(r.processName, mp.current_process().name)
3336 except ImportError:
3337 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003338
3339 def test_optional(self):
3340 r = logging.makeLogRecord({})
3341 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003342 if threading:
3343 NOT_NONE(r.thread)
3344 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003345 NOT_NONE(r.process)
3346 NOT_NONE(r.processName)
3347 log_threads = logging.logThreads
3348 log_processes = logging.logProcesses
3349 log_multiprocessing = logging.logMultiprocessing
3350 try:
3351 logging.logThreads = False
3352 logging.logProcesses = False
3353 logging.logMultiprocessing = False
3354 r = logging.makeLogRecord({})
3355 NONE = self.assertIsNone
3356 NONE(r.thread)
3357 NONE(r.threadName)
3358 NONE(r.process)
3359 NONE(r.processName)
3360 finally:
3361 logging.logThreads = log_threads
3362 logging.logProcesses = log_processes
3363 logging.logMultiprocessing = log_multiprocessing
3364
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003365class BasicConfigTest(unittest.TestCase):
3366
Vinay Sajip95bf5042011-04-20 11:50:56 +01003367 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003368
3369 def setUp(self):
3370 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003371 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003372 self.saved_handlers = logging._handlers.copy()
3373 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003374 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003375 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003376 logging.root.handlers = []
3377
3378 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003379 for h in logging.root.handlers[:]:
3380 logging.root.removeHandler(h)
3381 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003382 super(BasicConfigTest, self).tearDown()
3383
Vinay Sajip3def7e02011-04-20 10:58:06 +01003384 def cleanup(self):
3385 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003386 logging._handlers.clear()
3387 logging._handlers.update(self.saved_handlers)
3388 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003389 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003390
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003391 def test_no_kwargs(self):
3392 logging.basicConfig()
3393
3394 # handler defaults to a StreamHandler to sys.stderr
3395 self.assertEqual(len(logging.root.handlers), 1)
3396 handler = logging.root.handlers[0]
3397 self.assertIsInstance(handler, logging.StreamHandler)
3398 self.assertEqual(handler.stream, sys.stderr)
3399
3400 formatter = handler.formatter
3401 # format defaults to logging.BASIC_FORMAT
3402 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3403 # datefmt defaults to None
3404 self.assertIsNone(formatter.datefmt)
3405 # style defaults to %
3406 self.assertIsInstance(formatter._style, logging.PercentStyle)
3407
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003408 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003409 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003410
3411 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003412
3413 def cleanup(h1, h2, fn):
3414 h1.close()
3415 h2.close()
3416 os.remove(fn)
3417
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003418 logging.basicConfig(filename='test.log')
3419
3420 self.assertEqual(len(logging.root.handlers), 1)
3421 handler = logging.root.handlers[0]
3422 self.assertIsInstance(handler, logging.FileHandler)
3423
3424 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003425 self.assertEqual(handler.stream.mode, expected.stream.mode)
3426 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003427 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003428
3429 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003430
3431 def cleanup(h1, h2, fn):
3432 h1.close()
3433 h2.close()
3434 os.remove(fn)
3435
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003436 logging.basicConfig(filename='test.log', filemode='wb')
3437
3438 handler = logging.root.handlers[0]
3439 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003440 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003441 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003442
3443 def test_stream(self):
3444 stream = io.StringIO()
3445 self.addCleanup(stream.close)
3446 logging.basicConfig(stream=stream)
3447
3448 self.assertEqual(len(logging.root.handlers), 1)
3449 handler = logging.root.handlers[0]
3450 self.assertIsInstance(handler, logging.StreamHandler)
3451 self.assertEqual(handler.stream, stream)
3452
3453 def test_format(self):
3454 logging.basicConfig(format='foo')
3455
3456 formatter = logging.root.handlers[0].formatter
3457 self.assertEqual(formatter._style._fmt, 'foo')
3458
3459 def test_datefmt(self):
3460 logging.basicConfig(datefmt='bar')
3461
3462 formatter = logging.root.handlers[0].formatter
3463 self.assertEqual(formatter.datefmt, 'bar')
3464
3465 def test_style(self):
3466 logging.basicConfig(style='$')
3467
3468 formatter = logging.root.handlers[0].formatter
3469 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3470
3471 def test_level(self):
3472 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003473 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003474
3475 logging.basicConfig(level=57)
3476 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003477 # Test that second call has no effect
3478 logging.basicConfig(level=58)
3479 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003480
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003481 def test_incompatible(self):
3482 assertRaises = self.assertRaises
3483 handlers = [logging.StreamHandler()]
3484 stream = sys.stderr
3485 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3486 stream=stream)
3487 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3488 handlers=handlers)
3489 assertRaises(ValueError, logging.basicConfig, stream=stream,
3490 handlers=handlers)
3491
3492 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003493 handlers = [
3494 logging.StreamHandler(),
3495 logging.StreamHandler(sys.stdout),
3496 logging.StreamHandler(),
3497 ]
3498 f = logging.Formatter()
3499 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003500 logging.basicConfig(handlers=handlers)
3501 self.assertIs(handlers[0], logging.root.handlers[0])
3502 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003503 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003504 self.assertIsNotNone(handlers[0].formatter)
3505 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003506 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003507 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3508
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003509 def _test_log(self, method, level=None):
3510 # logging.root has no handlers so basicConfig should be called
3511 called = []
3512
3513 old_basic_config = logging.basicConfig
3514 def my_basic_config(*a, **kw):
3515 old_basic_config()
3516 old_level = logging.root.level
3517 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003518 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003519 called.append((a, kw))
3520
3521 patch(self, logging, 'basicConfig', my_basic_config)
3522
3523 log_method = getattr(logging, method)
3524 if level is not None:
3525 log_method(level, "test me")
3526 else:
3527 log_method("test me")
3528
3529 # basicConfig was called with no arguments
3530 self.assertEqual(called, [((), {})])
3531
3532 def test_log(self):
3533 self._test_log('log', logging.WARNING)
3534
3535 def test_debug(self):
3536 self._test_log('debug')
3537
3538 def test_info(self):
3539 self._test_log('info')
3540
3541 def test_warning(self):
3542 self._test_log('warning')
3543
3544 def test_error(self):
3545 self._test_log('error')
3546
3547 def test_critical(self):
3548 self._test_log('critical')
3549
3550
3551class LoggerAdapterTest(unittest.TestCase):
3552
3553 def setUp(self):
3554 super(LoggerAdapterTest, self).setUp()
3555 old_handler_list = logging._handlerList[:]
3556
3557 self.recording = RecordingHandler()
3558 self.logger = logging.root
3559 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003560 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561 self.addCleanup(self.recording.close)
3562
3563 def cleanup():
3564 logging._handlerList[:] = old_handler_list
3565
3566 self.addCleanup(cleanup)
3567 self.addCleanup(logging.shutdown)
3568 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3569
3570 def test_exception(self):
3571 msg = 'testing exception: %r'
3572 exc = None
3573 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003574 1 / 0
3575 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003576 exc = e
3577 self.adapter.exception(msg, self.recording)
3578
3579 self.assertEqual(len(self.recording.records), 1)
3580 record = self.recording.records[0]
3581 self.assertEqual(record.levelno, logging.ERROR)
3582 self.assertEqual(record.msg, msg)
3583 self.assertEqual(record.args, (self.recording,))
3584 self.assertEqual(record.exc_info,
3585 (exc.__class__, exc, exc.__traceback__))
3586
3587 def test_critical(self):
3588 msg = 'critical test! %r'
3589 self.adapter.critical(msg, self.recording)
3590
3591 self.assertEqual(len(self.recording.records), 1)
3592 record = self.recording.records[0]
3593 self.assertEqual(record.levelno, logging.CRITICAL)
3594 self.assertEqual(record.msg, msg)
3595 self.assertEqual(record.args, (self.recording,))
3596
3597 def test_is_enabled_for(self):
3598 old_disable = self.adapter.logger.manager.disable
3599 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003600 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3601 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003602 self.assertFalse(self.adapter.isEnabledFor(32))
3603
3604 def test_has_handlers(self):
3605 self.assertTrue(self.adapter.hasHandlers())
3606
3607 for handler in self.logger.handlers:
3608 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003609
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003610 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003611 self.assertFalse(self.adapter.hasHandlers())
3612
3613
3614class LoggerTest(BaseTest):
3615
3616 def setUp(self):
3617 super(LoggerTest, self).setUp()
3618 self.recording = RecordingHandler()
3619 self.logger = logging.Logger(name='blah')
3620 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003621 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003622 self.addCleanup(self.recording.close)
3623 self.addCleanup(logging.shutdown)
3624
3625 def test_set_invalid_level(self):
3626 self.assertRaises(TypeError, self.logger.setLevel, object())
3627
3628 def test_exception(self):
3629 msg = 'testing exception: %r'
3630 exc = None
3631 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003632 1 / 0
3633 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003634 exc = e
3635 self.logger.exception(msg, self.recording)
3636
3637 self.assertEqual(len(self.recording.records), 1)
3638 record = self.recording.records[0]
3639 self.assertEqual(record.levelno, logging.ERROR)
3640 self.assertEqual(record.msg, msg)
3641 self.assertEqual(record.args, (self.recording,))
3642 self.assertEqual(record.exc_info,
3643 (exc.__class__, exc, exc.__traceback__))
3644
3645 def test_log_invalid_level_with_raise(self):
3646 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003647 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003648
3649 logging.raiseExceptions = True
3650 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3651
3652 def test_log_invalid_level_no_raise(self):
3653 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003654 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003655
3656 logging.raiseExceptions = False
3657 self.logger.log('10', 'test message') # no exception happens
3658
3659 def test_find_caller_with_stack_info(self):
3660 called = []
3661 patch(self, logging.traceback, 'print_stack',
3662 lambda f, file: called.append(file.getvalue()))
3663
3664 self.logger.findCaller(stack_info=True)
3665
3666 self.assertEqual(len(called), 1)
3667 self.assertEqual('Stack (most recent call last):\n', called[0])
3668
3669 def test_make_record_with_extra_overwrite(self):
3670 name = 'my record'
3671 level = 13
3672 fn = lno = msg = args = exc_info = func = sinfo = None
3673 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3674 exc_info, func, sinfo)
3675
3676 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3677 extra = {key: 'some value'}
3678 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3679 fn, lno, msg, args, exc_info,
3680 extra=extra, sinfo=sinfo)
3681
3682 def test_make_record_with_extra_no_overwrite(self):
3683 name = 'my record'
3684 level = 13
3685 fn = lno = msg = args = exc_info = func = sinfo = None
3686 extra = {'valid_key': 'some value'}
3687 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3688 exc_info, extra=extra, sinfo=sinfo)
3689 self.assertIn('valid_key', result.__dict__)
3690
3691 def test_has_handlers(self):
3692 self.assertTrue(self.logger.hasHandlers())
3693
3694 for handler in self.logger.handlers:
3695 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003696 self.assertFalse(self.logger.hasHandlers())
3697
3698 def test_has_handlers_no_propagate(self):
3699 child_logger = logging.getLogger('blah.child')
3700 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003701 self.assertFalse(child_logger.hasHandlers())
3702
3703 def test_is_enabled_for(self):
3704 old_disable = self.logger.manager.disable
3705 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003706 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003707 self.assertFalse(self.logger.isEnabledFor(22))
3708
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003709 def test_root_logger_aliases(self):
3710 root = logging.getLogger()
3711 self.assertIs(root, logging.root)
3712 self.assertIs(root, logging.getLogger(None))
3713 self.assertIs(root, logging.getLogger(''))
3714 self.assertIs(root, logging.getLogger('foo').root)
3715 self.assertIs(root, logging.getLogger('foo.bar').root)
3716 self.assertIs(root, logging.getLogger('foo').parent)
3717
3718 self.assertIsNot(root, logging.getLogger('\0'))
3719 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3720
3721 def test_invalid_names(self):
3722 self.assertRaises(TypeError, logging.getLogger, any)
3723 self.assertRaises(TypeError, logging.getLogger, b'foo')
3724
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003725
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003726class BaseFileTest(BaseTest):
3727 "Base class for handler tests that write log files"
3728
3729 def setUp(self):
3730 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003731 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3732 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003733 self.rmfiles = []
3734
3735 def tearDown(self):
3736 for fn in self.rmfiles:
3737 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003738 if os.path.exists(self.fn):
3739 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003740 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003741
3742 def assertLogFile(self, filename):
3743 "Assert a log file is there and register it for deletion"
3744 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003745 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003746 self.rmfiles.append(filename)
3747
3748
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003749class FileHandlerTest(BaseFileTest):
3750 def test_delay(self):
3751 os.unlink(self.fn)
3752 fh = logging.FileHandler(self.fn, delay=True)
3753 self.assertIsNone(fh.stream)
3754 self.assertFalse(os.path.exists(self.fn))
3755 fh.handle(logging.makeLogRecord({}))
3756 self.assertIsNotNone(fh.stream)
3757 self.assertTrue(os.path.exists(self.fn))
3758 fh.close()
3759
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003760class RotatingFileHandlerTest(BaseFileTest):
3761 def next_rec(self):
3762 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3763 self.next_message(), None, None, None)
3764
3765 def test_should_not_rollover(self):
3766 # If maxbytes is zero rollover never occurs
3767 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3768 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003769 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003770
3771 def test_should_rollover(self):
3772 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3773 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003774 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003775
3776 def test_file_created(self):
3777 # checks that the file is created and assumes it was created
3778 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003779 rh = logging.handlers.RotatingFileHandler(self.fn)
3780 rh.emit(self.next_rec())
3781 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003782 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003783
3784 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003785 def namer(name):
3786 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003787 rh = logging.handlers.RotatingFileHandler(
3788 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003789 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003790 rh.emit(self.next_rec())
3791 self.assertLogFile(self.fn)
3792 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003793 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003794 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003795 self.assertLogFile(namer(self.fn + ".2"))
3796 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3797 rh.close()
3798
Eric V. Smith851cad72012-03-11 22:46:04 -07003799 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003800 def test_rotator(self):
3801 def namer(name):
3802 return name + ".gz"
3803
3804 def rotator(source, dest):
3805 with open(source, "rb") as sf:
3806 data = sf.read()
3807 compressed = zlib.compress(data, 9)
3808 with open(dest, "wb") as df:
3809 df.write(compressed)
3810 os.remove(source)
3811
3812 rh = logging.handlers.RotatingFileHandler(
3813 self.fn, backupCount=2, maxBytes=1)
3814 rh.rotator = rotator
3815 rh.namer = namer
3816 m1 = self.next_rec()
3817 rh.emit(m1)
3818 self.assertLogFile(self.fn)
3819 m2 = self.next_rec()
3820 rh.emit(m2)
3821 fn = namer(self.fn + ".1")
3822 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003823 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003824 with open(fn, "rb") as f:
3825 compressed = f.read()
3826 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003827 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003828 rh.emit(self.next_rec())
3829 fn = namer(self.fn + ".2")
3830 self.assertLogFile(fn)
3831 with open(fn, "rb") as f:
3832 compressed = f.read()
3833 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003834 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003835 rh.emit(self.next_rec())
3836 fn = namer(self.fn + ".2")
3837 with open(fn, "rb") as f:
3838 compressed = f.read()
3839 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003840 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003841 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003842 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003843
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003844class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003845 # other test methods added below
3846 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003847 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3848 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003849 fmt = logging.Formatter('%(asctime)s %(message)s')
3850 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003851 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003852 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003853 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003854 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003855 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003856 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003857 fh.close()
3858 # At this point, we should have a recent rotated file which we
3859 # can test for the existence of. However, in practice, on some
3860 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003861 # in time to go to look for the log file. So, we go back a fair
3862 # bit, and stop as soon as we see a rotated file. In theory this
3863 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003864 found = False
3865 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003866 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003867 for secs in range(GO_BACK):
3868 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003869 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3870 found = os.path.exists(fn)
3871 if found:
3872 self.rmfiles.append(fn)
3873 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003874 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3875 if not found:
3876 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003877 dn, fn = os.path.split(self.fn)
3878 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003879 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3880 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003881 for f in files:
3882 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003883 path = os.path.join(dn, f)
3884 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003885 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003886 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003887
Vinay Sajip0372e102011-05-05 12:59:14 +01003888 def test_invalid(self):
3889 assertRaises = self.assertRaises
3890 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003891 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003892 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003893 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003894 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003895 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003896
Vinay Sajipa7130792013-04-12 17:04:23 +01003897 def test_compute_rollover_daily_attime(self):
3898 currentTime = 0
3899 atTime = datetime.time(12, 0, 0)
3900 rh = logging.handlers.TimedRotatingFileHandler(
3901 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
3902 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01003903 try:
3904 actual = rh.computeRollover(currentTime)
3905 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01003906
Vinay Sajipd86ac962013-04-14 12:20:46 +01003907 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
3908 self.assertEqual(actual, currentTime + 36 * 60 * 60)
3909 finally:
3910 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01003911
Vinay Sajip10e8c492013-05-18 10:19:54 -07003912 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01003913 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01003914 currentTime = int(time.time())
3915 today = currentTime - currentTime % 86400
3916
Vinay Sajipa7130792013-04-12 17:04:23 +01003917 atTime = datetime.time(12, 0, 0)
3918
Vinay Sajip10e8c492013-05-18 10:19:54 -07003919 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01003920 for day in range(7):
3921 rh = logging.handlers.TimedRotatingFileHandler(
3922 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
3923 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01003924 try:
3925 if wday > day:
3926 # The rollover day has already passed this week, so we
3927 # go over into next week
3928 expected = (7 - wday + day)
3929 else:
3930 expected = (day - wday)
3931 # At this point expected is in days from now, convert to seconds
3932 expected *= 24 * 60 * 60
3933 # Add in the rollover time
3934 expected += 12 * 60 * 60
3935 # Add in adjustment for today
3936 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01003937 actual = rh.computeRollover(today)
3938 if actual != expected:
3939 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01003940 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01003941 self.assertEqual(actual, expected)
3942 if day == wday:
3943 # goes into following week
3944 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01003945 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01003946 if actual != expected:
3947 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01003948 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01003949 self.assertEqual(actual, expected)
3950 finally:
3951 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01003952
3953
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003954def secs(**kw):
3955 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3956
3957for when, exp in (('S', 1),
3958 ('M', 60),
3959 ('H', 60 * 60),
3960 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003961 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003962 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003963 ('W0', secs(days=4, hours=24)),
3964 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003965 def test_compute_rollover(self, when=when, exp=exp):
3966 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003967 self.fn, when=when, interval=1, backupCount=0, utc=True)
3968 currentTime = 0.0
3969 actual = rh.computeRollover(currentTime)
3970 if exp != actual:
3971 # Failures occur on some systems for MIDNIGHT and W0.
3972 # Print detailed calculation for MIDNIGHT so we can try to see
3973 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00003974 if when == 'MIDNIGHT':
3975 try:
3976 if rh.utc:
3977 t = time.gmtime(currentTime)
3978 else:
3979 t = time.localtime(currentTime)
3980 currentHour = t[3]
3981 currentMinute = t[4]
3982 currentSecond = t[5]
3983 # r is the number of seconds left between now and midnight
3984 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3985 currentMinute) * 60 +
3986 currentSecond)
3987 result = currentTime + r
3988 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3989 print('currentHour: %s' % currentHour, file=sys.stderr)
3990 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3991 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3992 print('r: %s' % r, file=sys.stderr)
3993 print('result: %s' % result, file=sys.stderr)
3994 except Exception:
3995 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3996 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003997 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003998 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3999
Vinay Sajip60ccd822011-05-09 17:32:09 +01004000
4001@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4002class NTEventLogHandlerTest(BaseTest):
4003 def test_basic(self):
4004 logtype = 'Application'
4005 elh = win32evtlog.OpenEventLog(None, logtype)
4006 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4007 h = logging.handlers.NTEventLogHandler('test_logging')
4008 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4009 h.handle(r)
4010 h.close()
4011 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004012 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004013 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4014 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4015 found = False
4016 GO_BACK = 100
4017 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4018 for e in events:
4019 if e.SourceName != 'test_logging':
4020 continue
4021 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4022 if msg != 'Test Log Message\r\n':
4023 continue
4024 found = True
4025 break
4026 msg = 'Record not found in event log, went back %d records' % GO_BACK
4027 self.assertTrue(found, msg=msg)
4028
Christian Heimes180510d2008-03-03 19:15:45 +00004029# Set the locale to the platform-dependent default. I have no idea
4030# why the test does this, but in any case we save the current locale
4031# first and restore it at the end.
4032@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004033def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004034 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004035 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004036 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4037 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4038 ManagerTest, FormatterTest, BufferingFormatterTest,
4039 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4040 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4041 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4042 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004043 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004044 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00004045 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004046 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004047
Christian Heimes180510d2008-03-03 19:15:45 +00004048if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004049 test_main()