blob: d5aec9ae443269bc0e2c0f448624df6ffa16878e [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
Vinay Sajip9ba87612011-05-21 11:32:15 +01001634 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1635MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1636zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1637aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1638AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16390tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16405LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1641piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16422z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1643i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1644PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1645E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1646rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1647/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1648-----END RSA PRIVATE KEY-----
1649-----BEGIN CERTIFICATE-----
1650MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1651BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1652EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1653xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1654l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1655vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1656BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1657S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1658BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16594f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16601c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1661IRbTpvlHWPjsSvHz0ZOH
1662-----END CERTIFICATE-----"""
1663
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 def setUp(self):
1665 """Set up an HTTP server to receive log messages, and a HTTPHandler
1666 pointing to that server's address and port."""
1667 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001668 self.handled = threading.Event()
1669
Vinay Sajip7367d082011-05-02 13:17:27 +01001670 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001671 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001672 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001673 if self.command == 'POST':
1674 try:
1675 rlen = int(request.headers['Content-Length'])
1676 self.post_data = request.rfile.read(rlen)
1677 except:
1678 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001680 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001681 self.handled.set()
1682
1683 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001684 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001685 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001686 root_logger = self.root_logger
1687 root_logger.removeHandler(self.root_logger.handlers[0])
1688 for secure in (False, True):
1689 addr = ('localhost', 0)
1690 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001691 try:
1692 import ssl
1693 fd, fn = tempfile.mkstemp()
1694 os.close(fd)
1695 with open(fn, 'w') as f:
1696 f.write(self.PEMFILE)
1697 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1698 sslctx.load_cert_chain(fn)
1699 os.unlink(fn)
1700 except ImportError:
1701 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001702 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001703 sslctx = None
1704 self.server = server = TestHTTPServer(addr, self.handle_request,
1705 0.01, sslctx=sslctx)
1706 server.start()
1707 server.ready.wait()
1708 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001709 secure_client = secure and sslctx
1710 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1711 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001712 self.log_data = None
1713 root_logger.addHandler(self.h_hdlr)
1714
1715 for method in ('GET', 'POST'):
1716 self.h_hdlr.method = method
1717 self.handled.clear()
1718 msg = "sp\xe4m"
1719 logger.error(msg)
1720 self.handled.wait()
1721 self.assertEqual(self.log_data.path, '/frob')
1722 self.assertEqual(self.command, method)
1723 if method == 'GET':
1724 d = parse_qs(self.log_data.query)
1725 else:
1726 d = parse_qs(self.post_data.decode('utf-8'))
1727 self.assertEqual(d['name'], ['http'])
1728 self.assertEqual(d['funcName'], ['test_output'])
1729 self.assertEqual(d['msg'], [msg])
1730
1731 self.server.stop(2.0)
1732 self.root_logger.removeHandler(self.h_hdlr)
1733 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001734
Christian Heimes180510d2008-03-03 19:15:45 +00001735class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001736
Christian Heimes180510d2008-03-03 19:15:45 +00001737 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001738
Christian Heimes180510d2008-03-03 19:15:45 +00001739 def setUp(self):
1740 """Create a dict to remember potentially destroyed objects."""
1741 BaseTest.setUp(self)
1742 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001743
Christian Heimes180510d2008-03-03 19:15:45 +00001744 def _watch_for_survival(self, *args):
1745 """Watch the given objects for survival, by creating weakrefs to
1746 them."""
1747 for obj in args:
1748 key = id(obj), repr(obj)
1749 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001750
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001751 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001752 """Assert that all objects watched for survival have survived."""
1753 # Trigger cycle breaking.
1754 gc.collect()
1755 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001756 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001757 if ref() is None:
1758 dead.append(repr_)
1759 if dead:
1760 self.fail("%d objects should have survived "
1761 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001762
Christian Heimes180510d2008-03-03 19:15:45 +00001763 def test_persistent_loggers(self):
1764 # Logger objects are persistent and retain their configuration, even
1765 # if visible references are destroyed.
1766 self.root_logger.setLevel(logging.INFO)
1767 foo = logging.getLogger("foo")
1768 self._watch_for_survival(foo)
1769 foo.setLevel(logging.DEBUG)
1770 self.root_logger.debug(self.next_message())
1771 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001772 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001773 ('foo', 'DEBUG', '2'),
1774 ])
1775 del foo
1776 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001777 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001778 # foo has retained its settings.
1779 bar = logging.getLogger("foo")
1780 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001781 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001782 ('foo', 'DEBUG', '2'),
1783 ('foo', 'DEBUG', '3'),
1784 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001785
Benjamin Petersonf91df042009-02-13 02:50:59 +00001786
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001787class EncodingTest(BaseTest):
1788 def test_encoding_plain_file(self):
1789 # In Python 2.x, a plain file object is treated as having no encoding.
1790 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001791 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1792 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001793 # the non-ascii data we write to the log.
1794 data = "foo\x80"
1795 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001796 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001797 log.addHandler(handler)
1798 try:
1799 # write non-ascii data to the log.
1800 log.warning(data)
1801 finally:
1802 log.removeHandler(handler)
1803 handler.close()
1804 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001805 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001806 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001807 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001808 finally:
1809 f.close()
1810 finally:
1811 if os.path.isfile(fn):
1812 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001813
Benjamin Petersonf91df042009-02-13 02:50:59 +00001814 def test_encoding_cyrillic_unicode(self):
1815 log = logging.getLogger("test")
1816 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1817 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1818 #Ensure it's written in a Cyrillic encoding
1819 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001820 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001821 stream = io.BytesIO()
1822 writer = writer_class(stream, 'strict')
1823 handler = logging.StreamHandler(writer)
1824 log.addHandler(handler)
1825 try:
1826 log.warning(message)
1827 finally:
1828 log.removeHandler(handler)
1829 handler.close()
1830 # check we wrote exactly those bytes, ignoring trailing \n etc
1831 s = stream.getvalue()
1832 #Compare against what the data should be when encoded in CP-1251
1833 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1834
1835
Georg Brandlf9734072008-12-07 15:30:06 +00001836class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001837
Georg Brandlf9734072008-12-07 15:30:06 +00001838 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001839 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001840 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001841 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001842 warnings.filterwarnings("always", category=UserWarning)
1843 stream = io.StringIO()
1844 h = logging.StreamHandler(stream)
1845 logger = logging.getLogger("py.warnings")
1846 logger.addHandler(h)
1847 warnings.warn("I'm warning you...")
1848 logger.removeHandler(h)
1849 s = stream.getvalue()
1850 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001851 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001852
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001853 #See if an explicit file uses the original implementation
1854 a_file = io.StringIO()
1855 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1856 a_file, "Dummy line")
1857 s = a_file.getvalue()
1858 a_file.close()
1859 self.assertEqual(s,
1860 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1861
1862 def test_warnings_no_handlers(self):
1863 with warnings.catch_warnings():
1864 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001865 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001866
1867 # confirm our assumption: no loggers are set
1868 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001869 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001870
1871 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001872 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001873 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001874
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001875
1876def formatFunc(format, datefmt=None):
1877 return logging.Formatter(format, datefmt)
1878
1879def handlerFunc():
1880 return logging.StreamHandler()
1881
1882class CustomHandler(logging.StreamHandler):
1883 pass
1884
1885class ConfigDictTest(BaseTest):
1886
1887 """Reading logging config from a dictionary."""
1888
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001889 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001890
1891 # config0 is a standard configuration.
1892 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001893 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001894 'formatters': {
1895 'form1' : {
1896 'format' : '%(levelname)s ++ %(message)s',
1897 },
1898 },
1899 'handlers' : {
1900 'hand1' : {
1901 'class' : 'logging.StreamHandler',
1902 'formatter' : 'form1',
1903 'level' : 'NOTSET',
1904 'stream' : 'ext://sys.stdout',
1905 },
1906 },
1907 'root' : {
1908 'level' : 'WARNING',
1909 'handlers' : ['hand1'],
1910 },
1911 }
1912
1913 # config1 adds a little to the standard configuration.
1914 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001915 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001916 'formatters': {
1917 'form1' : {
1918 'format' : '%(levelname)s ++ %(message)s',
1919 },
1920 },
1921 'handlers' : {
1922 'hand1' : {
1923 'class' : 'logging.StreamHandler',
1924 'formatter' : 'form1',
1925 'level' : 'NOTSET',
1926 'stream' : 'ext://sys.stdout',
1927 },
1928 },
1929 'loggers' : {
1930 'compiler.parser' : {
1931 'level' : 'DEBUG',
1932 'handlers' : ['hand1'],
1933 },
1934 },
1935 'root' : {
1936 'level' : 'WARNING',
1937 },
1938 }
1939
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001940 # config1a moves the handler to the root. Used with config8a
1941 config1a = {
1942 'version': 1,
1943 'formatters': {
1944 'form1' : {
1945 'format' : '%(levelname)s ++ %(message)s',
1946 },
1947 },
1948 'handlers' : {
1949 'hand1' : {
1950 'class' : 'logging.StreamHandler',
1951 'formatter' : 'form1',
1952 'level' : 'NOTSET',
1953 'stream' : 'ext://sys.stdout',
1954 },
1955 },
1956 'loggers' : {
1957 'compiler.parser' : {
1958 'level' : 'DEBUG',
1959 },
1960 },
1961 'root' : {
1962 'level' : 'WARNING',
1963 'handlers' : ['hand1'],
1964 },
1965 }
1966
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001967 # config2 has a subtle configuration error that should be reported
1968 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001969 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001970 'formatters': {
1971 'form1' : {
1972 'format' : '%(levelname)s ++ %(message)s',
1973 },
1974 },
1975 'handlers' : {
1976 'hand1' : {
1977 'class' : 'logging.StreamHandler',
1978 'formatter' : 'form1',
1979 'level' : 'NOTSET',
1980 'stream' : 'ext://sys.stdbout',
1981 },
1982 },
1983 'loggers' : {
1984 'compiler.parser' : {
1985 'level' : 'DEBUG',
1986 'handlers' : ['hand1'],
1987 },
1988 },
1989 'root' : {
1990 'level' : 'WARNING',
1991 },
1992 }
1993
1994 #As config1 but with a misspelt level on a handler
1995 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001996 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001997 'formatters': {
1998 'form1' : {
1999 'format' : '%(levelname)s ++ %(message)s',
2000 },
2001 },
2002 'handlers' : {
2003 'hand1' : {
2004 'class' : 'logging.StreamHandler',
2005 'formatter' : 'form1',
2006 'level' : 'NTOSET',
2007 'stream' : 'ext://sys.stdout',
2008 },
2009 },
2010 'loggers' : {
2011 'compiler.parser' : {
2012 'level' : 'DEBUG',
2013 'handlers' : ['hand1'],
2014 },
2015 },
2016 'root' : {
2017 'level' : 'WARNING',
2018 },
2019 }
2020
2021
2022 #As config1 but with a misspelt level on a logger
2023 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002024 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002025 'formatters': {
2026 'form1' : {
2027 'format' : '%(levelname)s ++ %(message)s',
2028 },
2029 },
2030 'handlers' : {
2031 'hand1' : {
2032 'class' : 'logging.StreamHandler',
2033 'formatter' : 'form1',
2034 'level' : 'NOTSET',
2035 'stream' : 'ext://sys.stdout',
2036 },
2037 },
2038 'loggers' : {
2039 'compiler.parser' : {
2040 'level' : 'DEBUG',
2041 'handlers' : ['hand1'],
2042 },
2043 },
2044 'root' : {
2045 'level' : 'WRANING',
2046 },
2047 }
2048
2049 # config3 has a less subtle configuration error
2050 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002051 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002052 'formatters': {
2053 'form1' : {
2054 'format' : '%(levelname)s ++ %(message)s',
2055 },
2056 },
2057 'handlers' : {
2058 'hand1' : {
2059 'class' : 'logging.StreamHandler',
2060 'formatter' : 'misspelled_name',
2061 'level' : 'NOTSET',
2062 'stream' : 'ext://sys.stdout',
2063 },
2064 },
2065 'loggers' : {
2066 'compiler.parser' : {
2067 'level' : 'DEBUG',
2068 'handlers' : ['hand1'],
2069 },
2070 },
2071 'root' : {
2072 'level' : 'WARNING',
2073 },
2074 }
2075
2076 # config4 specifies a custom formatter class to be loaded
2077 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002078 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002079 'formatters': {
2080 'form1' : {
2081 '()' : __name__ + '.ExceptionFormatter',
2082 'format' : '%(levelname)s:%(name)s:%(message)s',
2083 },
2084 },
2085 'handlers' : {
2086 'hand1' : {
2087 'class' : 'logging.StreamHandler',
2088 'formatter' : 'form1',
2089 'level' : 'NOTSET',
2090 'stream' : 'ext://sys.stdout',
2091 },
2092 },
2093 'root' : {
2094 'level' : 'NOTSET',
2095 'handlers' : ['hand1'],
2096 },
2097 }
2098
2099 # As config4 but using an actual callable rather than a string
2100 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002101 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002102 'formatters': {
2103 'form1' : {
2104 '()' : ExceptionFormatter,
2105 'format' : '%(levelname)s:%(name)s:%(message)s',
2106 },
2107 'form2' : {
2108 '()' : __name__ + '.formatFunc',
2109 'format' : '%(levelname)s:%(name)s:%(message)s',
2110 },
2111 'form3' : {
2112 '()' : formatFunc,
2113 'format' : '%(levelname)s:%(name)s:%(message)s',
2114 },
2115 },
2116 'handlers' : {
2117 'hand1' : {
2118 'class' : 'logging.StreamHandler',
2119 'formatter' : 'form1',
2120 'level' : 'NOTSET',
2121 'stream' : 'ext://sys.stdout',
2122 },
2123 'hand2' : {
2124 '()' : handlerFunc,
2125 },
2126 },
2127 'root' : {
2128 'level' : 'NOTSET',
2129 'handlers' : ['hand1'],
2130 },
2131 }
2132
2133 # config5 specifies a custom handler class to be loaded
2134 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002135 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002136 'formatters': {
2137 'form1' : {
2138 'format' : '%(levelname)s ++ %(message)s',
2139 },
2140 },
2141 'handlers' : {
2142 'hand1' : {
2143 'class' : __name__ + '.CustomHandler',
2144 'formatter' : 'form1',
2145 'level' : 'NOTSET',
2146 'stream' : 'ext://sys.stdout',
2147 },
2148 },
2149 'loggers' : {
2150 'compiler.parser' : {
2151 'level' : 'DEBUG',
2152 'handlers' : ['hand1'],
2153 },
2154 },
2155 'root' : {
2156 'level' : 'WARNING',
2157 },
2158 }
2159
2160 # config6 specifies a custom handler class to be loaded
2161 # but has bad arguments
2162 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002163 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002164 'formatters': {
2165 'form1' : {
2166 'format' : '%(levelname)s ++ %(message)s',
2167 },
2168 },
2169 'handlers' : {
2170 'hand1' : {
2171 'class' : __name__ + '.CustomHandler',
2172 'formatter' : 'form1',
2173 'level' : 'NOTSET',
2174 'stream' : 'ext://sys.stdout',
2175 '9' : 'invalid parameter name',
2176 },
2177 },
2178 'loggers' : {
2179 'compiler.parser' : {
2180 'level' : 'DEBUG',
2181 'handlers' : ['hand1'],
2182 },
2183 },
2184 'root' : {
2185 'level' : 'WARNING',
2186 },
2187 }
2188
2189 #config 7 does not define compiler.parser but defines compiler.lexer
2190 #so compiler.parser should be disabled after applying it
2191 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002192 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002193 'formatters': {
2194 'form1' : {
2195 'format' : '%(levelname)s ++ %(message)s',
2196 },
2197 },
2198 'handlers' : {
2199 'hand1' : {
2200 'class' : 'logging.StreamHandler',
2201 'formatter' : 'form1',
2202 'level' : 'NOTSET',
2203 'stream' : 'ext://sys.stdout',
2204 },
2205 },
2206 'loggers' : {
2207 'compiler.lexer' : {
2208 'level' : 'DEBUG',
2209 'handlers' : ['hand1'],
2210 },
2211 },
2212 'root' : {
2213 'level' : 'WARNING',
2214 },
2215 }
2216
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002217 # config8 defines both compiler and compiler.lexer
2218 # so compiler.parser should not be disabled (since
2219 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002220 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002221 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002222 'disable_existing_loggers' : False,
2223 'formatters': {
2224 'form1' : {
2225 'format' : '%(levelname)s ++ %(message)s',
2226 },
2227 },
2228 'handlers' : {
2229 'hand1' : {
2230 'class' : 'logging.StreamHandler',
2231 'formatter' : 'form1',
2232 'level' : 'NOTSET',
2233 'stream' : 'ext://sys.stdout',
2234 },
2235 },
2236 'loggers' : {
2237 'compiler' : {
2238 'level' : 'DEBUG',
2239 'handlers' : ['hand1'],
2240 },
2241 'compiler.lexer' : {
2242 },
2243 },
2244 'root' : {
2245 'level' : 'WARNING',
2246 },
2247 }
2248
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002249 # config8a disables existing loggers
2250 config8a = {
2251 'version': 1,
2252 'disable_existing_loggers' : True,
2253 'formatters': {
2254 'form1' : {
2255 'format' : '%(levelname)s ++ %(message)s',
2256 },
2257 },
2258 'handlers' : {
2259 'hand1' : {
2260 'class' : 'logging.StreamHandler',
2261 'formatter' : 'form1',
2262 'level' : 'NOTSET',
2263 'stream' : 'ext://sys.stdout',
2264 },
2265 },
2266 'loggers' : {
2267 'compiler' : {
2268 'level' : 'DEBUG',
2269 'handlers' : ['hand1'],
2270 },
2271 'compiler.lexer' : {
2272 },
2273 },
2274 'root' : {
2275 'level' : 'WARNING',
2276 },
2277 }
2278
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002279 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002280 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002281 'formatters': {
2282 'form1' : {
2283 'format' : '%(levelname)s ++ %(message)s',
2284 },
2285 },
2286 'handlers' : {
2287 'hand1' : {
2288 'class' : 'logging.StreamHandler',
2289 'formatter' : 'form1',
2290 'level' : 'WARNING',
2291 'stream' : 'ext://sys.stdout',
2292 },
2293 },
2294 'loggers' : {
2295 'compiler.parser' : {
2296 'level' : 'WARNING',
2297 'handlers' : ['hand1'],
2298 },
2299 },
2300 'root' : {
2301 'level' : 'NOTSET',
2302 },
2303 }
2304
2305 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002306 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002307 'incremental' : True,
2308 'handlers' : {
2309 'hand1' : {
2310 'level' : 'WARNING',
2311 },
2312 },
2313 'loggers' : {
2314 'compiler.parser' : {
2315 'level' : 'INFO',
2316 },
2317 },
2318 }
2319
2320 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002321 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002322 'incremental' : True,
2323 'handlers' : {
2324 'hand1' : {
2325 'level' : 'INFO',
2326 },
2327 },
2328 'loggers' : {
2329 'compiler.parser' : {
2330 'level' : 'INFO',
2331 },
2332 },
2333 }
2334
2335 #As config1 but with a filter added
2336 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002337 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002338 'formatters': {
2339 'form1' : {
2340 'format' : '%(levelname)s ++ %(message)s',
2341 },
2342 },
2343 'filters' : {
2344 'filt1' : {
2345 'name' : 'compiler.parser',
2346 },
2347 },
2348 'handlers' : {
2349 'hand1' : {
2350 'class' : 'logging.StreamHandler',
2351 'formatter' : 'form1',
2352 'level' : 'NOTSET',
2353 'stream' : 'ext://sys.stdout',
2354 'filters' : ['filt1'],
2355 },
2356 },
2357 'loggers' : {
2358 'compiler.parser' : {
2359 'level' : 'DEBUG',
2360 'filters' : ['filt1'],
2361 },
2362 },
2363 'root' : {
2364 'level' : 'WARNING',
2365 'handlers' : ['hand1'],
2366 },
2367 }
2368
2369 #As config1 but using cfg:// references
2370 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002371 'version': 1,
2372 'true_formatters': {
2373 'form1' : {
2374 'format' : '%(levelname)s ++ %(message)s',
2375 },
2376 },
2377 'handler_configs': {
2378 'hand1' : {
2379 'class' : 'logging.StreamHandler',
2380 'formatter' : 'form1',
2381 'level' : 'NOTSET',
2382 'stream' : 'ext://sys.stdout',
2383 },
2384 },
2385 'formatters' : 'cfg://true_formatters',
2386 'handlers' : {
2387 'hand1' : 'cfg://handler_configs[hand1]',
2388 },
2389 'loggers' : {
2390 'compiler.parser' : {
2391 'level' : 'DEBUG',
2392 'handlers' : ['hand1'],
2393 },
2394 },
2395 'root' : {
2396 'level' : 'WARNING',
2397 },
2398 }
2399
2400 #As config11 but missing the version key
2401 config12 = {
2402 'true_formatters': {
2403 'form1' : {
2404 'format' : '%(levelname)s ++ %(message)s',
2405 },
2406 },
2407 'handler_configs': {
2408 'hand1' : {
2409 'class' : 'logging.StreamHandler',
2410 'formatter' : 'form1',
2411 'level' : 'NOTSET',
2412 'stream' : 'ext://sys.stdout',
2413 },
2414 },
2415 'formatters' : 'cfg://true_formatters',
2416 'handlers' : {
2417 'hand1' : 'cfg://handler_configs[hand1]',
2418 },
2419 'loggers' : {
2420 'compiler.parser' : {
2421 'level' : 'DEBUG',
2422 'handlers' : ['hand1'],
2423 },
2424 },
2425 'root' : {
2426 'level' : 'WARNING',
2427 },
2428 }
2429
2430 #As config11 but using an unsupported version
2431 config13 = {
2432 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002433 'true_formatters': {
2434 'form1' : {
2435 'format' : '%(levelname)s ++ %(message)s',
2436 },
2437 },
2438 'handler_configs': {
2439 'hand1' : {
2440 'class' : 'logging.StreamHandler',
2441 'formatter' : 'form1',
2442 'level' : 'NOTSET',
2443 'stream' : 'ext://sys.stdout',
2444 },
2445 },
2446 'formatters' : 'cfg://true_formatters',
2447 'handlers' : {
2448 'hand1' : 'cfg://handler_configs[hand1]',
2449 },
2450 'loggers' : {
2451 'compiler.parser' : {
2452 'level' : 'DEBUG',
2453 'handlers' : ['hand1'],
2454 },
2455 },
2456 'root' : {
2457 'level' : 'WARNING',
2458 },
2459 }
2460
Vinay Sajip8d270232012-11-15 14:20:18 +00002461 # As config0, but with properties
2462 config14 = {
2463 'version': 1,
2464 'formatters': {
2465 'form1' : {
2466 'format' : '%(levelname)s ++ %(message)s',
2467 },
2468 },
2469 'handlers' : {
2470 'hand1' : {
2471 'class' : 'logging.StreamHandler',
2472 'formatter' : 'form1',
2473 'level' : 'NOTSET',
2474 'stream' : 'ext://sys.stdout',
2475 '.': {
2476 'foo': 'bar',
2477 'terminator': '!\n',
2478 }
2479 },
2480 },
2481 'root' : {
2482 'level' : 'WARNING',
2483 'handlers' : ['hand1'],
2484 },
2485 }
2486
Vinay Sajip3f885b52013-03-22 15:19:54 +00002487 out_of_order = {
2488 "version": 1,
2489 "formatters": {
2490 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002491 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2492 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002493 }
2494 },
2495 "handlers": {
2496 "fileGlobal": {
2497 "class": "logging.StreamHandler",
2498 "level": "DEBUG",
2499 "formatter": "mySimpleFormatter"
2500 },
2501 "bufferGlobal": {
2502 "class": "logging.handlers.MemoryHandler",
2503 "capacity": 5,
2504 "formatter": "mySimpleFormatter",
2505 "target": "fileGlobal",
2506 "level": "DEBUG"
2507 }
2508 },
2509 "loggers": {
2510 "mymodule": {
2511 "level": "DEBUG",
2512 "handlers": ["bufferGlobal"],
2513 "propagate": "true"
2514 }
2515 }
2516 }
2517
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002518 def apply_config(self, conf):
2519 logging.config.dictConfig(conf)
2520
2521 def test_config0_ok(self):
2522 # A simple config which overrides the default settings.
2523 with captured_stdout() as output:
2524 self.apply_config(self.config0)
2525 logger = logging.getLogger()
2526 # Won't output anything
2527 logger.info(self.next_message())
2528 # Outputs a message
2529 logger.error(self.next_message())
2530 self.assert_log_lines([
2531 ('ERROR', '2'),
2532 ], stream=output)
2533 # Original logger output is empty.
2534 self.assert_log_lines([])
2535
2536 def test_config1_ok(self, config=config1):
2537 # A config defining a sub-parser as well.
2538 with captured_stdout() as output:
2539 self.apply_config(config)
2540 logger = logging.getLogger("compiler.parser")
2541 # Both will output a message
2542 logger.info(self.next_message())
2543 logger.error(self.next_message())
2544 self.assert_log_lines([
2545 ('INFO', '1'),
2546 ('ERROR', '2'),
2547 ], stream=output)
2548 # Original logger output is empty.
2549 self.assert_log_lines([])
2550
2551 def test_config2_failure(self):
2552 # A simple config which overrides the default settings.
2553 self.assertRaises(Exception, self.apply_config, self.config2)
2554
2555 def test_config2a_failure(self):
2556 # A simple config which overrides the default settings.
2557 self.assertRaises(Exception, self.apply_config, self.config2a)
2558
2559 def test_config2b_failure(self):
2560 # A simple config which overrides the default settings.
2561 self.assertRaises(Exception, self.apply_config, self.config2b)
2562
2563 def test_config3_failure(self):
2564 # A simple config which overrides the default settings.
2565 self.assertRaises(Exception, self.apply_config, self.config3)
2566
2567 def test_config4_ok(self):
2568 # A config specifying a custom formatter class.
2569 with captured_stdout() as output:
2570 self.apply_config(self.config4)
2571 #logger = logging.getLogger()
2572 try:
2573 raise RuntimeError()
2574 except RuntimeError:
2575 logging.exception("just testing")
2576 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002577 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002578 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2579 # Original logger output is empty
2580 self.assert_log_lines([])
2581
2582 def test_config4a_ok(self):
2583 # A config specifying a custom formatter class.
2584 with captured_stdout() as output:
2585 self.apply_config(self.config4a)
2586 #logger = logging.getLogger()
2587 try:
2588 raise RuntimeError()
2589 except RuntimeError:
2590 logging.exception("just testing")
2591 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002592 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002593 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2594 # Original logger output is empty
2595 self.assert_log_lines([])
2596
2597 def test_config5_ok(self):
2598 self.test_config1_ok(config=self.config5)
2599
2600 def test_config6_failure(self):
2601 self.assertRaises(Exception, self.apply_config, self.config6)
2602
2603 def test_config7_ok(self):
2604 with captured_stdout() as output:
2605 self.apply_config(self.config1)
2606 logger = logging.getLogger("compiler.parser")
2607 # Both will output a message
2608 logger.info(self.next_message())
2609 logger.error(self.next_message())
2610 self.assert_log_lines([
2611 ('INFO', '1'),
2612 ('ERROR', '2'),
2613 ], stream=output)
2614 # Original logger output is empty.
2615 self.assert_log_lines([])
2616 with captured_stdout() as output:
2617 self.apply_config(self.config7)
2618 logger = logging.getLogger("compiler.parser")
2619 self.assertTrue(logger.disabled)
2620 logger = logging.getLogger("compiler.lexer")
2621 # Both will output a message
2622 logger.info(self.next_message())
2623 logger.error(self.next_message())
2624 self.assert_log_lines([
2625 ('INFO', '3'),
2626 ('ERROR', '4'),
2627 ], stream=output)
2628 # Original logger output is empty.
2629 self.assert_log_lines([])
2630
2631 #Same as test_config_7_ok but don't disable old loggers.
2632 def test_config_8_ok(self):
2633 with captured_stdout() as output:
2634 self.apply_config(self.config1)
2635 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002636 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002637 logger.info(self.next_message())
2638 logger.error(self.next_message())
2639 self.assert_log_lines([
2640 ('INFO', '1'),
2641 ('ERROR', '2'),
2642 ], stream=output)
2643 # Original logger output is empty.
2644 self.assert_log_lines([])
2645 with captured_stdout() as output:
2646 self.apply_config(self.config8)
2647 logger = logging.getLogger("compiler.parser")
2648 self.assertFalse(logger.disabled)
2649 # Both will output a message
2650 logger.info(self.next_message())
2651 logger.error(self.next_message())
2652 logger = logging.getLogger("compiler.lexer")
2653 # Both will output a message
2654 logger.info(self.next_message())
2655 logger.error(self.next_message())
2656 self.assert_log_lines([
2657 ('INFO', '3'),
2658 ('ERROR', '4'),
2659 ('INFO', '5'),
2660 ('ERROR', '6'),
2661 ], stream=output)
2662 # Original logger output is empty.
2663 self.assert_log_lines([])
2664
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002665 def test_config_8a_ok(self):
2666 with captured_stdout() as output:
2667 self.apply_config(self.config1a)
2668 logger = logging.getLogger("compiler.parser")
2669 # See issue #11424. compiler-hyphenated sorts
2670 # between compiler and compiler.xyz and this
2671 # was preventing compiler.xyz from being included
2672 # in the child loggers of compiler because of an
2673 # overzealous loop termination condition.
2674 hyphenated = logging.getLogger('compiler-hyphenated')
2675 # All will output a message
2676 logger.info(self.next_message())
2677 logger.error(self.next_message())
2678 hyphenated.critical(self.next_message())
2679 self.assert_log_lines([
2680 ('INFO', '1'),
2681 ('ERROR', '2'),
2682 ('CRITICAL', '3'),
2683 ], stream=output)
2684 # Original logger output is empty.
2685 self.assert_log_lines([])
2686 with captured_stdout() as output:
2687 self.apply_config(self.config8a)
2688 logger = logging.getLogger("compiler.parser")
2689 self.assertFalse(logger.disabled)
2690 # Both will output a message
2691 logger.info(self.next_message())
2692 logger.error(self.next_message())
2693 logger = logging.getLogger("compiler.lexer")
2694 # Both will output a message
2695 logger.info(self.next_message())
2696 logger.error(self.next_message())
2697 # Will not appear
2698 hyphenated.critical(self.next_message())
2699 self.assert_log_lines([
2700 ('INFO', '4'),
2701 ('ERROR', '5'),
2702 ('INFO', '6'),
2703 ('ERROR', '7'),
2704 ], stream=output)
2705 # Original logger output is empty.
2706 self.assert_log_lines([])
2707
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002708 def test_config_9_ok(self):
2709 with captured_stdout() as output:
2710 self.apply_config(self.config9)
2711 logger = logging.getLogger("compiler.parser")
2712 #Nothing will be output since both handler and logger are set to WARNING
2713 logger.info(self.next_message())
2714 self.assert_log_lines([], stream=output)
2715 self.apply_config(self.config9a)
2716 #Nothing will be output since both handler is still set to WARNING
2717 logger.info(self.next_message())
2718 self.assert_log_lines([], stream=output)
2719 self.apply_config(self.config9b)
2720 #Message should now be output
2721 logger.info(self.next_message())
2722 self.assert_log_lines([
2723 ('INFO', '3'),
2724 ], stream=output)
2725
2726 def test_config_10_ok(self):
2727 with captured_stdout() as output:
2728 self.apply_config(self.config10)
2729 logger = logging.getLogger("compiler.parser")
2730 logger.warning(self.next_message())
2731 logger = logging.getLogger('compiler')
2732 #Not output, because filtered
2733 logger.warning(self.next_message())
2734 logger = logging.getLogger('compiler.lexer')
2735 #Not output, because filtered
2736 logger.warning(self.next_message())
2737 logger = logging.getLogger("compiler.parser.codegen")
2738 #Output, as not filtered
2739 logger.error(self.next_message())
2740 self.assert_log_lines([
2741 ('WARNING', '1'),
2742 ('ERROR', '4'),
2743 ], stream=output)
2744
2745 def test_config11_ok(self):
2746 self.test_config1_ok(self.config11)
2747
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002748 def test_config12_failure(self):
2749 self.assertRaises(Exception, self.apply_config, self.config12)
2750
2751 def test_config13_failure(self):
2752 self.assertRaises(Exception, self.apply_config, self.config13)
2753
Vinay Sajip8d270232012-11-15 14:20:18 +00002754 def test_config14_ok(self):
2755 with captured_stdout() as output:
2756 self.apply_config(self.config14)
2757 h = logging._handlers['hand1']
2758 self.assertEqual(h.foo, 'bar')
2759 self.assertEqual(h.terminator, '!\n')
2760 logging.warning('Exclamation')
2761 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2762
Victor Stinner45df8202010-04-28 22:31:17 +00002763 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002764 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002765 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002766 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002767 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 t.start()
2769 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002770 # Now get the port allocated
2771 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002772 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002773 try:
2774 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2775 sock.settimeout(2.0)
2776 sock.connect(('localhost', port))
2777
2778 slen = struct.pack('>L', len(text))
2779 s = slen + text
2780 sentsofar = 0
2781 left = len(s)
2782 while left > 0:
2783 sent = sock.send(s[sentsofar:])
2784 sentsofar += sent
2785 left -= sent
2786 sock.close()
2787 finally:
2788 t.ready.wait(2.0)
2789 logging.config.stopListening()
2790 t.join(2.0)
2791
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002792 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002793 def test_listen_config_10_ok(self):
2794 with captured_stdout() as output:
2795 self.setup_via_listener(json.dumps(self.config10))
2796 logger = logging.getLogger("compiler.parser")
2797 logger.warning(self.next_message())
2798 logger = logging.getLogger('compiler')
2799 #Not output, because filtered
2800 logger.warning(self.next_message())
2801 logger = logging.getLogger('compiler.lexer')
2802 #Not output, because filtered
2803 logger.warning(self.next_message())
2804 logger = logging.getLogger("compiler.parser.codegen")
2805 #Output, as not filtered
2806 logger.error(self.next_message())
2807 self.assert_log_lines([
2808 ('WARNING', '1'),
2809 ('ERROR', '4'),
2810 ], stream=output)
2811
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002812 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002813 def test_listen_config_1_ok(self):
2814 with captured_stdout() as output:
2815 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2816 logger = logging.getLogger("compiler.parser")
2817 # Both will output a message
2818 logger.info(self.next_message())
2819 logger.error(self.next_message())
2820 self.assert_log_lines([
2821 ('INFO', '1'),
2822 ('ERROR', '2'),
2823 ], stream=output)
2824 # Original logger output is empty.
2825 self.assert_log_lines([])
2826
Vinay Sajip4ded5512012-10-02 15:56:16 +01002827 @unittest.skipUnless(threading, 'Threading required for this test.')
2828 def test_listen_verify(self):
2829
2830 def verify_fail(stuff):
2831 return None
2832
2833 def verify_reverse(stuff):
2834 return stuff[::-1]
2835
2836 logger = logging.getLogger("compiler.parser")
2837 to_send = textwrap.dedent(ConfigFileTest.config1)
2838 # First, specify a verification function that will fail.
2839 # We expect to see no output, since our configuration
2840 # never took effect.
2841 with captured_stdout() as output:
2842 self.setup_via_listener(to_send, verify_fail)
2843 # Both will output a message
2844 logger.info(self.next_message())
2845 logger.error(self.next_message())
2846 self.assert_log_lines([], stream=output)
2847 # Original logger output has the stuff we logged.
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 no verification. Our configuration
2854 # should take effect.
2855
2856 with captured_stdout() as output:
2857 self.setup_via_listener(to_send) # no verify callable specified
2858 logger = logging.getLogger("compiler.parser")
2859 # Both will output a message
2860 logger.info(self.next_message())
2861 logger.error(self.next_message())
2862 self.assert_log_lines([
2863 ('INFO', '3'),
2864 ('ERROR', '4'),
2865 ], stream=output)
2866 # Original logger output still has the stuff we logged before.
2867 self.assert_log_lines([
2868 ('INFO', '1'),
2869 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002870 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002871
2872 # Now, perform verification which transforms the bytes.
2873
2874 with captured_stdout() as output:
2875 self.setup_via_listener(to_send[::-1], verify_reverse)
2876 logger = logging.getLogger("compiler.parser")
2877 # Both will output a message
2878 logger.info(self.next_message())
2879 logger.error(self.next_message())
2880 self.assert_log_lines([
2881 ('INFO', '5'),
2882 ('ERROR', '6'),
2883 ], stream=output)
2884 # Original logger output still has the stuff we logged before.
2885 self.assert_log_lines([
2886 ('INFO', '1'),
2887 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002888 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002889
Vinay Sajip3f885b52013-03-22 15:19:54 +00002890 def test_out_of_order(self):
2891 self.apply_config(self.out_of_order)
2892 handler = logging.getLogger('mymodule').handlers[0]
2893 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002894 self.assertIsInstance(handler.formatter._style,
2895 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002896
Vinay Sajip373baef2011-04-26 20:05:24 +01002897 def test_baseconfig(self):
2898 d = {
2899 'atuple': (1, 2, 3),
2900 'alist': ['a', 'b', 'c'],
2901 'adict': {'d': 'e', 'f': 3 },
2902 'nest1': ('g', ('h', 'i'), 'j'),
2903 'nest2': ['k', ['l', 'm'], 'n'],
2904 'nest3': ['o', 'cfg://alist', 'p'],
2905 }
2906 bc = logging.config.BaseConfigurator(d)
2907 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2908 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2909 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2910 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2911 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2912 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2913 v = bc.convert('cfg://nest3')
2914 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2915 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2916 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2917 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002918
2919class ManagerTest(BaseTest):
2920 def test_manager_loggerclass(self):
2921 logged = []
2922
2923 class MyLogger(logging.Logger):
2924 def _log(self, level, msg, args, exc_info=None, extra=None):
2925 logged.append(msg)
2926
2927 man = logging.Manager(None)
2928 self.assertRaises(TypeError, man.setLoggerClass, int)
2929 man.setLoggerClass(MyLogger)
2930 logger = man.getLogger('test')
2931 logger.warning('should appear in logged')
2932 logging.warning('should not appear in logged')
2933
2934 self.assertEqual(logged, ['should appear in logged'])
2935
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002936 def test_set_log_record_factory(self):
2937 man = logging.Manager(None)
2938 expected = object()
2939 man.setLogRecordFactory(expected)
2940 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002941
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002942class ChildLoggerTest(BaseTest):
2943 def test_child_loggers(self):
2944 r = logging.getLogger()
2945 l1 = logging.getLogger('abc')
2946 l2 = logging.getLogger('def.ghi')
2947 c1 = r.getChild('xyz')
2948 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002949 self.assertIs(c1, logging.getLogger('xyz'))
2950 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002951 c1 = l1.getChild('def')
2952 c2 = c1.getChild('ghi')
2953 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002954 self.assertIs(c1, logging.getLogger('abc.def'))
2955 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2956 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002957
2958
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959class DerivedLogRecord(logging.LogRecord):
2960 pass
2961
Vinay Sajip61561522010-12-03 11:50:38 +00002962class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002963
2964 def setUp(self):
2965 class CheckingFilter(logging.Filter):
2966 def __init__(self, cls):
2967 self.cls = cls
2968
2969 def filter(self, record):
2970 t = type(record)
2971 if t is not self.cls:
2972 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2973 self.cls)
2974 raise TypeError(msg)
2975 return True
2976
2977 BaseTest.setUp(self)
2978 self.filter = CheckingFilter(DerivedLogRecord)
2979 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002980 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002981
2982 def tearDown(self):
2983 self.root_logger.removeFilter(self.filter)
2984 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002985 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002986
2987 def test_logrecord_class(self):
2988 self.assertRaises(TypeError, self.root_logger.warning,
2989 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002990 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002991 self.root_logger.error(self.next_message())
2992 self.assert_log_lines([
2993 ('root', 'ERROR', '2'),
2994 ])
2995
2996
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002997class QueueHandlerTest(BaseTest):
2998 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002999 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003000
3001 def setUp(self):
3002 BaseTest.setUp(self)
3003 self.queue = queue.Queue(-1)
3004 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3005 self.que_logger = logging.getLogger('que')
3006 self.que_logger.propagate = False
3007 self.que_logger.setLevel(logging.WARNING)
3008 self.que_logger.addHandler(self.que_hdlr)
3009
3010 def tearDown(self):
3011 self.que_hdlr.close()
3012 BaseTest.tearDown(self)
3013
3014 def test_queue_handler(self):
3015 self.que_logger.debug(self.next_message())
3016 self.assertRaises(queue.Empty, self.queue.get_nowait)
3017 self.que_logger.info(self.next_message())
3018 self.assertRaises(queue.Empty, self.queue.get_nowait)
3019 msg = self.next_message()
3020 self.que_logger.warning(msg)
3021 data = self.queue.get_nowait()
3022 self.assertTrue(isinstance(data, logging.LogRecord))
3023 self.assertEqual(data.name, self.que_logger.name)
3024 self.assertEqual((data.msg, data.args), (msg, None))
3025
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003026 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3027 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003028 def test_queue_listener(self):
3029 handler = TestHandler(Matcher())
3030 listener = logging.handlers.QueueListener(self.queue, handler)
3031 listener.start()
3032 try:
3033 self.que_logger.warning(self.next_message())
3034 self.que_logger.error(self.next_message())
3035 self.que_logger.critical(self.next_message())
3036 finally:
3037 listener.stop()
3038 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3039 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3040 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3041
Vinay Sajip37eb3382011-04-26 20:26:41 +01003042ZERO = datetime.timedelta(0)
3043
3044class UTC(datetime.tzinfo):
3045 def utcoffset(self, dt):
3046 return ZERO
3047
3048 dst = utcoffset
3049
3050 def tzname(self, dt):
3051 return 'UTC'
3052
3053utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003054
Vinay Sajipa39c5712010-10-25 13:57:39 +00003055class FormatterTest(unittest.TestCase):
3056 def setUp(self):
3057 self.common = {
3058 'name': 'formatter.test',
3059 'level': logging.DEBUG,
3060 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3061 'lineno': 42,
3062 'exc_info': None,
3063 'func': None,
3064 'msg': 'Message with %d %s',
3065 'args': (2, 'placeholders'),
3066 }
3067 self.variants = {
3068 }
3069
3070 def get_record(self, name=None):
3071 result = dict(self.common)
3072 if name is not None:
3073 result.update(self.variants[name])
3074 return logging.makeLogRecord(result)
3075
3076 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003077 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003078 r = self.get_record()
3079 f = logging.Formatter('${%(message)s}')
3080 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3081 f = logging.Formatter('%(random)s')
3082 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003083 self.assertFalse(f.usesTime())
3084 f = logging.Formatter('%(asctime)s')
3085 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003086 f = logging.Formatter('%(asctime)-15s')
3087 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003088 f = logging.Formatter('asctime')
3089 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003090
3091 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003092 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003093 r = self.get_record()
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!s:15}', style='{')
3102 self.assertTrue(f.usesTime())
3103 f = logging.Formatter('{asctime:15}', style='{')
3104 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003105 f = logging.Formatter('asctime', style='{')
3106 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003107
3108 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003109 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003110 r = self.get_record()
3111 f = logging.Formatter('$message', style='$')
3112 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3113 f = logging.Formatter('$$%${message}%$$', style='$')
3114 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3115 f = logging.Formatter('${random}', style='$')
3116 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003117 self.assertFalse(f.usesTime())
3118 f = logging.Formatter('${asctime}', style='$')
3119 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003120 f = logging.Formatter('${asctime', style='$')
3121 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003122 f = logging.Formatter('$asctime', style='$')
3123 self.assertTrue(f.usesTime())
3124 f = logging.Formatter('asctime', style='$')
3125 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003126
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003127 def test_invalid_style(self):
3128 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3129
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003130 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003131 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003132 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3133 # We use None to indicate we want the local timezone
3134 # We're essentially converting a UTC time to local time
3135 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003136 r.msecs = 123
3137 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003138 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003139 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3140 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003141 f.format(r)
3142 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3143
3144class TestBufferingFormatter(logging.BufferingFormatter):
3145 def formatHeader(self, records):
3146 return '[(%d)' % len(records)
3147
3148 def formatFooter(self, records):
3149 return '(%d)]' % len(records)
3150
3151class BufferingFormatterTest(unittest.TestCase):
3152 def setUp(self):
3153 self.records = [
3154 logging.makeLogRecord({'msg': 'one'}),
3155 logging.makeLogRecord({'msg': 'two'}),
3156 ]
3157
3158 def test_default(self):
3159 f = logging.BufferingFormatter()
3160 self.assertEqual('', f.format([]))
3161 self.assertEqual('onetwo', f.format(self.records))
3162
3163 def test_custom(self):
3164 f = TestBufferingFormatter()
3165 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3166 lf = logging.Formatter('<%(message)s>')
3167 f = TestBufferingFormatter(lf)
3168 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003169
3170class ExceptionTest(BaseTest):
3171 def test_formatting(self):
3172 r = self.root_logger
3173 h = RecordingHandler()
3174 r.addHandler(h)
3175 try:
3176 raise RuntimeError('deliberate mistake')
3177 except:
3178 logging.exception('failed', stack_info=True)
3179 r.removeHandler(h)
3180 h.close()
3181 r = h.records[0]
3182 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3183 'call last):\n'))
3184 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3185 'deliberate mistake'))
3186 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3187 'call last):\n'))
3188 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3189 'stack_info=True)'))
3190
3191
Vinay Sajip5a27d402010-12-10 11:42:57 +00003192class LastResortTest(BaseTest):
3193 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003194 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003195 root = self.root_logger
3196 root.removeHandler(self.root_hdlr)
3197 old_stderr = sys.stderr
3198 old_lastresort = logging.lastResort
3199 old_raise_exceptions = logging.raiseExceptions
3200 try:
3201 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003202 root.debug('This should not appear')
3203 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003204 root.warning('This is your final chance!')
3205 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3206 #No handlers and no last resort, so 'No handlers' message
3207 logging.lastResort = None
3208 sys.stderr = sio = io.StringIO()
3209 root.warning('This is your final chance!')
3210 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3211 # 'No handlers' message only printed once
3212 sys.stderr = sio = io.StringIO()
3213 root.warning('This is your final chance!')
3214 self.assertEqual(sio.getvalue(), '')
3215 root.manager.emittedNoHandlerWarning = False
3216 #If raiseExceptions is False, no message is printed
3217 logging.raiseExceptions = False
3218 sys.stderr = sio = io.StringIO()
3219 root.warning('This is your final chance!')
3220 self.assertEqual(sio.getvalue(), '')
3221 finally:
3222 sys.stderr = old_stderr
3223 root.addHandler(self.root_hdlr)
3224 logging.lastResort = old_lastresort
3225 logging.raiseExceptions = old_raise_exceptions
3226
3227
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003228class FakeHandler:
3229
3230 def __init__(self, identifier, called):
3231 for method in ('acquire', 'flush', 'close', 'release'):
3232 setattr(self, method, self.record_call(identifier, method, called))
3233
3234 def record_call(self, identifier, method_name, called):
3235 def inner():
3236 called.append('{} - {}'.format(identifier, method_name))
3237 return inner
3238
3239
3240class RecordingHandler(logging.NullHandler):
3241
3242 def __init__(self, *args, **kwargs):
3243 super(RecordingHandler, self).__init__(*args, **kwargs)
3244 self.records = []
3245
3246 def handle(self, record):
3247 """Keep track of all the emitted records."""
3248 self.records.append(record)
3249
3250
3251class ShutdownTest(BaseTest):
3252
Vinay Sajip5e66b162011-04-20 15:41:14 +01003253 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003254
3255 def setUp(self):
3256 super(ShutdownTest, self).setUp()
3257 self.called = []
3258
3259 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003260 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003261
3262 def raise_error(self, error):
3263 def inner():
3264 raise error()
3265 return inner
3266
3267 def test_no_failure(self):
3268 # create some fake handlers
3269 handler0 = FakeHandler(0, self.called)
3270 handler1 = FakeHandler(1, self.called)
3271 handler2 = FakeHandler(2, self.called)
3272
3273 # create live weakref to those handlers
3274 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3275
3276 logging.shutdown(handlerList=list(handlers))
3277
3278 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3279 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3280 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3281 self.assertEqual(expected, self.called)
3282
3283 def _test_with_failure_in_method(self, method, error):
3284 handler = FakeHandler(0, self.called)
3285 setattr(handler, method, self.raise_error(error))
3286 handlers = [logging.weakref.ref(handler)]
3287
3288 logging.shutdown(handlerList=list(handlers))
3289
3290 self.assertEqual('0 - release', self.called[-1])
3291
3292 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003293 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003294
3295 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003296 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003297
3298 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003299 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003300
3301 def test_with_valueerror_in_acquire(self):
3302 self._test_with_failure_in_method('acquire', ValueError)
3303
3304 def test_with_valueerror_in_flush(self):
3305 self._test_with_failure_in_method('flush', ValueError)
3306
3307 def test_with_valueerror_in_close(self):
3308 self._test_with_failure_in_method('close', ValueError)
3309
3310 def test_with_other_error_in_acquire_without_raise(self):
3311 logging.raiseExceptions = False
3312 self._test_with_failure_in_method('acquire', IndexError)
3313
3314 def test_with_other_error_in_flush_without_raise(self):
3315 logging.raiseExceptions = False
3316 self._test_with_failure_in_method('flush', IndexError)
3317
3318 def test_with_other_error_in_close_without_raise(self):
3319 logging.raiseExceptions = False
3320 self._test_with_failure_in_method('close', IndexError)
3321
3322 def test_with_other_error_in_acquire_with_raise(self):
3323 logging.raiseExceptions = True
3324 self.assertRaises(IndexError, self._test_with_failure_in_method,
3325 'acquire', IndexError)
3326
3327 def test_with_other_error_in_flush_with_raise(self):
3328 logging.raiseExceptions = True
3329 self.assertRaises(IndexError, self._test_with_failure_in_method,
3330 'flush', IndexError)
3331
3332 def test_with_other_error_in_close_with_raise(self):
3333 logging.raiseExceptions = True
3334 self.assertRaises(IndexError, self._test_with_failure_in_method,
3335 'close', IndexError)
3336
3337
3338class ModuleLevelMiscTest(BaseTest):
3339
Vinay Sajip5e66b162011-04-20 15:41:14 +01003340 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003341
3342 def test_disable(self):
3343 old_disable = logging.root.manager.disable
3344 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003345 self.assertEqual(old_disable, 0)
3346 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003347
3348 logging.disable(83)
3349 self.assertEqual(logging.root.manager.disable, 83)
3350
3351 def _test_log(self, method, level=None):
3352 called = []
3353 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003354 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003355
3356 recording = RecordingHandler()
3357 logging.root.addHandler(recording)
3358
3359 log_method = getattr(logging, method)
3360 if level is not None:
3361 log_method(level, "test me: %r", recording)
3362 else:
3363 log_method("test me: %r", recording)
3364
3365 self.assertEqual(len(recording.records), 1)
3366 record = recording.records[0]
3367 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3368
3369 expected_level = level if level is not None else getattr(logging, method.upper())
3370 self.assertEqual(record.levelno, expected_level)
3371
3372 # basicConfig was not called!
3373 self.assertEqual(called, [])
3374
3375 def test_log(self):
3376 self._test_log('log', logging.ERROR)
3377
3378 def test_debug(self):
3379 self._test_log('debug')
3380
3381 def test_info(self):
3382 self._test_log('info')
3383
3384 def test_warning(self):
3385 self._test_log('warning')
3386
3387 def test_error(self):
3388 self._test_log('error')
3389
3390 def test_critical(self):
3391 self._test_log('critical')
3392
3393 def test_set_logger_class(self):
3394 self.assertRaises(TypeError, logging.setLoggerClass, object)
3395
3396 class MyLogger(logging.Logger):
3397 pass
3398
3399 logging.setLoggerClass(MyLogger)
3400 self.assertEqual(logging.getLoggerClass(), MyLogger)
3401
3402 logging.setLoggerClass(logging.Logger)
3403 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3404
Antoine Pitrou712cb732013-12-21 15:51:54 +01003405 def test_logging_at_shutdown(self):
3406 # Issue #20037
3407 code = """if 1:
3408 import logging
3409
3410 class A:
3411 def __del__(self):
3412 try:
3413 raise ValueError("some error")
3414 except Exception:
3415 logging.exception("exception in __del__")
3416
3417 a = A()"""
3418 rc, out, err = assert_python_ok("-c", code)
3419 err = err.decode()
3420 self.assertIn("exception in __del__", err)
3421 self.assertIn("ValueError: some error", err)
3422
3423
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003424class LogRecordTest(BaseTest):
3425 def test_str_rep(self):
3426 r = logging.makeLogRecord({})
3427 s = str(r)
3428 self.assertTrue(s.startswith('<LogRecord: '))
3429 self.assertTrue(s.endswith('>'))
3430
3431 def test_dict_arg(self):
3432 h = RecordingHandler()
3433 r = logging.getLogger()
3434 r.addHandler(h)
3435 d = {'less' : 'more' }
3436 logging.warning('less is %(less)s', d)
3437 self.assertIs(h.records[0].args, d)
3438 self.assertEqual(h.records[0].message, 'less is more')
3439 r.removeHandler(h)
3440 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003441
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003442 def test_multiprocessing(self):
3443 r = logging.makeLogRecord({})
3444 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003445 try:
3446 import multiprocessing as mp
3447 r = logging.makeLogRecord({})
3448 self.assertEqual(r.processName, mp.current_process().name)
3449 except ImportError:
3450 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003451
3452 def test_optional(self):
3453 r = logging.makeLogRecord({})
3454 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003455 if threading:
3456 NOT_NONE(r.thread)
3457 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003458 NOT_NONE(r.process)
3459 NOT_NONE(r.processName)
3460 log_threads = logging.logThreads
3461 log_processes = logging.logProcesses
3462 log_multiprocessing = logging.logMultiprocessing
3463 try:
3464 logging.logThreads = False
3465 logging.logProcesses = False
3466 logging.logMultiprocessing = False
3467 r = logging.makeLogRecord({})
3468 NONE = self.assertIsNone
3469 NONE(r.thread)
3470 NONE(r.threadName)
3471 NONE(r.process)
3472 NONE(r.processName)
3473 finally:
3474 logging.logThreads = log_threads
3475 logging.logProcesses = log_processes
3476 logging.logMultiprocessing = log_multiprocessing
3477
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003478class BasicConfigTest(unittest.TestCase):
3479
Vinay Sajip95bf5042011-04-20 11:50:56 +01003480 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003481
3482 def setUp(self):
3483 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003484 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003485 self.saved_handlers = logging._handlers.copy()
3486 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003487 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003488 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003489 logging.root.handlers = []
3490
3491 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003492 for h in logging.root.handlers[:]:
3493 logging.root.removeHandler(h)
3494 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003495 super(BasicConfigTest, self).tearDown()
3496
Vinay Sajip3def7e02011-04-20 10:58:06 +01003497 def cleanup(self):
3498 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003499 logging._handlers.clear()
3500 logging._handlers.update(self.saved_handlers)
3501 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003502 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003503
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003504 def test_no_kwargs(self):
3505 logging.basicConfig()
3506
3507 # handler defaults to a StreamHandler to sys.stderr
3508 self.assertEqual(len(logging.root.handlers), 1)
3509 handler = logging.root.handlers[0]
3510 self.assertIsInstance(handler, logging.StreamHandler)
3511 self.assertEqual(handler.stream, sys.stderr)
3512
3513 formatter = handler.formatter
3514 # format defaults to logging.BASIC_FORMAT
3515 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3516 # datefmt defaults to None
3517 self.assertIsNone(formatter.datefmt)
3518 # style defaults to %
3519 self.assertIsInstance(formatter._style, logging.PercentStyle)
3520
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003521 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003522 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003523
Vinay Sajip1fd12022014-01-13 21:59:56 +00003524 def test_strformatstyle(self):
3525 with captured_stdout() as output:
3526 logging.basicConfig(stream=sys.stdout, style="{")
3527 logging.error("Log an error")
3528 sys.stdout.seek(0)
3529 self.assertEqual(output.getvalue().strip(),
3530 "ERROR:root:Log an error")
3531
3532 def test_stringtemplatestyle(self):
3533 with captured_stdout() as output:
3534 logging.basicConfig(stream=sys.stdout, style="$")
3535 logging.error("Log an error")
3536 sys.stdout.seek(0)
3537 self.assertEqual(output.getvalue().strip(),
3538 "ERROR:root:Log an error")
3539
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003540 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003541
3542 def cleanup(h1, h2, fn):
3543 h1.close()
3544 h2.close()
3545 os.remove(fn)
3546
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547 logging.basicConfig(filename='test.log')
3548
3549 self.assertEqual(len(logging.root.handlers), 1)
3550 handler = logging.root.handlers[0]
3551 self.assertIsInstance(handler, logging.FileHandler)
3552
3553 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003554 self.assertEqual(handler.stream.mode, expected.stream.mode)
3555 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003556 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003557
3558 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003559
3560 def cleanup(h1, h2, fn):
3561 h1.close()
3562 h2.close()
3563 os.remove(fn)
3564
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003565 logging.basicConfig(filename='test.log', filemode='wb')
3566
3567 handler = logging.root.handlers[0]
3568 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003569 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003570 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003571
3572 def test_stream(self):
3573 stream = io.StringIO()
3574 self.addCleanup(stream.close)
3575 logging.basicConfig(stream=stream)
3576
3577 self.assertEqual(len(logging.root.handlers), 1)
3578 handler = logging.root.handlers[0]
3579 self.assertIsInstance(handler, logging.StreamHandler)
3580 self.assertEqual(handler.stream, stream)
3581
3582 def test_format(self):
3583 logging.basicConfig(format='foo')
3584
3585 formatter = logging.root.handlers[0].formatter
3586 self.assertEqual(formatter._style._fmt, 'foo')
3587
3588 def test_datefmt(self):
3589 logging.basicConfig(datefmt='bar')
3590
3591 formatter = logging.root.handlers[0].formatter
3592 self.assertEqual(formatter.datefmt, 'bar')
3593
3594 def test_style(self):
3595 logging.basicConfig(style='$')
3596
3597 formatter = logging.root.handlers[0].formatter
3598 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3599
3600 def test_level(self):
3601 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003602 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003603
3604 logging.basicConfig(level=57)
3605 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003606 # Test that second call has no effect
3607 logging.basicConfig(level=58)
3608 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003609
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003610 def test_incompatible(self):
3611 assertRaises = self.assertRaises
3612 handlers = [logging.StreamHandler()]
3613 stream = sys.stderr
3614 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3615 stream=stream)
3616 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3617 handlers=handlers)
3618 assertRaises(ValueError, logging.basicConfig, stream=stream,
3619 handlers=handlers)
3620
3621 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003622 handlers = [
3623 logging.StreamHandler(),
3624 logging.StreamHandler(sys.stdout),
3625 logging.StreamHandler(),
3626 ]
3627 f = logging.Formatter()
3628 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003629 logging.basicConfig(handlers=handlers)
3630 self.assertIs(handlers[0], logging.root.handlers[0])
3631 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003632 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003633 self.assertIsNotNone(handlers[0].formatter)
3634 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003635 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003636 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3637
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003638 def _test_log(self, method, level=None):
3639 # logging.root has no handlers so basicConfig should be called
3640 called = []
3641
3642 old_basic_config = logging.basicConfig
3643 def my_basic_config(*a, **kw):
3644 old_basic_config()
3645 old_level = logging.root.level
3646 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003647 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003648 called.append((a, kw))
3649
3650 patch(self, logging, 'basicConfig', my_basic_config)
3651
3652 log_method = getattr(logging, method)
3653 if level is not None:
3654 log_method(level, "test me")
3655 else:
3656 log_method("test me")
3657
3658 # basicConfig was called with no arguments
3659 self.assertEqual(called, [((), {})])
3660
3661 def test_log(self):
3662 self._test_log('log', logging.WARNING)
3663
3664 def test_debug(self):
3665 self._test_log('debug')
3666
3667 def test_info(self):
3668 self._test_log('info')
3669
3670 def test_warning(self):
3671 self._test_log('warning')
3672
3673 def test_error(self):
3674 self._test_log('error')
3675
3676 def test_critical(self):
3677 self._test_log('critical')
3678
3679
3680class LoggerAdapterTest(unittest.TestCase):
3681
3682 def setUp(self):
3683 super(LoggerAdapterTest, self).setUp()
3684 old_handler_list = logging._handlerList[:]
3685
3686 self.recording = RecordingHandler()
3687 self.logger = logging.root
3688 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003689 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003690 self.addCleanup(self.recording.close)
3691
3692 def cleanup():
3693 logging._handlerList[:] = old_handler_list
3694
3695 self.addCleanup(cleanup)
3696 self.addCleanup(logging.shutdown)
3697 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3698
3699 def test_exception(self):
3700 msg = 'testing exception: %r'
3701 exc = None
3702 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003703 1 / 0
3704 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003705 exc = e
3706 self.adapter.exception(msg, self.recording)
3707
3708 self.assertEqual(len(self.recording.records), 1)
3709 record = self.recording.records[0]
3710 self.assertEqual(record.levelno, logging.ERROR)
3711 self.assertEqual(record.msg, msg)
3712 self.assertEqual(record.args, (self.recording,))
3713 self.assertEqual(record.exc_info,
3714 (exc.__class__, exc, exc.__traceback__))
3715
3716 def test_critical(self):
3717 msg = 'critical test! %r'
3718 self.adapter.critical(msg, self.recording)
3719
3720 self.assertEqual(len(self.recording.records), 1)
3721 record = self.recording.records[0]
3722 self.assertEqual(record.levelno, logging.CRITICAL)
3723 self.assertEqual(record.msg, msg)
3724 self.assertEqual(record.args, (self.recording,))
3725
3726 def test_is_enabled_for(self):
3727 old_disable = self.adapter.logger.manager.disable
3728 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003729 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3730 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003731 self.assertFalse(self.adapter.isEnabledFor(32))
3732
3733 def test_has_handlers(self):
3734 self.assertTrue(self.adapter.hasHandlers())
3735
3736 for handler in self.logger.handlers:
3737 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003738
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003739 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003740 self.assertFalse(self.adapter.hasHandlers())
3741
3742
3743class LoggerTest(BaseTest):
3744
3745 def setUp(self):
3746 super(LoggerTest, self).setUp()
3747 self.recording = RecordingHandler()
3748 self.logger = logging.Logger(name='blah')
3749 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003750 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751 self.addCleanup(self.recording.close)
3752 self.addCleanup(logging.shutdown)
3753
3754 def test_set_invalid_level(self):
3755 self.assertRaises(TypeError, self.logger.setLevel, object())
3756
3757 def test_exception(self):
3758 msg = 'testing exception: %r'
3759 exc = None
3760 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003761 1 / 0
3762 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003763 exc = e
3764 self.logger.exception(msg, self.recording)
3765
3766 self.assertEqual(len(self.recording.records), 1)
3767 record = self.recording.records[0]
3768 self.assertEqual(record.levelno, logging.ERROR)
3769 self.assertEqual(record.msg, msg)
3770 self.assertEqual(record.args, (self.recording,))
3771 self.assertEqual(record.exc_info,
3772 (exc.__class__, exc, exc.__traceback__))
3773
3774 def test_log_invalid_level_with_raise(self):
3775 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003776 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003777
3778 logging.raiseExceptions = True
3779 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3780
3781 def test_log_invalid_level_no_raise(self):
3782 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003783 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003784
3785 logging.raiseExceptions = False
3786 self.logger.log('10', 'test message') # no exception happens
3787
3788 def test_find_caller_with_stack_info(self):
3789 called = []
3790 patch(self, logging.traceback, 'print_stack',
3791 lambda f, file: called.append(file.getvalue()))
3792
3793 self.logger.findCaller(stack_info=True)
3794
3795 self.assertEqual(len(called), 1)
3796 self.assertEqual('Stack (most recent call last):\n', called[0])
3797
3798 def test_make_record_with_extra_overwrite(self):
3799 name = 'my record'
3800 level = 13
3801 fn = lno = msg = args = exc_info = func = sinfo = None
3802 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3803 exc_info, func, sinfo)
3804
3805 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3806 extra = {key: 'some value'}
3807 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3808 fn, lno, msg, args, exc_info,
3809 extra=extra, sinfo=sinfo)
3810
3811 def test_make_record_with_extra_no_overwrite(self):
3812 name = 'my record'
3813 level = 13
3814 fn = lno = msg = args = exc_info = func = sinfo = None
3815 extra = {'valid_key': 'some value'}
3816 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3817 exc_info, extra=extra, sinfo=sinfo)
3818 self.assertIn('valid_key', result.__dict__)
3819
3820 def test_has_handlers(self):
3821 self.assertTrue(self.logger.hasHandlers())
3822
3823 for handler in self.logger.handlers:
3824 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825 self.assertFalse(self.logger.hasHandlers())
3826
3827 def test_has_handlers_no_propagate(self):
3828 child_logger = logging.getLogger('blah.child')
3829 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003830 self.assertFalse(child_logger.hasHandlers())
3831
3832 def test_is_enabled_for(self):
3833 old_disable = self.logger.manager.disable
3834 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003835 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003836 self.assertFalse(self.logger.isEnabledFor(22))
3837
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003838 def test_root_logger_aliases(self):
3839 root = logging.getLogger()
3840 self.assertIs(root, logging.root)
3841 self.assertIs(root, logging.getLogger(None))
3842 self.assertIs(root, logging.getLogger(''))
3843 self.assertIs(root, logging.getLogger('foo').root)
3844 self.assertIs(root, logging.getLogger('foo.bar').root)
3845 self.assertIs(root, logging.getLogger('foo').parent)
3846
3847 self.assertIsNot(root, logging.getLogger('\0'))
3848 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3849
3850 def test_invalid_names(self):
3851 self.assertRaises(TypeError, logging.getLogger, any)
3852 self.assertRaises(TypeError, logging.getLogger, b'foo')
3853
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003854
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003855class BaseFileTest(BaseTest):
3856 "Base class for handler tests that write log files"
3857
3858 def setUp(self):
3859 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003860 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3861 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003862 self.rmfiles = []
3863
3864 def tearDown(self):
3865 for fn in self.rmfiles:
3866 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003867 if os.path.exists(self.fn):
3868 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003869 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003870
3871 def assertLogFile(self, filename):
3872 "Assert a log file is there and register it for deletion"
3873 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003874 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003875 self.rmfiles.append(filename)
3876
3877
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003878class FileHandlerTest(BaseFileTest):
3879 def test_delay(self):
3880 os.unlink(self.fn)
3881 fh = logging.FileHandler(self.fn, delay=True)
3882 self.assertIsNone(fh.stream)
3883 self.assertFalse(os.path.exists(self.fn))
3884 fh.handle(logging.makeLogRecord({}))
3885 self.assertIsNotNone(fh.stream)
3886 self.assertTrue(os.path.exists(self.fn))
3887 fh.close()
3888
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003889class RotatingFileHandlerTest(BaseFileTest):
3890 def next_rec(self):
3891 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3892 self.next_message(), None, None, None)
3893
3894 def test_should_not_rollover(self):
3895 # If maxbytes is zero rollover never occurs
3896 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3897 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003898 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003899
3900 def test_should_rollover(self):
3901 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3902 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003903 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003904
3905 def test_file_created(self):
3906 # checks that the file is created and assumes it was created
3907 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003908 rh = logging.handlers.RotatingFileHandler(self.fn)
3909 rh.emit(self.next_rec())
3910 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003911 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003912
3913 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003914 def namer(name):
3915 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003916 rh = logging.handlers.RotatingFileHandler(
3917 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003918 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003919 rh.emit(self.next_rec())
3920 self.assertLogFile(self.fn)
3921 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003922 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003923 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003924 self.assertLogFile(namer(self.fn + ".2"))
3925 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3926 rh.close()
3927
Eric V. Smith851cad72012-03-11 22:46:04 -07003928 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003929 def test_rotator(self):
3930 def namer(name):
3931 return name + ".gz"
3932
3933 def rotator(source, dest):
3934 with open(source, "rb") as sf:
3935 data = sf.read()
3936 compressed = zlib.compress(data, 9)
3937 with open(dest, "wb") as df:
3938 df.write(compressed)
3939 os.remove(source)
3940
3941 rh = logging.handlers.RotatingFileHandler(
3942 self.fn, backupCount=2, maxBytes=1)
3943 rh.rotator = rotator
3944 rh.namer = namer
3945 m1 = self.next_rec()
3946 rh.emit(m1)
3947 self.assertLogFile(self.fn)
3948 m2 = self.next_rec()
3949 rh.emit(m2)
3950 fn = namer(self.fn + ".1")
3951 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003952 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003953 with open(fn, "rb") as f:
3954 compressed = f.read()
3955 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003956 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003957 rh.emit(self.next_rec())
3958 fn = namer(self.fn + ".2")
3959 self.assertLogFile(fn)
3960 with open(fn, "rb") as f:
3961 compressed = f.read()
3962 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003963 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003964 rh.emit(self.next_rec())
3965 fn = namer(self.fn + ".2")
3966 with open(fn, "rb") as f:
3967 compressed = f.read()
3968 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003969 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003970 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003971 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003972
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003973class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003974 # other test methods added below
3975 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003976 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3977 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003978 fmt = logging.Formatter('%(asctime)s %(message)s')
3979 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003980 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003981 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003982 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003983 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003984 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003985 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003986 fh.close()
3987 # At this point, we should have a recent rotated file which we
3988 # can test for the existence of. However, in practice, on some
3989 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003990 # in time to go to look for the log file. So, we go back a fair
3991 # bit, and stop as soon as we see a rotated file. In theory this
3992 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003993 found = False
3994 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003995 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003996 for secs in range(GO_BACK):
3997 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003998 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3999 found = os.path.exists(fn)
4000 if found:
4001 self.rmfiles.append(fn)
4002 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004003 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4004 if not found:
4005 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004006 dn, fn = os.path.split(self.fn)
4007 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004008 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4009 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004010 for f in files:
4011 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004012 path = os.path.join(dn, f)
4013 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004014 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004015 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004016
Vinay Sajip0372e102011-05-05 12:59:14 +01004017 def test_invalid(self):
4018 assertRaises = self.assertRaises
4019 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004020 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004021 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004022 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004023 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004024 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004025
Vinay Sajipa7130792013-04-12 17:04:23 +01004026 def test_compute_rollover_daily_attime(self):
4027 currentTime = 0
4028 atTime = datetime.time(12, 0, 0)
4029 rh = logging.handlers.TimedRotatingFileHandler(
4030 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4031 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004032 try:
4033 actual = rh.computeRollover(currentTime)
4034 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004035
Vinay Sajipd86ac962013-04-14 12:20:46 +01004036 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4037 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4038 finally:
4039 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004040
Vinay Sajip10e8c492013-05-18 10:19:54 -07004041 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004042 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004043 currentTime = int(time.time())
4044 today = currentTime - currentTime % 86400
4045
Vinay Sajipa7130792013-04-12 17:04:23 +01004046 atTime = datetime.time(12, 0, 0)
4047
Vinay Sajip10e8c492013-05-18 10:19:54 -07004048 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004049 for day in range(7):
4050 rh = logging.handlers.TimedRotatingFileHandler(
4051 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4052 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004053 try:
4054 if wday > day:
4055 # The rollover day has already passed this week, so we
4056 # go over into next week
4057 expected = (7 - wday + day)
4058 else:
4059 expected = (day - wday)
4060 # At this point expected is in days from now, convert to seconds
4061 expected *= 24 * 60 * 60
4062 # Add in the rollover time
4063 expected += 12 * 60 * 60
4064 # Add in adjustment for today
4065 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004066 actual = rh.computeRollover(today)
4067 if actual != expected:
4068 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004069 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004070 self.assertEqual(actual, expected)
4071 if day == wday:
4072 # goes into following week
4073 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004074 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004075 if actual != expected:
4076 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004077 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004078 self.assertEqual(actual, expected)
4079 finally:
4080 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004081
4082
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004083def secs(**kw):
4084 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4085
4086for when, exp in (('S', 1),
4087 ('M', 60),
4088 ('H', 60 * 60),
4089 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004090 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004091 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004092 ('W0', secs(days=4, hours=24)),
4093 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004094 def test_compute_rollover(self, when=when, exp=exp):
4095 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004096 self.fn, when=when, interval=1, backupCount=0, utc=True)
4097 currentTime = 0.0
4098 actual = rh.computeRollover(currentTime)
4099 if exp != actual:
4100 # Failures occur on some systems for MIDNIGHT and W0.
4101 # Print detailed calculation for MIDNIGHT so we can try to see
4102 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004103 if when == 'MIDNIGHT':
4104 try:
4105 if rh.utc:
4106 t = time.gmtime(currentTime)
4107 else:
4108 t = time.localtime(currentTime)
4109 currentHour = t[3]
4110 currentMinute = t[4]
4111 currentSecond = t[5]
4112 # r is the number of seconds left between now and midnight
4113 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4114 currentMinute) * 60 +
4115 currentSecond)
4116 result = currentTime + r
4117 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4118 print('currentHour: %s' % currentHour, file=sys.stderr)
4119 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4120 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4121 print('r: %s' % r, file=sys.stderr)
4122 print('result: %s' % result, file=sys.stderr)
4123 except Exception:
4124 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4125 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004126 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004127 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4128
Vinay Sajip60ccd822011-05-09 17:32:09 +01004129
4130@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4131class NTEventLogHandlerTest(BaseTest):
4132 def test_basic(self):
4133 logtype = 'Application'
4134 elh = win32evtlog.OpenEventLog(None, logtype)
4135 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4136 h = logging.handlers.NTEventLogHandler('test_logging')
4137 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4138 h.handle(r)
4139 h.close()
4140 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004141 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004142 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4143 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4144 found = False
4145 GO_BACK = 100
4146 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4147 for e in events:
4148 if e.SourceName != 'test_logging':
4149 continue
4150 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4151 if msg != 'Test Log Message\r\n':
4152 continue
4153 found = True
4154 break
4155 msg = 'Record not found in event log, went back %d records' % GO_BACK
4156 self.assertTrue(found, msg=msg)
4157
Christian Heimes180510d2008-03-03 19:15:45 +00004158# Set the locale to the platform-dependent default. I have no idea
4159# why the test does this, but in any case we save the current locale
4160# first and restore it at the end.
4161@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004162def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004163 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004164 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004165 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4166 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4167 ManagerTest, FormatterTest, BufferingFormatterTest,
4168 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4169 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4170 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4171 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004172 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004173 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004174 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4175 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004176 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004177
Christian Heimes180510d2008-03-03 19:15:45 +00004178if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004179 test_main()