blob: 5729678ff5487c57e5890fdea846e59adde7d7d8 [file] [log] [blame]
Vinay Sajip3f885b52013-03-22 15:19:54 +00001# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip3f885b52013-03-22 15:19:54 +000019Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000029import pickle
30import io
31import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000032import json
Christian Heimes180510d2008-03-03 19:15:45 +000033import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000034import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010035import random
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000037import select
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Antoine Pitrou712cb732013-12-21 15:51:54 +010042from test.script_helper import assert_python_ok
Eric V. Smith851cad72012-03-11 22:46:04 -070043from test.support import (captured_stdout, run_with_locale, run_unittest,
44 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000045import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010046import time
Christian Heimes180510d2008-03-03 19:15:45 +000047import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000048import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000049import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000050try:
51 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010053 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 import asynchat
55 import asyncore
56 import errno
57 from http.server import HTTPServer, BaseHTTPRequestHandler
58 import smtpd
59 from urllib.parse import urlparse, parse_qs
60 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip5421f352013-09-27 18:18:28 +010061 ThreadingTCPServer, StreamRequestHandler,
62 ThreadingUnixStreamServer,
63 ThreadingUnixDatagramServer)
Victor Stinner45df8202010-04-28 22:31:17 +000064except ImportError:
65 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010066try:
67 import win32evtlog
68except ImportError:
69 win32evtlog = None
70try:
71 import win32evtlogutil
72except ImportError:
73 win32evtlogutil = None
74 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070075try:
76 import zlib
77except ImportError:
78 pass
Christian Heimes18c66892008-02-17 13:31:39 +000079
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)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300163 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100164 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000165 for actual, expected in zip(actual_lines, expected_values):
166 match = pat.search(actual)
167 if not match:
168 self.fail("Log line does not match expected pattern:\n" +
169 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000170 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000171 s = stream.read()
172 if s:
173 self.fail("Remaining output at end of log stream:\n" + s)
174
175 def next_message(self):
176 """Generate a message consisting solely of an auto-incrementing
177 integer."""
178 self.message_num += 1
179 return "%d" % self.message_num
180
181
182class BuiltinLevelsTest(BaseTest):
183 """Test builtin levels and their inheritance."""
184
185 def test_flat(self):
186 #Logging levels in a flat logger namespace.
187 m = self.next_message
188
189 ERR = logging.getLogger("ERR")
190 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000191 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000192 INF.setLevel(logging.INFO)
193 DEB = logging.getLogger("DEB")
194 DEB.setLevel(logging.DEBUG)
195
196 # These should log.
197 ERR.log(logging.CRITICAL, m())
198 ERR.error(m())
199
200 INF.log(logging.CRITICAL, m())
201 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 INF.info(m())
204
205 DEB.log(logging.CRITICAL, m())
206 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 DEB.warning(m())
208 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000209 DEB.debug(m())
210
211 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100212 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000213 ERR.info(m())
214 ERR.debug(m())
215
216 INF.debug(m())
217
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000218 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000219 ('ERR', 'CRITICAL', '1'),
220 ('ERR', 'ERROR', '2'),
221 ('INF', 'CRITICAL', '3'),
222 ('INF', 'ERROR', '4'),
223 ('INF', 'WARNING', '5'),
224 ('INF', 'INFO', '6'),
225 ('DEB', 'CRITICAL', '7'),
226 ('DEB', 'ERROR', '8'),
227 ('DEB', 'WARNING', '9'),
228 ('DEB', 'INFO', '10'),
229 ('DEB', 'DEBUG', '11'),
230 ])
231
232 def test_nested_explicit(self):
233 # Logging levels in a nested namespace, all explicitly set.
234 m = self.next_message
235
236 INF = logging.getLogger("INF")
237 INF.setLevel(logging.INFO)
238 INF_ERR = logging.getLogger("INF.ERR")
239 INF_ERR.setLevel(logging.ERROR)
240
241 # These should log.
242 INF_ERR.log(logging.CRITICAL, m())
243 INF_ERR.error(m())
244
245 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100246 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000247 INF_ERR.info(m())
248 INF_ERR.debug(m())
249
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000250 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000251 ('INF.ERR', 'CRITICAL', '1'),
252 ('INF.ERR', 'ERROR', '2'),
253 ])
254
255 def test_nested_inherited(self):
256 #Logging levels in a nested namespace, inherited from parent loggers.
257 m = self.next_message
258
259 INF = logging.getLogger("INF")
260 INF.setLevel(logging.INFO)
261 INF_ERR = logging.getLogger("INF.ERR")
262 INF_ERR.setLevel(logging.ERROR)
263 INF_UNDEF = logging.getLogger("INF.UNDEF")
264 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
265 UNDEF = logging.getLogger("UNDEF")
266
267 # These should log.
268 INF_UNDEF.log(logging.CRITICAL, m())
269 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100270 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000271 INF_UNDEF.info(m())
272 INF_ERR_UNDEF.log(logging.CRITICAL, m())
273 INF_ERR_UNDEF.error(m())
274
275 # These should not log.
276 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100277 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000278 INF_ERR_UNDEF.info(m())
279 INF_ERR_UNDEF.debug(m())
280
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000281 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000282 ('INF.UNDEF', 'CRITICAL', '1'),
283 ('INF.UNDEF', 'ERROR', '2'),
284 ('INF.UNDEF', 'WARNING', '3'),
285 ('INF.UNDEF', 'INFO', '4'),
286 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
287 ('INF.ERR.UNDEF', 'ERROR', '6'),
288 ])
289
290 def test_nested_with_virtual_parent(self):
291 # Logging levels when some parent does not exist yet.
292 m = self.next_message
293
294 INF = logging.getLogger("INF")
295 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
296 CHILD = logging.getLogger("INF.BADPARENT")
297 INF.setLevel(logging.INFO)
298
299 # These should log.
300 GRANDCHILD.log(logging.FATAL, m())
301 GRANDCHILD.info(m())
302 CHILD.log(logging.FATAL, m())
303 CHILD.info(m())
304
305 # These should not log.
306 GRANDCHILD.debug(m())
307 CHILD.debug(m())
308
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000309 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000310 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
311 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
312 ('INF.BADPARENT', 'CRITICAL', '3'),
313 ('INF.BADPARENT', 'INFO', '4'),
314 ])
315
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100316 def test_regression_22386(self):
317 """See issue #22386 for more information."""
318 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
319 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000320
321class BasicFilterTest(BaseTest):
322
323 """Test the bundled Filter class."""
324
325 def test_filter(self):
326 # Only messages satisfying the specified criteria pass through the
327 # filter.
328 filter_ = logging.Filter("spam.eggs")
329 handler = self.root_logger.handlers[0]
330 try:
331 handler.addFilter(filter_)
332 spam = logging.getLogger("spam")
333 spam_eggs = logging.getLogger("spam.eggs")
334 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
335 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
336
337 spam.info(self.next_message())
338 spam_eggs.info(self.next_message()) # Good.
339 spam_eggs_fish.info(self.next_message()) # Good.
340 spam_bakedbeans.info(self.next_message())
341
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000342 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000343 ('spam.eggs', 'INFO', '2'),
344 ('spam.eggs.fish', 'INFO', '3'),
345 ])
346 finally:
347 handler.removeFilter(filter_)
348
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000349 def test_callable_filter(self):
350 # Only messages satisfying the specified criteria pass through the
351 # filter.
352
353 def filterfunc(record):
354 parts = record.name.split('.')
355 prefix = '.'.join(parts[:2])
356 return prefix == 'spam.eggs'
357
358 handler = self.root_logger.handlers[0]
359 try:
360 handler.addFilter(filterfunc)
361 spam = logging.getLogger("spam")
362 spam_eggs = logging.getLogger("spam.eggs")
363 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
364 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
365
366 spam.info(self.next_message())
367 spam_eggs.info(self.next_message()) # Good.
368 spam_eggs_fish.info(self.next_message()) # Good.
369 spam_bakedbeans.info(self.next_message())
370
371 self.assert_log_lines([
372 ('spam.eggs', 'INFO', '2'),
373 ('spam.eggs.fish', 'INFO', '3'),
374 ])
375 finally:
376 handler.removeFilter(filterfunc)
377
Vinay Sajip985ef872011-04-26 19:34:04 +0100378 def test_empty_filter(self):
379 f = logging.Filter()
380 r = logging.makeLogRecord({'name': 'spam.eggs'})
381 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000382
383#
384# First, we define our levels. There can be as many as you want - the only
385# limitations are that they should be integers, the lowest should be > 0 and
386# larger values mean less information being logged. If you need specific
387# level values which do not fit into these limitations, you can use a
388# mapping dictionary to convert between your application levels and the
389# logging system.
390#
391SILENT = 120
392TACITURN = 119
393TERSE = 118
394EFFUSIVE = 117
395SOCIABLE = 116
396VERBOSE = 115
397TALKATIVE = 114
398GARRULOUS = 113
399CHATTERBOX = 112
400BORING = 111
401
402LEVEL_RANGE = range(BORING, SILENT + 1)
403
404#
405# Next, we define names for our levels. You don't need to do this - in which
406# case the system will use "Level n" to denote the text for the level.
407#
408my_logging_levels = {
409 SILENT : 'Silent',
410 TACITURN : 'Taciturn',
411 TERSE : 'Terse',
412 EFFUSIVE : 'Effusive',
413 SOCIABLE : 'Sociable',
414 VERBOSE : 'Verbose',
415 TALKATIVE : 'Talkative',
416 GARRULOUS : 'Garrulous',
417 CHATTERBOX : 'Chatterbox',
418 BORING : 'Boring',
419}
420
421class GarrulousFilter(logging.Filter):
422
423 """A filter which blocks garrulous messages."""
424
425 def filter(self, record):
426 return record.levelno != GARRULOUS
427
428class VerySpecificFilter(logging.Filter):
429
430 """A filter which blocks sociable and taciturn messages."""
431
432 def filter(self, record):
433 return record.levelno not in [SOCIABLE, TACITURN]
434
435
436class CustomLevelsAndFiltersTest(BaseTest):
437
438 """Test various filtering possibilities with custom logging levels."""
439
440 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300441 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000442
443 def setUp(self):
444 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000445 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000446 logging.addLevelName(k, v)
447
448 def log_at_all_levels(self, logger):
449 for lvl in LEVEL_RANGE:
450 logger.log(lvl, self.next_message())
451
452 def test_logger_filter(self):
453 # Filter at logger level.
454 self.root_logger.setLevel(VERBOSE)
455 # Levels >= 'Verbose' are good.
456 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000457 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000458 ('Verbose', '5'),
459 ('Sociable', '6'),
460 ('Effusive', '7'),
461 ('Terse', '8'),
462 ('Taciturn', '9'),
463 ('Silent', '10'),
464 ])
465
466 def test_handler_filter(self):
467 # Filter at handler level.
468 self.root_logger.handlers[0].setLevel(SOCIABLE)
469 try:
470 # Levels >= 'Sociable' are good.
471 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000472 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000473 ('Sociable', '6'),
474 ('Effusive', '7'),
475 ('Terse', '8'),
476 ('Taciturn', '9'),
477 ('Silent', '10'),
478 ])
479 finally:
480 self.root_logger.handlers[0].setLevel(logging.NOTSET)
481
482 def test_specific_filters(self):
483 # Set a specific filter object on the handler, and then add another
484 # filter object on the logger itself.
485 handler = self.root_logger.handlers[0]
486 specific_filter = None
487 garr = GarrulousFilter()
488 handler.addFilter(garr)
489 try:
490 self.log_at_all_levels(self.root_logger)
491 first_lines = [
492 # Notice how 'Garrulous' is missing
493 ('Boring', '1'),
494 ('Chatterbox', '2'),
495 ('Talkative', '4'),
496 ('Verbose', '5'),
497 ('Sociable', '6'),
498 ('Effusive', '7'),
499 ('Terse', '8'),
500 ('Taciturn', '9'),
501 ('Silent', '10'),
502 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000503 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000504
505 specific_filter = VerySpecificFilter()
506 self.root_logger.addFilter(specific_filter)
507 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000508 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000509 # Not only 'Garrulous' is still missing, but also 'Sociable'
510 # and 'Taciturn'
511 ('Boring', '11'),
512 ('Chatterbox', '12'),
513 ('Talkative', '14'),
514 ('Verbose', '15'),
515 ('Effusive', '17'),
516 ('Terse', '18'),
517 ('Silent', '20'),
518 ])
519 finally:
520 if specific_filter:
521 self.root_logger.removeFilter(specific_filter)
522 handler.removeFilter(garr)
523
524
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100525class HandlerTest(BaseTest):
526 def test_name(self):
527 h = logging.Handler()
528 h.name = 'generic'
529 self.assertEqual(h.name, 'generic')
530 h.name = 'anothergeneric'
531 self.assertEqual(h.name, 'anothergeneric')
532 self.assertRaises(NotImplementedError, h.emit, None)
533
Vinay Sajip5a35b062011-04-27 11:31:14 +0100534 def test_builtin_handlers(self):
535 # We can't actually *use* too many handlers in the tests,
536 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200537 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100538 for existing in (True, False):
539 fd, fn = tempfile.mkstemp()
540 os.close(fd)
541 if not existing:
542 os.unlink(fn)
543 h = logging.handlers.WatchedFileHandler(fn, delay=True)
544 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100545 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100546 self.assertEqual(dev, -1)
547 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100548 r = logging.makeLogRecord({'msg': 'Test'})
549 h.handle(r)
550 # Now remove the file.
551 os.unlink(fn)
552 self.assertFalse(os.path.exists(fn))
553 # The next call should recreate the file.
554 h.handle(r)
555 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100556 else:
557 self.assertEqual(h.dev, -1)
558 self.assertEqual(h.ino, -1)
559 h.close()
560 if existing:
561 os.unlink(fn)
562 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100563 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100564 else:
565 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100566 try:
567 h = logging.handlers.SysLogHandler(sockname)
568 self.assertEqual(h.facility, h.LOG_USER)
569 self.assertTrue(h.unixsocket)
570 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200571 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100572 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100573 for method in ('GET', 'POST', 'PUT'):
574 if method == 'PUT':
575 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
576 'localhost', '/log', method)
577 else:
578 h = logging.handlers.HTTPHandler('localhost', '/log', method)
579 h.close()
580 h = logging.handlers.BufferingHandler(0)
581 r = logging.makeLogRecord({})
582 self.assertTrue(h.shouldFlush(r))
583 h.close()
584 h = logging.handlers.BufferingHandler(1)
585 self.assertFalse(h.shouldFlush(r))
586 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100587
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100588 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100589 @unittest.skipUnless(threading, 'Threading required for this test.')
590 def test_race(self):
591 # Issue #14632 refers.
592 def remove_loop(fname, tries):
593 for _ in range(tries):
594 try:
595 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000596 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597 except OSError:
598 pass
599 time.sleep(0.004 * random.randint(0, 4))
600
Vinay Sajipc94871a2012-04-25 10:51:35 +0100601 del_count = 500
602 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000604 self.handle_time = None
605 self.deletion_time = None
606
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' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000620 try:
621 self.handle_time = time.time()
622 h.handle(r)
623 except Exception:
624 print('Deleted at %s, '
625 'opened at %s' % (self.deletion_time,
626 self.handle_time))
627 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100628 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100629 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100630 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100631 if os.path.exists(fn):
632 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100633
634
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100635class BadStream(object):
636 def write(self, data):
637 raise RuntimeError('deliberate mistake')
638
639class TestStreamHandler(logging.StreamHandler):
640 def handleError(self, record):
641 self.error_record = record
642
643class StreamHandlerTest(BaseTest):
644 def test_error_handling(self):
645 h = TestStreamHandler(BadStream())
646 r = logging.makeLogRecord({})
647 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100648 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100649 try:
650 h.handle(r)
651 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100652 h = logging.StreamHandler(BadStream())
653 sys.stderr = sio = io.StringIO()
654 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100655 self.assertIn('\nRuntimeError: deliberate mistake\n',
656 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100657 logging.raiseExceptions = False
658 sys.stderr = sio = io.StringIO()
659 h.handle(r)
660 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100661 finally:
662 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100663 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100664
Vinay Sajip7367d082011-05-02 13:17:27 +0100665# -- The following section could be moved into a server_helper.py module
666# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100667
Vinay Sajipce7c9782011-05-17 07:15:53 +0100668if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100669 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100670 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100671 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100672
Vinay Sajipce7c9782011-05-17 07:15:53 +0100673 :param addr: A (host, port) tuple which the server listens on.
674 You can specify a port value of zero: the server's
675 *port* attribute will hold the actual port number
676 used, which can be used in client connections.
677 :param handler: A callable which will be called to process
678 incoming messages. The handler will be passed
679 the client address tuple, who the message is from,
680 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100681 :param poll_interval: The interval, in seconds, used in the underlying
682 :func:`select` or :func:`poll` call by
683 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100684 :param sockmap: A dictionary which will be used to hold
685 :class:`asyncore.dispatcher` instances used by
686 :func:`asyncore.loop`. This avoids changing the
687 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100688 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689
690 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100691 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
692 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 self._handler = handler
694 self._thread = None
695 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100696
Vinay Sajipce7c9782011-05-17 07:15:53 +0100697 def process_message(self, peer, mailfrom, rcpttos, data):
698 """
699 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701 Typically, this will be a test case method.
702 :param peer: The client (host, port) tuple.
703 :param mailfrom: The address of the sender.
704 :param rcpttos: The addresses of the recipients.
705 :param data: The message.
706 """
707 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100708
Vinay Sajipce7c9782011-05-17 07:15:53 +0100709 def start(self):
710 """
711 Start the server running on a separate daemon thread.
712 """
713 self._thread = t = threading.Thread(target=self.serve_forever,
714 args=(self.poll_interval,))
715 t.setDaemon(True)
716 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100717
Vinay Sajipce7c9782011-05-17 07:15:53 +0100718 def serve_forever(self, poll_interval):
719 """
720 Run the :mod:`asyncore` loop until normal termination
721 conditions arise.
722 :param poll_interval: The interval, in seconds, used in the underlying
723 :func:`select` or :func:`poll` call by
724 :func:`asyncore.loop`.
725 """
726 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100727 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200728 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100729 # On FreeBSD 8, closing the server repeatably
730 # raises this error. We swallow it if the
731 # server has been closed.
732 if self.connected or self.accepting:
733 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100734
Vinay Sajipce7c9782011-05-17 07:15:53 +0100735 def stop(self, timeout=None):
736 """
737 Stop the thread by closing the server instance.
738 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100739
Vinay Sajipce7c9782011-05-17 07:15:53 +0100740 :param timeout: How long to wait for the server thread
741 to terminate.
742 """
743 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100744 self._thread.join(timeout)
745 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100746
Vinay Sajipce7c9782011-05-17 07:15:53 +0100747 class ControlMixin(object):
748 """
749 This mixin is used to start a server on a separate thread, and
750 shut it down programmatically. Request handling is simplified - instead
751 of needing to derive a suitable RequestHandler subclass, you just
752 provide a callable which will be passed each received request to be
753 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100754
Vinay Sajipce7c9782011-05-17 07:15:53 +0100755 :param handler: A handler callable which will be called with a
756 single parameter - the request - in order to
757 process the request. This handler is called on the
758 server thread, effectively meaning that requests are
759 processed serially. While not quite Web scale ;-),
760 this should be fine for testing applications.
761 :param poll_interval: The polling interval in seconds.
762 """
763 def __init__(self, handler, poll_interval):
764 self._thread = None
765 self.poll_interval = poll_interval
766 self._handler = handler
767 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100768
Vinay Sajipce7c9782011-05-17 07:15:53 +0100769 def start(self):
770 """
771 Create a daemon thread to run the server, and start it.
772 """
773 self._thread = t = threading.Thread(target=self.serve_forever,
774 args=(self.poll_interval,))
775 t.setDaemon(True)
776 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100777
Vinay Sajipce7c9782011-05-17 07:15:53 +0100778 def serve_forever(self, poll_interval):
779 """
780 Run the server. Set the ready flag before entering the
781 service loop.
782 """
783 self.ready.set()
784 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 def stop(self, timeout=None):
787 """
788 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100789
Vinay Sajipce7c9782011-05-17 07:15:53 +0100790 :param timeout: How long to wait for the server thread
791 to terminate.
792 """
793 self.shutdown()
794 if self._thread is not None:
795 self._thread.join(timeout)
796 self._thread = None
797 self.server_close()
798 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Vinay Sajipce7c9782011-05-17 07:15:53 +0100800 class TestHTTPServer(ControlMixin, HTTPServer):
801 """
802 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100803
Vinay Sajipce7c9782011-05-17 07:15:53 +0100804 :param addr: A tuple with the IP address and port to listen on.
805 :param handler: A handler callable which will be called with a
806 single parameter - the request - in order to
807 process the request.
808 :param poll_interval: The polling interval in seconds.
809 :param log: Pass ``True`` to enable log messages.
810 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100811 def __init__(self, addr, handler, poll_interval=0.5,
812 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100813 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
814 def __getattr__(self, name, default=None):
815 if name.startswith('do_'):
816 return self.process_request
817 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100818
Vinay Sajipce7c9782011-05-17 07:15:53 +0100819 def process_request(self):
820 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100821
Vinay Sajipce7c9782011-05-17 07:15:53 +0100822 def log_message(self, format, *args):
823 if log:
824 super(DelegatingHTTPRequestHandler,
825 self).log_message(format, *args)
826 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
827 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100828 self.sslctx = sslctx
829
830 def get_request(self):
831 try:
832 sock, addr = self.socket.accept()
833 if self.sslctx:
834 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200835 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100836 # socket errors are silenced by the caller, print them here
837 sys.stderr.write("Got an error:\n%s\n" % e)
838 raise
839 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 class TestTCPServer(ControlMixin, ThreadingTCPServer):
842 """
843 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100844
Vinay Sajipce7c9782011-05-17 07:15:53 +0100845 :param addr: A tuple with the IP address and port to listen on.
846 :param handler: A handler callable which will be called with a single
847 parameter - the request - in order to process the request.
848 :param poll_interval: The polling interval in seconds.
849 :bind_and_activate: If True (the default), binds the server and starts it
850 listening. If False, you need to call
851 :meth:`server_bind` and :meth:`server_activate` at
852 some later time before calling :meth:`start`, so that
853 the server will set up the socket and listen on it.
854 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100855
Vinay Sajipce7c9782011-05-17 07:15:53 +0100856 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100857
Vinay Sajipce7c9782011-05-17 07:15:53 +0100858 def __init__(self, addr, handler, poll_interval=0.5,
859 bind_and_activate=True):
860 class DelegatingTCPRequestHandler(StreamRequestHandler):
861
862 def handle(self):
863 self.server._handler(self)
864 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
865 bind_and_activate)
866 ControlMixin.__init__(self, handler, poll_interval)
867
868 def server_bind(self):
869 super(TestTCPServer, self).server_bind()
870 self.port = self.socket.getsockname()[1]
871
872 class TestUDPServer(ControlMixin, ThreadingUDPServer):
873 """
874 A UDP server which is controllable using :class:`ControlMixin`.
875
876 :param addr: A tuple with the IP address and port to listen on.
877 :param handler: A handler callable which will be called with a
878 single parameter - the request - in order to
879 process the request.
880 :param poll_interval: The polling interval for shutdown requests,
881 in seconds.
882 :bind_and_activate: If True (the default), binds the server and
883 starts it listening. If False, you need to
884 call :meth:`server_bind` and
885 :meth:`server_activate` at some later time
886 before calling :meth:`start`, so that the server will
887 set up the socket and listen on it.
888 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100889 def __init__(self, addr, handler, poll_interval=0.5,
890 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100891 class DelegatingUDPRequestHandler(DatagramRequestHandler):
892
893 def handle(self):
894 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100895
896 def finish(self):
897 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 if data:
899 try:
900 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200901 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100902 if not self.server._closed:
903 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100904
Vinay Sajip3ef12292011-05-23 23:00:42 +0100905 ThreadingUDPServer.__init__(self, addr,
906 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100907 bind_and_activate)
908 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100909 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100910
911 def server_bind(self):
912 super(TestUDPServer, self).server_bind()
913 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Vinay Sajipba980db2011-05-23 21:37:54 +0100915 def server_close(self):
916 super(TestUDPServer, self).server_close()
917 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100918
Victor Stinnerec5a8602014-06-02 14:41:51 +0200919 if hasattr(socket, "AF_UNIX"):
920 class TestUnixStreamServer(TestTCPServer):
921 address_family = socket.AF_UNIX
922
923 class TestUnixDatagramServer(TestUDPServer):
924 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100925
Vinay Sajip7367d082011-05-02 13:17:27 +0100926# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100927
Vinay Sajipce7c9782011-05-17 07:15:53 +0100928@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100929class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000930 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100932 sockmap = {}
933 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
934 sockmap)
935 server.start()
936 addr = ('localhost', server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000937 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
938 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 self.assertEqual(h.toaddrs, ['you'])
940 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100941 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100942 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100943 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000944 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100945 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000946 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100947 self.assertEqual(len(self.messages), 1)
948 peer, mailfrom, rcpttos, data = self.messages[0]
949 self.assertEqual(mailfrom, 'me')
950 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100951 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100952 self.assertTrue(data.endswith('\n\nHello'))
953 h.close()
954
955 def process_message(self, *args):
956 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100957 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100958
Christian Heimes180510d2008-03-03 19:15:45 +0000959class MemoryHandlerTest(BaseTest):
960
961 """Tests for the MemoryHandler."""
962
963 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300964 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000965
966 def setUp(self):
967 BaseTest.setUp(self)
968 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
969 self.root_hdlr)
970 self.mem_logger = logging.getLogger('mem')
971 self.mem_logger.propagate = 0
972 self.mem_logger.addHandler(self.mem_hdlr)
973
974 def tearDown(self):
975 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000976 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000977
978 def test_flush(self):
979 # The memory handler flushes to its target handler based on specific
980 # criteria (message count and message level).
981 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000982 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000983 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000984 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000985 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100986 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000987 lines = [
988 ('DEBUG', '1'),
989 ('INFO', '2'),
990 ('WARNING', '3'),
991 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000992 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000993 for n in (4, 14):
994 for i in range(9):
995 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000996 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000997 # This will flush because it's the 10th message since the last
998 # flush.
999 self.mem_logger.debug(self.next_message())
1000 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001001 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001002
1003 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001004 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001005
1006
1007class ExceptionFormatter(logging.Formatter):
1008 """A special exception formatter."""
1009 def formatException(self, ei):
1010 return "Got a [%s]" % ei[0].__name__
1011
1012
1013class ConfigFileTest(BaseTest):
1014
1015 """Reading logging config from a .ini-style config file."""
1016
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001017 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001018
1019 # config0 is a standard configuration.
1020 config0 = """
1021 [loggers]
1022 keys=root
1023
1024 [handlers]
1025 keys=hand1
1026
1027 [formatters]
1028 keys=form1
1029
1030 [logger_root]
1031 level=WARNING
1032 handlers=hand1
1033
1034 [handler_hand1]
1035 class=StreamHandler
1036 level=NOTSET
1037 formatter=form1
1038 args=(sys.stdout,)
1039
1040 [formatter_form1]
1041 format=%(levelname)s ++ %(message)s
1042 datefmt=
1043 """
1044
1045 # config1 adds a little to the standard configuration.
1046 config1 = """
1047 [loggers]
1048 keys=root,parser
1049
1050 [handlers]
1051 keys=hand1
1052
1053 [formatters]
1054 keys=form1
1055
1056 [logger_root]
1057 level=WARNING
1058 handlers=
1059
1060 [logger_parser]
1061 level=DEBUG
1062 handlers=hand1
1063 propagate=1
1064 qualname=compiler.parser
1065
1066 [handler_hand1]
1067 class=StreamHandler
1068 level=NOTSET
1069 formatter=form1
1070 args=(sys.stdout,)
1071
1072 [formatter_form1]
1073 format=%(levelname)s ++ %(message)s
1074 datefmt=
1075 """
1076
Vinay Sajip3f84b072011-03-07 17:49:33 +00001077 # config1a moves the handler to the root.
1078 config1a = """
1079 [loggers]
1080 keys=root,parser
1081
1082 [handlers]
1083 keys=hand1
1084
1085 [formatters]
1086 keys=form1
1087
1088 [logger_root]
1089 level=WARNING
1090 handlers=hand1
1091
1092 [logger_parser]
1093 level=DEBUG
1094 handlers=
1095 propagate=1
1096 qualname=compiler.parser
1097
1098 [handler_hand1]
1099 class=StreamHandler
1100 level=NOTSET
1101 formatter=form1
1102 args=(sys.stdout,)
1103
1104 [formatter_form1]
1105 format=%(levelname)s ++ %(message)s
1106 datefmt=
1107 """
1108
Christian Heimes180510d2008-03-03 19:15:45 +00001109 # config2 has a subtle configuration error that should be reported
1110 config2 = config1.replace("sys.stdout", "sys.stbout")
1111
1112 # config3 has a less subtle configuration error
1113 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1114
1115 # config4 specifies a custom formatter class to be loaded
1116 config4 = """
1117 [loggers]
1118 keys=root
1119
1120 [handlers]
1121 keys=hand1
1122
1123 [formatters]
1124 keys=form1
1125
1126 [logger_root]
1127 level=NOTSET
1128 handlers=hand1
1129
1130 [handler_hand1]
1131 class=StreamHandler
1132 level=NOTSET
1133 formatter=form1
1134 args=(sys.stdout,)
1135
1136 [formatter_form1]
1137 class=""" + __name__ + """.ExceptionFormatter
1138 format=%(levelname)s:%(name)s:%(message)s
1139 datefmt=
1140 """
1141
Georg Brandl3dbca812008-07-23 16:10:53 +00001142 # config5 specifies a custom handler class to be loaded
1143 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1144
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001145 # config6 uses ', ' delimiters in the handlers and formatters sections
1146 config6 = """
1147 [loggers]
1148 keys=root,parser
1149
1150 [handlers]
1151 keys=hand1, hand2
1152
1153 [formatters]
1154 keys=form1, form2
1155
1156 [logger_root]
1157 level=WARNING
1158 handlers=
1159
1160 [logger_parser]
1161 level=DEBUG
1162 handlers=hand1
1163 propagate=1
1164 qualname=compiler.parser
1165
1166 [handler_hand1]
1167 class=StreamHandler
1168 level=NOTSET
1169 formatter=form1
1170 args=(sys.stdout,)
1171
1172 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001173 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001174 level=NOTSET
1175 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001176 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001177
1178 [formatter_form1]
1179 format=%(levelname)s ++ %(message)s
1180 datefmt=
1181
1182 [formatter_form2]
1183 format=%(message)s
1184 datefmt=
1185 """
1186
Vinay Sajip3f84b072011-03-07 17:49:33 +00001187 # config7 adds a compiler logger.
1188 config7 = """
1189 [loggers]
1190 keys=root,parser,compiler
1191
1192 [handlers]
1193 keys=hand1
1194
1195 [formatters]
1196 keys=form1
1197
1198 [logger_root]
1199 level=WARNING
1200 handlers=hand1
1201
1202 [logger_compiler]
1203 level=DEBUG
1204 handlers=
1205 propagate=1
1206 qualname=compiler
1207
1208 [logger_parser]
1209 level=DEBUG
1210 handlers=
1211 propagate=1
1212 qualname=compiler.parser
1213
1214 [handler_hand1]
1215 class=StreamHandler
1216 level=NOTSET
1217 formatter=form1
1218 args=(sys.stdout,)
1219
1220 [formatter_form1]
1221 format=%(levelname)s ++ %(message)s
1222 datefmt=
1223 """
1224
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001225 disable_test = """
1226 [loggers]
1227 keys=root
1228
1229 [handlers]
1230 keys=screen
1231
1232 [formatters]
1233 keys=
1234
1235 [logger_root]
1236 level=DEBUG
1237 handlers=screen
1238
1239 [handler_screen]
1240 level=DEBUG
1241 class=StreamHandler
1242 args=(sys.stdout,)
1243 formatter=
1244 """
1245
1246 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001247 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001248 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001249
1250 def test_config0_ok(self):
1251 # A simple config file which overrides the default settings.
1252 with captured_stdout() as output:
1253 self.apply_config(self.config0)
1254 logger = logging.getLogger()
1255 # Won't output anything
1256 logger.info(self.next_message())
1257 # Outputs a message
1258 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001259 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001260 ('ERROR', '2'),
1261 ], stream=output)
1262 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001263 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001264
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001265 def test_config0_using_cp_ok(self):
1266 # A simple config file which overrides the default settings.
1267 with captured_stdout() as output:
1268 file = io.StringIO(textwrap.dedent(self.config0))
1269 cp = configparser.ConfigParser()
1270 cp.read_file(file)
1271 logging.config.fileConfig(cp)
1272 logger = logging.getLogger()
1273 # Won't output anything
1274 logger.info(self.next_message())
1275 # Outputs a message
1276 logger.error(self.next_message())
1277 self.assert_log_lines([
1278 ('ERROR', '2'),
1279 ], stream=output)
1280 # Original logger output is empty.
1281 self.assert_log_lines([])
1282
Georg Brandl3dbca812008-07-23 16:10:53 +00001283 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001284 # A config file defining a sub-parser as well.
1285 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001286 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001287 logger = logging.getLogger("compiler.parser")
1288 # Both will output a message
1289 logger.info(self.next_message())
1290 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001291 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001292 ('INFO', '1'),
1293 ('ERROR', '2'),
1294 ], stream=output)
1295 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001296 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001297
1298 def test_config2_failure(self):
1299 # A simple config file which overrides the default settings.
1300 self.assertRaises(Exception, self.apply_config, self.config2)
1301
1302 def test_config3_failure(self):
1303 # A simple config file which overrides the default settings.
1304 self.assertRaises(Exception, self.apply_config, self.config3)
1305
1306 def test_config4_ok(self):
1307 # A config file specifying a custom formatter class.
1308 with captured_stdout() as output:
1309 self.apply_config(self.config4)
1310 logger = logging.getLogger()
1311 try:
1312 raise RuntimeError()
1313 except RuntimeError:
1314 logging.exception("just testing")
1315 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001316 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001317 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1318 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001319 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001320
Georg Brandl3dbca812008-07-23 16:10:53 +00001321 def test_config5_ok(self):
1322 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001323
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001324 def test_config6_ok(self):
1325 self.test_config1_ok(config=self.config6)
1326
Vinay Sajip3f84b072011-03-07 17:49:33 +00001327 def test_config7_ok(self):
1328 with captured_stdout() as output:
1329 self.apply_config(self.config1a)
1330 logger = logging.getLogger("compiler.parser")
1331 # See issue #11424. compiler-hyphenated sorts
1332 # between compiler and compiler.xyz and this
1333 # was preventing compiler.xyz from being included
1334 # in the child loggers of compiler because of an
1335 # overzealous loop termination condition.
1336 hyphenated = logging.getLogger('compiler-hyphenated')
1337 # All will output a message
1338 logger.info(self.next_message())
1339 logger.error(self.next_message())
1340 hyphenated.critical(self.next_message())
1341 self.assert_log_lines([
1342 ('INFO', '1'),
1343 ('ERROR', '2'),
1344 ('CRITICAL', '3'),
1345 ], stream=output)
1346 # Original logger output is empty.
1347 self.assert_log_lines([])
1348 with captured_stdout() as output:
1349 self.apply_config(self.config7)
1350 logger = logging.getLogger("compiler.parser")
1351 self.assertFalse(logger.disabled)
1352 # Both will output a message
1353 logger.info(self.next_message())
1354 logger.error(self.next_message())
1355 logger = logging.getLogger("compiler.lexer")
1356 # Both will output a message
1357 logger.info(self.next_message())
1358 logger.error(self.next_message())
1359 # Will not appear
1360 hyphenated.critical(self.next_message())
1361 self.assert_log_lines([
1362 ('INFO', '4'),
1363 ('ERROR', '5'),
1364 ('INFO', '6'),
1365 ('ERROR', '7'),
1366 ], stream=output)
1367 # Original logger output is empty.
1368 self.assert_log_lines([])
1369
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001370 def test_logger_disabling(self):
1371 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001372 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001373 self.assertFalse(logger.disabled)
1374 self.apply_config(self.disable_test)
1375 self.assertTrue(logger.disabled)
1376 self.apply_config(self.disable_test, disable_existing_loggers=False)
1377 self.assertFalse(logger.disabled)
1378
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001379
Victor Stinner45df8202010-04-28 22:31:17 +00001380@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001381class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001382
Christian Heimes180510d2008-03-03 19:15:45 +00001383 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001384
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001385 if threading:
1386 server_class = TestTCPServer
1387 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001388
Christian Heimes180510d2008-03-03 19:15:45 +00001389 def setUp(self):
1390 """Set up a TCP server to receive log messages, and a SocketHandler
1391 pointing to that server's address and port."""
1392 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001393 self.server = server = self.server_class(self.address,
1394 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001395 server.start()
1396 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001397 hcls = logging.handlers.SocketHandler
1398 if isinstance(server.server_address, tuple):
1399 self.sock_hdlr = hcls('localhost', server.port)
1400 else:
1401 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001402 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001403 self.root_logger.removeHandler(self.root_logger.handlers[0])
1404 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001405 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001406
Christian Heimes180510d2008-03-03 19:15:45 +00001407 def tearDown(self):
1408 """Shutdown the TCP server."""
1409 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001410 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001411 self.root_logger.removeHandler(self.sock_hdlr)
1412 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001413 finally:
1414 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001415
Vinay Sajip7367d082011-05-02 13:17:27 +01001416 def handle_socket(self, request):
1417 conn = request.connection
1418 while True:
1419 chunk = conn.recv(4)
1420 if len(chunk) < 4:
1421 break
1422 slen = struct.unpack(">L", chunk)[0]
1423 chunk = conn.recv(slen)
1424 while len(chunk) < slen:
1425 chunk = chunk + conn.recv(slen - len(chunk))
1426 obj = pickle.loads(chunk)
1427 record = logging.makeLogRecord(obj)
1428 self.log_output += record.msg + '\n'
1429 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001430
Christian Heimes180510d2008-03-03 19:15:45 +00001431 def test_output(self):
1432 # The log message sent to the SocketHandler is properly received.
1433 logger = logging.getLogger("tcp")
1434 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001435 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001436 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001437 self.handled.acquire()
1438 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001439
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001440 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001441 # Avoid timing-related failures due to SocketHandler's own hard-wired
1442 # one-second timeout on socket.create_connection() (issue #16264).
1443 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001444 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001445 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001446 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001447 try:
1448 raise RuntimeError('Deliberate mistake')
1449 except RuntimeError:
1450 self.root_logger.exception('Never sent')
1451 self.root_logger.error('Never sent, either')
1452 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001453 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001454 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1455 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001456
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001457def _get_temp_domain_socket():
1458 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1459 os.close(fd)
1460 # just need a name - file can't be present, or we'll get an
1461 # 'address already in use' error.
1462 os.remove(fn)
1463 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001464
Victor Stinnerec5a8602014-06-02 14:41:51 +02001465@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001466@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001467class UnixSocketHandlerTest(SocketHandlerTest):
1468
1469 """Test for SocketHandler with unix sockets."""
1470
Victor Stinnerec5a8602014-06-02 14:41:51 +02001471 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001472 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001473
1474 def setUp(self):
1475 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001476 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001477 SocketHandlerTest.setUp(self)
1478
1479 def tearDown(self):
1480 SocketHandlerTest.tearDown(self)
1481 os.remove(self.address)
1482
1483@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001484class DatagramHandlerTest(BaseTest):
1485
1486 """Test for DatagramHandler."""
1487
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001488 if threading:
1489 server_class = TestUDPServer
1490 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001491
Vinay Sajip7367d082011-05-02 13:17:27 +01001492 def setUp(self):
1493 """Set up a UDP server to receive log messages, and a DatagramHandler
1494 pointing to that server's address and port."""
1495 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001496 self.server = server = self.server_class(self.address,
1497 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001498 server.start()
1499 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001500 hcls = logging.handlers.DatagramHandler
1501 if isinstance(server.server_address, tuple):
1502 self.sock_hdlr = hcls('localhost', server.port)
1503 else:
1504 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001505 self.log_output = ''
1506 self.root_logger.removeHandler(self.root_logger.handlers[0])
1507 self.root_logger.addHandler(self.sock_hdlr)
1508 self.handled = threading.Event()
1509
1510 def tearDown(self):
1511 """Shutdown the UDP server."""
1512 try:
1513 self.server.stop(2.0)
1514 self.root_logger.removeHandler(self.sock_hdlr)
1515 self.sock_hdlr.close()
1516 finally:
1517 BaseTest.tearDown(self)
1518
1519 def handle_datagram(self, request):
1520 slen = struct.pack('>L', 0) # length of prefix
1521 packet = request.packet[len(slen):]
1522 obj = pickle.loads(packet)
1523 record = logging.makeLogRecord(obj)
1524 self.log_output += record.msg + '\n'
1525 self.handled.set()
1526
1527 def test_output(self):
1528 # The log message sent to the DatagramHandler is properly received.
1529 logger = logging.getLogger("udp")
1530 logger.error("spam")
1531 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001532 self.handled.clear()
1533 logger.error("eggs")
1534 self.handled.wait()
1535 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001536
Victor Stinnerec5a8602014-06-02 14:41:51 +02001537@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001538@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001539class UnixDatagramHandlerTest(DatagramHandlerTest):
1540
1541 """Test for DatagramHandler using Unix sockets."""
1542
Victor Stinnerec5a8602014-06-02 14:41:51 +02001543 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001544 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001545
1546 def setUp(self):
1547 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001548 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001549 DatagramHandlerTest.setUp(self)
1550
1551 def tearDown(self):
1552 DatagramHandlerTest.tearDown(self)
1553 os.remove(self.address)
1554
1555@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001556class SysLogHandlerTest(BaseTest):
1557
1558 """Test for SysLogHandler using UDP."""
1559
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001560 if threading:
1561 server_class = TestUDPServer
1562 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001563
Vinay Sajip7367d082011-05-02 13:17:27 +01001564 def setUp(self):
1565 """Set up a UDP server to receive log messages, and a SysLogHandler
1566 pointing to that server's address and port."""
1567 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001568 self.server = server = self.server_class(self.address,
1569 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001570 server.start()
1571 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001572 hcls = logging.handlers.SysLogHandler
1573 if isinstance(server.server_address, tuple):
1574 self.sl_hdlr = hcls(('localhost', server.port))
1575 else:
1576 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001577 self.log_output = ''
1578 self.root_logger.removeHandler(self.root_logger.handlers[0])
1579 self.root_logger.addHandler(self.sl_hdlr)
1580 self.handled = threading.Event()
1581
1582 def tearDown(self):
1583 """Shutdown the UDP server."""
1584 try:
1585 self.server.stop(2.0)
1586 self.root_logger.removeHandler(self.sl_hdlr)
1587 self.sl_hdlr.close()
1588 finally:
1589 BaseTest.tearDown(self)
1590
1591 def handle_datagram(self, request):
1592 self.log_output = request.packet
1593 self.handled.set()
1594
1595 def test_output(self):
1596 # The log message sent to the SysLogHandler is properly received.
1597 logger = logging.getLogger("slh")
1598 logger.error("sp\xe4m")
1599 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001600 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001601 self.handled.clear()
1602 self.sl_hdlr.append_nul = False
1603 logger.error("sp\xe4m")
1604 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001605 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001606 self.handled.clear()
1607 self.sl_hdlr.ident = "h\xe4m-"
1608 logger.error("sp\xe4m")
1609 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001610 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001611
Victor Stinnerec5a8602014-06-02 14:41:51 +02001612@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001613@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001614class UnixSysLogHandlerTest(SysLogHandlerTest):
1615
1616 """Test for SysLogHandler with Unix sockets."""
1617
Victor Stinnerec5a8602014-06-02 14:41:51 +02001618 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001619 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001620
1621 def setUp(self):
1622 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001623 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001624 SysLogHandlerTest.setUp(self)
1625
1626 def tearDown(self):
1627 SysLogHandlerTest.tearDown(self)
1628 os.remove(self.address)
1629
Vinay Sajip5421f352013-09-27 18:18:28 +01001630@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001631class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001632 """Test for HTTPHandler."""
1633
1634 def setUp(self):
1635 """Set up an HTTP server to receive log messages, and a HTTPHandler
1636 pointing to that server's address and port."""
1637 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001638 self.handled = threading.Event()
1639
Vinay Sajip7367d082011-05-02 13:17:27 +01001640 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001641 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001642 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001643 if self.command == 'POST':
1644 try:
1645 rlen = int(request.headers['Content-Length'])
1646 self.post_data = request.rfile.read(rlen)
1647 except:
1648 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001649 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001650 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001651 self.handled.set()
1652
1653 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001654 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001655 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001656 root_logger = self.root_logger
1657 root_logger.removeHandler(self.root_logger.handlers[0])
1658 for secure in (False, True):
1659 addr = ('localhost', 0)
1660 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001661 try:
1662 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001663 except ImportError:
1664 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001665 else:
1666 here = os.path.dirname(__file__)
1667 localhost_cert = os.path.join(here, "keycert.pem")
1668 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1669 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001670
1671 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001672 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001673 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001674 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001675 self.server = server = TestHTTPServer(addr, self.handle_request,
1676 0.01, sslctx=sslctx)
1677 server.start()
1678 server.ready.wait()
1679 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001680 secure_client = secure and sslctx
1681 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001682 secure=secure_client,
1683 context=context)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001684 self.log_data = None
1685 root_logger.addHandler(self.h_hdlr)
1686
1687 for method in ('GET', 'POST'):
1688 self.h_hdlr.method = method
1689 self.handled.clear()
1690 msg = "sp\xe4m"
1691 logger.error(msg)
1692 self.handled.wait()
1693 self.assertEqual(self.log_data.path, '/frob')
1694 self.assertEqual(self.command, method)
1695 if method == 'GET':
1696 d = parse_qs(self.log_data.query)
1697 else:
1698 d = parse_qs(self.post_data.decode('utf-8'))
1699 self.assertEqual(d['name'], ['http'])
1700 self.assertEqual(d['funcName'], ['test_output'])
1701 self.assertEqual(d['msg'], [msg])
1702
1703 self.server.stop(2.0)
1704 self.root_logger.removeHandler(self.h_hdlr)
1705 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001706
Christian Heimes180510d2008-03-03 19:15:45 +00001707class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001708
Christian Heimes180510d2008-03-03 19:15:45 +00001709 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001710
Christian Heimes180510d2008-03-03 19:15:45 +00001711 def setUp(self):
1712 """Create a dict to remember potentially destroyed objects."""
1713 BaseTest.setUp(self)
1714 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001715
Christian Heimes180510d2008-03-03 19:15:45 +00001716 def _watch_for_survival(self, *args):
1717 """Watch the given objects for survival, by creating weakrefs to
1718 them."""
1719 for obj in args:
1720 key = id(obj), repr(obj)
1721 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001722
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001723 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001724 """Assert that all objects watched for survival have survived."""
1725 # Trigger cycle breaking.
1726 gc.collect()
1727 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001728 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001729 if ref() is None:
1730 dead.append(repr_)
1731 if dead:
1732 self.fail("%d objects should have survived "
1733 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001734
Christian Heimes180510d2008-03-03 19:15:45 +00001735 def test_persistent_loggers(self):
1736 # Logger objects are persistent and retain their configuration, even
1737 # if visible references are destroyed.
1738 self.root_logger.setLevel(logging.INFO)
1739 foo = logging.getLogger("foo")
1740 self._watch_for_survival(foo)
1741 foo.setLevel(logging.DEBUG)
1742 self.root_logger.debug(self.next_message())
1743 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001744 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001745 ('foo', 'DEBUG', '2'),
1746 ])
1747 del foo
1748 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001749 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001750 # foo has retained its settings.
1751 bar = logging.getLogger("foo")
1752 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001753 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001754 ('foo', 'DEBUG', '2'),
1755 ('foo', 'DEBUG', '3'),
1756 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001757
Benjamin Petersonf91df042009-02-13 02:50:59 +00001758
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001759class EncodingTest(BaseTest):
1760 def test_encoding_plain_file(self):
1761 # In Python 2.x, a plain file object is treated as having no encoding.
1762 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001763 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1764 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001765 # the non-ascii data we write to the log.
1766 data = "foo\x80"
1767 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001768 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001769 log.addHandler(handler)
1770 try:
1771 # write non-ascii data to the log.
1772 log.warning(data)
1773 finally:
1774 log.removeHandler(handler)
1775 handler.close()
1776 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001777 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001778 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001779 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001780 finally:
1781 f.close()
1782 finally:
1783 if os.path.isfile(fn):
1784 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001785
Benjamin Petersonf91df042009-02-13 02:50:59 +00001786 def test_encoding_cyrillic_unicode(self):
1787 log = logging.getLogger("test")
1788 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1789 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1790 #Ensure it's written in a Cyrillic encoding
1791 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001792 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001793 stream = io.BytesIO()
1794 writer = writer_class(stream, 'strict')
1795 handler = logging.StreamHandler(writer)
1796 log.addHandler(handler)
1797 try:
1798 log.warning(message)
1799 finally:
1800 log.removeHandler(handler)
1801 handler.close()
1802 # check we wrote exactly those bytes, ignoring trailing \n etc
1803 s = stream.getvalue()
1804 #Compare against what the data should be when encoded in CP-1251
1805 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1806
1807
Georg Brandlf9734072008-12-07 15:30:06 +00001808class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001809
Georg Brandlf9734072008-12-07 15:30:06 +00001810 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001811 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001812 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001813 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001814 warnings.filterwarnings("always", category=UserWarning)
1815 stream = io.StringIO()
1816 h = logging.StreamHandler(stream)
1817 logger = logging.getLogger("py.warnings")
1818 logger.addHandler(h)
1819 warnings.warn("I'm warning you...")
1820 logger.removeHandler(h)
1821 s = stream.getvalue()
1822 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001823 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001824
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001825 #See if an explicit file uses the original implementation
1826 a_file = io.StringIO()
1827 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1828 a_file, "Dummy line")
1829 s = a_file.getvalue()
1830 a_file.close()
1831 self.assertEqual(s,
1832 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1833
1834 def test_warnings_no_handlers(self):
1835 with warnings.catch_warnings():
1836 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838
1839 # confirm our assumption: no loggers are set
1840 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001841 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001842
1843 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001844 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001845 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001846
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001847
1848def formatFunc(format, datefmt=None):
1849 return logging.Formatter(format, datefmt)
1850
1851def handlerFunc():
1852 return logging.StreamHandler()
1853
1854class CustomHandler(logging.StreamHandler):
1855 pass
1856
1857class ConfigDictTest(BaseTest):
1858
1859 """Reading logging config from a dictionary."""
1860
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001861 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001862
1863 # config0 is a standard configuration.
1864 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001865 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001866 'formatters': {
1867 'form1' : {
1868 'format' : '%(levelname)s ++ %(message)s',
1869 },
1870 },
1871 'handlers' : {
1872 'hand1' : {
1873 'class' : 'logging.StreamHandler',
1874 'formatter' : 'form1',
1875 'level' : 'NOTSET',
1876 'stream' : 'ext://sys.stdout',
1877 },
1878 },
1879 'root' : {
1880 'level' : 'WARNING',
1881 'handlers' : ['hand1'],
1882 },
1883 }
1884
1885 # config1 adds a little to the standard configuration.
1886 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001887 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001888 'formatters': {
1889 'form1' : {
1890 'format' : '%(levelname)s ++ %(message)s',
1891 },
1892 },
1893 'handlers' : {
1894 'hand1' : {
1895 'class' : 'logging.StreamHandler',
1896 'formatter' : 'form1',
1897 'level' : 'NOTSET',
1898 'stream' : 'ext://sys.stdout',
1899 },
1900 },
1901 'loggers' : {
1902 'compiler.parser' : {
1903 'level' : 'DEBUG',
1904 'handlers' : ['hand1'],
1905 },
1906 },
1907 'root' : {
1908 'level' : 'WARNING',
1909 },
1910 }
1911
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001912 # config1a moves the handler to the root. Used with config8a
1913 config1a = {
1914 'version': 1,
1915 'formatters': {
1916 'form1' : {
1917 'format' : '%(levelname)s ++ %(message)s',
1918 },
1919 },
1920 'handlers' : {
1921 'hand1' : {
1922 'class' : 'logging.StreamHandler',
1923 'formatter' : 'form1',
1924 'level' : 'NOTSET',
1925 'stream' : 'ext://sys.stdout',
1926 },
1927 },
1928 'loggers' : {
1929 'compiler.parser' : {
1930 'level' : 'DEBUG',
1931 },
1932 },
1933 'root' : {
1934 'level' : 'WARNING',
1935 'handlers' : ['hand1'],
1936 },
1937 }
1938
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001939 # config2 has a subtle configuration error that should be reported
1940 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001941 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001942 'formatters': {
1943 'form1' : {
1944 'format' : '%(levelname)s ++ %(message)s',
1945 },
1946 },
1947 'handlers' : {
1948 'hand1' : {
1949 'class' : 'logging.StreamHandler',
1950 'formatter' : 'form1',
1951 'level' : 'NOTSET',
1952 'stream' : 'ext://sys.stdbout',
1953 },
1954 },
1955 'loggers' : {
1956 'compiler.parser' : {
1957 'level' : 'DEBUG',
1958 'handlers' : ['hand1'],
1959 },
1960 },
1961 'root' : {
1962 'level' : 'WARNING',
1963 },
1964 }
1965
1966 #As config1 but with a misspelt level on a handler
1967 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001968 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001969 'formatters': {
1970 'form1' : {
1971 'format' : '%(levelname)s ++ %(message)s',
1972 },
1973 },
1974 'handlers' : {
1975 'hand1' : {
1976 'class' : 'logging.StreamHandler',
1977 'formatter' : 'form1',
1978 'level' : 'NTOSET',
1979 'stream' : 'ext://sys.stdout',
1980 },
1981 },
1982 'loggers' : {
1983 'compiler.parser' : {
1984 'level' : 'DEBUG',
1985 'handlers' : ['hand1'],
1986 },
1987 },
1988 'root' : {
1989 'level' : 'WARNING',
1990 },
1991 }
1992
1993
1994 #As config1 but with a misspelt level on a logger
1995 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001996 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001997 'formatters': {
1998 'form1' : {
1999 'format' : '%(levelname)s ++ %(message)s',
2000 },
2001 },
2002 'handlers' : {
2003 'hand1' : {
2004 'class' : 'logging.StreamHandler',
2005 'formatter' : 'form1',
2006 'level' : 'NOTSET',
2007 'stream' : 'ext://sys.stdout',
2008 },
2009 },
2010 'loggers' : {
2011 'compiler.parser' : {
2012 'level' : 'DEBUG',
2013 'handlers' : ['hand1'],
2014 },
2015 },
2016 'root' : {
2017 'level' : 'WRANING',
2018 },
2019 }
2020
2021 # config3 has a less subtle configuration error
2022 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002023 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002024 'formatters': {
2025 'form1' : {
2026 'format' : '%(levelname)s ++ %(message)s',
2027 },
2028 },
2029 'handlers' : {
2030 'hand1' : {
2031 'class' : 'logging.StreamHandler',
2032 'formatter' : 'misspelled_name',
2033 'level' : 'NOTSET',
2034 'stream' : 'ext://sys.stdout',
2035 },
2036 },
2037 'loggers' : {
2038 'compiler.parser' : {
2039 'level' : 'DEBUG',
2040 'handlers' : ['hand1'],
2041 },
2042 },
2043 'root' : {
2044 'level' : 'WARNING',
2045 },
2046 }
2047
2048 # config4 specifies a custom formatter class to be loaded
2049 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002050 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002051 'formatters': {
2052 'form1' : {
2053 '()' : __name__ + '.ExceptionFormatter',
2054 'format' : '%(levelname)s:%(name)s:%(message)s',
2055 },
2056 },
2057 'handlers' : {
2058 'hand1' : {
2059 'class' : 'logging.StreamHandler',
2060 'formatter' : 'form1',
2061 'level' : 'NOTSET',
2062 'stream' : 'ext://sys.stdout',
2063 },
2064 },
2065 'root' : {
2066 'level' : 'NOTSET',
2067 'handlers' : ['hand1'],
2068 },
2069 }
2070
2071 # As config4 but using an actual callable rather than a string
2072 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002073 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002074 'formatters': {
2075 'form1' : {
2076 '()' : ExceptionFormatter,
2077 'format' : '%(levelname)s:%(name)s:%(message)s',
2078 },
2079 'form2' : {
2080 '()' : __name__ + '.formatFunc',
2081 'format' : '%(levelname)s:%(name)s:%(message)s',
2082 },
2083 'form3' : {
2084 '()' : formatFunc,
2085 'format' : '%(levelname)s:%(name)s:%(message)s',
2086 },
2087 },
2088 'handlers' : {
2089 'hand1' : {
2090 'class' : 'logging.StreamHandler',
2091 'formatter' : 'form1',
2092 'level' : 'NOTSET',
2093 'stream' : 'ext://sys.stdout',
2094 },
2095 'hand2' : {
2096 '()' : handlerFunc,
2097 },
2098 },
2099 'root' : {
2100 'level' : 'NOTSET',
2101 'handlers' : ['hand1'],
2102 },
2103 }
2104
2105 # config5 specifies a custom handler class to be loaded
2106 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002107 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002108 'formatters': {
2109 'form1' : {
2110 'format' : '%(levelname)s ++ %(message)s',
2111 },
2112 },
2113 'handlers' : {
2114 'hand1' : {
2115 'class' : __name__ + '.CustomHandler',
2116 'formatter' : 'form1',
2117 'level' : 'NOTSET',
2118 'stream' : 'ext://sys.stdout',
2119 },
2120 },
2121 'loggers' : {
2122 'compiler.parser' : {
2123 'level' : 'DEBUG',
2124 'handlers' : ['hand1'],
2125 },
2126 },
2127 'root' : {
2128 'level' : 'WARNING',
2129 },
2130 }
2131
2132 # config6 specifies a custom handler class to be loaded
2133 # but has bad arguments
2134 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002135 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002136 'formatters': {
2137 'form1' : {
2138 'format' : '%(levelname)s ++ %(message)s',
2139 },
2140 },
2141 'handlers' : {
2142 'hand1' : {
2143 'class' : __name__ + '.CustomHandler',
2144 'formatter' : 'form1',
2145 'level' : 'NOTSET',
2146 'stream' : 'ext://sys.stdout',
2147 '9' : 'invalid parameter name',
2148 },
2149 },
2150 'loggers' : {
2151 'compiler.parser' : {
2152 'level' : 'DEBUG',
2153 'handlers' : ['hand1'],
2154 },
2155 },
2156 'root' : {
2157 'level' : 'WARNING',
2158 },
2159 }
2160
2161 #config 7 does not define compiler.parser but defines compiler.lexer
2162 #so compiler.parser should be disabled after applying it
2163 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002164 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002165 'formatters': {
2166 'form1' : {
2167 'format' : '%(levelname)s ++ %(message)s',
2168 },
2169 },
2170 'handlers' : {
2171 'hand1' : {
2172 'class' : 'logging.StreamHandler',
2173 'formatter' : 'form1',
2174 'level' : 'NOTSET',
2175 'stream' : 'ext://sys.stdout',
2176 },
2177 },
2178 'loggers' : {
2179 'compiler.lexer' : {
2180 'level' : 'DEBUG',
2181 'handlers' : ['hand1'],
2182 },
2183 },
2184 'root' : {
2185 'level' : 'WARNING',
2186 },
2187 }
2188
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002189 # config8 defines both compiler and compiler.lexer
2190 # so compiler.parser should not be disabled (since
2191 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002192 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002193 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002194 'disable_existing_loggers' : False,
2195 'formatters': {
2196 'form1' : {
2197 'format' : '%(levelname)s ++ %(message)s',
2198 },
2199 },
2200 'handlers' : {
2201 'hand1' : {
2202 'class' : 'logging.StreamHandler',
2203 'formatter' : 'form1',
2204 'level' : 'NOTSET',
2205 'stream' : 'ext://sys.stdout',
2206 },
2207 },
2208 'loggers' : {
2209 'compiler' : {
2210 'level' : 'DEBUG',
2211 'handlers' : ['hand1'],
2212 },
2213 'compiler.lexer' : {
2214 },
2215 },
2216 'root' : {
2217 'level' : 'WARNING',
2218 },
2219 }
2220
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002221 # config8a disables existing loggers
2222 config8a = {
2223 'version': 1,
2224 'disable_existing_loggers' : True,
2225 'formatters': {
2226 'form1' : {
2227 'format' : '%(levelname)s ++ %(message)s',
2228 },
2229 },
2230 'handlers' : {
2231 'hand1' : {
2232 'class' : 'logging.StreamHandler',
2233 'formatter' : 'form1',
2234 'level' : 'NOTSET',
2235 'stream' : 'ext://sys.stdout',
2236 },
2237 },
2238 'loggers' : {
2239 'compiler' : {
2240 'level' : 'DEBUG',
2241 'handlers' : ['hand1'],
2242 },
2243 'compiler.lexer' : {
2244 },
2245 },
2246 'root' : {
2247 'level' : 'WARNING',
2248 },
2249 }
2250
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002251 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002252 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002253 'formatters': {
2254 'form1' : {
2255 'format' : '%(levelname)s ++ %(message)s',
2256 },
2257 },
2258 'handlers' : {
2259 'hand1' : {
2260 'class' : 'logging.StreamHandler',
2261 'formatter' : 'form1',
2262 'level' : 'WARNING',
2263 'stream' : 'ext://sys.stdout',
2264 },
2265 },
2266 'loggers' : {
2267 'compiler.parser' : {
2268 'level' : 'WARNING',
2269 'handlers' : ['hand1'],
2270 },
2271 },
2272 'root' : {
2273 'level' : 'NOTSET',
2274 },
2275 }
2276
2277 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002278 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002279 'incremental' : True,
2280 'handlers' : {
2281 'hand1' : {
2282 'level' : 'WARNING',
2283 },
2284 },
2285 'loggers' : {
2286 'compiler.parser' : {
2287 'level' : 'INFO',
2288 },
2289 },
2290 }
2291
2292 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002293 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002294 'incremental' : True,
2295 'handlers' : {
2296 'hand1' : {
2297 'level' : 'INFO',
2298 },
2299 },
2300 'loggers' : {
2301 'compiler.parser' : {
2302 'level' : 'INFO',
2303 },
2304 },
2305 }
2306
2307 #As config1 but with a filter added
2308 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002309 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002310 'formatters': {
2311 'form1' : {
2312 'format' : '%(levelname)s ++ %(message)s',
2313 },
2314 },
2315 'filters' : {
2316 'filt1' : {
2317 'name' : 'compiler.parser',
2318 },
2319 },
2320 'handlers' : {
2321 'hand1' : {
2322 'class' : 'logging.StreamHandler',
2323 'formatter' : 'form1',
2324 'level' : 'NOTSET',
2325 'stream' : 'ext://sys.stdout',
2326 'filters' : ['filt1'],
2327 },
2328 },
2329 'loggers' : {
2330 'compiler.parser' : {
2331 'level' : 'DEBUG',
2332 'filters' : ['filt1'],
2333 },
2334 },
2335 'root' : {
2336 'level' : 'WARNING',
2337 'handlers' : ['hand1'],
2338 },
2339 }
2340
2341 #As config1 but using cfg:// references
2342 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002343 'version': 1,
2344 'true_formatters': {
2345 'form1' : {
2346 'format' : '%(levelname)s ++ %(message)s',
2347 },
2348 },
2349 'handler_configs': {
2350 'hand1' : {
2351 'class' : 'logging.StreamHandler',
2352 'formatter' : 'form1',
2353 'level' : 'NOTSET',
2354 'stream' : 'ext://sys.stdout',
2355 },
2356 },
2357 'formatters' : 'cfg://true_formatters',
2358 'handlers' : {
2359 'hand1' : 'cfg://handler_configs[hand1]',
2360 },
2361 'loggers' : {
2362 'compiler.parser' : {
2363 'level' : 'DEBUG',
2364 'handlers' : ['hand1'],
2365 },
2366 },
2367 'root' : {
2368 'level' : 'WARNING',
2369 },
2370 }
2371
2372 #As config11 but missing the version key
2373 config12 = {
2374 'true_formatters': {
2375 'form1' : {
2376 'format' : '%(levelname)s ++ %(message)s',
2377 },
2378 },
2379 'handler_configs': {
2380 'hand1' : {
2381 'class' : 'logging.StreamHandler',
2382 'formatter' : 'form1',
2383 'level' : 'NOTSET',
2384 'stream' : 'ext://sys.stdout',
2385 },
2386 },
2387 'formatters' : 'cfg://true_formatters',
2388 'handlers' : {
2389 'hand1' : 'cfg://handler_configs[hand1]',
2390 },
2391 'loggers' : {
2392 'compiler.parser' : {
2393 'level' : 'DEBUG',
2394 'handlers' : ['hand1'],
2395 },
2396 },
2397 'root' : {
2398 'level' : 'WARNING',
2399 },
2400 }
2401
2402 #As config11 but using an unsupported version
2403 config13 = {
2404 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002405 'true_formatters': {
2406 'form1' : {
2407 'format' : '%(levelname)s ++ %(message)s',
2408 },
2409 },
2410 'handler_configs': {
2411 'hand1' : {
2412 'class' : 'logging.StreamHandler',
2413 'formatter' : 'form1',
2414 'level' : 'NOTSET',
2415 'stream' : 'ext://sys.stdout',
2416 },
2417 },
2418 'formatters' : 'cfg://true_formatters',
2419 'handlers' : {
2420 'hand1' : 'cfg://handler_configs[hand1]',
2421 },
2422 'loggers' : {
2423 'compiler.parser' : {
2424 'level' : 'DEBUG',
2425 'handlers' : ['hand1'],
2426 },
2427 },
2428 'root' : {
2429 'level' : 'WARNING',
2430 },
2431 }
2432
Vinay Sajip8d270232012-11-15 14:20:18 +00002433 # As config0, but with properties
2434 config14 = {
2435 'version': 1,
2436 'formatters': {
2437 'form1' : {
2438 'format' : '%(levelname)s ++ %(message)s',
2439 },
2440 },
2441 'handlers' : {
2442 'hand1' : {
2443 'class' : 'logging.StreamHandler',
2444 'formatter' : 'form1',
2445 'level' : 'NOTSET',
2446 'stream' : 'ext://sys.stdout',
2447 '.': {
2448 'foo': 'bar',
2449 'terminator': '!\n',
2450 }
2451 },
2452 },
2453 'root' : {
2454 'level' : 'WARNING',
2455 'handlers' : ['hand1'],
2456 },
2457 }
2458
Vinay Sajip3f885b52013-03-22 15:19:54 +00002459 out_of_order = {
2460 "version": 1,
2461 "formatters": {
2462 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002463 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2464 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002465 }
2466 },
2467 "handlers": {
2468 "fileGlobal": {
2469 "class": "logging.StreamHandler",
2470 "level": "DEBUG",
2471 "formatter": "mySimpleFormatter"
2472 },
2473 "bufferGlobal": {
2474 "class": "logging.handlers.MemoryHandler",
2475 "capacity": 5,
2476 "formatter": "mySimpleFormatter",
2477 "target": "fileGlobal",
2478 "level": "DEBUG"
2479 }
2480 },
2481 "loggers": {
2482 "mymodule": {
2483 "level": "DEBUG",
2484 "handlers": ["bufferGlobal"],
2485 "propagate": "true"
2486 }
2487 }
2488 }
2489
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002490 def apply_config(self, conf):
2491 logging.config.dictConfig(conf)
2492
2493 def test_config0_ok(self):
2494 # A simple config which overrides the default settings.
2495 with captured_stdout() as output:
2496 self.apply_config(self.config0)
2497 logger = logging.getLogger()
2498 # Won't output anything
2499 logger.info(self.next_message())
2500 # Outputs a message
2501 logger.error(self.next_message())
2502 self.assert_log_lines([
2503 ('ERROR', '2'),
2504 ], stream=output)
2505 # Original logger output is empty.
2506 self.assert_log_lines([])
2507
2508 def test_config1_ok(self, config=config1):
2509 # A config defining a sub-parser as well.
2510 with captured_stdout() as output:
2511 self.apply_config(config)
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
2523 def test_config2_failure(self):
2524 # A simple config which overrides the default settings.
2525 self.assertRaises(Exception, self.apply_config, self.config2)
2526
2527 def test_config2a_failure(self):
2528 # A simple config which overrides the default settings.
2529 self.assertRaises(Exception, self.apply_config, self.config2a)
2530
2531 def test_config2b_failure(self):
2532 # A simple config which overrides the default settings.
2533 self.assertRaises(Exception, self.apply_config, self.config2b)
2534
2535 def test_config3_failure(self):
2536 # A simple config which overrides the default settings.
2537 self.assertRaises(Exception, self.apply_config, self.config3)
2538
2539 def test_config4_ok(self):
2540 # A config specifying a custom formatter class.
2541 with captured_stdout() as output:
2542 self.apply_config(self.config4)
2543 #logger = logging.getLogger()
2544 try:
2545 raise RuntimeError()
2546 except RuntimeError:
2547 logging.exception("just testing")
2548 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002549 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002550 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2551 # Original logger output is empty
2552 self.assert_log_lines([])
2553
2554 def test_config4a_ok(self):
2555 # A config specifying a custom formatter class.
2556 with captured_stdout() as output:
2557 self.apply_config(self.config4a)
2558 #logger = logging.getLogger()
2559 try:
2560 raise RuntimeError()
2561 except RuntimeError:
2562 logging.exception("just testing")
2563 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002564 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002565 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2566 # Original logger output is empty
2567 self.assert_log_lines([])
2568
2569 def test_config5_ok(self):
2570 self.test_config1_ok(config=self.config5)
2571
2572 def test_config6_failure(self):
2573 self.assertRaises(Exception, self.apply_config, self.config6)
2574
2575 def test_config7_ok(self):
2576 with captured_stdout() as output:
2577 self.apply_config(self.config1)
2578 logger = logging.getLogger("compiler.parser")
2579 # Both will output a message
2580 logger.info(self.next_message())
2581 logger.error(self.next_message())
2582 self.assert_log_lines([
2583 ('INFO', '1'),
2584 ('ERROR', '2'),
2585 ], stream=output)
2586 # Original logger output is empty.
2587 self.assert_log_lines([])
2588 with captured_stdout() as output:
2589 self.apply_config(self.config7)
2590 logger = logging.getLogger("compiler.parser")
2591 self.assertTrue(logger.disabled)
2592 logger = logging.getLogger("compiler.lexer")
2593 # Both will output a message
2594 logger.info(self.next_message())
2595 logger.error(self.next_message())
2596 self.assert_log_lines([
2597 ('INFO', '3'),
2598 ('ERROR', '4'),
2599 ], stream=output)
2600 # Original logger output is empty.
2601 self.assert_log_lines([])
2602
2603 #Same as test_config_7_ok but don't disable old loggers.
2604 def test_config_8_ok(self):
2605 with captured_stdout() as output:
2606 self.apply_config(self.config1)
2607 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002608 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002609 logger.info(self.next_message())
2610 logger.error(self.next_message())
2611 self.assert_log_lines([
2612 ('INFO', '1'),
2613 ('ERROR', '2'),
2614 ], stream=output)
2615 # Original logger output is empty.
2616 self.assert_log_lines([])
2617 with captured_stdout() as output:
2618 self.apply_config(self.config8)
2619 logger = logging.getLogger("compiler.parser")
2620 self.assertFalse(logger.disabled)
2621 # Both will output a message
2622 logger.info(self.next_message())
2623 logger.error(self.next_message())
2624 logger = logging.getLogger("compiler.lexer")
2625 # Both will output a message
2626 logger.info(self.next_message())
2627 logger.error(self.next_message())
2628 self.assert_log_lines([
2629 ('INFO', '3'),
2630 ('ERROR', '4'),
2631 ('INFO', '5'),
2632 ('ERROR', '6'),
2633 ], stream=output)
2634 # Original logger output is empty.
2635 self.assert_log_lines([])
2636
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002637 def test_config_8a_ok(self):
2638 with captured_stdout() as output:
2639 self.apply_config(self.config1a)
2640 logger = logging.getLogger("compiler.parser")
2641 # See issue #11424. compiler-hyphenated sorts
2642 # between compiler and compiler.xyz and this
2643 # was preventing compiler.xyz from being included
2644 # in the child loggers of compiler because of an
2645 # overzealous loop termination condition.
2646 hyphenated = logging.getLogger('compiler-hyphenated')
2647 # All will output a message
2648 logger.info(self.next_message())
2649 logger.error(self.next_message())
2650 hyphenated.critical(self.next_message())
2651 self.assert_log_lines([
2652 ('INFO', '1'),
2653 ('ERROR', '2'),
2654 ('CRITICAL', '3'),
2655 ], stream=output)
2656 # Original logger output is empty.
2657 self.assert_log_lines([])
2658 with captured_stdout() as output:
2659 self.apply_config(self.config8a)
2660 logger = logging.getLogger("compiler.parser")
2661 self.assertFalse(logger.disabled)
2662 # Both will output a message
2663 logger.info(self.next_message())
2664 logger.error(self.next_message())
2665 logger = logging.getLogger("compiler.lexer")
2666 # Both will output a message
2667 logger.info(self.next_message())
2668 logger.error(self.next_message())
2669 # Will not appear
2670 hyphenated.critical(self.next_message())
2671 self.assert_log_lines([
2672 ('INFO', '4'),
2673 ('ERROR', '5'),
2674 ('INFO', '6'),
2675 ('ERROR', '7'),
2676 ], stream=output)
2677 # Original logger output is empty.
2678 self.assert_log_lines([])
2679
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002680 def test_config_9_ok(self):
2681 with captured_stdout() as output:
2682 self.apply_config(self.config9)
2683 logger = logging.getLogger("compiler.parser")
2684 #Nothing will be output since both handler and logger are set to WARNING
2685 logger.info(self.next_message())
2686 self.assert_log_lines([], stream=output)
2687 self.apply_config(self.config9a)
2688 #Nothing will be output since both handler is still set to WARNING
2689 logger.info(self.next_message())
2690 self.assert_log_lines([], stream=output)
2691 self.apply_config(self.config9b)
2692 #Message should now be output
2693 logger.info(self.next_message())
2694 self.assert_log_lines([
2695 ('INFO', '3'),
2696 ], stream=output)
2697
2698 def test_config_10_ok(self):
2699 with captured_stdout() as output:
2700 self.apply_config(self.config10)
2701 logger = logging.getLogger("compiler.parser")
2702 logger.warning(self.next_message())
2703 logger = logging.getLogger('compiler')
2704 #Not output, because filtered
2705 logger.warning(self.next_message())
2706 logger = logging.getLogger('compiler.lexer')
2707 #Not output, because filtered
2708 logger.warning(self.next_message())
2709 logger = logging.getLogger("compiler.parser.codegen")
2710 #Output, as not filtered
2711 logger.error(self.next_message())
2712 self.assert_log_lines([
2713 ('WARNING', '1'),
2714 ('ERROR', '4'),
2715 ], stream=output)
2716
2717 def test_config11_ok(self):
2718 self.test_config1_ok(self.config11)
2719
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002720 def test_config12_failure(self):
2721 self.assertRaises(Exception, self.apply_config, self.config12)
2722
2723 def test_config13_failure(self):
2724 self.assertRaises(Exception, self.apply_config, self.config13)
2725
Vinay Sajip8d270232012-11-15 14:20:18 +00002726 def test_config14_ok(self):
2727 with captured_stdout() as output:
2728 self.apply_config(self.config14)
2729 h = logging._handlers['hand1']
2730 self.assertEqual(h.foo, 'bar')
2731 self.assertEqual(h.terminator, '!\n')
2732 logging.warning('Exclamation')
2733 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2734
Victor Stinner45df8202010-04-28 22:31:17 +00002735 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002736 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002737 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002738 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002739 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002740 t.start()
2741 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002742 # Now get the port allocated
2743 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002744 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002745 try:
2746 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2747 sock.settimeout(2.0)
2748 sock.connect(('localhost', port))
2749
2750 slen = struct.pack('>L', len(text))
2751 s = slen + text
2752 sentsofar = 0
2753 left = len(s)
2754 while left > 0:
2755 sent = sock.send(s[sentsofar:])
2756 sentsofar += sent
2757 left -= sent
2758 sock.close()
2759 finally:
2760 t.ready.wait(2.0)
2761 logging.config.stopListening()
2762 t.join(2.0)
2763
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002764 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002765 def test_listen_config_10_ok(self):
2766 with captured_stdout() as output:
2767 self.setup_via_listener(json.dumps(self.config10))
2768 logger = logging.getLogger("compiler.parser")
2769 logger.warning(self.next_message())
2770 logger = logging.getLogger('compiler')
2771 #Not output, because filtered
2772 logger.warning(self.next_message())
2773 logger = logging.getLogger('compiler.lexer')
2774 #Not output, because filtered
2775 logger.warning(self.next_message())
2776 logger = logging.getLogger("compiler.parser.codegen")
2777 #Output, as not filtered
2778 logger.error(self.next_message())
2779 self.assert_log_lines([
2780 ('WARNING', '1'),
2781 ('ERROR', '4'),
2782 ], stream=output)
2783
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002784 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002785 def test_listen_config_1_ok(self):
2786 with captured_stdout() as output:
2787 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2788 logger = logging.getLogger("compiler.parser")
2789 # Both will output a message
2790 logger.info(self.next_message())
2791 logger.error(self.next_message())
2792 self.assert_log_lines([
2793 ('INFO', '1'),
2794 ('ERROR', '2'),
2795 ], stream=output)
2796 # Original logger output is empty.
2797 self.assert_log_lines([])
2798
Vinay Sajip4ded5512012-10-02 15:56:16 +01002799 @unittest.skipUnless(threading, 'Threading required for this test.')
2800 def test_listen_verify(self):
2801
2802 def verify_fail(stuff):
2803 return None
2804
2805 def verify_reverse(stuff):
2806 return stuff[::-1]
2807
2808 logger = logging.getLogger("compiler.parser")
2809 to_send = textwrap.dedent(ConfigFileTest.config1)
2810 # First, specify a verification function that will fail.
2811 # We expect to see no output, since our configuration
2812 # never took effect.
2813 with captured_stdout() as output:
2814 self.setup_via_listener(to_send, verify_fail)
2815 # Both will output a message
2816 logger.info(self.next_message())
2817 logger.error(self.next_message())
2818 self.assert_log_lines([], stream=output)
2819 # Original logger output has the stuff we logged.
2820 self.assert_log_lines([
2821 ('INFO', '1'),
2822 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002823 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002824
2825 # Now, perform no verification. Our configuration
2826 # should take effect.
2827
2828 with captured_stdout() as output:
2829 self.setup_via_listener(to_send) # no verify callable specified
2830 logger = logging.getLogger("compiler.parser")
2831 # Both will output a message
2832 logger.info(self.next_message())
2833 logger.error(self.next_message())
2834 self.assert_log_lines([
2835 ('INFO', '3'),
2836 ('ERROR', '4'),
2837 ], stream=output)
2838 # Original logger output still has the stuff we logged before.
2839 self.assert_log_lines([
2840 ('INFO', '1'),
2841 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002842 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002843
2844 # Now, perform verification which transforms the bytes.
2845
2846 with captured_stdout() as output:
2847 self.setup_via_listener(to_send[::-1], verify_reverse)
2848 logger = logging.getLogger("compiler.parser")
2849 # Both will output a message
2850 logger.info(self.next_message())
2851 logger.error(self.next_message())
2852 self.assert_log_lines([
2853 ('INFO', '5'),
2854 ('ERROR', '6'),
2855 ], stream=output)
2856 # Original logger output still has the stuff we logged before.
2857 self.assert_log_lines([
2858 ('INFO', '1'),
2859 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002860 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002861
Vinay Sajip3f885b52013-03-22 15:19:54 +00002862 def test_out_of_order(self):
2863 self.apply_config(self.out_of_order)
2864 handler = logging.getLogger('mymodule').handlers[0]
2865 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002866 self.assertIsInstance(handler.formatter._style,
2867 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002868
Vinay Sajip373baef2011-04-26 20:05:24 +01002869 def test_baseconfig(self):
2870 d = {
2871 'atuple': (1, 2, 3),
2872 'alist': ['a', 'b', 'c'],
2873 'adict': {'d': 'e', 'f': 3 },
2874 'nest1': ('g', ('h', 'i'), 'j'),
2875 'nest2': ['k', ['l', 'm'], 'n'],
2876 'nest3': ['o', 'cfg://alist', 'p'],
2877 }
2878 bc = logging.config.BaseConfigurator(d)
2879 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2880 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2881 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2882 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2883 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2884 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2885 v = bc.convert('cfg://nest3')
2886 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2887 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2888 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2889 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890
2891class ManagerTest(BaseTest):
2892 def test_manager_loggerclass(self):
2893 logged = []
2894
2895 class MyLogger(logging.Logger):
2896 def _log(self, level, msg, args, exc_info=None, extra=None):
2897 logged.append(msg)
2898
2899 man = logging.Manager(None)
2900 self.assertRaises(TypeError, man.setLoggerClass, int)
2901 man.setLoggerClass(MyLogger)
2902 logger = man.getLogger('test')
2903 logger.warning('should appear in logged')
2904 logging.warning('should not appear in logged')
2905
2906 self.assertEqual(logged, ['should appear in logged'])
2907
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002908 def test_set_log_record_factory(self):
2909 man = logging.Manager(None)
2910 expected = object()
2911 man.setLogRecordFactory(expected)
2912 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002913
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002914class ChildLoggerTest(BaseTest):
2915 def test_child_loggers(self):
2916 r = logging.getLogger()
2917 l1 = logging.getLogger('abc')
2918 l2 = logging.getLogger('def.ghi')
2919 c1 = r.getChild('xyz')
2920 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002921 self.assertIs(c1, logging.getLogger('xyz'))
2922 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002923 c1 = l1.getChild('def')
2924 c2 = c1.getChild('ghi')
2925 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002926 self.assertIs(c1, logging.getLogger('abc.def'))
2927 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2928 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002929
2930
Vinay Sajip6fac8172010-10-19 20:44:14 +00002931class DerivedLogRecord(logging.LogRecord):
2932 pass
2933
Vinay Sajip61561522010-12-03 11:50:38 +00002934class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002935
2936 def setUp(self):
2937 class CheckingFilter(logging.Filter):
2938 def __init__(self, cls):
2939 self.cls = cls
2940
2941 def filter(self, record):
2942 t = type(record)
2943 if t is not self.cls:
2944 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2945 self.cls)
2946 raise TypeError(msg)
2947 return True
2948
2949 BaseTest.setUp(self)
2950 self.filter = CheckingFilter(DerivedLogRecord)
2951 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002952 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002953
2954 def tearDown(self):
2955 self.root_logger.removeFilter(self.filter)
2956 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002957 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002958
2959 def test_logrecord_class(self):
2960 self.assertRaises(TypeError, self.root_logger.warning,
2961 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002962 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002963 self.root_logger.error(self.next_message())
2964 self.assert_log_lines([
2965 ('root', 'ERROR', '2'),
2966 ])
2967
2968
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002969class QueueHandlerTest(BaseTest):
2970 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002971 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002972
2973 def setUp(self):
2974 BaseTest.setUp(self)
2975 self.queue = queue.Queue(-1)
2976 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2977 self.que_logger = logging.getLogger('que')
2978 self.que_logger.propagate = False
2979 self.que_logger.setLevel(logging.WARNING)
2980 self.que_logger.addHandler(self.que_hdlr)
2981
2982 def tearDown(self):
2983 self.que_hdlr.close()
2984 BaseTest.tearDown(self)
2985
2986 def test_queue_handler(self):
2987 self.que_logger.debug(self.next_message())
2988 self.assertRaises(queue.Empty, self.queue.get_nowait)
2989 self.que_logger.info(self.next_message())
2990 self.assertRaises(queue.Empty, self.queue.get_nowait)
2991 msg = self.next_message()
2992 self.que_logger.warning(msg)
2993 data = self.queue.get_nowait()
2994 self.assertTrue(isinstance(data, logging.LogRecord))
2995 self.assertEqual(data.name, self.que_logger.name)
2996 self.assertEqual((data.msg, data.args), (msg, None))
2997
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002998 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2999 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003000 def test_queue_listener(self):
3001 handler = TestHandler(Matcher())
3002 listener = logging.handlers.QueueListener(self.queue, handler)
3003 listener.start()
3004 try:
3005 self.que_logger.warning(self.next_message())
3006 self.que_logger.error(self.next_message())
3007 self.que_logger.critical(self.next_message())
3008 finally:
3009 listener.stop()
3010 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3011 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3012 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3013
Vinay Sajip37eb3382011-04-26 20:26:41 +01003014ZERO = datetime.timedelta(0)
3015
3016class UTC(datetime.tzinfo):
3017 def utcoffset(self, dt):
3018 return ZERO
3019
3020 dst = utcoffset
3021
3022 def tzname(self, dt):
3023 return 'UTC'
3024
3025utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003026
Vinay Sajipa39c5712010-10-25 13:57:39 +00003027class FormatterTest(unittest.TestCase):
3028 def setUp(self):
3029 self.common = {
3030 'name': 'formatter.test',
3031 'level': logging.DEBUG,
3032 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3033 'lineno': 42,
3034 'exc_info': None,
3035 'func': None,
3036 'msg': 'Message with %d %s',
3037 'args': (2, 'placeholders'),
3038 }
3039 self.variants = {
3040 }
3041
3042 def get_record(self, name=None):
3043 result = dict(self.common)
3044 if name is not None:
3045 result.update(self.variants[name])
3046 return logging.makeLogRecord(result)
3047
3048 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003049 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003050 r = self.get_record()
3051 f = logging.Formatter('${%(message)s}')
3052 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3053 f = logging.Formatter('%(random)s')
3054 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003055 self.assertFalse(f.usesTime())
3056 f = logging.Formatter('%(asctime)s')
3057 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003058 f = logging.Formatter('%(asctime)-15s')
3059 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003060 f = logging.Formatter('asctime')
3061 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003062
3063 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003064 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003065 r = self.get_record()
3066 f = logging.Formatter('$%{message}%$', style='{')
3067 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3068 f = logging.Formatter('{random}', style='{')
3069 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003070 self.assertFalse(f.usesTime())
3071 f = logging.Formatter('{asctime}', style='{')
3072 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003073 f = logging.Formatter('{asctime!s:15}', style='{')
3074 self.assertTrue(f.usesTime())
3075 f = logging.Formatter('{asctime:15}', style='{')
3076 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003077 f = logging.Formatter('asctime', style='{')
3078 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003079
3080 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003081 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003082 r = self.get_record()
3083 f = logging.Formatter('$message', style='$')
3084 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3085 f = logging.Formatter('$$%${message}%$$', style='$')
3086 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3087 f = logging.Formatter('${random}', style='$')
3088 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003089 self.assertFalse(f.usesTime())
3090 f = logging.Formatter('${asctime}', style='$')
3091 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003092 f = logging.Formatter('${asctime', style='$')
3093 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003094 f = logging.Formatter('$asctime', style='$')
3095 self.assertTrue(f.usesTime())
3096 f = logging.Formatter('asctime', style='$')
3097 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003098
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003099 def test_invalid_style(self):
3100 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3101
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003102 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003103 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003104 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3105 # We use None to indicate we want the local timezone
3106 # We're essentially converting a UTC time to local time
3107 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003108 r.msecs = 123
3109 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003110 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003111 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3112 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003113 f.format(r)
3114 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3115
3116class TestBufferingFormatter(logging.BufferingFormatter):
3117 def formatHeader(self, records):
3118 return '[(%d)' % len(records)
3119
3120 def formatFooter(self, records):
3121 return '(%d)]' % len(records)
3122
3123class BufferingFormatterTest(unittest.TestCase):
3124 def setUp(self):
3125 self.records = [
3126 logging.makeLogRecord({'msg': 'one'}),
3127 logging.makeLogRecord({'msg': 'two'}),
3128 ]
3129
3130 def test_default(self):
3131 f = logging.BufferingFormatter()
3132 self.assertEqual('', f.format([]))
3133 self.assertEqual('onetwo', f.format(self.records))
3134
3135 def test_custom(self):
3136 f = TestBufferingFormatter()
3137 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3138 lf = logging.Formatter('<%(message)s>')
3139 f = TestBufferingFormatter(lf)
3140 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003141
3142class ExceptionTest(BaseTest):
3143 def test_formatting(self):
3144 r = self.root_logger
3145 h = RecordingHandler()
3146 r.addHandler(h)
3147 try:
3148 raise RuntimeError('deliberate mistake')
3149 except:
3150 logging.exception('failed', stack_info=True)
3151 r.removeHandler(h)
3152 h.close()
3153 r = h.records[0]
3154 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3155 'call last):\n'))
3156 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3157 'deliberate mistake'))
3158 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3159 'call last):\n'))
3160 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3161 'stack_info=True)'))
3162
3163
Vinay Sajip5a27d402010-12-10 11:42:57 +00003164class LastResortTest(BaseTest):
3165 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003166 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003167 root = self.root_logger
3168 root.removeHandler(self.root_hdlr)
3169 old_stderr = sys.stderr
3170 old_lastresort = logging.lastResort
3171 old_raise_exceptions = logging.raiseExceptions
3172 try:
3173 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003174 root.debug('This should not appear')
3175 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003176 root.warning('This is your final chance!')
3177 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3178 #No handlers and no last resort, so 'No handlers' message
3179 logging.lastResort = None
3180 sys.stderr = sio = io.StringIO()
3181 root.warning('This is your final chance!')
3182 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3183 # 'No handlers' message only printed once
3184 sys.stderr = sio = io.StringIO()
3185 root.warning('This is your final chance!')
3186 self.assertEqual(sio.getvalue(), '')
3187 root.manager.emittedNoHandlerWarning = False
3188 #If raiseExceptions is False, no message is printed
3189 logging.raiseExceptions = False
3190 sys.stderr = sio = io.StringIO()
3191 root.warning('This is your final chance!')
3192 self.assertEqual(sio.getvalue(), '')
3193 finally:
3194 sys.stderr = old_stderr
3195 root.addHandler(self.root_hdlr)
3196 logging.lastResort = old_lastresort
3197 logging.raiseExceptions = old_raise_exceptions
3198
3199
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003200class FakeHandler:
3201
3202 def __init__(self, identifier, called):
3203 for method in ('acquire', 'flush', 'close', 'release'):
3204 setattr(self, method, self.record_call(identifier, method, called))
3205
3206 def record_call(self, identifier, method_name, called):
3207 def inner():
3208 called.append('{} - {}'.format(identifier, method_name))
3209 return inner
3210
3211
3212class RecordingHandler(logging.NullHandler):
3213
3214 def __init__(self, *args, **kwargs):
3215 super(RecordingHandler, self).__init__(*args, **kwargs)
3216 self.records = []
3217
3218 def handle(self, record):
3219 """Keep track of all the emitted records."""
3220 self.records.append(record)
3221
3222
3223class ShutdownTest(BaseTest):
3224
Vinay Sajip5e66b162011-04-20 15:41:14 +01003225 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003226
3227 def setUp(self):
3228 super(ShutdownTest, self).setUp()
3229 self.called = []
3230
3231 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003232 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003233
3234 def raise_error(self, error):
3235 def inner():
3236 raise error()
3237 return inner
3238
3239 def test_no_failure(self):
3240 # create some fake handlers
3241 handler0 = FakeHandler(0, self.called)
3242 handler1 = FakeHandler(1, self.called)
3243 handler2 = FakeHandler(2, self.called)
3244
3245 # create live weakref to those handlers
3246 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3247
3248 logging.shutdown(handlerList=list(handlers))
3249
3250 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3251 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3252 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3253 self.assertEqual(expected, self.called)
3254
3255 def _test_with_failure_in_method(self, method, error):
3256 handler = FakeHandler(0, self.called)
3257 setattr(handler, method, self.raise_error(error))
3258 handlers = [logging.weakref.ref(handler)]
3259
3260 logging.shutdown(handlerList=list(handlers))
3261
3262 self.assertEqual('0 - release', self.called[-1])
3263
3264 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003265 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003266
3267 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003268 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003269
3270 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003271 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003272
3273 def test_with_valueerror_in_acquire(self):
3274 self._test_with_failure_in_method('acquire', ValueError)
3275
3276 def test_with_valueerror_in_flush(self):
3277 self._test_with_failure_in_method('flush', ValueError)
3278
3279 def test_with_valueerror_in_close(self):
3280 self._test_with_failure_in_method('close', ValueError)
3281
3282 def test_with_other_error_in_acquire_without_raise(self):
3283 logging.raiseExceptions = False
3284 self._test_with_failure_in_method('acquire', IndexError)
3285
3286 def test_with_other_error_in_flush_without_raise(self):
3287 logging.raiseExceptions = False
3288 self._test_with_failure_in_method('flush', IndexError)
3289
3290 def test_with_other_error_in_close_without_raise(self):
3291 logging.raiseExceptions = False
3292 self._test_with_failure_in_method('close', IndexError)
3293
3294 def test_with_other_error_in_acquire_with_raise(self):
3295 logging.raiseExceptions = True
3296 self.assertRaises(IndexError, self._test_with_failure_in_method,
3297 'acquire', IndexError)
3298
3299 def test_with_other_error_in_flush_with_raise(self):
3300 logging.raiseExceptions = True
3301 self.assertRaises(IndexError, self._test_with_failure_in_method,
3302 'flush', IndexError)
3303
3304 def test_with_other_error_in_close_with_raise(self):
3305 logging.raiseExceptions = True
3306 self.assertRaises(IndexError, self._test_with_failure_in_method,
3307 'close', IndexError)
3308
3309
3310class ModuleLevelMiscTest(BaseTest):
3311
Vinay Sajip5e66b162011-04-20 15:41:14 +01003312 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003313
3314 def test_disable(self):
3315 old_disable = logging.root.manager.disable
3316 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003317 self.assertEqual(old_disable, 0)
3318 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003319
3320 logging.disable(83)
3321 self.assertEqual(logging.root.manager.disable, 83)
3322
3323 def _test_log(self, method, level=None):
3324 called = []
3325 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003326 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003327
3328 recording = RecordingHandler()
3329 logging.root.addHandler(recording)
3330
3331 log_method = getattr(logging, method)
3332 if level is not None:
3333 log_method(level, "test me: %r", recording)
3334 else:
3335 log_method("test me: %r", recording)
3336
3337 self.assertEqual(len(recording.records), 1)
3338 record = recording.records[0]
3339 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3340
3341 expected_level = level if level is not None else getattr(logging, method.upper())
3342 self.assertEqual(record.levelno, expected_level)
3343
3344 # basicConfig was not called!
3345 self.assertEqual(called, [])
3346
3347 def test_log(self):
3348 self._test_log('log', logging.ERROR)
3349
3350 def test_debug(self):
3351 self._test_log('debug')
3352
3353 def test_info(self):
3354 self._test_log('info')
3355
3356 def test_warning(self):
3357 self._test_log('warning')
3358
3359 def test_error(self):
3360 self._test_log('error')
3361
3362 def test_critical(self):
3363 self._test_log('critical')
3364
3365 def test_set_logger_class(self):
3366 self.assertRaises(TypeError, logging.setLoggerClass, object)
3367
3368 class MyLogger(logging.Logger):
3369 pass
3370
3371 logging.setLoggerClass(MyLogger)
3372 self.assertEqual(logging.getLoggerClass(), MyLogger)
3373
3374 logging.setLoggerClass(logging.Logger)
3375 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3376
Antoine Pitrou712cb732013-12-21 15:51:54 +01003377 def test_logging_at_shutdown(self):
3378 # Issue #20037
3379 code = """if 1:
3380 import logging
3381
3382 class A:
3383 def __del__(self):
3384 try:
3385 raise ValueError("some error")
3386 except Exception:
3387 logging.exception("exception in __del__")
3388
3389 a = A()"""
3390 rc, out, err = assert_python_ok("-c", code)
3391 err = err.decode()
3392 self.assertIn("exception in __del__", err)
3393 self.assertIn("ValueError: some error", err)
3394
3395
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003396class LogRecordTest(BaseTest):
3397 def test_str_rep(self):
3398 r = logging.makeLogRecord({})
3399 s = str(r)
3400 self.assertTrue(s.startswith('<LogRecord: '))
3401 self.assertTrue(s.endswith('>'))
3402
3403 def test_dict_arg(self):
3404 h = RecordingHandler()
3405 r = logging.getLogger()
3406 r.addHandler(h)
3407 d = {'less' : 'more' }
3408 logging.warning('less is %(less)s', d)
3409 self.assertIs(h.records[0].args, d)
3410 self.assertEqual(h.records[0].message, 'less is more')
3411 r.removeHandler(h)
3412 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003413
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003414 def test_multiprocessing(self):
3415 r = logging.makeLogRecord({})
3416 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003417 try:
3418 import multiprocessing as mp
3419 r = logging.makeLogRecord({})
3420 self.assertEqual(r.processName, mp.current_process().name)
3421 except ImportError:
3422 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003423
3424 def test_optional(self):
3425 r = logging.makeLogRecord({})
3426 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003427 if threading:
3428 NOT_NONE(r.thread)
3429 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003430 NOT_NONE(r.process)
3431 NOT_NONE(r.processName)
3432 log_threads = logging.logThreads
3433 log_processes = logging.logProcesses
3434 log_multiprocessing = logging.logMultiprocessing
3435 try:
3436 logging.logThreads = False
3437 logging.logProcesses = False
3438 logging.logMultiprocessing = False
3439 r = logging.makeLogRecord({})
3440 NONE = self.assertIsNone
3441 NONE(r.thread)
3442 NONE(r.threadName)
3443 NONE(r.process)
3444 NONE(r.processName)
3445 finally:
3446 logging.logThreads = log_threads
3447 logging.logProcesses = log_processes
3448 logging.logMultiprocessing = log_multiprocessing
3449
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003450class BasicConfigTest(unittest.TestCase):
3451
Vinay Sajip95bf5042011-04-20 11:50:56 +01003452 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003453
3454 def setUp(self):
3455 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003456 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003457 self.saved_handlers = logging._handlers.copy()
3458 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003459 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003460 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003461 logging.root.handlers = []
3462
3463 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003464 for h in logging.root.handlers[:]:
3465 logging.root.removeHandler(h)
3466 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003467 super(BasicConfigTest, self).tearDown()
3468
Vinay Sajip3def7e02011-04-20 10:58:06 +01003469 def cleanup(self):
3470 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003471 logging._handlers.clear()
3472 logging._handlers.update(self.saved_handlers)
3473 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003474 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003475
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003476 def test_no_kwargs(self):
3477 logging.basicConfig()
3478
3479 # handler defaults to a StreamHandler to sys.stderr
3480 self.assertEqual(len(logging.root.handlers), 1)
3481 handler = logging.root.handlers[0]
3482 self.assertIsInstance(handler, logging.StreamHandler)
3483 self.assertEqual(handler.stream, sys.stderr)
3484
3485 formatter = handler.formatter
3486 # format defaults to logging.BASIC_FORMAT
3487 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3488 # datefmt defaults to None
3489 self.assertIsNone(formatter.datefmt)
3490 # style defaults to %
3491 self.assertIsInstance(formatter._style, logging.PercentStyle)
3492
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003493 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003494 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003495
Vinay Sajip1fd12022014-01-13 21:59:56 +00003496 def test_strformatstyle(self):
3497 with captured_stdout() as output:
3498 logging.basicConfig(stream=sys.stdout, style="{")
3499 logging.error("Log an error")
3500 sys.stdout.seek(0)
3501 self.assertEqual(output.getvalue().strip(),
3502 "ERROR:root:Log an error")
3503
3504 def test_stringtemplatestyle(self):
3505 with captured_stdout() as output:
3506 logging.basicConfig(stream=sys.stdout, style="$")
3507 logging.error("Log an error")
3508 sys.stdout.seek(0)
3509 self.assertEqual(output.getvalue().strip(),
3510 "ERROR:root:Log an error")
3511
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003512 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003513
3514 def cleanup(h1, h2, fn):
3515 h1.close()
3516 h2.close()
3517 os.remove(fn)
3518
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003519 logging.basicConfig(filename='test.log')
3520
3521 self.assertEqual(len(logging.root.handlers), 1)
3522 handler = logging.root.handlers[0]
3523 self.assertIsInstance(handler, logging.FileHandler)
3524
3525 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003526 self.assertEqual(handler.stream.mode, expected.stream.mode)
3527 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003528 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003529
3530 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003531
3532 def cleanup(h1, h2, fn):
3533 h1.close()
3534 h2.close()
3535 os.remove(fn)
3536
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003537 logging.basicConfig(filename='test.log', filemode='wb')
3538
3539 handler = logging.root.handlers[0]
3540 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003541 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003542 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003543
3544 def test_stream(self):
3545 stream = io.StringIO()
3546 self.addCleanup(stream.close)
3547 logging.basicConfig(stream=stream)
3548
3549 self.assertEqual(len(logging.root.handlers), 1)
3550 handler = logging.root.handlers[0]
3551 self.assertIsInstance(handler, logging.StreamHandler)
3552 self.assertEqual(handler.stream, stream)
3553
3554 def test_format(self):
3555 logging.basicConfig(format='foo')
3556
3557 formatter = logging.root.handlers[0].formatter
3558 self.assertEqual(formatter._style._fmt, 'foo')
3559
3560 def test_datefmt(self):
3561 logging.basicConfig(datefmt='bar')
3562
3563 formatter = logging.root.handlers[0].formatter
3564 self.assertEqual(formatter.datefmt, 'bar')
3565
3566 def test_style(self):
3567 logging.basicConfig(style='$')
3568
3569 formatter = logging.root.handlers[0].formatter
3570 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3571
3572 def test_level(self):
3573 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003574 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003575
3576 logging.basicConfig(level=57)
3577 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003578 # Test that second call has no effect
3579 logging.basicConfig(level=58)
3580 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003581
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003582 def test_incompatible(self):
3583 assertRaises = self.assertRaises
3584 handlers = [logging.StreamHandler()]
3585 stream = sys.stderr
3586 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3587 stream=stream)
3588 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3589 handlers=handlers)
3590 assertRaises(ValueError, logging.basicConfig, stream=stream,
3591 handlers=handlers)
3592
3593 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003594 handlers = [
3595 logging.StreamHandler(),
3596 logging.StreamHandler(sys.stdout),
3597 logging.StreamHandler(),
3598 ]
3599 f = logging.Formatter()
3600 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003601 logging.basicConfig(handlers=handlers)
3602 self.assertIs(handlers[0], logging.root.handlers[0])
3603 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003604 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003605 self.assertIsNotNone(handlers[0].formatter)
3606 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003607 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003608 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3609
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003610 def _test_log(self, method, level=None):
3611 # logging.root has no handlers so basicConfig should be called
3612 called = []
3613
3614 old_basic_config = logging.basicConfig
3615 def my_basic_config(*a, **kw):
3616 old_basic_config()
3617 old_level = logging.root.level
3618 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003619 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003620 called.append((a, kw))
3621
3622 patch(self, logging, 'basicConfig', my_basic_config)
3623
3624 log_method = getattr(logging, method)
3625 if level is not None:
3626 log_method(level, "test me")
3627 else:
3628 log_method("test me")
3629
3630 # basicConfig was called with no arguments
3631 self.assertEqual(called, [((), {})])
3632
3633 def test_log(self):
3634 self._test_log('log', logging.WARNING)
3635
3636 def test_debug(self):
3637 self._test_log('debug')
3638
3639 def test_info(self):
3640 self._test_log('info')
3641
3642 def test_warning(self):
3643 self._test_log('warning')
3644
3645 def test_error(self):
3646 self._test_log('error')
3647
3648 def test_critical(self):
3649 self._test_log('critical')
3650
3651
3652class LoggerAdapterTest(unittest.TestCase):
3653
3654 def setUp(self):
3655 super(LoggerAdapterTest, self).setUp()
3656 old_handler_list = logging._handlerList[:]
3657
3658 self.recording = RecordingHandler()
3659 self.logger = logging.root
3660 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003661 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003662 self.addCleanup(self.recording.close)
3663
3664 def cleanup():
3665 logging._handlerList[:] = old_handler_list
3666
3667 self.addCleanup(cleanup)
3668 self.addCleanup(logging.shutdown)
3669 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3670
3671 def test_exception(self):
3672 msg = 'testing exception: %r'
3673 exc = None
3674 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003675 1 / 0
3676 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003677 exc = e
3678 self.adapter.exception(msg, self.recording)
3679
3680 self.assertEqual(len(self.recording.records), 1)
3681 record = self.recording.records[0]
3682 self.assertEqual(record.levelno, logging.ERROR)
3683 self.assertEqual(record.msg, msg)
3684 self.assertEqual(record.args, (self.recording,))
3685 self.assertEqual(record.exc_info,
3686 (exc.__class__, exc, exc.__traceback__))
3687
3688 def test_critical(self):
3689 msg = 'critical test! %r'
3690 self.adapter.critical(msg, self.recording)
3691
3692 self.assertEqual(len(self.recording.records), 1)
3693 record = self.recording.records[0]
3694 self.assertEqual(record.levelno, logging.CRITICAL)
3695 self.assertEqual(record.msg, msg)
3696 self.assertEqual(record.args, (self.recording,))
3697
3698 def test_is_enabled_for(self):
3699 old_disable = self.adapter.logger.manager.disable
3700 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003701 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3702 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003703 self.assertFalse(self.adapter.isEnabledFor(32))
3704
3705 def test_has_handlers(self):
3706 self.assertTrue(self.adapter.hasHandlers())
3707
3708 for handler in self.logger.handlers:
3709 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003710
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003711 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003712 self.assertFalse(self.adapter.hasHandlers())
3713
3714
3715class LoggerTest(BaseTest):
3716
3717 def setUp(self):
3718 super(LoggerTest, self).setUp()
3719 self.recording = RecordingHandler()
3720 self.logger = logging.Logger(name='blah')
3721 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003722 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003723 self.addCleanup(self.recording.close)
3724 self.addCleanup(logging.shutdown)
3725
3726 def test_set_invalid_level(self):
3727 self.assertRaises(TypeError, self.logger.setLevel, object())
3728
3729 def test_exception(self):
3730 msg = 'testing exception: %r'
3731 exc = None
3732 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003733 1 / 0
3734 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003735 exc = e
3736 self.logger.exception(msg, self.recording)
3737
3738 self.assertEqual(len(self.recording.records), 1)
3739 record = self.recording.records[0]
3740 self.assertEqual(record.levelno, logging.ERROR)
3741 self.assertEqual(record.msg, msg)
3742 self.assertEqual(record.args, (self.recording,))
3743 self.assertEqual(record.exc_info,
3744 (exc.__class__, exc, exc.__traceback__))
3745
3746 def test_log_invalid_level_with_raise(self):
3747 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003748 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003749
3750 logging.raiseExceptions = True
3751 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3752
3753 def test_log_invalid_level_no_raise(self):
3754 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003755 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003756
3757 logging.raiseExceptions = False
3758 self.logger.log('10', 'test message') # no exception happens
3759
3760 def test_find_caller_with_stack_info(self):
3761 called = []
3762 patch(self, logging.traceback, 'print_stack',
3763 lambda f, file: called.append(file.getvalue()))
3764
3765 self.logger.findCaller(stack_info=True)
3766
3767 self.assertEqual(len(called), 1)
3768 self.assertEqual('Stack (most recent call last):\n', called[0])
3769
3770 def test_make_record_with_extra_overwrite(self):
3771 name = 'my record'
3772 level = 13
3773 fn = lno = msg = args = exc_info = func = sinfo = None
3774 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3775 exc_info, func, sinfo)
3776
3777 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3778 extra = {key: 'some value'}
3779 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3780 fn, lno, msg, args, exc_info,
3781 extra=extra, sinfo=sinfo)
3782
3783 def test_make_record_with_extra_no_overwrite(self):
3784 name = 'my record'
3785 level = 13
3786 fn = lno = msg = args = exc_info = func = sinfo = None
3787 extra = {'valid_key': 'some value'}
3788 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3789 exc_info, extra=extra, sinfo=sinfo)
3790 self.assertIn('valid_key', result.__dict__)
3791
3792 def test_has_handlers(self):
3793 self.assertTrue(self.logger.hasHandlers())
3794
3795 for handler in self.logger.handlers:
3796 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003797 self.assertFalse(self.logger.hasHandlers())
3798
3799 def test_has_handlers_no_propagate(self):
3800 child_logger = logging.getLogger('blah.child')
3801 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003802 self.assertFalse(child_logger.hasHandlers())
3803
3804 def test_is_enabled_for(self):
3805 old_disable = self.logger.manager.disable
3806 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003807 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003808 self.assertFalse(self.logger.isEnabledFor(22))
3809
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003810 def test_root_logger_aliases(self):
3811 root = logging.getLogger()
3812 self.assertIs(root, logging.root)
3813 self.assertIs(root, logging.getLogger(None))
3814 self.assertIs(root, logging.getLogger(''))
3815 self.assertIs(root, logging.getLogger('foo').root)
3816 self.assertIs(root, logging.getLogger('foo.bar').root)
3817 self.assertIs(root, logging.getLogger('foo').parent)
3818
3819 self.assertIsNot(root, logging.getLogger('\0'))
3820 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3821
3822 def test_invalid_names(self):
3823 self.assertRaises(TypeError, logging.getLogger, any)
3824 self.assertRaises(TypeError, logging.getLogger, b'foo')
3825
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003826
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003827class BaseFileTest(BaseTest):
3828 "Base class for handler tests that write log files"
3829
3830 def setUp(self):
3831 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003832 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3833 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003834 self.rmfiles = []
3835
3836 def tearDown(self):
3837 for fn in self.rmfiles:
3838 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003839 if os.path.exists(self.fn):
3840 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003841 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003842
3843 def assertLogFile(self, filename):
3844 "Assert a log file is there and register it for deletion"
3845 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003846 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003847 self.rmfiles.append(filename)
3848
3849
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003850class FileHandlerTest(BaseFileTest):
3851 def test_delay(self):
3852 os.unlink(self.fn)
3853 fh = logging.FileHandler(self.fn, delay=True)
3854 self.assertIsNone(fh.stream)
3855 self.assertFalse(os.path.exists(self.fn))
3856 fh.handle(logging.makeLogRecord({}))
3857 self.assertIsNotNone(fh.stream)
3858 self.assertTrue(os.path.exists(self.fn))
3859 fh.close()
3860
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003861class RotatingFileHandlerTest(BaseFileTest):
3862 def next_rec(self):
3863 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3864 self.next_message(), None, None, None)
3865
3866 def test_should_not_rollover(self):
3867 # If maxbytes is zero rollover never occurs
3868 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3869 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003870 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003871
3872 def test_should_rollover(self):
3873 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3874 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003875 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003876
3877 def test_file_created(self):
3878 # checks that the file is created and assumes it was created
3879 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003880 rh = logging.handlers.RotatingFileHandler(self.fn)
3881 rh.emit(self.next_rec())
3882 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003883 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003884
3885 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003886 def namer(name):
3887 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003888 rh = logging.handlers.RotatingFileHandler(
3889 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003890 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003891 rh.emit(self.next_rec())
3892 self.assertLogFile(self.fn)
3893 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003894 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003895 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003896 self.assertLogFile(namer(self.fn + ".2"))
3897 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3898 rh.close()
3899
Eric V. Smith851cad72012-03-11 22:46:04 -07003900 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003901 def test_rotator(self):
3902 def namer(name):
3903 return name + ".gz"
3904
3905 def rotator(source, dest):
3906 with open(source, "rb") as sf:
3907 data = sf.read()
3908 compressed = zlib.compress(data, 9)
3909 with open(dest, "wb") as df:
3910 df.write(compressed)
3911 os.remove(source)
3912
3913 rh = logging.handlers.RotatingFileHandler(
3914 self.fn, backupCount=2, maxBytes=1)
3915 rh.rotator = rotator
3916 rh.namer = namer
3917 m1 = self.next_rec()
3918 rh.emit(m1)
3919 self.assertLogFile(self.fn)
3920 m2 = self.next_rec()
3921 rh.emit(m2)
3922 fn = namer(self.fn + ".1")
3923 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003924 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003925 with open(fn, "rb") as f:
3926 compressed = f.read()
3927 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003928 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003929 rh.emit(self.next_rec())
3930 fn = namer(self.fn + ".2")
3931 self.assertLogFile(fn)
3932 with open(fn, "rb") as f:
3933 compressed = f.read()
3934 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003935 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003936 rh.emit(self.next_rec())
3937 fn = namer(self.fn + ".2")
3938 with open(fn, "rb") as f:
3939 compressed = f.read()
3940 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003941 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003942 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003943 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003944
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003945class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003946 # other test methods added below
3947 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003948 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3949 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003950 fmt = logging.Formatter('%(asctime)s %(message)s')
3951 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003952 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003953 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003954 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003955 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003956 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003957 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003958 fh.close()
3959 # At this point, we should have a recent rotated file which we
3960 # can test for the existence of. However, in practice, on some
3961 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003962 # in time to go to look for the log file. So, we go back a fair
3963 # bit, and stop as soon as we see a rotated file. In theory this
3964 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003965 found = False
3966 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003967 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003968 for secs in range(GO_BACK):
3969 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003970 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3971 found = os.path.exists(fn)
3972 if found:
3973 self.rmfiles.append(fn)
3974 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003975 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3976 if not found:
3977 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003978 dn, fn = os.path.split(self.fn)
3979 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003980 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3981 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003982 for f in files:
3983 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003984 path = os.path.join(dn, f)
3985 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003986 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003987 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003988
Vinay Sajip0372e102011-05-05 12:59:14 +01003989 def test_invalid(self):
3990 assertRaises = self.assertRaises
3991 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003992 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003993 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003994 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003995 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003996 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003997
Vinay Sajipa7130792013-04-12 17:04:23 +01003998 def test_compute_rollover_daily_attime(self):
3999 currentTime = 0
4000 atTime = datetime.time(12, 0, 0)
4001 rh = logging.handlers.TimedRotatingFileHandler(
4002 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4003 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004004 try:
4005 actual = rh.computeRollover(currentTime)
4006 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004007
Vinay Sajipd86ac962013-04-14 12:20:46 +01004008 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4009 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4010 finally:
4011 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004012
Vinay Sajip10e8c492013-05-18 10:19:54 -07004013 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004014 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004015 currentTime = int(time.time())
4016 today = currentTime - currentTime % 86400
4017
Vinay Sajipa7130792013-04-12 17:04:23 +01004018 atTime = datetime.time(12, 0, 0)
4019
Vinay Sajip10e8c492013-05-18 10:19:54 -07004020 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004021 for day in range(7):
4022 rh = logging.handlers.TimedRotatingFileHandler(
4023 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4024 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004025 try:
4026 if wday > day:
4027 # The rollover day has already passed this week, so we
4028 # go over into next week
4029 expected = (7 - wday + day)
4030 else:
4031 expected = (day - wday)
4032 # At this point expected is in days from now, convert to seconds
4033 expected *= 24 * 60 * 60
4034 # Add in the rollover time
4035 expected += 12 * 60 * 60
4036 # Add in adjustment for today
4037 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004038 actual = rh.computeRollover(today)
4039 if actual != expected:
4040 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004041 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004042 self.assertEqual(actual, expected)
4043 if day == wday:
4044 # goes into following week
4045 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004046 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004047 if actual != expected:
4048 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004049 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004050 self.assertEqual(actual, expected)
4051 finally:
4052 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004053
4054
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004055def secs(**kw):
4056 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4057
4058for when, exp in (('S', 1),
4059 ('M', 60),
4060 ('H', 60 * 60),
4061 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004062 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004063 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004064 ('W0', secs(days=4, hours=24)),
4065 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004066 def test_compute_rollover(self, when=when, exp=exp):
4067 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004068 self.fn, when=when, interval=1, backupCount=0, utc=True)
4069 currentTime = 0.0
4070 actual = rh.computeRollover(currentTime)
4071 if exp != actual:
4072 # Failures occur on some systems for MIDNIGHT and W0.
4073 # Print detailed calculation for MIDNIGHT so we can try to see
4074 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004075 if when == 'MIDNIGHT':
4076 try:
4077 if rh.utc:
4078 t = time.gmtime(currentTime)
4079 else:
4080 t = time.localtime(currentTime)
4081 currentHour = t[3]
4082 currentMinute = t[4]
4083 currentSecond = t[5]
4084 # r is the number of seconds left between now and midnight
4085 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4086 currentMinute) * 60 +
4087 currentSecond)
4088 result = currentTime + r
4089 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4090 print('currentHour: %s' % currentHour, file=sys.stderr)
4091 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4092 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4093 print('r: %s' % r, file=sys.stderr)
4094 print('result: %s' % result, file=sys.stderr)
4095 except Exception:
4096 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4097 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004098 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004099 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4100
Vinay Sajip60ccd822011-05-09 17:32:09 +01004101
4102@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4103class NTEventLogHandlerTest(BaseTest):
4104 def test_basic(self):
4105 logtype = 'Application'
4106 elh = win32evtlog.OpenEventLog(None, logtype)
4107 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4108 h = logging.handlers.NTEventLogHandler('test_logging')
4109 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4110 h.handle(r)
4111 h.close()
4112 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004113 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004114 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4115 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4116 found = False
4117 GO_BACK = 100
4118 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4119 for e in events:
4120 if e.SourceName != 'test_logging':
4121 continue
4122 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4123 if msg != 'Test Log Message\r\n':
4124 continue
4125 found = True
4126 break
4127 msg = 'Record not found in event log, went back %d records' % GO_BACK
4128 self.assertTrue(found, msg=msg)
4129
Christian Heimes180510d2008-03-03 19:15:45 +00004130# Set the locale to the platform-dependent default. I have no idea
4131# why the test does this, but in any case we save the current locale
4132# first and restore it at the end.
4133@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004134def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004135 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004136 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004137 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4138 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4139 ManagerTest, FormatterTest, BufferingFormatterTest,
4140 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4141 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4142 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4143 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004144 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004145 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004146 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4147 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004148 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004149
Christian Heimes180510d2008-03-03 19:15:45 +00004150if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004151 test_main()