blob: ba790d1ea2a78655c5b91121251cb5dcde75890a [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)
1670 # Unfortunately, HTTPHandler doesn't allow us to change the
1671 # SSLContext used by HTTPSConnection, so we have to
1672 # monkeypatch. This can be cleaned up if issue 22788 is
1673 # fixed.
1674 old = ssl._create_default_https_context
1675 def restore_handler():
1676 ssl._create_default_https_context = old
1677 self.addCleanup(restore_handler)
1678 def hack_create_ctx():
1679 ctx = old()
1680 ctx.load_verify_locations(localhost_cert)
1681 return ctx
1682 ssl._create_default_https_context = hack_create_ctx
Vinay Sajip0372e102011-05-05 12:59:14 +01001683 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001684 sslctx = None
1685 self.server = server = TestHTTPServer(addr, self.handle_request,
1686 0.01, sslctx=sslctx)
1687 server.start()
1688 server.ready.wait()
1689 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001690 secure_client = secure and sslctx
1691 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1692 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001693 self.log_data = None
1694 root_logger.addHandler(self.h_hdlr)
1695
1696 for method in ('GET', 'POST'):
1697 self.h_hdlr.method = method
1698 self.handled.clear()
1699 msg = "sp\xe4m"
1700 logger.error(msg)
1701 self.handled.wait()
1702 self.assertEqual(self.log_data.path, '/frob')
1703 self.assertEqual(self.command, method)
1704 if method == 'GET':
1705 d = parse_qs(self.log_data.query)
1706 else:
1707 d = parse_qs(self.post_data.decode('utf-8'))
1708 self.assertEqual(d['name'], ['http'])
1709 self.assertEqual(d['funcName'], ['test_output'])
1710 self.assertEqual(d['msg'], [msg])
1711
1712 self.server.stop(2.0)
1713 self.root_logger.removeHandler(self.h_hdlr)
1714 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001715
Christian Heimes180510d2008-03-03 19:15:45 +00001716class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001717
Christian Heimes180510d2008-03-03 19:15:45 +00001718 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001719
Christian Heimes180510d2008-03-03 19:15:45 +00001720 def setUp(self):
1721 """Create a dict to remember potentially destroyed objects."""
1722 BaseTest.setUp(self)
1723 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001724
Christian Heimes180510d2008-03-03 19:15:45 +00001725 def _watch_for_survival(self, *args):
1726 """Watch the given objects for survival, by creating weakrefs to
1727 them."""
1728 for obj in args:
1729 key = id(obj), repr(obj)
1730 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001731
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001732 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001733 """Assert that all objects watched for survival have survived."""
1734 # Trigger cycle breaking.
1735 gc.collect()
1736 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001737 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001738 if ref() is None:
1739 dead.append(repr_)
1740 if dead:
1741 self.fail("%d objects should have survived "
1742 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001743
Christian Heimes180510d2008-03-03 19:15:45 +00001744 def test_persistent_loggers(self):
1745 # Logger objects are persistent and retain their configuration, even
1746 # if visible references are destroyed.
1747 self.root_logger.setLevel(logging.INFO)
1748 foo = logging.getLogger("foo")
1749 self._watch_for_survival(foo)
1750 foo.setLevel(logging.DEBUG)
1751 self.root_logger.debug(self.next_message())
1752 foo.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 ])
1756 del foo
1757 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001758 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001759 # foo has retained its settings.
1760 bar = logging.getLogger("foo")
1761 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001762 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001763 ('foo', 'DEBUG', '2'),
1764 ('foo', 'DEBUG', '3'),
1765 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001766
Benjamin Petersonf91df042009-02-13 02:50:59 +00001767
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001768class EncodingTest(BaseTest):
1769 def test_encoding_plain_file(self):
1770 # In Python 2.x, a plain file object is treated as having no encoding.
1771 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001772 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1773 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001774 # the non-ascii data we write to the log.
1775 data = "foo\x80"
1776 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001777 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001778 log.addHandler(handler)
1779 try:
1780 # write non-ascii data to the log.
1781 log.warning(data)
1782 finally:
1783 log.removeHandler(handler)
1784 handler.close()
1785 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001786 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001787 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001788 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001789 finally:
1790 f.close()
1791 finally:
1792 if os.path.isfile(fn):
1793 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001794
Benjamin Petersonf91df042009-02-13 02:50:59 +00001795 def test_encoding_cyrillic_unicode(self):
1796 log = logging.getLogger("test")
1797 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1798 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1799 #Ensure it's written in a Cyrillic encoding
1800 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001801 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001802 stream = io.BytesIO()
1803 writer = writer_class(stream, 'strict')
1804 handler = logging.StreamHandler(writer)
1805 log.addHandler(handler)
1806 try:
1807 log.warning(message)
1808 finally:
1809 log.removeHandler(handler)
1810 handler.close()
1811 # check we wrote exactly those bytes, ignoring trailing \n etc
1812 s = stream.getvalue()
1813 #Compare against what the data should be when encoded in CP-1251
1814 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1815
1816
Georg Brandlf9734072008-12-07 15:30:06 +00001817class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001818
Georg Brandlf9734072008-12-07 15:30:06 +00001819 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001820 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001821 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001822 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001823 warnings.filterwarnings("always", category=UserWarning)
1824 stream = io.StringIO()
1825 h = logging.StreamHandler(stream)
1826 logger = logging.getLogger("py.warnings")
1827 logger.addHandler(h)
1828 warnings.warn("I'm warning you...")
1829 logger.removeHandler(h)
1830 s = stream.getvalue()
1831 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001832 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001833
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001834 #See if an explicit file uses the original implementation
1835 a_file = io.StringIO()
1836 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1837 a_file, "Dummy line")
1838 s = a_file.getvalue()
1839 a_file.close()
1840 self.assertEqual(s,
1841 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1842
1843 def test_warnings_no_handlers(self):
1844 with warnings.catch_warnings():
1845 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001846 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001847
1848 # confirm our assumption: no loggers are set
1849 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001850 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001851
1852 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001853 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001854 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001855
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001856
1857def formatFunc(format, datefmt=None):
1858 return logging.Formatter(format, datefmt)
1859
1860def handlerFunc():
1861 return logging.StreamHandler()
1862
1863class CustomHandler(logging.StreamHandler):
1864 pass
1865
1866class ConfigDictTest(BaseTest):
1867
1868 """Reading logging config from a dictionary."""
1869
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001870 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001871
1872 # config0 is a standard configuration.
1873 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001874 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001875 'formatters': {
1876 'form1' : {
1877 'format' : '%(levelname)s ++ %(message)s',
1878 },
1879 },
1880 'handlers' : {
1881 'hand1' : {
1882 'class' : 'logging.StreamHandler',
1883 'formatter' : 'form1',
1884 'level' : 'NOTSET',
1885 'stream' : 'ext://sys.stdout',
1886 },
1887 },
1888 'root' : {
1889 'level' : 'WARNING',
1890 'handlers' : ['hand1'],
1891 },
1892 }
1893
1894 # config1 adds a little to the standard configuration.
1895 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001896 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001897 'formatters': {
1898 'form1' : {
1899 'format' : '%(levelname)s ++ %(message)s',
1900 },
1901 },
1902 'handlers' : {
1903 'hand1' : {
1904 'class' : 'logging.StreamHandler',
1905 'formatter' : 'form1',
1906 'level' : 'NOTSET',
1907 'stream' : 'ext://sys.stdout',
1908 },
1909 },
1910 'loggers' : {
1911 'compiler.parser' : {
1912 'level' : 'DEBUG',
1913 'handlers' : ['hand1'],
1914 },
1915 },
1916 'root' : {
1917 'level' : 'WARNING',
1918 },
1919 }
1920
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001921 # config1a moves the handler to the root. Used with config8a
1922 config1a = {
1923 'version': 1,
1924 'formatters': {
1925 'form1' : {
1926 'format' : '%(levelname)s ++ %(message)s',
1927 },
1928 },
1929 'handlers' : {
1930 'hand1' : {
1931 'class' : 'logging.StreamHandler',
1932 'formatter' : 'form1',
1933 'level' : 'NOTSET',
1934 'stream' : 'ext://sys.stdout',
1935 },
1936 },
1937 'loggers' : {
1938 'compiler.parser' : {
1939 'level' : 'DEBUG',
1940 },
1941 },
1942 'root' : {
1943 'level' : 'WARNING',
1944 'handlers' : ['hand1'],
1945 },
1946 }
1947
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001948 # config2 has a subtle configuration error that should be reported
1949 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001950 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001951 'formatters': {
1952 'form1' : {
1953 'format' : '%(levelname)s ++ %(message)s',
1954 },
1955 },
1956 'handlers' : {
1957 'hand1' : {
1958 'class' : 'logging.StreamHandler',
1959 'formatter' : 'form1',
1960 'level' : 'NOTSET',
1961 'stream' : 'ext://sys.stdbout',
1962 },
1963 },
1964 'loggers' : {
1965 'compiler.parser' : {
1966 'level' : 'DEBUG',
1967 'handlers' : ['hand1'],
1968 },
1969 },
1970 'root' : {
1971 'level' : 'WARNING',
1972 },
1973 }
1974
1975 #As config1 but with a misspelt level on a handler
1976 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001977 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001978 'formatters': {
1979 'form1' : {
1980 'format' : '%(levelname)s ++ %(message)s',
1981 },
1982 },
1983 'handlers' : {
1984 'hand1' : {
1985 'class' : 'logging.StreamHandler',
1986 'formatter' : 'form1',
1987 'level' : 'NTOSET',
1988 'stream' : 'ext://sys.stdout',
1989 },
1990 },
1991 'loggers' : {
1992 'compiler.parser' : {
1993 'level' : 'DEBUG',
1994 'handlers' : ['hand1'],
1995 },
1996 },
1997 'root' : {
1998 'level' : 'WARNING',
1999 },
2000 }
2001
2002
2003 #As config1 but with a misspelt level on a logger
2004 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002005 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002006 'formatters': {
2007 'form1' : {
2008 'format' : '%(levelname)s ++ %(message)s',
2009 },
2010 },
2011 'handlers' : {
2012 'hand1' : {
2013 'class' : 'logging.StreamHandler',
2014 'formatter' : 'form1',
2015 'level' : 'NOTSET',
2016 'stream' : 'ext://sys.stdout',
2017 },
2018 },
2019 'loggers' : {
2020 'compiler.parser' : {
2021 'level' : 'DEBUG',
2022 'handlers' : ['hand1'],
2023 },
2024 },
2025 'root' : {
2026 'level' : 'WRANING',
2027 },
2028 }
2029
2030 # config3 has a less subtle configuration error
2031 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002032 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002033 'formatters': {
2034 'form1' : {
2035 'format' : '%(levelname)s ++ %(message)s',
2036 },
2037 },
2038 'handlers' : {
2039 'hand1' : {
2040 'class' : 'logging.StreamHandler',
2041 'formatter' : 'misspelled_name',
2042 'level' : 'NOTSET',
2043 'stream' : 'ext://sys.stdout',
2044 },
2045 },
2046 'loggers' : {
2047 'compiler.parser' : {
2048 'level' : 'DEBUG',
2049 'handlers' : ['hand1'],
2050 },
2051 },
2052 'root' : {
2053 'level' : 'WARNING',
2054 },
2055 }
2056
2057 # config4 specifies a custom formatter class to be loaded
2058 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002059 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002060 'formatters': {
2061 'form1' : {
2062 '()' : __name__ + '.ExceptionFormatter',
2063 'format' : '%(levelname)s:%(name)s:%(message)s',
2064 },
2065 },
2066 'handlers' : {
2067 'hand1' : {
2068 'class' : 'logging.StreamHandler',
2069 'formatter' : 'form1',
2070 'level' : 'NOTSET',
2071 'stream' : 'ext://sys.stdout',
2072 },
2073 },
2074 'root' : {
2075 'level' : 'NOTSET',
2076 'handlers' : ['hand1'],
2077 },
2078 }
2079
2080 # As config4 but using an actual callable rather than a string
2081 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002082 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002083 'formatters': {
2084 'form1' : {
2085 '()' : ExceptionFormatter,
2086 'format' : '%(levelname)s:%(name)s:%(message)s',
2087 },
2088 'form2' : {
2089 '()' : __name__ + '.formatFunc',
2090 'format' : '%(levelname)s:%(name)s:%(message)s',
2091 },
2092 'form3' : {
2093 '()' : formatFunc,
2094 'format' : '%(levelname)s:%(name)s:%(message)s',
2095 },
2096 },
2097 'handlers' : {
2098 'hand1' : {
2099 'class' : 'logging.StreamHandler',
2100 'formatter' : 'form1',
2101 'level' : 'NOTSET',
2102 'stream' : 'ext://sys.stdout',
2103 },
2104 'hand2' : {
2105 '()' : handlerFunc,
2106 },
2107 },
2108 'root' : {
2109 'level' : 'NOTSET',
2110 'handlers' : ['hand1'],
2111 },
2112 }
2113
2114 # config5 specifies a custom handler class to be loaded
2115 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002116 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002117 'formatters': {
2118 'form1' : {
2119 'format' : '%(levelname)s ++ %(message)s',
2120 },
2121 },
2122 'handlers' : {
2123 'hand1' : {
2124 'class' : __name__ + '.CustomHandler',
2125 'formatter' : 'form1',
2126 'level' : 'NOTSET',
2127 'stream' : 'ext://sys.stdout',
2128 },
2129 },
2130 'loggers' : {
2131 'compiler.parser' : {
2132 'level' : 'DEBUG',
2133 'handlers' : ['hand1'],
2134 },
2135 },
2136 'root' : {
2137 'level' : 'WARNING',
2138 },
2139 }
2140
2141 # config6 specifies a custom handler class to be loaded
2142 # but has bad arguments
2143 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002144 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002145 'formatters': {
2146 'form1' : {
2147 'format' : '%(levelname)s ++ %(message)s',
2148 },
2149 },
2150 'handlers' : {
2151 'hand1' : {
2152 'class' : __name__ + '.CustomHandler',
2153 'formatter' : 'form1',
2154 'level' : 'NOTSET',
2155 'stream' : 'ext://sys.stdout',
2156 '9' : 'invalid parameter name',
2157 },
2158 },
2159 'loggers' : {
2160 'compiler.parser' : {
2161 'level' : 'DEBUG',
2162 'handlers' : ['hand1'],
2163 },
2164 },
2165 'root' : {
2166 'level' : 'WARNING',
2167 },
2168 }
2169
2170 #config 7 does not define compiler.parser but defines compiler.lexer
2171 #so compiler.parser should be disabled after applying it
2172 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002173 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002174 'formatters': {
2175 'form1' : {
2176 'format' : '%(levelname)s ++ %(message)s',
2177 },
2178 },
2179 'handlers' : {
2180 'hand1' : {
2181 'class' : 'logging.StreamHandler',
2182 'formatter' : 'form1',
2183 'level' : 'NOTSET',
2184 'stream' : 'ext://sys.stdout',
2185 },
2186 },
2187 'loggers' : {
2188 'compiler.lexer' : {
2189 'level' : 'DEBUG',
2190 'handlers' : ['hand1'],
2191 },
2192 },
2193 'root' : {
2194 'level' : 'WARNING',
2195 },
2196 }
2197
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002198 # config8 defines both compiler and compiler.lexer
2199 # so compiler.parser should not be disabled (since
2200 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002201 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002202 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002203 'disable_existing_loggers' : False,
2204 'formatters': {
2205 'form1' : {
2206 'format' : '%(levelname)s ++ %(message)s',
2207 },
2208 },
2209 'handlers' : {
2210 'hand1' : {
2211 'class' : 'logging.StreamHandler',
2212 'formatter' : 'form1',
2213 'level' : 'NOTSET',
2214 'stream' : 'ext://sys.stdout',
2215 },
2216 },
2217 'loggers' : {
2218 'compiler' : {
2219 'level' : 'DEBUG',
2220 'handlers' : ['hand1'],
2221 },
2222 'compiler.lexer' : {
2223 },
2224 },
2225 'root' : {
2226 'level' : 'WARNING',
2227 },
2228 }
2229
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002230 # config8a disables existing loggers
2231 config8a = {
2232 'version': 1,
2233 'disable_existing_loggers' : True,
2234 'formatters': {
2235 'form1' : {
2236 'format' : '%(levelname)s ++ %(message)s',
2237 },
2238 },
2239 'handlers' : {
2240 'hand1' : {
2241 'class' : 'logging.StreamHandler',
2242 'formatter' : 'form1',
2243 'level' : 'NOTSET',
2244 'stream' : 'ext://sys.stdout',
2245 },
2246 },
2247 'loggers' : {
2248 'compiler' : {
2249 'level' : 'DEBUG',
2250 'handlers' : ['hand1'],
2251 },
2252 'compiler.lexer' : {
2253 },
2254 },
2255 'root' : {
2256 'level' : 'WARNING',
2257 },
2258 }
2259
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002260 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002261 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002262 'formatters': {
2263 'form1' : {
2264 'format' : '%(levelname)s ++ %(message)s',
2265 },
2266 },
2267 'handlers' : {
2268 'hand1' : {
2269 'class' : 'logging.StreamHandler',
2270 'formatter' : 'form1',
2271 'level' : 'WARNING',
2272 'stream' : 'ext://sys.stdout',
2273 },
2274 },
2275 'loggers' : {
2276 'compiler.parser' : {
2277 'level' : 'WARNING',
2278 'handlers' : ['hand1'],
2279 },
2280 },
2281 'root' : {
2282 'level' : 'NOTSET',
2283 },
2284 }
2285
2286 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002287 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002288 'incremental' : True,
2289 'handlers' : {
2290 'hand1' : {
2291 'level' : 'WARNING',
2292 },
2293 },
2294 'loggers' : {
2295 'compiler.parser' : {
2296 'level' : 'INFO',
2297 },
2298 },
2299 }
2300
2301 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002302 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002303 'incremental' : True,
2304 'handlers' : {
2305 'hand1' : {
2306 'level' : 'INFO',
2307 },
2308 },
2309 'loggers' : {
2310 'compiler.parser' : {
2311 'level' : 'INFO',
2312 },
2313 },
2314 }
2315
2316 #As config1 but with a filter added
2317 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002318 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002319 'formatters': {
2320 'form1' : {
2321 'format' : '%(levelname)s ++ %(message)s',
2322 },
2323 },
2324 'filters' : {
2325 'filt1' : {
2326 'name' : 'compiler.parser',
2327 },
2328 },
2329 'handlers' : {
2330 'hand1' : {
2331 'class' : 'logging.StreamHandler',
2332 'formatter' : 'form1',
2333 'level' : 'NOTSET',
2334 'stream' : 'ext://sys.stdout',
2335 'filters' : ['filt1'],
2336 },
2337 },
2338 'loggers' : {
2339 'compiler.parser' : {
2340 'level' : 'DEBUG',
2341 'filters' : ['filt1'],
2342 },
2343 },
2344 'root' : {
2345 'level' : 'WARNING',
2346 'handlers' : ['hand1'],
2347 },
2348 }
2349
2350 #As config1 but using cfg:// references
2351 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002352 'version': 1,
2353 'true_formatters': {
2354 'form1' : {
2355 'format' : '%(levelname)s ++ %(message)s',
2356 },
2357 },
2358 'handler_configs': {
2359 'hand1' : {
2360 'class' : 'logging.StreamHandler',
2361 'formatter' : 'form1',
2362 'level' : 'NOTSET',
2363 'stream' : 'ext://sys.stdout',
2364 },
2365 },
2366 'formatters' : 'cfg://true_formatters',
2367 'handlers' : {
2368 'hand1' : 'cfg://handler_configs[hand1]',
2369 },
2370 'loggers' : {
2371 'compiler.parser' : {
2372 'level' : 'DEBUG',
2373 'handlers' : ['hand1'],
2374 },
2375 },
2376 'root' : {
2377 'level' : 'WARNING',
2378 },
2379 }
2380
2381 #As config11 but missing the version key
2382 config12 = {
2383 'true_formatters': {
2384 'form1' : {
2385 'format' : '%(levelname)s ++ %(message)s',
2386 },
2387 },
2388 'handler_configs': {
2389 'hand1' : {
2390 'class' : 'logging.StreamHandler',
2391 'formatter' : 'form1',
2392 'level' : 'NOTSET',
2393 'stream' : 'ext://sys.stdout',
2394 },
2395 },
2396 'formatters' : 'cfg://true_formatters',
2397 'handlers' : {
2398 'hand1' : 'cfg://handler_configs[hand1]',
2399 },
2400 'loggers' : {
2401 'compiler.parser' : {
2402 'level' : 'DEBUG',
2403 'handlers' : ['hand1'],
2404 },
2405 },
2406 'root' : {
2407 'level' : 'WARNING',
2408 },
2409 }
2410
2411 #As config11 but using an unsupported version
2412 config13 = {
2413 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002414 'true_formatters': {
2415 'form1' : {
2416 'format' : '%(levelname)s ++ %(message)s',
2417 },
2418 },
2419 'handler_configs': {
2420 'hand1' : {
2421 'class' : 'logging.StreamHandler',
2422 'formatter' : 'form1',
2423 'level' : 'NOTSET',
2424 'stream' : 'ext://sys.stdout',
2425 },
2426 },
2427 'formatters' : 'cfg://true_formatters',
2428 'handlers' : {
2429 'hand1' : 'cfg://handler_configs[hand1]',
2430 },
2431 'loggers' : {
2432 'compiler.parser' : {
2433 'level' : 'DEBUG',
2434 'handlers' : ['hand1'],
2435 },
2436 },
2437 'root' : {
2438 'level' : 'WARNING',
2439 },
2440 }
2441
Vinay Sajip8d270232012-11-15 14:20:18 +00002442 # As config0, but with properties
2443 config14 = {
2444 'version': 1,
2445 'formatters': {
2446 'form1' : {
2447 'format' : '%(levelname)s ++ %(message)s',
2448 },
2449 },
2450 'handlers' : {
2451 'hand1' : {
2452 'class' : 'logging.StreamHandler',
2453 'formatter' : 'form1',
2454 'level' : 'NOTSET',
2455 'stream' : 'ext://sys.stdout',
2456 '.': {
2457 'foo': 'bar',
2458 'terminator': '!\n',
2459 }
2460 },
2461 },
2462 'root' : {
2463 'level' : 'WARNING',
2464 'handlers' : ['hand1'],
2465 },
2466 }
2467
Vinay Sajip3f885b52013-03-22 15:19:54 +00002468 out_of_order = {
2469 "version": 1,
2470 "formatters": {
2471 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002472 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2473 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002474 }
2475 },
2476 "handlers": {
2477 "fileGlobal": {
2478 "class": "logging.StreamHandler",
2479 "level": "DEBUG",
2480 "formatter": "mySimpleFormatter"
2481 },
2482 "bufferGlobal": {
2483 "class": "logging.handlers.MemoryHandler",
2484 "capacity": 5,
2485 "formatter": "mySimpleFormatter",
2486 "target": "fileGlobal",
2487 "level": "DEBUG"
2488 }
2489 },
2490 "loggers": {
2491 "mymodule": {
2492 "level": "DEBUG",
2493 "handlers": ["bufferGlobal"],
2494 "propagate": "true"
2495 }
2496 }
2497 }
2498
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002499 def apply_config(self, conf):
2500 logging.config.dictConfig(conf)
2501
2502 def test_config0_ok(self):
2503 # A simple config which overrides the default settings.
2504 with captured_stdout() as output:
2505 self.apply_config(self.config0)
2506 logger = logging.getLogger()
2507 # Won't output anything
2508 logger.info(self.next_message())
2509 # Outputs a message
2510 logger.error(self.next_message())
2511 self.assert_log_lines([
2512 ('ERROR', '2'),
2513 ], stream=output)
2514 # Original logger output is empty.
2515 self.assert_log_lines([])
2516
2517 def test_config1_ok(self, config=config1):
2518 # A config defining a sub-parser as well.
2519 with captured_stdout() as output:
2520 self.apply_config(config)
2521 logger = logging.getLogger("compiler.parser")
2522 # Both will output a message
2523 logger.info(self.next_message())
2524 logger.error(self.next_message())
2525 self.assert_log_lines([
2526 ('INFO', '1'),
2527 ('ERROR', '2'),
2528 ], stream=output)
2529 # Original logger output is empty.
2530 self.assert_log_lines([])
2531
2532 def test_config2_failure(self):
2533 # A simple config which overrides the default settings.
2534 self.assertRaises(Exception, self.apply_config, self.config2)
2535
2536 def test_config2a_failure(self):
2537 # A simple config which overrides the default settings.
2538 self.assertRaises(Exception, self.apply_config, self.config2a)
2539
2540 def test_config2b_failure(self):
2541 # A simple config which overrides the default settings.
2542 self.assertRaises(Exception, self.apply_config, self.config2b)
2543
2544 def test_config3_failure(self):
2545 # A simple config which overrides the default settings.
2546 self.assertRaises(Exception, self.apply_config, self.config3)
2547
2548 def test_config4_ok(self):
2549 # A config specifying a custom formatter class.
2550 with captured_stdout() as output:
2551 self.apply_config(self.config4)
2552 #logger = logging.getLogger()
2553 try:
2554 raise RuntimeError()
2555 except RuntimeError:
2556 logging.exception("just testing")
2557 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002558 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002559 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2560 # Original logger output is empty
2561 self.assert_log_lines([])
2562
2563 def test_config4a_ok(self):
2564 # A config specifying a custom formatter class.
2565 with captured_stdout() as output:
2566 self.apply_config(self.config4a)
2567 #logger = logging.getLogger()
2568 try:
2569 raise RuntimeError()
2570 except RuntimeError:
2571 logging.exception("just testing")
2572 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002573 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002574 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2575 # Original logger output is empty
2576 self.assert_log_lines([])
2577
2578 def test_config5_ok(self):
2579 self.test_config1_ok(config=self.config5)
2580
2581 def test_config6_failure(self):
2582 self.assertRaises(Exception, self.apply_config, self.config6)
2583
2584 def test_config7_ok(self):
2585 with captured_stdout() as output:
2586 self.apply_config(self.config1)
2587 logger = logging.getLogger("compiler.parser")
2588 # Both will output a message
2589 logger.info(self.next_message())
2590 logger.error(self.next_message())
2591 self.assert_log_lines([
2592 ('INFO', '1'),
2593 ('ERROR', '2'),
2594 ], stream=output)
2595 # Original logger output is empty.
2596 self.assert_log_lines([])
2597 with captured_stdout() as output:
2598 self.apply_config(self.config7)
2599 logger = logging.getLogger("compiler.parser")
2600 self.assertTrue(logger.disabled)
2601 logger = logging.getLogger("compiler.lexer")
2602 # Both will output a message
2603 logger.info(self.next_message())
2604 logger.error(self.next_message())
2605 self.assert_log_lines([
2606 ('INFO', '3'),
2607 ('ERROR', '4'),
2608 ], stream=output)
2609 # Original logger output is empty.
2610 self.assert_log_lines([])
2611
2612 #Same as test_config_7_ok but don't disable old loggers.
2613 def test_config_8_ok(self):
2614 with captured_stdout() as output:
2615 self.apply_config(self.config1)
2616 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002617 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002618 logger.info(self.next_message())
2619 logger.error(self.next_message())
2620 self.assert_log_lines([
2621 ('INFO', '1'),
2622 ('ERROR', '2'),
2623 ], stream=output)
2624 # Original logger output is empty.
2625 self.assert_log_lines([])
2626 with captured_stdout() as output:
2627 self.apply_config(self.config8)
2628 logger = logging.getLogger("compiler.parser")
2629 self.assertFalse(logger.disabled)
2630 # Both will output a message
2631 logger.info(self.next_message())
2632 logger.error(self.next_message())
2633 logger = logging.getLogger("compiler.lexer")
2634 # Both will output a message
2635 logger.info(self.next_message())
2636 logger.error(self.next_message())
2637 self.assert_log_lines([
2638 ('INFO', '3'),
2639 ('ERROR', '4'),
2640 ('INFO', '5'),
2641 ('ERROR', '6'),
2642 ], stream=output)
2643 # Original logger output is empty.
2644 self.assert_log_lines([])
2645
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002646 def test_config_8a_ok(self):
2647 with captured_stdout() as output:
2648 self.apply_config(self.config1a)
2649 logger = logging.getLogger("compiler.parser")
2650 # See issue #11424. compiler-hyphenated sorts
2651 # between compiler and compiler.xyz and this
2652 # was preventing compiler.xyz from being included
2653 # in the child loggers of compiler because of an
2654 # overzealous loop termination condition.
2655 hyphenated = logging.getLogger('compiler-hyphenated')
2656 # All will output a message
2657 logger.info(self.next_message())
2658 logger.error(self.next_message())
2659 hyphenated.critical(self.next_message())
2660 self.assert_log_lines([
2661 ('INFO', '1'),
2662 ('ERROR', '2'),
2663 ('CRITICAL', '3'),
2664 ], stream=output)
2665 # Original logger output is empty.
2666 self.assert_log_lines([])
2667 with captured_stdout() as output:
2668 self.apply_config(self.config8a)
2669 logger = logging.getLogger("compiler.parser")
2670 self.assertFalse(logger.disabled)
2671 # Both will output a message
2672 logger.info(self.next_message())
2673 logger.error(self.next_message())
2674 logger = logging.getLogger("compiler.lexer")
2675 # Both will output a message
2676 logger.info(self.next_message())
2677 logger.error(self.next_message())
2678 # Will not appear
2679 hyphenated.critical(self.next_message())
2680 self.assert_log_lines([
2681 ('INFO', '4'),
2682 ('ERROR', '5'),
2683 ('INFO', '6'),
2684 ('ERROR', '7'),
2685 ], stream=output)
2686 # Original logger output is empty.
2687 self.assert_log_lines([])
2688
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002689 def test_config_9_ok(self):
2690 with captured_stdout() as output:
2691 self.apply_config(self.config9)
2692 logger = logging.getLogger("compiler.parser")
2693 #Nothing will be output since both handler and logger are set to WARNING
2694 logger.info(self.next_message())
2695 self.assert_log_lines([], stream=output)
2696 self.apply_config(self.config9a)
2697 #Nothing will be output since both handler is still set to WARNING
2698 logger.info(self.next_message())
2699 self.assert_log_lines([], stream=output)
2700 self.apply_config(self.config9b)
2701 #Message should now be output
2702 logger.info(self.next_message())
2703 self.assert_log_lines([
2704 ('INFO', '3'),
2705 ], stream=output)
2706
2707 def test_config_10_ok(self):
2708 with captured_stdout() as output:
2709 self.apply_config(self.config10)
2710 logger = logging.getLogger("compiler.parser")
2711 logger.warning(self.next_message())
2712 logger = logging.getLogger('compiler')
2713 #Not output, because filtered
2714 logger.warning(self.next_message())
2715 logger = logging.getLogger('compiler.lexer')
2716 #Not output, because filtered
2717 logger.warning(self.next_message())
2718 logger = logging.getLogger("compiler.parser.codegen")
2719 #Output, as not filtered
2720 logger.error(self.next_message())
2721 self.assert_log_lines([
2722 ('WARNING', '1'),
2723 ('ERROR', '4'),
2724 ], stream=output)
2725
2726 def test_config11_ok(self):
2727 self.test_config1_ok(self.config11)
2728
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002729 def test_config12_failure(self):
2730 self.assertRaises(Exception, self.apply_config, self.config12)
2731
2732 def test_config13_failure(self):
2733 self.assertRaises(Exception, self.apply_config, self.config13)
2734
Vinay Sajip8d270232012-11-15 14:20:18 +00002735 def test_config14_ok(self):
2736 with captured_stdout() as output:
2737 self.apply_config(self.config14)
2738 h = logging._handlers['hand1']
2739 self.assertEqual(h.foo, 'bar')
2740 self.assertEqual(h.terminator, '!\n')
2741 logging.warning('Exclamation')
2742 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2743
Victor Stinner45df8202010-04-28 22:31:17 +00002744 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002745 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002746 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002747 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002748 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002749 t.start()
2750 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002751 # Now get the port allocated
2752 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002753 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002754 try:
2755 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2756 sock.settimeout(2.0)
2757 sock.connect(('localhost', port))
2758
2759 slen = struct.pack('>L', len(text))
2760 s = slen + text
2761 sentsofar = 0
2762 left = len(s)
2763 while left > 0:
2764 sent = sock.send(s[sentsofar:])
2765 sentsofar += sent
2766 left -= sent
2767 sock.close()
2768 finally:
2769 t.ready.wait(2.0)
2770 logging.config.stopListening()
2771 t.join(2.0)
2772
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002773 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002774 def test_listen_config_10_ok(self):
2775 with captured_stdout() as output:
2776 self.setup_via_listener(json.dumps(self.config10))
2777 logger = logging.getLogger("compiler.parser")
2778 logger.warning(self.next_message())
2779 logger = logging.getLogger('compiler')
2780 #Not output, because filtered
2781 logger.warning(self.next_message())
2782 logger = logging.getLogger('compiler.lexer')
2783 #Not output, because filtered
2784 logger.warning(self.next_message())
2785 logger = logging.getLogger("compiler.parser.codegen")
2786 #Output, as not filtered
2787 logger.error(self.next_message())
2788 self.assert_log_lines([
2789 ('WARNING', '1'),
2790 ('ERROR', '4'),
2791 ], stream=output)
2792
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002793 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002794 def test_listen_config_1_ok(self):
2795 with captured_stdout() as output:
2796 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2797 logger = logging.getLogger("compiler.parser")
2798 # Both will output a message
2799 logger.info(self.next_message())
2800 logger.error(self.next_message())
2801 self.assert_log_lines([
2802 ('INFO', '1'),
2803 ('ERROR', '2'),
2804 ], stream=output)
2805 # Original logger output is empty.
2806 self.assert_log_lines([])
2807
Vinay Sajip4ded5512012-10-02 15:56:16 +01002808 @unittest.skipUnless(threading, 'Threading required for this test.')
2809 def test_listen_verify(self):
2810
2811 def verify_fail(stuff):
2812 return None
2813
2814 def verify_reverse(stuff):
2815 return stuff[::-1]
2816
2817 logger = logging.getLogger("compiler.parser")
2818 to_send = textwrap.dedent(ConfigFileTest.config1)
2819 # First, specify a verification function that will fail.
2820 # We expect to see no output, since our configuration
2821 # never took effect.
2822 with captured_stdout() as output:
2823 self.setup_via_listener(to_send, verify_fail)
2824 # Both will output a message
2825 logger.info(self.next_message())
2826 logger.error(self.next_message())
2827 self.assert_log_lines([], stream=output)
2828 # Original logger output has the stuff we logged.
2829 self.assert_log_lines([
2830 ('INFO', '1'),
2831 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002832 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002833
2834 # Now, perform no verification. Our configuration
2835 # should take effect.
2836
2837 with captured_stdout() as output:
2838 self.setup_via_listener(to_send) # no verify callable specified
2839 logger = logging.getLogger("compiler.parser")
2840 # Both will output a message
2841 logger.info(self.next_message())
2842 logger.error(self.next_message())
2843 self.assert_log_lines([
2844 ('INFO', '3'),
2845 ('ERROR', '4'),
2846 ], stream=output)
2847 # Original logger output still has the stuff we logged before.
2848 self.assert_log_lines([
2849 ('INFO', '1'),
2850 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002851 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002852
2853 # Now, perform verification which transforms the bytes.
2854
2855 with captured_stdout() as output:
2856 self.setup_via_listener(to_send[::-1], verify_reverse)
2857 logger = logging.getLogger("compiler.parser")
2858 # Both will output a message
2859 logger.info(self.next_message())
2860 logger.error(self.next_message())
2861 self.assert_log_lines([
2862 ('INFO', '5'),
2863 ('ERROR', '6'),
2864 ], stream=output)
2865 # Original logger output still has the stuff we logged before.
2866 self.assert_log_lines([
2867 ('INFO', '1'),
2868 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002869 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002870
Vinay Sajip3f885b52013-03-22 15:19:54 +00002871 def test_out_of_order(self):
2872 self.apply_config(self.out_of_order)
2873 handler = logging.getLogger('mymodule').handlers[0]
2874 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002875 self.assertIsInstance(handler.formatter._style,
2876 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002877
Vinay Sajip373baef2011-04-26 20:05:24 +01002878 def test_baseconfig(self):
2879 d = {
2880 'atuple': (1, 2, 3),
2881 'alist': ['a', 'b', 'c'],
2882 'adict': {'d': 'e', 'f': 3 },
2883 'nest1': ('g', ('h', 'i'), 'j'),
2884 'nest2': ['k', ['l', 'm'], 'n'],
2885 'nest3': ['o', 'cfg://alist', 'p'],
2886 }
2887 bc = logging.config.BaseConfigurator(d)
2888 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2889 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2890 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2891 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2892 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2893 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2894 v = bc.convert('cfg://nest3')
2895 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2896 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2897 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2898 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002899
2900class ManagerTest(BaseTest):
2901 def test_manager_loggerclass(self):
2902 logged = []
2903
2904 class MyLogger(logging.Logger):
2905 def _log(self, level, msg, args, exc_info=None, extra=None):
2906 logged.append(msg)
2907
2908 man = logging.Manager(None)
2909 self.assertRaises(TypeError, man.setLoggerClass, int)
2910 man.setLoggerClass(MyLogger)
2911 logger = man.getLogger('test')
2912 logger.warning('should appear in logged')
2913 logging.warning('should not appear in logged')
2914
2915 self.assertEqual(logged, ['should appear in logged'])
2916
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002917 def test_set_log_record_factory(self):
2918 man = logging.Manager(None)
2919 expected = object()
2920 man.setLogRecordFactory(expected)
2921 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002922
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002923class ChildLoggerTest(BaseTest):
2924 def test_child_loggers(self):
2925 r = logging.getLogger()
2926 l1 = logging.getLogger('abc')
2927 l2 = logging.getLogger('def.ghi')
2928 c1 = r.getChild('xyz')
2929 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002930 self.assertIs(c1, logging.getLogger('xyz'))
2931 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002932 c1 = l1.getChild('def')
2933 c2 = c1.getChild('ghi')
2934 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002935 self.assertIs(c1, logging.getLogger('abc.def'))
2936 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2937 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002938
2939
Vinay Sajip6fac8172010-10-19 20:44:14 +00002940class DerivedLogRecord(logging.LogRecord):
2941 pass
2942
Vinay Sajip61561522010-12-03 11:50:38 +00002943class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002944
2945 def setUp(self):
2946 class CheckingFilter(logging.Filter):
2947 def __init__(self, cls):
2948 self.cls = cls
2949
2950 def filter(self, record):
2951 t = type(record)
2952 if t is not self.cls:
2953 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2954 self.cls)
2955 raise TypeError(msg)
2956 return True
2957
2958 BaseTest.setUp(self)
2959 self.filter = CheckingFilter(DerivedLogRecord)
2960 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002961 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002962
2963 def tearDown(self):
2964 self.root_logger.removeFilter(self.filter)
2965 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002966 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002967
2968 def test_logrecord_class(self):
2969 self.assertRaises(TypeError, self.root_logger.warning,
2970 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002971 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002972 self.root_logger.error(self.next_message())
2973 self.assert_log_lines([
2974 ('root', 'ERROR', '2'),
2975 ])
2976
2977
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002978class QueueHandlerTest(BaseTest):
2979 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002980 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002981
2982 def setUp(self):
2983 BaseTest.setUp(self)
2984 self.queue = queue.Queue(-1)
2985 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2986 self.que_logger = logging.getLogger('que')
2987 self.que_logger.propagate = False
2988 self.que_logger.setLevel(logging.WARNING)
2989 self.que_logger.addHandler(self.que_hdlr)
2990
2991 def tearDown(self):
2992 self.que_hdlr.close()
2993 BaseTest.tearDown(self)
2994
2995 def test_queue_handler(self):
2996 self.que_logger.debug(self.next_message())
2997 self.assertRaises(queue.Empty, self.queue.get_nowait)
2998 self.que_logger.info(self.next_message())
2999 self.assertRaises(queue.Empty, self.queue.get_nowait)
3000 msg = self.next_message()
3001 self.que_logger.warning(msg)
3002 data = self.queue.get_nowait()
3003 self.assertTrue(isinstance(data, logging.LogRecord))
3004 self.assertEqual(data.name, self.que_logger.name)
3005 self.assertEqual((data.msg, data.args), (msg, None))
3006
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003007 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3008 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003009 def test_queue_listener(self):
3010 handler = TestHandler(Matcher())
3011 listener = logging.handlers.QueueListener(self.queue, handler)
3012 listener.start()
3013 try:
3014 self.que_logger.warning(self.next_message())
3015 self.que_logger.error(self.next_message())
3016 self.que_logger.critical(self.next_message())
3017 finally:
3018 listener.stop()
3019 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3020 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3021 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3022
Vinay Sajip37eb3382011-04-26 20:26:41 +01003023ZERO = datetime.timedelta(0)
3024
3025class UTC(datetime.tzinfo):
3026 def utcoffset(self, dt):
3027 return ZERO
3028
3029 dst = utcoffset
3030
3031 def tzname(self, dt):
3032 return 'UTC'
3033
3034utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003035
Vinay Sajipa39c5712010-10-25 13:57:39 +00003036class FormatterTest(unittest.TestCase):
3037 def setUp(self):
3038 self.common = {
3039 'name': 'formatter.test',
3040 'level': logging.DEBUG,
3041 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3042 'lineno': 42,
3043 'exc_info': None,
3044 'func': None,
3045 'msg': 'Message with %d %s',
3046 'args': (2, 'placeholders'),
3047 }
3048 self.variants = {
3049 }
3050
3051 def get_record(self, name=None):
3052 result = dict(self.common)
3053 if name is not None:
3054 result.update(self.variants[name])
3055 return logging.makeLogRecord(result)
3056
3057 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003058 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003059 r = self.get_record()
3060 f = logging.Formatter('${%(message)s}')
3061 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3062 f = logging.Formatter('%(random)s')
3063 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003064 self.assertFalse(f.usesTime())
3065 f = logging.Formatter('%(asctime)s')
3066 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003067 f = logging.Formatter('%(asctime)-15s')
3068 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003069 f = logging.Formatter('asctime')
3070 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003071
3072 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003073 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003074 r = self.get_record()
3075 f = logging.Formatter('$%{message}%$', style='{')
3076 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3077 f = logging.Formatter('{random}', style='{')
3078 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003079 self.assertFalse(f.usesTime())
3080 f = logging.Formatter('{asctime}', style='{')
3081 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003082 f = logging.Formatter('{asctime!s:15}', style='{')
3083 self.assertTrue(f.usesTime())
3084 f = logging.Formatter('{asctime:15}', style='{')
3085 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003086 f = logging.Formatter('asctime', style='{')
3087 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003088
3089 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003090 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003091 r = self.get_record()
3092 f = logging.Formatter('$message', style='$')
3093 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3094 f = logging.Formatter('$$%${message}%$$', style='$')
3095 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3096 f = logging.Formatter('${random}', style='$')
3097 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003098 self.assertFalse(f.usesTime())
3099 f = logging.Formatter('${asctime}', style='$')
3100 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003101 f = logging.Formatter('${asctime', style='$')
3102 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003103 f = logging.Formatter('$asctime', style='$')
3104 self.assertTrue(f.usesTime())
3105 f = logging.Formatter('asctime', style='$')
3106 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003107
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003108 def test_invalid_style(self):
3109 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3110
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003111 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003112 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003113 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3114 # We use None to indicate we want the local timezone
3115 # We're essentially converting a UTC time to local time
3116 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003117 r.msecs = 123
3118 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003119 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003120 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3121 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003122 f.format(r)
3123 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3124
3125class TestBufferingFormatter(logging.BufferingFormatter):
3126 def formatHeader(self, records):
3127 return '[(%d)' % len(records)
3128
3129 def formatFooter(self, records):
3130 return '(%d)]' % len(records)
3131
3132class BufferingFormatterTest(unittest.TestCase):
3133 def setUp(self):
3134 self.records = [
3135 logging.makeLogRecord({'msg': 'one'}),
3136 logging.makeLogRecord({'msg': 'two'}),
3137 ]
3138
3139 def test_default(self):
3140 f = logging.BufferingFormatter()
3141 self.assertEqual('', f.format([]))
3142 self.assertEqual('onetwo', f.format(self.records))
3143
3144 def test_custom(self):
3145 f = TestBufferingFormatter()
3146 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3147 lf = logging.Formatter('<%(message)s>')
3148 f = TestBufferingFormatter(lf)
3149 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003150
3151class ExceptionTest(BaseTest):
3152 def test_formatting(self):
3153 r = self.root_logger
3154 h = RecordingHandler()
3155 r.addHandler(h)
3156 try:
3157 raise RuntimeError('deliberate mistake')
3158 except:
3159 logging.exception('failed', stack_info=True)
3160 r.removeHandler(h)
3161 h.close()
3162 r = h.records[0]
3163 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3164 'call last):\n'))
3165 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3166 'deliberate mistake'))
3167 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3168 'call last):\n'))
3169 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3170 'stack_info=True)'))
3171
3172
Vinay Sajip5a27d402010-12-10 11:42:57 +00003173class LastResortTest(BaseTest):
3174 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003175 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003176 root = self.root_logger
3177 root.removeHandler(self.root_hdlr)
3178 old_stderr = sys.stderr
3179 old_lastresort = logging.lastResort
3180 old_raise_exceptions = logging.raiseExceptions
3181 try:
3182 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003183 root.debug('This should not appear')
3184 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003185 root.warning('This is your final chance!')
3186 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3187 #No handlers and no last resort, so 'No handlers' message
3188 logging.lastResort = None
3189 sys.stderr = sio = io.StringIO()
3190 root.warning('This is your final chance!')
3191 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3192 # 'No handlers' message only printed once
3193 sys.stderr = sio = io.StringIO()
3194 root.warning('This is your final chance!')
3195 self.assertEqual(sio.getvalue(), '')
3196 root.manager.emittedNoHandlerWarning = False
3197 #If raiseExceptions is False, no message is printed
3198 logging.raiseExceptions = False
3199 sys.stderr = sio = io.StringIO()
3200 root.warning('This is your final chance!')
3201 self.assertEqual(sio.getvalue(), '')
3202 finally:
3203 sys.stderr = old_stderr
3204 root.addHandler(self.root_hdlr)
3205 logging.lastResort = old_lastresort
3206 logging.raiseExceptions = old_raise_exceptions
3207
3208
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003209class FakeHandler:
3210
3211 def __init__(self, identifier, called):
3212 for method in ('acquire', 'flush', 'close', 'release'):
3213 setattr(self, method, self.record_call(identifier, method, called))
3214
3215 def record_call(self, identifier, method_name, called):
3216 def inner():
3217 called.append('{} - {}'.format(identifier, method_name))
3218 return inner
3219
3220
3221class RecordingHandler(logging.NullHandler):
3222
3223 def __init__(self, *args, **kwargs):
3224 super(RecordingHandler, self).__init__(*args, **kwargs)
3225 self.records = []
3226
3227 def handle(self, record):
3228 """Keep track of all the emitted records."""
3229 self.records.append(record)
3230
3231
3232class ShutdownTest(BaseTest):
3233
Vinay Sajip5e66b162011-04-20 15:41:14 +01003234 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003235
3236 def setUp(self):
3237 super(ShutdownTest, self).setUp()
3238 self.called = []
3239
3240 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003241 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003242
3243 def raise_error(self, error):
3244 def inner():
3245 raise error()
3246 return inner
3247
3248 def test_no_failure(self):
3249 # create some fake handlers
3250 handler0 = FakeHandler(0, self.called)
3251 handler1 = FakeHandler(1, self.called)
3252 handler2 = FakeHandler(2, self.called)
3253
3254 # create live weakref to those handlers
3255 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3256
3257 logging.shutdown(handlerList=list(handlers))
3258
3259 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3260 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3261 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3262 self.assertEqual(expected, self.called)
3263
3264 def _test_with_failure_in_method(self, method, error):
3265 handler = FakeHandler(0, self.called)
3266 setattr(handler, method, self.raise_error(error))
3267 handlers = [logging.weakref.ref(handler)]
3268
3269 logging.shutdown(handlerList=list(handlers))
3270
3271 self.assertEqual('0 - release', self.called[-1])
3272
3273 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003274 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003275
3276 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003277 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003278
3279 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003280 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003281
3282 def test_with_valueerror_in_acquire(self):
3283 self._test_with_failure_in_method('acquire', ValueError)
3284
3285 def test_with_valueerror_in_flush(self):
3286 self._test_with_failure_in_method('flush', ValueError)
3287
3288 def test_with_valueerror_in_close(self):
3289 self._test_with_failure_in_method('close', ValueError)
3290
3291 def test_with_other_error_in_acquire_without_raise(self):
3292 logging.raiseExceptions = False
3293 self._test_with_failure_in_method('acquire', IndexError)
3294
3295 def test_with_other_error_in_flush_without_raise(self):
3296 logging.raiseExceptions = False
3297 self._test_with_failure_in_method('flush', IndexError)
3298
3299 def test_with_other_error_in_close_without_raise(self):
3300 logging.raiseExceptions = False
3301 self._test_with_failure_in_method('close', IndexError)
3302
3303 def test_with_other_error_in_acquire_with_raise(self):
3304 logging.raiseExceptions = True
3305 self.assertRaises(IndexError, self._test_with_failure_in_method,
3306 'acquire', IndexError)
3307
3308 def test_with_other_error_in_flush_with_raise(self):
3309 logging.raiseExceptions = True
3310 self.assertRaises(IndexError, self._test_with_failure_in_method,
3311 'flush', IndexError)
3312
3313 def test_with_other_error_in_close_with_raise(self):
3314 logging.raiseExceptions = True
3315 self.assertRaises(IndexError, self._test_with_failure_in_method,
3316 'close', IndexError)
3317
3318
3319class ModuleLevelMiscTest(BaseTest):
3320
Vinay Sajip5e66b162011-04-20 15:41:14 +01003321 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003322
3323 def test_disable(self):
3324 old_disable = logging.root.manager.disable
3325 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003326 self.assertEqual(old_disable, 0)
3327 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003328
3329 logging.disable(83)
3330 self.assertEqual(logging.root.manager.disable, 83)
3331
3332 def _test_log(self, method, level=None):
3333 called = []
3334 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003335 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003336
3337 recording = RecordingHandler()
3338 logging.root.addHandler(recording)
3339
3340 log_method = getattr(logging, method)
3341 if level is not None:
3342 log_method(level, "test me: %r", recording)
3343 else:
3344 log_method("test me: %r", recording)
3345
3346 self.assertEqual(len(recording.records), 1)
3347 record = recording.records[0]
3348 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3349
3350 expected_level = level if level is not None else getattr(logging, method.upper())
3351 self.assertEqual(record.levelno, expected_level)
3352
3353 # basicConfig was not called!
3354 self.assertEqual(called, [])
3355
3356 def test_log(self):
3357 self._test_log('log', logging.ERROR)
3358
3359 def test_debug(self):
3360 self._test_log('debug')
3361
3362 def test_info(self):
3363 self._test_log('info')
3364
3365 def test_warning(self):
3366 self._test_log('warning')
3367
3368 def test_error(self):
3369 self._test_log('error')
3370
3371 def test_critical(self):
3372 self._test_log('critical')
3373
3374 def test_set_logger_class(self):
3375 self.assertRaises(TypeError, logging.setLoggerClass, object)
3376
3377 class MyLogger(logging.Logger):
3378 pass
3379
3380 logging.setLoggerClass(MyLogger)
3381 self.assertEqual(logging.getLoggerClass(), MyLogger)
3382
3383 logging.setLoggerClass(logging.Logger)
3384 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3385
Antoine Pitrou712cb732013-12-21 15:51:54 +01003386 def test_logging_at_shutdown(self):
3387 # Issue #20037
3388 code = """if 1:
3389 import logging
3390
3391 class A:
3392 def __del__(self):
3393 try:
3394 raise ValueError("some error")
3395 except Exception:
3396 logging.exception("exception in __del__")
3397
3398 a = A()"""
3399 rc, out, err = assert_python_ok("-c", code)
3400 err = err.decode()
3401 self.assertIn("exception in __del__", err)
3402 self.assertIn("ValueError: some error", err)
3403
3404
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003405class LogRecordTest(BaseTest):
3406 def test_str_rep(self):
3407 r = logging.makeLogRecord({})
3408 s = str(r)
3409 self.assertTrue(s.startswith('<LogRecord: '))
3410 self.assertTrue(s.endswith('>'))
3411
3412 def test_dict_arg(self):
3413 h = RecordingHandler()
3414 r = logging.getLogger()
3415 r.addHandler(h)
3416 d = {'less' : 'more' }
3417 logging.warning('less is %(less)s', d)
3418 self.assertIs(h.records[0].args, d)
3419 self.assertEqual(h.records[0].message, 'less is more')
3420 r.removeHandler(h)
3421 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003422
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003423 def test_multiprocessing(self):
3424 r = logging.makeLogRecord({})
3425 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003426 try:
3427 import multiprocessing as mp
3428 r = logging.makeLogRecord({})
3429 self.assertEqual(r.processName, mp.current_process().name)
3430 except ImportError:
3431 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003432
3433 def test_optional(self):
3434 r = logging.makeLogRecord({})
3435 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003436 if threading:
3437 NOT_NONE(r.thread)
3438 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003439 NOT_NONE(r.process)
3440 NOT_NONE(r.processName)
3441 log_threads = logging.logThreads
3442 log_processes = logging.logProcesses
3443 log_multiprocessing = logging.logMultiprocessing
3444 try:
3445 logging.logThreads = False
3446 logging.logProcesses = False
3447 logging.logMultiprocessing = False
3448 r = logging.makeLogRecord({})
3449 NONE = self.assertIsNone
3450 NONE(r.thread)
3451 NONE(r.threadName)
3452 NONE(r.process)
3453 NONE(r.processName)
3454 finally:
3455 logging.logThreads = log_threads
3456 logging.logProcesses = log_processes
3457 logging.logMultiprocessing = log_multiprocessing
3458
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003459class BasicConfigTest(unittest.TestCase):
3460
Vinay Sajip95bf5042011-04-20 11:50:56 +01003461 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003462
3463 def setUp(self):
3464 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003465 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003466 self.saved_handlers = logging._handlers.copy()
3467 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003468 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003469 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003470 logging.root.handlers = []
3471
3472 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003473 for h in logging.root.handlers[:]:
3474 logging.root.removeHandler(h)
3475 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003476 super(BasicConfigTest, self).tearDown()
3477
Vinay Sajip3def7e02011-04-20 10:58:06 +01003478 def cleanup(self):
3479 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003480 logging._handlers.clear()
3481 logging._handlers.update(self.saved_handlers)
3482 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003483 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003484
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003485 def test_no_kwargs(self):
3486 logging.basicConfig()
3487
3488 # handler defaults to a StreamHandler to sys.stderr
3489 self.assertEqual(len(logging.root.handlers), 1)
3490 handler = logging.root.handlers[0]
3491 self.assertIsInstance(handler, logging.StreamHandler)
3492 self.assertEqual(handler.stream, sys.stderr)
3493
3494 formatter = handler.formatter
3495 # format defaults to logging.BASIC_FORMAT
3496 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3497 # datefmt defaults to None
3498 self.assertIsNone(formatter.datefmt)
3499 # style defaults to %
3500 self.assertIsInstance(formatter._style, logging.PercentStyle)
3501
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003502 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003503 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003504
Vinay Sajip1fd12022014-01-13 21:59:56 +00003505 def test_strformatstyle(self):
3506 with captured_stdout() as output:
3507 logging.basicConfig(stream=sys.stdout, style="{")
3508 logging.error("Log an error")
3509 sys.stdout.seek(0)
3510 self.assertEqual(output.getvalue().strip(),
3511 "ERROR:root:Log an error")
3512
3513 def test_stringtemplatestyle(self):
3514 with captured_stdout() as output:
3515 logging.basicConfig(stream=sys.stdout, style="$")
3516 logging.error("Log an error")
3517 sys.stdout.seek(0)
3518 self.assertEqual(output.getvalue().strip(),
3519 "ERROR:root:Log an error")
3520
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003521 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003522
3523 def cleanup(h1, h2, fn):
3524 h1.close()
3525 h2.close()
3526 os.remove(fn)
3527
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003528 logging.basicConfig(filename='test.log')
3529
3530 self.assertEqual(len(logging.root.handlers), 1)
3531 handler = logging.root.handlers[0]
3532 self.assertIsInstance(handler, logging.FileHandler)
3533
3534 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003535 self.assertEqual(handler.stream.mode, expected.stream.mode)
3536 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003537 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003538
3539 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003540
3541 def cleanup(h1, h2, fn):
3542 h1.close()
3543 h2.close()
3544 os.remove(fn)
3545
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003546 logging.basicConfig(filename='test.log', filemode='wb')
3547
3548 handler = logging.root.handlers[0]
3549 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003550 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003551 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003552
3553 def test_stream(self):
3554 stream = io.StringIO()
3555 self.addCleanup(stream.close)
3556 logging.basicConfig(stream=stream)
3557
3558 self.assertEqual(len(logging.root.handlers), 1)
3559 handler = logging.root.handlers[0]
3560 self.assertIsInstance(handler, logging.StreamHandler)
3561 self.assertEqual(handler.stream, stream)
3562
3563 def test_format(self):
3564 logging.basicConfig(format='foo')
3565
3566 formatter = logging.root.handlers[0].formatter
3567 self.assertEqual(formatter._style._fmt, 'foo')
3568
3569 def test_datefmt(self):
3570 logging.basicConfig(datefmt='bar')
3571
3572 formatter = logging.root.handlers[0].formatter
3573 self.assertEqual(formatter.datefmt, 'bar')
3574
3575 def test_style(self):
3576 logging.basicConfig(style='$')
3577
3578 formatter = logging.root.handlers[0].formatter
3579 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3580
3581 def test_level(self):
3582 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003583 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003584
3585 logging.basicConfig(level=57)
3586 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003587 # Test that second call has no effect
3588 logging.basicConfig(level=58)
3589 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003590
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003591 def test_incompatible(self):
3592 assertRaises = self.assertRaises
3593 handlers = [logging.StreamHandler()]
3594 stream = sys.stderr
3595 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3596 stream=stream)
3597 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3598 handlers=handlers)
3599 assertRaises(ValueError, logging.basicConfig, stream=stream,
3600 handlers=handlers)
3601
3602 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003603 handlers = [
3604 logging.StreamHandler(),
3605 logging.StreamHandler(sys.stdout),
3606 logging.StreamHandler(),
3607 ]
3608 f = logging.Formatter()
3609 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003610 logging.basicConfig(handlers=handlers)
3611 self.assertIs(handlers[0], logging.root.handlers[0])
3612 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003613 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003614 self.assertIsNotNone(handlers[0].formatter)
3615 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003616 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003617 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3618
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003619 def _test_log(self, method, level=None):
3620 # logging.root has no handlers so basicConfig should be called
3621 called = []
3622
3623 old_basic_config = logging.basicConfig
3624 def my_basic_config(*a, **kw):
3625 old_basic_config()
3626 old_level = logging.root.level
3627 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003628 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003629 called.append((a, kw))
3630
3631 patch(self, logging, 'basicConfig', my_basic_config)
3632
3633 log_method = getattr(logging, method)
3634 if level is not None:
3635 log_method(level, "test me")
3636 else:
3637 log_method("test me")
3638
3639 # basicConfig was called with no arguments
3640 self.assertEqual(called, [((), {})])
3641
3642 def test_log(self):
3643 self._test_log('log', logging.WARNING)
3644
3645 def test_debug(self):
3646 self._test_log('debug')
3647
3648 def test_info(self):
3649 self._test_log('info')
3650
3651 def test_warning(self):
3652 self._test_log('warning')
3653
3654 def test_error(self):
3655 self._test_log('error')
3656
3657 def test_critical(self):
3658 self._test_log('critical')
3659
3660
3661class LoggerAdapterTest(unittest.TestCase):
3662
3663 def setUp(self):
3664 super(LoggerAdapterTest, self).setUp()
3665 old_handler_list = logging._handlerList[:]
3666
3667 self.recording = RecordingHandler()
3668 self.logger = logging.root
3669 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003670 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003671 self.addCleanup(self.recording.close)
3672
3673 def cleanup():
3674 logging._handlerList[:] = old_handler_list
3675
3676 self.addCleanup(cleanup)
3677 self.addCleanup(logging.shutdown)
3678 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3679
3680 def test_exception(self):
3681 msg = 'testing exception: %r'
3682 exc = None
3683 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003684 1 / 0
3685 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003686 exc = e
3687 self.adapter.exception(msg, self.recording)
3688
3689 self.assertEqual(len(self.recording.records), 1)
3690 record = self.recording.records[0]
3691 self.assertEqual(record.levelno, logging.ERROR)
3692 self.assertEqual(record.msg, msg)
3693 self.assertEqual(record.args, (self.recording,))
3694 self.assertEqual(record.exc_info,
3695 (exc.__class__, exc, exc.__traceback__))
3696
3697 def test_critical(self):
3698 msg = 'critical test! %r'
3699 self.adapter.critical(msg, self.recording)
3700
3701 self.assertEqual(len(self.recording.records), 1)
3702 record = self.recording.records[0]
3703 self.assertEqual(record.levelno, logging.CRITICAL)
3704 self.assertEqual(record.msg, msg)
3705 self.assertEqual(record.args, (self.recording,))
3706
3707 def test_is_enabled_for(self):
3708 old_disable = self.adapter.logger.manager.disable
3709 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003710 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3711 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003712 self.assertFalse(self.adapter.isEnabledFor(32))
3713
3714 def test_has_handlers(self):
3715 self.assertTrue(self.adapter.hasHandlers())
3716
3717 for handler in self.logger.handlers:
3718 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003719
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003720 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003721 self.assertFalse(self.adapter.hasHandlers())
3722
3723
3724class LoggerTest(BaseTest):
3725
3726 def setUp(self):
3727 super(LoggerTest, self).setUp()
3728 self.recording = RecordingHandler()
3729 self.logger = logging.Logger(name='blah')
3730 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003731 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003732 self.addCleanup(self.recording.close)
3733 self.addCleanup(logging.shutdown)
3734
3735 def test_set_invalid_level(self):
3736 self.assertRaises(TypeError, self.logger.setLevel, object())
3737
3738 def test_exception(self):
3739 msg = 'testing exception: %r'
3740 exc = None
3741 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003742 1 / 0
3743 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003744 exc = e
3745 self.logger.exception(msg, self.recording)
3746
3747 self.assertEqual(len(self.recording.records), 1)
3748 record = self.recording.records[0]
3749 self.assertEqual(record.levelno, logging.ERROR)
3750 self.assertEqual(record.msg, msg)
3751 self.assertEqual(record.args, (self.recording,))
3752 self.assertEqual(record.exc_info,
3753 (exc.__class__, exc, exc.__traceback__))
3754
3755 def test_log_invalid_level_with_raise(self):
3756 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003757 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003758
3759 logging.raiseExceptions = True
3760 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3761
3762 def test_log_invalid_level_no_raise(self):
3763 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003764 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003765
3766 logging.raiseExceptions = False
3767 self.logger.log('10', 'test message') # no exception happens
3768
3769 def test_find_caller_with_stack_info(self):
3770 called = []
3771 patch(self, logging.traceback, 'print_stack',
3772 lambda f, file: called.append(file.getvalue()))
3773
3774 self.logger.findCaller(stack_info=True)
3775
3776 self.assertEqual(len(called), 1)
3777 self.assertEqual('Stack (most recent call last):\n', called[0])
3778
3779 def test_make_record_with_extra_overwrite(self):
3780 name = 'my record'
3781 level = 13
3782 fn = lno = msg = args = exc_info = func = sinfo = None
3783 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3784 exc_info, func, sinfo)
3785
3786 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3787 extra = {key: 'some value'}
3788 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3789 fn, lno, msg, args, exc_info,
3790 extra=extra, sinfo=sinfo)
3791
3792 def test_make_record_with_extra_no_overwrite(self):
3793 name = 'my record'
3794 level = 13
3795 fn = lno = msg = args = exc_info = func = sinfo = None
3796 extra = {'valid_key': 'some value'}
3797 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3798 exc_info, extra=extra, sinfo=sinfo)
3799 self.assertIn('valid_key', result.__dict__)
3800
3801 def test_has_handlers(self):
3802 self.assertTrue(self.logger.hasHandlers())
3803
3804 for handler in self.logger.handlers:
3805 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003806 self.assertFalse(self.logger.hasHandlers())
3807
3808 def test_has_handlers_no_propagate(self):
3809 child_logger = logging.getLogger('blah.child')
3810 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003811 self.assertFalse(child_logger.hasHandlers())
3812
3813 def test_is_enabled_for(self):
3814 old_disable = self.logger.manager.disable
3815 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003816 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003817 self.assertFalse(self.logger.isEnabledFor(22))
3818
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003819 def test_root_logger_aliases(self):
3820 root = logging.getLogger()
3821 self.assertIs(root, logging.root)
3822 self.assertIs(root, logging.getLogger(None))
3823 self.assertIs(root, logging.getLogger(''))
3824 self.assertIs(root, logging.getLogger('foo').root)
3825 self.assertIs(root, logging.getLogger('foo.bar').root)
3826 self.assertIs(root, logging.getLogger('foo').parent)
3827
3828 self.assertIsNot(root, logging.getLogger('\0'))
3829 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3830
3831 def test_invalid_names(self):
3832 self.assertRaises(TypeError, logging.getLogger, any)
3833 self.assertRaises(TypeError, logging.getLogger, b'foo')
3834
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003835
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003836class BaseFileTest(BaseTest):
3837 "Base class for handler tests that write log files"
3838
3839 def setUp(self):
3840 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003841 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3842 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003843 self.rmfiles = []
3844
3845 def tearDown(self):
3846 for fn in self.rmfiles:
3847 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003848 if os.path.exists(self.fn):
3849 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003850 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003851
3852 def assertLogFile(self, filename):
3853 "Assert a log file is there and register it for deletion"
3854 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003855 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003856 self.rmfiles.append(filename)
3857
3858
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003859class FileHandlerTest(BaseFileTest):
3860 def test_delay(self):
3861 os.unlink(self.fn)
3862 fh = logging.FileHandler(self.fn, delay=True)
3863 self.assertIsNone(fh.stream)
3864 self.assertFalse(os.path.exists(self.fn))
3865 fh.handle(logging.makeLogRecord({}))
3866 self.assertIsNotNone(fh.stream)
3867 self.assertTrue(os.path.exists(self.fn))
3868 fh.close()
3869
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003870class RotatingFileHandlerTest(BaseFileTest):
3871 def next_rec(self):
3872 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3873 self.next_message(), None, None, None)
3874
3875 def test_should_not_rollover(self):
3876 # If maxbytes is zero rollover never occurs
3877 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3878 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003879 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003880
3881 def test_should_rollover(self):
3882 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3883 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003884 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003885
3886 def test_file_created(self):
3887 # checks that the file is created and assumes it was created
3888 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003889 rh = logging.handlers.RotatingFileHandler(self.fn)
3890 rh.emit(self.next_rec())
3891 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003892 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003893
3894 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003895 def namer(name):
3896 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003897 rh = logging.handlers.RotatingFileHandler(
3898 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003899 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003900 rh.emit(self.next_rec())
3901 self.assertLogFile(self.fn)
3902 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003903 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003904 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003905 self.assertLogFile(namer(self.fn + ".2"))
3906 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3907 rh.close()
3908
Eric V. Smith851cad72012-03-11 22:46:04 -07003909 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003910 def test_rotator(self):
3911 def namer(name):
3912 return name + ".gz"
3913
3914 def rotator(source, dest):
3915 with open(source, "rb") as sf:
3916 data = sf.read()
3917 compressed = zlib.compress(data, 9)
3918 with open(dest, "wb") as df:
3919 df.write(compressed)
3920 os.remove(source)
3921
3922 rh = logging.handlers.RotatingFileHandler(
3923 self.fn, backupCount=2, maxBytes=1)
3924 rh.rotator = rotator
3925 rh.namer = namer
3926 m1 = self.next_rec()
3927 rh.emit(m1)
3928 self.assertLogFile(self.fn)
3929 m2 = self.next_rec()
3930 rh.emit(m2)
3931 fn = namer(self.fn + ".1")
3932 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003933 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003934 with open(fn, "rb") as f:
3935 compressed = f.read()
3936 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003937 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003938 rh.emit(self.next_rec())
3939 fn = namer(self.fn + ".2")
3940 self.assertLogFile(fn)
3941 with open(fn, "rb") as f:
3942 compressed = f.read()
3943 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003944 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003945 rh.emit(self.next_rec())
3946 fn = namer(self.fn + ".2")
3947 with open(fn, "rb") as f:
3948 compressed = f.read()
3949 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003950 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003951 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003952 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003953
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003954class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003955 # other test methods added below
3956 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003957 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3958 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003959 fmt = logging.Formatter('%(asctime)s %(message)s')
3960 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003961 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003962 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003963 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003964 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003965 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003966 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003967 fh.close()
3968 # At this point, we should have a recent rotated file which we
3969 # can test for the existence of. However, in practice, on some
3970 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003971 # in time to go to look for the log file. So, we go back a fair
3972 # bit, and stop as soon as we see a rotated file. In theory this
3973 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003974 found = False
3975 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003976 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003977 for secs in range(GO_BACK):
3978 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003979 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3980 found = os.path.exists(fn)
3981 if found:
3982 self.rmfiles.append(fn)
3983 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003984 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3985 if not found:
3986 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003987 dn, fn = os.path.split(self.fn)
3988 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003989 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3990 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003991 for f in files:
3992 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003993 path = os.path.join(dn, f)
3994 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003995 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003996 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003997
Vinay Sajip0372e102011-05-05 12:59:14 +01003998 def test_invalid(self):
3999 assertRaises = self.assertRaises
4000 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004001 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004002 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004003 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004004 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004005 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004006
Vinay Sajipa7130792013-04-12 17:04:23 +01004007 def test_compute_rollover_daily_attime(self):
4008 currentTime = 0
4009 atTime = datetime.time(12, 0, 0)
4010 rh = logging.handlers.TimedRotatingFileHandler(
4011 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4012 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004013 try:
4014 actual = rh.computeRollover(currentTime)
4015 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004016
Vinay Sajipd86ac962013-04-14 12:20:46 +01004017 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4018 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4019 finally:
4020 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004021
Vinay Sajip10e8c492013-05-18 10:19:54 -07004022 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004023 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004024 currentTime = int(time.time())
4025 today = currentTime - currentTime % 86400
4026
Vinay Sajipa7130792013-04-12 17:04:23 +01004027 atTime = datetime.time(12, 0, 0)
4028
Vinay Sajip10e8c492013-05-18 10:19:54 -07004029 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004030 for day in range(7):
4031 rh = logging.handlers.TimedRotatingFileHandler(
4032 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4033 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004034 try:
4035 if wday > day:
4036 # The rollover day has already passed this week, so we
4037 # go over into next week
4038 expected = (7 - wday + day)
4039 else:
4040 expected = (day - wday)
4041 # At this point expected is in days from now, convert to seconds
4042 expected *= 24 * 60 * 60
4043 # Add in the rollover time
4044 expected += 12 * 60 * 60
4045 # Add in adjustment for today
4046 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004047 actual = rh.computeRollover(today)
4048 if actual != expected:
4049 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004050 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004051 self.assertEqual(actual, expected)
4052 if day == wday:
4053 # goes into following week
4054 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004055 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004056 if actual != expected:
4057 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004058 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004059 self.assertEqual(actual, expected)
4060 finally:
4061 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004062
4063
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004064def secs(**kw):
4065 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4066
4067for when, exp in (('S', 1),
4068 ('M', 60),
4069 ('H', 60 * 60),
4070 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004071 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004072 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004073 ('W0', secs(days=4, hours=24)),
4074 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004075 def test_compute_rollover(self, when=when, exp=exp):
4076 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004077 self.fn, when=when, interval=1, backupCount=0, utc=True)
4078 currentTime = 0.0
4079 actual = rh.computeRollover(currentTime)
4080 if exp != actual:
4081 # Failures occur on some systems for MIDNIGHT and W0.
4082 # Print detailed calculation for MIDNIGHT so we can try to see
4083 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004084 if when == 'MIDNIGHT':
4085 try:
4086 if rh.utc:
4087 t = time.gmtime(currentTime)
4088 else:
4089 t = time.localtime(currentTime)
4090 currentHour = t[3]
4091 currentMinute = t[4]
4092 currentSecond = t[5]
4093 # r is the number of seconds left between now and midnight
4094 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4095 currentMinute) * 60 +
4096 currentSecond)
4097 result = currentTime + r
4098 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4099 print('currentHour: %s' % currentHour, file=sys.stderr)
4100 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4101 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4102 print('r: %s' % r, file=sys.stderr)
4103 print('result: %s' % result, file=sys.stderr)
4104 except Exception:
4105 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4106 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004107 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004108 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4109
Vinay Sajip60ccd822011-05-09 17:32:09 +01004110
4111@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4112class NTEventLogHandlerTest(BaseTest):
4113 def test_basic(self):
4114 logtype = 'Application'
4115 elh = win32evtlog.OpenEventLog(None, logtype)
4116 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4117 h = logging.handlers.NTEventLogHandler('test_logging')
4118 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4119 h.handle(r)
4120 h.close()
4121 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004122 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004123 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4124 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4125 found = False
4126 GO_BACK = 100
4127 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4128 for e in events:
4129 if e.SourceName != 'test_logging':
4130 continue
4131 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4132 if msg != 'Test Log Message\r\n':
4133 continue
4134 found = True
4135 break
4136 msg = 'Record not found in event log, went back %d records' % GO_BACK
4137 self.assertTrue(found, msg=msg)
4138
Christian Heimes180510d2008-03-03 19:15:45 +00004139# Set the locale to the platform-dependent default. I have no idea
4140# why the test does this, but in any case we save the current locale
4141# first and restore it at the end.
4142@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004143def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004144 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004145 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004146 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4147 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4148 ManagerTest, FormatterTest, BufferingFormatterTest,
4149 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4150 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4151 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4152 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004153 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004154 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004155 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4156 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004157 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004158
Christian Heimes180510d2008-03-03 19:15:45 +00004159if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004160 test_main()