blob: 967432251580755305507ff75678778296d4214b [file] [log] [blame]
Vinay Sajip1feedb42014-05-31 08:19:12 +01001# Copyright 2001-2014 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 Sajip1feedb42014-05-31 08:19:12 +010019Copyright (C) 2001-2014 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
Christian Heimes180510d2008-03-03 19:15:45 +000037import socket
Christian Heimes180510d2008-03-03 19:15:45 +000038import struct
39import sys
40import tempfile
Antoine Pitrou712cb732013-12-21 15:51:54 +010041from test.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010042from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000043import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010044import time
Christian Heimes180510d2008-03-03 19:15:45 +000045import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000046import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000047import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000048try:
49 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010050 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010051 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 from http.server import HTTPServer, BaseHTTPRequestHandler
54 import smtpd
55 from urllib.parse import urlparse, parse_qs
56 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010057 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000058except ImportError:
59 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010060try:
61 import win32evtlog
62except ImportError:
63 win32evtlog = None
64try:
65 import win32evtlogutil
66except ImportError:
67 win32evtlogutil = None
68 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070069try:
70 import zlib
71except ImportError:
72 pass
Christian Heimes18c66892008-02-17 13:31:39 +000073
Christian Heimes180510d2008-03-03 19:15:45 +000074class BaseTest(unittest.TestCase):
75
76 """Base class for logging tests."""
77
78 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030079 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000080 message_num = 0
81
82 def setUp(self):
83 """Setup the default logging stream to an internal StringIO instance,
84 so that we can examine log output as we want."""
85 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000086 logging._acquireLock()
87 try:
Christian Heimes180510d2008-03-03 19:15:45 +000088 self.saved_handlers = logging._handlers.copy()
89 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070091 self.saved_name_to_level = logging._nameToLevel.copy()
92 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000093 self.logger_states = logger_states = {}
94 for name in saved_loggers:
95 logger_states[name] = getattr(saved_loggers[name],
96 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000097 finally:
98 logging._releaseLock()
99
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100100 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000101 self.logger1 = logging.getLogger("\xab\xd7\xbb")
102 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000103
Christian Heimes180510d2008-03-03 19:15:45 +0000104 self.root_logger = logging.getLogger("")
105 self.original_logging_level = self.root_logger.getEffectiveLevel()
106
107 self.stream = io.StringIO()
108 self.root_logger.setLevel(logging.DEBUG)
109 self.root_hdlr = logging.StreamHandler(self.stream)
110 self.root_formatter = logging.Formatter(self.log_format)
111 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000112 if self.logger1.hasHandlers():
113 hlist = self.logger1.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
115 if self.logger2.hasHandlers():
116 hlist = self.logger2.handlers + self.root_logger.handlers
117 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000118 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000119 self.assertTrue(self.logger1.hasHandlers())
120 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000121
122 def tearDown(self):
123 """Remove our logging stream, and restore the original logging
124 level."""
125 self.stream.close()
126 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000127 while self.root_logger.handlers:
128 h = self.root_logger.handlers[0]
129 self.root_logger.removeHandler(h)
130 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000131 self.root_logger.setLevel(self.original_logging_level)
132 logging._acquireLock()
133 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700134 logging._levelToName.clear()
135 logging._levelToName.update(self.saved_level_to_name)
136 logging._nameToLevel.clear()
137 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000138 logging._handlers.clear()
139 logging._handlers.update(self.saved_handlers)
140 logging._handlerList[:] = self.saved_handler_list
141 loggerDict = logging.getLogger().manager.loggerDict
142 loggerDict.clear()
143 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000144 logger_states = self.logger_states
145 for name in self.logger_states:
146 if logger_states[name] is not None:
147 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000148 finally:
149 logging._releaseLock()
150
Vinay Sajip4ded5512012-10-02 15:56:16 +0100151 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000152 """Match the collected log lines against the regular expression
153 self.expected_log_pat, and compare the extracted group values to
154 the expected_values list of tuples."""
155 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100156 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300157 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100158 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000159 for actual, expected in zip(actual_lines, expected_values):
160 match = pat.search(actual)
161 if not match:
162 self.fail("Log line does not match expected pattern:\n" +
163 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000164 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000165 s = stream.read()
166 if s:
167 self.fail("Remaining output at end of log stream:\n" + s)
168
169 def next_message(self):
170 """Generate a message consisting solely of an auto-incrementing
171 integer."""
172 self.message_num += 1
173 return "%d" % self.message_num
174
175
176class BuiltinLevelsTest(BaseTest):
177 """Test builtin levels and their inheritance."""
178
179 def test_flat(self):
180 #Logging levels in a flat logger namespace.
181 m = self.next_message
182
183 ERR = logging.getLogger("ERR")
184 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000185 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000186 INF.setLevel(logging.INFO)
187 DEB = logging.getLogger("DEB")
188 DEB.setLevel(logging.DEBUG)
189
190 # These should log.
191 ERR.log(logging.CRITICAL, m())
192 ERR.error(m())
193
194 INF.log(logging.CRITICAL, m())
195 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100196 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000197 INF.info(m())
198
199 DEB.log(logging.CRITICAL, m())
200 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100201 DEB.warning(m())
202 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 DEB.debug(m())
204
205 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100206 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000207 ERR.info(m())
208 ERR.debug(m())
209
210 INF.debug(m())
211
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000212 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000213 ('ERR', 'CRITICAL', '1'),
214 ('ERR', 'ERROR', '2'),
215 ('INF', 'CRITICAL', '3'),
216 ('INF', 'ERROR', '4'),
217 ('INF', 'WARNING', '5'),
218 ('INF', 'INFO', '6'),
219 ('DEB', 'CRITICAL', '7'),
220 ('DEB', 'ERROR', '8'),
221 ('DEB', 'WARNING', '9'),
222 ('DEB', 'INFO', '10'),
223 ('DEB', 'DEBUG', '11'),
224 ])
225
226 def test_nested_explicit(self):
227 # Logging levels in a nested namespace, all explicitly set.
228 m = self.next_message
229
230 INF = logging.getLogger("INF")
231 INF.setLevel(logging.INFO)
232 INF_ERR = logging.getLogger("INF.ERR")
233 INF_ERR.setLevel(logging.ERROR)
234
235 # These should log.
236 INF_ERR.log(logging.CRITICAL, m())
237 INF_ERR.error(m())
238
239 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100240 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000241 INF_ERR.info(m())
242 INF_ERR.debug(m())
243
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000244 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000245 ('INF.ERR', 'CRITICAL', '1'),
246 ('INF.ERR', 'ERROR', '2'),
247 ])
248
249 def test_nested_inherited(self):
250 #Logging levels in a nested namespace, inherited from parent loggers.
251 m = self.next_message
252
253 INF = logging.getLogger("INF")
254 INF.setLevel(logging.INFO)
255 INF_ERR = logging.getLogger("INF.ERR")
256 INF_ERR.setLevel(logging.ERROR)
257 INF_UNDEF = logging.getLogger("INF.UNDEF")
258 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
259 UNDEF = logging.getLogger("UNDEF")
260
261 # These should log.
262 INF_UNDEF.log(logging.CRITICAL, m())
263 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100264 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000265 INF_UNDEF.info(m())
266 INF_ERR_UNDEF.log(logging.CRITICAL, m())
267 INF_ERR_UNDEF.error(m())
268
269 # These should not log.
270 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100271 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000272 INF_ERR_UNDEF.info(m())
273 INF_ERR_UNDEF.debug(m())
274
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000275 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000276 ('INF.UNDEF', 'CRITICAL', '1'),
277 ('INF.UNDEF', 'ERROR', '2'),
278 ('INF.UNDEF', 'WARNING', '3'),
279 ('INF.UNDEF', 'INFO', '4'),
280 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
281 ('INF.ERR.UNDEF', 'ERROR', '6'),
282 ])
283
284 def test_nested_with_virtual_parent(self):
285 # Logging levels when some parent does not exist yet.
286 m = self.next_message
287
288 INF = logging.getLogger("INF")
289 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
290 CHILD = logging.getLogger("INF.BADPARENT")
291 INF.setLevel(logging.INFO)
292
293 # These should log.
294 GRANDCHILD.log(logging.FATAL, m())
295 GRANDCHILD.info(m())
296 CHILD.log(logging.FATAL, m())
297 CHILD.info(m())
298
299 # These should not log.
300 GRANDCHILD.debug(m())
301 CHILD.debug(m())
302
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000303 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000304 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
305 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
306 ('INF.BADPARENT', 'CRITICAL', '3'),
307 ('INF.BADPARENT', 'INFO', '4'),
308 ])
309
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100310 def test_regression_22386(self):
311 """See issue #22386 for more information."""
312 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
313 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000314
315class BasicFilterTest(BaseTest):
316
317 """Test the bundled Filter class."""
318
319 def test_filter(self):
320 # Only messages satisfying the specified criteria pass through the
321 # filter.
322 filter_ = logging.Filter("spam.eggs")
323 handler = self.root_logger.handlers[0]
324 try:
325 handler.addFilter(filter_)
326 spam = logging.getLogger("spam")
327 spam_eggs = logging.getLogger("spam.eggs")
328 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
329 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
330
331 spam.info(self.next_message())
332 spam_eggs.info(self.next_message()) # Good.
333 spam_eggs_fish.info(self.next_message()) # Good.
334 spam_bakedbeans.info(self.next_message())
335
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000336 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000337 ('spam.eggs', 'INFO', '2'),
338 ('spam.eggs.fish', 'INFO', '3'),
339 ])
340 finally:
341 handler.removeFilter(filter_)
342
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000343 def test_callable_filter(self):
344 # Only messages satisfying the specified criteria pass through the
345 # filter.
346
347 def filterfunc(record):
348 parts = record.name.split('.')
349 prefix = '.'.join(parts[:2])
350 return prefix == 'spam.eggs'
351
352 handler = self.root_logger.handlers[0]
353 try:
354 handler.addFilter(filterfunc)
355 spam = logging.getLogger("spam")
356 spam_eggs = logging.getLogger("spam.eggs")
357 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
358 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
359
360 spam.info(self.next_message())
361 spam_eggs.info(self.next_message()) # Good.
362 spam_eggs_fish.info(self.next_message()) # Good.
363 spam_bakedbeans.info(self.next_message())
364
365 self.assert_log_lines([
366 ('spam.eggs', 'INFO', '2'),
367 ('spam.eggs.fish', 'INFO', '3'),
368 ])
369 finally:
370 handler.removeFilter(filterfunc)
371
Vinay Sajip985ef872011-04-26 19:34:04 +0100372 def test_empty_filter(self):
373 f = logging.Filter()
374 r = logging.makeLogRecord({'name': 'spam.eggs'})
375 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000376
377#
378# First, we define our levels. There can be as many as you want - the only
379# limitations are that they should be integers, the lowest should be > 0 and
380# larger values mean less information being logged. If you need specific
381# level values which do not fit into these limitations, you can use a
382# mapping dictionary to convert between your application levels and the
383# logging system.
384#
385SILENT = 120
386TACITURN = 119
387TERSE = 118
388EFFUSIVE = 117
389SOCIABLE = 116
390VERBOSE = 115
391TALKATIVE = 114
392GARRULOUS = 113
393CHATTERBOX = 112
394BORING = 111
395
396LEVEL_RANGE = range(BORING, SILENT + 1)
397
398#
399# Next, we define names for our levels. You don't need to do this - in which
400# case the system will use "Level n" to denote the text for the level.
401#
402my_logging_levels = {
403 SILENT : 'Silent',
404 TACITURN : 'Taciturn',
405 TERSE : 'Terse',
406 EFFUSIVE : 'Effusive',
407 SOCIABLE : 'Sociable',
408 VERBOSE : 'Verbose',
409 TALKATIVE : 'Talkative',
410 GARRULOUS : 'Garrulous',
411 CHATTERBOX : 'Chatterbox',
412 BORING : 'Boring',
413}
414
415class GarrulousFilter(logging.Filter):
416
417 """A filter which blocks garrulous messages."""
418
419 def filter(self, record):
420 return record.levelno != GARRULOUS
421
422class VerySpecificFilter(logging.Filter):
423
424 """A filter which blocks sociable and taciturn messages."""
425
426 def filter(self, record):
427 return record.levelno not in [SOCIABLE, TACITURN]
428
429
430class CustomLevelsAndFiltersTest(BaseTest):
431
432 """Test various filtering possibilities with custom logging levels."""
433
434 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300435 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000436
437 def setUp(self):
438 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000439 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000440 logging.addLevelName(k, v)
441
442 def log_at_all_levels(self, logger):
443 for lvl in LEVEL_RANGE:
444 logger.log(lvl, self.next_message())
445
446 def test_logger_filter(self):
447 # Filter at logger level.
448 self.root_logger.setLevel(VERBOSE)
449 # Levels >= 'Verbose' are good.
450 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000451 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000452 ('Verbose', '5'),
453 ('Sociable', '6'),
454 ('Effusive', '7'),
455 ('Terse', '8'),
456 ('Taciturn', '9'),
457 ('Silent', '10'),
458 ])
459
460 def test_handler_filter(self):
461 # Filter at handler level.
462 self.root_logger.handlers[0].setLevel(SOCIABLE)
463 try:
464 # Levels >= 'Sociable' are good.
465 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000466 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000467 ('Sociable', '6'),
468 ('Effusive', '7'),
469 ('Terse', '8'),
470 ('Taciturn', '9'),
471 ('Silent', '10'),
472 ])
473 finally:
474 self.root_logger.handlers[0].setLevel(logging.NOTSET)
475
476 def test_specific_filters(self):
477 # Set a specific filter object on the handler, and then add another
478 # filter object on the logger itself.
479 handler = self.root_logger.handlers[0]
480 specific_filter = None
481 garr = GarrulousFilter()
482 handler.addFilter(garr)
483 try:
484 self.log_at_all_levels(self.root_logger)
485 first_lines = [
486 # Notice how 'Garrulous' is missing
487 ('Boring', '1'),
488 ('Chatterbox', '2'),
489 ('Talkative', '4'),
490 ('Verbose', '5'),
491 ('Sociable', '6'),
492 ('Effusive', '7'),
493 ('Terse', '8'),
494 ('Taciturn', '9'),
495 ('Silent', '10'),
496 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000497 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000498
499 specific_filter = VerySpecificFilter()
500 self.root_logger.addFilter(specific_filter)
501 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000502 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000503 # Not only 'Garrulous' is still missing, but also 'Sociable'
504 # and 'Taciturn'
505 ('Boring', '11'),
506 ('Chatterbox', '12'),
507 ('Talkative', '14'),
508 ('Verbose', '15'),
509 ('Effusive', '17'),
510 ('Terse', '18'),
511 ('Silent', '20'),
512 ])
513 finally:
514 if specific_filter:
515 self.root_logger.removeFilter(specific_filter)
516 handler.removeFilter(garr)
517
518
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100519class HandlerTest(BaseTest):
520 def test_name(self):
521 h = logging.Handler()
522 h.name = 'generic'
523 self.assertEqual(h.name, 'generic')
524 h.name = 'anothergeneric'
525 self.assertEqual(h.name, 'anothergeneric')
526 self.assertRaises(NotImplementedError, h.emit, None)
527
Vinay Sajip5a35b062011-04-27 11:31:14 +0100528 def test_builtin_handlers(self):
529 # We can't actually *use* too many handlers in the tests,
530 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200531 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100532 for existing in (True, False):
533 fd, fn = tempfile.mkstemp()
534 os.close(fd)
535 if not existing:
536 os.unlink(fn)
537 h = logging.handlers.WatchedFileHandler(fn, delay=True)
538 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100539 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100540 self.assertEqual(dev, -1)
541 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100542 r = logging.makeLogRecord({'msg': 'Test'})
543 h.handle(r)
544 # Now remove the file.
545 os.unlink(fn)
546 self.assertFalse(os.path.exists(fn))
547 # The next call should recreate the file.
548 h.handle(r)
549 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100550 else:
551 self.assertEqual(h.dev, -1)
552 self.assertEqual(h.ino, -1)
553 h.close()
554 if existing:
555 os.unlink(fn)
556 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100557 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100558 else:
559 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100560 try:
561 h = logging.handlers.SysLogHandler(sockname)
562 self.assertEqual(h.facility, h.LOG_USER)
563 self.assertTrue(h.unixsocket)
564 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200565 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100566 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100567 for method in ('GET', 'POST', 'PUT'):
568 if method == 'PUT':
569 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
570 'localhost', '/log', method)
571 else:
572 h = logging.handlers.HTTPHandler('localhost', '/log', method)
573 h.close()
574 h = logging.handlers.BufferingHandler(0)
575 r = logging.makeLogRecord({})
576 self.assertTrue(h.shouldFlush(r))
577 h.close()
578 h = logging.handlers.BufferingHandler(1)
579 self.assertFalse(h.shouldFlush(r))
580 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100581
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100582 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100583 @unittest.skipUnless(threading, 'Threading required for this test.')
584 def test_race(self):
585 # Issue #14632 refers.
586 def remove_loop(fname, tries):
587 for _ in range(tries):
588 try:
589 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000590 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100591 except OSError:
592 pass
593 time.sleep(0.004 * random.randint(0, 4))
594
Vinay Sajipc94871a2012-04-25 10:51:35 +0100595 del_count = 500
596 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000598 self.handle_time = None
599 self.deletion_time = None
600
Vinay Sajipa5798de2012-04-24 23:33:33 +0100601 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100602 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
603 os.close(fd)
604 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
605 remover.daemon = True
606 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100607 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100608 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
609 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100610 try:
611 for _ in range(log_count):
612 time.sleep(0.005)
613 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000614 try:
615 self.handle_time = time.time()
616 h.handle(r)
617 except Exception:
618 print('Deleted at %s, '
619 'opened at %s' % (self.deletion_time,
620 self.handle_time))
621 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100622 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100623 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100624 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100625 if os.path.exists(fn):
626 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100627
628
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100629class BadStream(object):
630 def write(self, data):
631 raise RuntimeError('deliberate mistake')
632
633class TestStreamHandler(logging.StreamHandler):
634 def handleError(self, record):
635 self.error_record = record
636
637class StreamHandlerTest(BaseTest):
638 def test_error_handling(self):
639 h = TestStreamHandler(BadStream())
640 r = logging.makeLogRecord({})
641 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100642
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100643 try:
644 h.handle(r)
645 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100646
Vinay Sajip985ef872011-04-26 19:34:04 +0100647 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100648 with support.captured_stderr() as stderr:
649 h.handle(r)
650 msg = '\nRuntimeError: deliberate mistake\n'
651 self.assertIn(msg, stderr.getvalue())
652
Vinay Sajip985ef872011-04-26 19:34:04 +0100653 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100654 with support.captured_stderr() as stderr:
655 h.handle(r)
656 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100657 finally:
658 logging.raiseExceptions = old_raise
659
Vinay Sajip7367d082011-05-02 13:17:27 +0100660# -- The following section could be moved into a server_helper.py module
661# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100662
Vinay Sajipce7c9782011-05-17 07:15:53 +0100663if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100665 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100666 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100667
Vinay Sajipce7c9782011-05-17 07:15:53 +0100668 :param addr: A (host, port) tuple which the server listens on.
669 You can specify a port value of zero: the server's
670 *port* attribute will hold the actual port number
671 used, which can be used in client connections.
672 :param handler: A callable which will be called to process
673 incoming messages. The handler will be passed
674 the client address tuple, who the message is from,
675 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100676 :param poll_interval: The interval, in seconds, used in the underlying
677 :func:`select` or :func:`poll` call by
678 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100679 :param sockmap: A dictionary which will be used to hold
680 :class:`asyncore.dispatcher` instances used by
681 :func:`asyncore.loop`. This avoids changing the
682 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100683 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100684
685 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400686 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
687 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100688 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 self._handler = handler
690 self._thread = None
691 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 def process_message(self, peer, mailfrom, rcpttos, data):
694 """
695 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100696
Vinay Sajipce7c9782011-05-17 07:15:53 +0100697 Typically, this will be a test case method.
698 :param peer: The client (host, port) tuple.
699 :param mailfrom: The address of the sender.
700 :param rcpttos: The addresses of the recipients.
701 :param data: The message.
702 """
703 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100704
Vinay Sajipce7c9782011-05-17 07:15:53 +0100705 def start(self):
706 """
707 Start the server running on a separate daemon thread.
708 """
709 self._thread = t = threading.Thread(target=self.serve_forever,
710 args=(self.poll_interval,))
711 t.setDaemon(True)
712 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100713
Vinay Sajipce7c9782011-05-17 07:15:53 +0100714 def serve_forever(self, poll_interval):
715 """
716 Run the :mod:`asyncore` loop until normal termination
717 conditions arise.
718 :param poll_interval: The interval, in seconds, used in the underlying
719 :func:`select` or :func:`poll` call by
720 :func:`asyncore.loop`.
721 """
722 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100723 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200724 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 # On FreeBSD 8, closing the server repeatably
726 # raises this error. We swallow it if the
727 # server has been closed.
728 if self.connected or self.accepting:
729 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100730
Vinay Sajipce7c9782011-05-17 07:15:53 +0100731 def stop(self, timeout=None):
732 """
733 Stop the thread by closing the server instance.
734 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 :param timeout: How long to wait for the server thread
737 to terminate.
738 """
739 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100740 self._thread.join(timeout)
741 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100742
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743 class ControlMixin(object):
744 """
745 This mixin is used to start a server on a separate thread, and
746 shut it down programmatically. Request handling is simplified - instead
747 of needing to derive a suitable RequestHandler subclass, you just
748 provide a callable which will be passed each received request to be
749 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100750
Vinay Sajipce7c9782011-05-17 07:15:53 +0100751 :param handler: A handler callable which will be called with a
752 single parameter - the request - in order to
753 process the request. This handler is called on the
754 server thread, effectively meaning that requests are
755 processed serially. While not quite Web scale ;-),
756 this should be fine for testing applications.
757 :param poll_interval: The polling interval in seconds.
758 """
759 def __init__(self, handler, poll_interval):
760 self._thread = None
761 self.poll_interval = poll_interval
762 self._handler = handler
763 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100764
Vinay Sajipce7c9782011-05-17 07:15:53 +0100765 def start(self):
766 """
767 Create a daemon thread to run the server, and start it.
768 """
769 self._thread = t = threading.Thread(target=self.serve_forever,
770 args=(self.poll_interval,))
771 t.setDaemon(True)
772 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100773
Vinay Sajipce7c9782011-05-17 07:15:53 +0100774 def serve_forever(self, poll_interval):
775 """
776 Run the server. Set the ready flag before entering the
777 service loop.
778 """
779 self.ready.set()
780 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 def stop(self, timeout=None):
783 """
784 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 :param timeout: How long to wait for the server thread
787 to terminate.
788 """
789 self.shutdown()
790 if self._thread is not None:
791 self._thread.join(timeout)
792 self._thread = None
793 self.server_close()
794 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 class TestHTTPServer(ControlMixin, HTTPServer):
797 """
798 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Vinay Sajipce7c9782011-05-17 07:15:53 +0100800 :param addr: A tuple with the IP address and port to listen on.
801 :param handler: A handler callable which will be called with a
802 single parameter - the request - in order to
803 process the request.
804 :param poll_interval: The polling interval in seconds.
805 :param log: Pass ``True`` to enable log messages.
806 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100807 def __init__(self, addr, handler, poll_interval=0.5,
808 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100809 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
810 def __getattr__(self, name, default=None):
811 if name.startswith('do_'):
812 return self.process_request
813 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100814
Vinay Sajipce7c9782011-05-17 07:15:53 +0100815 def process_request(self):
816 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100817
Vinay Sajipce7c9782011-05-17 07:15:53 +0100818 def log_message(self, format, *args):
819 if log:
820 super(DelegatingHTTPRequestHandler,
821 self).log_message(format, *args)
822 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
823 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100824 self.sslctx = sslctx
825
826 def get_request(self):
827 try:
828 sock, addr = self.socket.accept()
829 if self.sslctx:
830 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200831 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100832 # socket errors are silenced by the caller, print them here
833 sys.stderr.write("Got an error:\n%s\n" % e)
834 raise
835 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 class TestTCPServer(ControlMixin, ThreadingTCPServer):
838 """
839 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 :param addr: A tuple with the IP address and port to listen on.
842 :param handler: A handler callable which will be called with a single
843 parameter - the request - in order to process the request.
844 :param poll_interval: The polling interval in seconds.
845 :bind_and_activate: If True (the default), binds the server and starts it
846 listening. If False, you need to call
847 :meth:`server_bind` and :meth:`server_activate` at
848 some later time before calling :meth:`start`, so that
849 the server will set up the socket and listen on it.
850 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Vinay Sajipce7c9782011-05-17 07:15:53 +0100852 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100853
Vinay Sajipce7c9782011-05-17 07:15:53 +0100854 def __init__(self, addr, handler, poll_interval=0.5,
855 bind_and_activate=True):
856 class DelegatingTCPRequestHandler(StreamRequestHandler):
857
858 def handle(self):
859 self.server._handler(self)
860 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
861 bind_and_activate)
862 ControlMixin.__init__(self, handler, poll_interval)
863
864 def server_bind(self):
865 super(TestTCPServer, self).server_bind()
866 self.port = self.socket.getsockname()[1]
867
868 class TestUDPServer(ControlMixin, ThreadingUDPServer):
869 """
870 A UDP server which is controllable using :class:`ControlMixin`.
871
872 :param addr: A tuple with the IP address and port to listen on.
873 :param handler: A handler callable which will be called with a
874 single parameter - the request - in order to
875 process the request.
876 :param poll_interval: The polling interval for shutdown requests,
877 in seconds.
878 :bind_and_activate: If True (the default), binds the server and
879 starts it listening. If False, you need to
880 call :meth:`server_bind` and
881 :meth:`server_activate` at some later time
882 before calling :meth:`start`, so that the server will
883 set up the socket and listen on it.
884 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100885 def __init__(self, addr, handler, poll_interval=0.5,
886 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100887 class DelegatingUDPRequestHandler(DatagramRequestHandler):
888
889 def handle(self):
890 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100891
892 def finish(self):
893 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if data:
895 try:
896 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200897 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 if not self.server._closed:
899 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100900
Vinay Sajip3ef12292011-05-23 23:00:42 +0100901 ThreadingUDPServer.__init__(self, addr,
902 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100903 bind_and_activate)
904 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100905 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906
907 def server_bind(self):
908 super(TestUDPServer, self).server_bind()
909 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Vinay Sajipba980db2011-05-23 21:37:54 +0100911 def server_close(self):
912 super(TestUDPServer, self).server_close()
913 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Victor Stinnerec5a8602014-06-02 14:41:51 +0200915 if hasattr(socket, "AF_UNIX"):
916 class TestUnixStreamServer(TestTCPServer):
917 address_family = socket.AF_UNIX
918
919 class TestUnixDatagramServer(TestUDPServer):
920 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100921
Vinay Sajip7367d082011-05-02 13:17:27 +0100922# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100923
Vinay Sajipce7c9782011-05-17 07:15:53 +0100924@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100925class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000926 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100927 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100928 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800929 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100930 sockmap)
931 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800932 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000933 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
934 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 self.assertEqual(h.toaddrs, ['you'])
936 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100938 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000940 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100941 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000942 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100943 self.assertEqual(len(self.messages), 1)
944 peer, mailfrom, rcpttos, data = self.messages[0]
945 self.assertEqual(mailfrom, 'me')
946 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100947 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100948 self.assertTrue(data.endswith('\n\nHello'))
949 h.close()
950
951 def process_message(self, *args):
952 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100953 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100954
Christian Heimes180510d2008-03-03 19:15:45 +0000955class MemoryHandlerTest(BaseTest):
956
957 """Tests for the MemoryHandler."""
958
959 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300960 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000961
962 def setUp(self):
963 BaseTest.setUp(self)
964 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
965 self.root_hdlr)
966 self.mem_logger = logging.getLogger('mem')
967 self.mem_logger.propagate = 0
968 self.mem_logger.addHandler(self.mem_hdlr)
969
970 def tearDown(self):
971 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000972 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000973
974 def test_flush(self):
975 # The memory handler flushes to its target handler based on specific
976 # criteria (message count and message level).
977 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000978 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000979 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000980 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000981 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100982 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000983 lines = [
984 ('DEBUG', '1'),
985 ('INFO', '2'),
986 ('WARNING', '3'),
987 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 for n in (4, 14):
990 for i in range(9):
991 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000992 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000993 # This will flush because it's the 10th message since the last
994 # flush.
995 self.mem_logger.debug(self.next_message())
996 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000997 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000998
999 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001000 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001001
1002
1003class ExceptionFormatter(logging.Formatter):
1004 """A special exception formatter."""
1005 def formatException(self, ei):
1006 return "Got a [%s]" % ei[0].__name__
1007
1008
1009class ConfigFileTest(BaseTest):
1010
1011 """Reading logging config from a .ini-style config file."""
1012
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001013 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001014
1015 # config0 is a standard configuration.
1016 config0 = """
1017 [loggers]
1018 keys=root
1019
1020 [handlers]
1021 keys=hand1
1022
1023 [formatters]
1024 keys=form1
1025
1026 [logger_root]
1027 level=WARNING
1028 handlers=hand1
1029
1030 [handler_hand1]
1031 class=StreamHandler
1032 level=NOTSET
1033 formatter=form1
1034 args=(sys.stdout,)
1035
1036 [formatter_form1]
1037 format=%(levelname)s ++ %(message)s
1038 datefmt=
1039 """
1040
1041 # config1 adds a little to the standard configuration.
1042 config1 = """
1043 [loggers]
1044 keys=root,parser
1045
1046 [handlers]
1047 keys=hand1
1048
1049 [formatters]
1050 keys=form1
1051
1052 [logger_root]
1053 level=WARNING
1054 handlers=
1055
1056 [logger_parser]
1057 level=DEBUG
1058 handlers=hand1
1059 propagate=1
1060 qualname=compiler.parser
1061
1062 [handler_hand1]
1063 class=StreamHandler
1064 level=NOTSET
1065 formatter=form1
1066 args=(sys.stdout,)
1067
1068 [formatter_form1]
1069 format=%(levelname)s ++ %(message)s
1070 datefmt=
1071 """
1072
Vinay Sajip3f84b072011-03-07 17:49:33 +00001073 # config1a moves the handler to the root.
1074 config1a = """
1075 [loggers]
1076 keys=root,parser
1077
1078 [handlers]
1079 keys=hand1
1080
1081 [formatters]
1082 keys=form1
1083
1084 [logger_root]
1085 level=WARNING
1086 handlers=hand1
1087
1088 [logger_parser]
1089 level=DEBUG
1090 handlers=
1091 propagate=1
1092 qualname=compiler.parser
1093
1094 [handler_hand1]
1095 class=StreamHandler
1096 level=NOTSET
1097 formatter=form1
1098 args=(sys.stdout,)
1099
1100 [formatter_form1]
1101 format=%(levelname)s ++ %(message)s
1102 datefmt=
1103 """
1104
Christian Heimes180510d2008-03-03 19:15:45 +00001105 # config2 has a subtle configuration error that should be reported
1106 config2 = config1.replace("sys.stdout", "sys.stbout")
1107
1108 # config3 has a less subtle configuration error
1109 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1110
1111 # config4 specifies a custom formatter class to be loaded
1112 config4 = """
1113 [loggers]
1114 keys=root
1115
1116 [handlers]
1117 keys=hand1
1118
1119 [formatters]
1120 keys=form1
1121
1122 [logger_root]
1123 level=NOTSET
1124 handlers=hand1
1125
1126 [handler_hand1]
1127 class=StreamHandler
1128 level=NOTSET
1129 formatter=form1
1130 args=(sys.stdout,)
1131
1132 [formatter_form1]
1133 class=""" + __name__ + """.ExceptionFormatter
1134 format=%(levelname)s:%(name)s:%(message)s
1135 datefmt=
1136 """
1137
Georg Brandl3dbca812008-07-23 16:10:53 +00001138 # config5 specifies a custom handler class to be loaded
1139 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1140
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001141 # config6 uses ', ' delimiters in the handlers and formatters sections
1142 config6 = """
1143 [loggers]
1144 keys=root,parser
1145
1146 [handlers]
1147 keys=hand1, hand2
1148
1149 [formatters]
1150 keys=form1, form2
1151
1152 [logger_root]
1153 level=WARNING
1154 handlers=
1155
1156 [logger_parser]
1157 level=DEBUG
1158 handlers=hand1
1159 propagate=1
1160 qualname=compiler.parser
1161
1162 [handler_hand1]
1163 class=StreamHandler
1164 level=NOTSET
1165 formatter=form1
1166 args=(sys.stdout,)
1167
1168 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001169 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001170 level=NOTSET
1171 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001172 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001173
1174 [formatter_form1]
1175 format=%(levelname)s ++ %(message)s
1176 datefmt=
1177
1178 [formatter_form2]
1179 format=%(message)s
1180 datefmt=
1181 """
1182
Vinay Sajip3f84b072011-03-07 17:49:33 +00001183 # config7 adds a compiler logger.
1184 config7 = """
1185 [loggers]
1186 keys=root,parser,compiler
1187
1188 [handlers]
1189 keys=hand1
1190
1191 [formatters]
1192 keys=form1
1193
1194 [logger_root]
1195 level=WARNING
1196 handlers=hand1
1197
1198 [logger_compiler]
1199 level=DEBUG
1200 handlers=
1201 propagate=1
1202 qualname=compiler
1203
1204 [logger_parser]
1205 level=DEBUG
1206 handlers=
1207 propagate=1
1208 qualname=compiler.parser
1209
1210 [handler_hand1]
1211 class=StreamHandler
1212 level=NOTSET
1213 formatter=form1
1214 args=(sys.stdout,)
1215
1216 [formatter_form1]
1217 format=%(levelname)s ++ %(message)s
1218 datefmt=
1219 """
1220
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001221 disable_test = """
1222 [loggers]
1223 keys=root
1224
1225 [handlers]
1226 keys=screen
1227
1228 [formatters]
1229 keys=
1230
1231 [logger_root]
1232 level=DEBUG
1233 handlers=screen
1234
1235 [handler_screen]
1236 level=DEBUG
1237 class=StreamHandler
1238 args=(sys.stdout,)
1239 formatter=
1240 """
1241
1242 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001243 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001244 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001245
1246 def test_config0_ok(self):
1247 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001248 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001249 self.apply_config(self.config0)
1250 logger = logging.getLogger()
1251 # Won't output anything
1252 logger.info(self.next_message())
1253 # Outputs a message
1254 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001255 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001256 ('ERROR', '2'),
1257 ], stream=output)
1258 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001259 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001260
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001261 def test_config0_using_cp_ok(self):
1262 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001263 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001264 file = io.StringIO(textwrap.dedent(self.config0))
1265 cp = configparser.ConfigParser()
1266 cp.read_file(file)
1267 logging.config.fileConfig(cp)
1268 logger = logging.getLogger()
1269 # Won't output anything
1270 logger.info(self.next_message())
1271 # Outputs a message
1272 logger.error(self.next_message())
1273 self.assert_log_lines([
1274 ('ERROR', '2'),
1275 ], stream=output)
1276 # Original logger output is empty.
1277 self.assert_log_lines([])
1278
Georg Brandl3dbca812008-07-23 16:10:53 +00001279 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001280 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001281 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001282 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001283 logger = logging.getLogger("compiler.parser")
1284 # Both will output a message
1285 logger.info(self.next_message())
1286 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001287 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001288 ('INFO', '1'),
1289 ('ERROR', '2'),
1290 ], stream=output)
1291 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001292 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001293
1294 def test_config2_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config2)
1297
1298 def test_config3_failure(self):
1299 # A simple config file which overrides the default settings.
1300 self.assertRaises(Exception, self.apply_config, self.config3)
1301
1302 def test_config4_ok(self):
1303 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001304 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001305 self.apply_config(self.config4)
1306 logger = logging.getLogger()
1307 try:
1308 raise RuntimeError()
1309 except RuntimeError:
1310 logging.exception("just testing")
1311 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001312 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001313 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1314 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001315 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001316
Georg Brandl3dbca812008-07-23 16:10:53 +00001317 def test_config5_ok(self):
1318 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001319
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001320 def test_config6_ok(self):
1321 self.test_config1_ok(config=self.config6)
1322
Vinay Sajip3f84b072011-03-07 17:49:33 +00001323 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001324 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001325 self.apply_config(self.config1a)
1326 logger = logging.getLogger("compiler.parser")
1327 # See issue #11424. compiler-hyphenated sorts
1328 # between compiler and compiler.xyz and this
1329 # was preventing compiler.xyz from being included
1330 # in the child loggers of compiler because of an
1331 # overzealous loop termination condition.
1332 hyphenated = logging.getLogger('compiler-hyphenated')
1333 # All will output a message
1334 logger.info(self.next_message())
1335 logger.error(self.next_message())
1336 hyphenated.critical(self.next_message())
1337 self.assert_log_lines([
1338 ('INFO', '1'),
1339 ('ERROR', '2'),
1340 ('CRITICAL', '3'),
1341 ], stream=output)
1342 # Original logger output is empty.
1343 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001344 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001345 self.apply_config(self.config7)
1346 logger = logging.getLogger("compiler.parser")
1347 self.assertFalse(logger.disabled)
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 logger = logging.getLogger("compiler.lexer")
1352 # Both will output a message
1353 logger.info(self.next_message())
1354 logger.error(self.next_message())
1355 # Will not appear
1356 hyphenated.critical(self.next_message())
1357 self.assert_log_lines([
1358 ('INFO', '4'),
1359 ('ERROR', '5'),
1360 ('INFO', '6'),
1361 ('ERROR', '7'),
1362 ], stream=output)
1363 # Original logger output is empty.
1364 self.assert_log_lines([])
1365
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001366 def test_logger_disabling(self):
1367 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001368 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001369 self.assertFalse(logger.disabled)
1370 self.apply_config(self.disable_test)
1371 self.assertTrue(logger.disabled)
1372 self.apply_config(self.disable_test, disable_existing_loggers=False)
1373 self.assertFalse(logger.disabled)
1374
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001375
Victor Stinner45df8202010-04-28 22:31:17 +00001376@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001377class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001378
Christian Heimes180510d2008-03-03 19:15:45 +00001379 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001380
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001381 if threading:
1382 server_class = TestTCPServer
1383 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001384
Christian Heimes180510d2008-03-03 19:15:45 +00001385 def setUp(self):
1386 """Set up a TCP server to receive log messages, and a SocketHandler
1387 pointing to that server's address and port."""
1388 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001389 self.server = server = self.server_class(self.address,
1390 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001391 server.start()
1392 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001393 hcls = logging.handlers.SocketHandler
1394 if isinstance(server.server_address, tuple):
1395 self.sock_hdlr = hcls('localhost', server.port)
1396 else:
1397 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001398 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001399 self.root_logger.removeHandler(self.root_logger.handlers[0])
1400 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001401 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001402
Christian Heimes180510d2008-03-03 19:15:45 +00001403 def tearDown(self):
1404 """Shutdown the TCP server."""
1405 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001406 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001407 self.root_logger.removeHandler(self.sock_hdlr)
1408 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001409 finally:
1410 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001411
Vinay Sajip7367d082011-05-02 13:17:27 +01001412 def handle_socket(self, request):
1413 conn = request.connection
1414 while True:
1415 chunk = conn.recv(4)
1416 if len(chunk) < 4:
1417 break
1418 slen = struct.unpack(">L", chunk)[0]
1419 chunk = conn.recv(slen)
1420 while len(chunk) < slen:
1421 chunk = chunk + conn.recv(slen - len(chunk))
1422 obj = pickle.loads(chunk)
1423 record = logging.makeLogRecord(obj)
1424 self.log_output += record.msg + '\n'
1425 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001426
Christian Heimes180510d2008-03-03 19:15:45 +00001427 def test_output(self):
1428 # The log message sent to the SocketHandler is properly received.
1429 logger = logging.getLogger("tcp")
1430 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001431 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001432 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001433 self.handled.acquire()
1434 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001435
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001436 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001437 # Avoid timing-related failures due to SocketHandler's own hard-wired
1438 # one-second timeout on socket.create_connection() (issue #16264).
1439 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001440 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001441 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001442 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001443 try:
1444 raise RuntimeError('Deliberate mistake')
1445 except RuntimeError:
1446 self.root_logger.exception('Never sent')
1447 self.root_logger.error('Never sent, either')
1448 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001449 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001450 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1451 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001452
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001453def _get_temp_domain_socket():
1454 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1455 os.close(fd)
1456 # just need a name - file can't be present, or we'll get an
1457 # 'address already in use' error.
1458 os.remove(fn)
1459 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001460
Victor Stinnerec5a8602014-06-02 14:41:51 +02001461@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001462@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001463class UnixSocketHandlerTest(SocketHandlerTest):
1464
1465 """Test for SocketHandler with unix sockets."""
1466
Victor Stinnerec5a8602014-06-02 14:41:51 +02001467 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001468 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001469
1470 def setUp(self):
1471 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001472 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001473 SocketHandlerTest.setUp(self)
1474
1475 def tearDown(self):
1476 SocketHandlerTest.tearDown(self)
1477 os.remove(self.address)
1478
1479@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001480class DatagramHandlerTest(BaseTest):
1481
1482 """Test for DatagramHandler."""
1483
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001484 if threading:
1485 server_class = TestUDPServer
1486 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001487
Vinay Sajip7367d082011-05-02 13:17:27 +01001488 def setUp(self):
1489 """Set up a UDP server to receive log messages, and a DatagramHandler
1490 pointing to that server's address and port."""
1491 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001492 self.server = server = self.server_class(self.address,
1493 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001494 server.start()
1495 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001496 hcls = logging.handlers.DatagramHandler
1497 if isinstance(server.server_address, tuple):
1498 self.sock_hdlr = hcls('localhost', server.port)
1499 else:
1500 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001501 self.log_output = ''
1502 self.root_logger.removeHandler(self.root_logger.handlers[0])
1503 self.root_logger.addHandler(self.sock_hdlr)
1504 self.handled = threading.Event()
1505
1506 def tearDown(self):
1507 """Shutdown the UDP server."""
1508 try:
1509 self.server.stop(2.0)
1510 self.root_logger.removeHandler(self.sock_hdlr)
1511 self.sock_hdlr.close()
1512 finally:
1513 BaseTest.tearDown(self)
1514
1515 def handle_datagram(self, request):
1516 slen = struct.pack('>L', 0) # length of prefix
1517 packet = request.packet[len(slen):]
1518 obj = pickle.loads(packet)
1519 record = logging.makeLogRecord(obj)
1520 self.log_output += record.msg + '\n'
1521 self.handled.set()
1522
1523 def test_output(self):
1524 # The log message sent to the DatagramHandler is properly received.
1525 logger = logging.getLogger("udp")
1526 logger.error("spam")
1527 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001528 self.handled.clear()
1529 logger.error("eggs")
1530 self.handled.wait()
1531 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001532
Victor Stinnerec5a8602014-06-02 14:41:51 +02001533@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001534@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001535class UnixDatagramHandlerTest(DatagramHandlerTest):
1536
1537 """Test for DatagramHandler using Unix sockets."""
1538
Victor Stinnerec5a8602014-06-02 14:41:51 +02001539 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001540 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001541
1542 def setUp(self):
1543 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001544 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001545 DatagramHandlerTest.setUp(self)
1546
1547 def tearDown(self):
1548 DatagramHandlerTest.tearDown(self)
1549 os.remove(self.address)
1550
1551@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001552class SysLogHandlerTest(BaseTest):
1553
1554 """Test for SysLogHandler using UDP."""
1555
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001556 if threading:
1557 server_class = TestUDPServer
1558 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001559
Vinay Sajip7367d082011-05-02 13:17:27 +01001560 def setUp(self):
1561 """Set up a UDP server to receive log messages, and a SysLogHandler
1562 pointing to that server's address and port."""
1563 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 self.server = server = self.server_class(self.address,
1565 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 server.start()
1567 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001568 hcls = logging.handlers.SysLogHandler
1569 if isinstance(server.server_address, tuple):
1570 self.sl_hdlr = hcls(('localhost', server.port))
1571 else:
1572 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001573 self.log_output = ''
1574 self.root_logger.removeHandler(self.root_logger.handlers[0])
1575 self.root_logger.addHandler(self.sl_hdlr)
1576 self.handled = threading.Event()
1577
1578 def tearDown(self):
1579 """Shutdown the UDP server."""
1580 try:
1581 self.server.stop(2.0)
1582 self.root_logger.removeHandler(self.sl_hdlr)
1583 self.sl_hdlr.close()
1584 finally:
1585 BaseTest.tearDown(self)
1586
1587 def handle_datagram(self, request):
1588 self.log_output = request.packet
1589 self.handled.set()
1590
1591 def test_output(self):
1592 # The log message sent to the SysLogHandler is properly received.
1593 logger = logging.getLogger("slh")
1594 logger.error("sp\xe4m")
1595 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001596 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001597 self.handled.clear()
1598 self.sl_hdlr.append_nul = False
1599 logger.error("sp\xe4m")
1600 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001601 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001602 self.handled.clear()
1603 self.sl_hdlr.ident = "h\xe4m-"
1604 logger.error("sp\xe4m")
1605 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001606 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001607
Victor Stinnerec5a8602014-06-02 14:41:51 +02001608@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001609@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001610class UnixSysLogHandlerTest(SysLogHandlerTest):
1611
1612 """Test for SysLogHandler with Unix sockets."""
1613
Victor Stinnerec5a8602014-06-02 14:41:51 +02001614 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001615 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001616
1617 def setUp(self):
1618 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001619 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001620 SysLogHandlerTest.setUp(self)
1621
1622 def tearDown(self):
1623 SysLogHandlerTest.tearDown(self)
1624 os.remove(self.address)
1625
Vinay Sajip5421f352013-09-27 18:18:28 +01001626@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001627class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001628 """Test for HTTPHandler."""
1629
1630 def setUp(self):
1631 """Set up an HTTP server to receive log messages, and a HTTPHandler
1632 pointing to that server's address and port."""
1633 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001634 self.handled = threading.Event()
1635
Vinay Sajip7367d082011-05-02 13:17:27 +01001636 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001637 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001638 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001639 if self.command == 'POST':
1640 try:
1641 rlen = int(request.headers['Content-Length'])
1642 self.post_data = request.rfile.read(rlen)
1643 except:
1644 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001645 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001646 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001647 self.handled.set()
1648
1649 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001650 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001651 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001652 root_logger = self.root_logger
1653 root_logger.removeHandler(self.root_logger.handlers[0])
1654 for secure in (False, True):
1655 addr = ('localhost', 0)
1656 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001657 try:
1658 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001659 except ImportError:
1660 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001661 else:
1662 here = os.path.dirname(__file__)
1663 localhost_cert = os.path.join(here, "keycert.pem")
1664 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1665 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001666
1667 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001668 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001669 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001670 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001671 self.server = server = TestHTTPServer(addr, self.handle_request,
1672 0.01, sslctx=sslctx)
1673 server.start()
1674 server.ready.wait()
1675 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001676 secure_client = secure and sslctx
1677 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001678 secure=secure_client,
1679 context=context)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001680 self.log_data = None
1681 root_logger.addHandler(self.h_hdlr)
1682
1683 for method in ('GET', 'POST'):
1684 self.h_hdlr.method = method
1685 self.handled.clear()
1686 msg = "sp\xe4m"
1687 logger.error(msg)
1688 self.handled.wait()
1689 self.assertEqual(self.log_data.path, '/frob')
1690 self.assertEqual(self.command, method)
1691 if method == 'GET':
1692 d = parse_qs(self.log_data.query)
1693 else:
1694 d = parse_qs(self.post_data.decode('utf-8'))
1695 self.assertEqual(d['name'], ['http'])
1696 self.assertEqual(d['funcName'], ['test_output'])
1697 self.assertEqual(d['msg'], [msg])
1698
1699 self.server.stop(2.0)
1700 self.root_logger.removeHandler(self.h_hdlr)
1701 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001702
Christian Heimes180510d2008-03-03 19:15:45 +00001703class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001704
Christian Heimes180510d2008-03-03 19:15:45 +00001705 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001706
Christian Heimes180510d2008-03-03 19:15:45 +00001707 def setUp(self):
1708 """Create a dict to remember potentially destroyed objects."""
1709 BaseTest.setUp(self)
1710 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001711
Christian Heimes180510d2008-03-03 19:15:45 +00001712 def _watch_for_survival(self, *args):
1713 """Watch the given objects for survival, by creating weakrefs to
1714 them."""
1715 for obj in args:
1716 key = id(obj), repr(obj)
1717 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001718
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001719 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001720 """Assert that all objects watched for survival have survived."""
1721 # Trigger cycle breaking.
1722 gc.collect()
1723 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001724 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001725 if ref() is None:
1726 dead.append(repr_)
1727 if dead:
1728 self.fail("%d objects should have survived "
1729 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731 def test_persistent_loggers(self):
1732 # Logger objects are persistent and retain their configuration, even
1733 # if visible references are destroyed.
1734 self.root_logger.setLevel(logging.INFO)
1735 foo = logging.getLogger("foo")
1736 self._watch_for_survival(foo)
1737 foo.setLevel(logging.DEBUG)
1738 self.root_logger.debug(self.next_message())
1739 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001740 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001741 ('foo', 'DEBUG', '2'),
1742 ])
1743 del foo
1744 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001745 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001746 # foo has retained its settings.
1747 bar = logging.getLogger("foo")
1748 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001749 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001750 ('foo', 'DEBUG', '2'),
1751 ('foo', 'DEBUG', '3'),
1752 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001753
Benjamin Petersonf91df042009-02-13 02:50:59 +00001754
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001755class EncodingTest(BaseTest):
1756 def test_encoding_plain_file(self):
1757 # In Python 2.x, a plain file object is treated as having no encoding.
1758 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001759 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1760 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001761 # the non-ascii data we write to the log.
1762 data = "foo\x80"
1763 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001764 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001765 log.addHandler(handler)
1766 try:
1767 # write non-ascii data to the log.
1768 log.warning(data)
1769 finally:
1770 log.removeHandler(handler)
1771 handler.close()
1772 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001773 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001774 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001775 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001776 finally:
1777 f.close()
1778 finally:
1779 if os.path.isfile(fn):
1780 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001781
Benjamin Petersonf91df042009-02-13 02:50:59 +00001782 def test_encoding_cyrillic_unicode(self):
1783 log = logging.getLogger("test")
1784 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1785 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1786 #Ensure it's written in a Cyrillic encoding
1787 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001788 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001789 stream = io.BytesIO()
1790 writer = writer_class(stream, 'strict')
1791 handler = logging.StreamHandler(writer)
1792 log.addHandler(handler)
1793 try:
1794 log.warning(message)
1795 finally:
1796 log.removeHandler(handler)
1797 handler.close()
1798 # check we wrote exactly those bytes, ignoring trailing \n etc
1799 s = stream.getvalue()
1800 #Compare against what the data should be when encoded in CP-1251
1801 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1802
1803
Georg Brandlf9734072008-12-07 15:30:06 +00001804class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001805
Georg Brandlf9734072008-12-07 15:30:06 +00001806 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001807 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001808 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001809 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001810 warnings.filterwarnings("always", category=UserWarning)
1811 stream = io.StringIO()
1812 h = logging.StreamHandler(stream)
1813 logger = logging.getLogger("py.warnings")
1814 logger.addHandler(h)
1815 warnings.warn("I'm warning you...")
1816 logger.removeHandler(h)
1817 s = stream.getvalue()
1818 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001819 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001820
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001821 #See if an explicit file uses the original implementation
1822 a_file = io.StringIO()
1823 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1824 a_file, "Dummy line")
1825 s = a_file.getvalue()
1826 a_file.close()
1827 self.assertEqual(s,
1828 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1829
1830 def test_warnings_no_handlers(self):
1831 with warnings.catch_warnings():
1832 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001833 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001834
1835 # confirm our assumption: no loggers are set
1836 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838
1839 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001840 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001841 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001842
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001843
1844def formatFunc(format, datefmt=None):
1845 return logging.Formatter(format, datefmt)
1846
1847def handlerFunc():
1848 return logging.StreamHandler()
1849
1850class CustomHandler(logging.StreamHandler):
1851 pass
1852
1853class ConfigDictTest(BaseTest):
1854
1855 """Reading logging config from a dictionary."""
1856
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001857 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001858
1859 # config0 is a standard configuration.
1860 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001861 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001862 'formatters': {
1863 'form1' : {
1864 'format' : '%(levelname)s ++ %(message)s',
1865 },
1866 },
1867 'handlers' : {
1868 'hand1' : {
1869 'class' : 'logging.StreamHandler',
1870 'formatter' : 'form1',
1871 'level' : 'NOTSET',
1872 'stream' : 'ext://sys.stdout',
1873 },
1874 },
1875 'root' : {
1876 'level' : 'WARNING',
1877 'handlers' : ['hand1'],
1878 },
1879 }
1880
1881 # config1 adds a little to the standard configuration.
1882 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001883 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001884 'formatters': {
1885 'form1' : {
1886 'format' : '%(levelname)s ++ %(message)s',
1887 },
1888 },
1889 'handlers' : {
1890 'hand1' : {
1891 'class' : 'logging.StreamHandler',
1892 'formatter' : 'form1',
1893 'level' : 'NOTSET',
1894 'stream' : 'ext://sys.stdout',
1895 },
1896 },
1897 'loggers' : {
1898 'compiler.parser' : {
1899 'level' : 'DEBUG',
1900 'handlers' : ['hand1'],
1901 },
1902 },
1903 'root' : {
1904 'level' : 'WARNING',
1905 },
1906 }
1907
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001908 # config1a moves the handler to the root. Used with config8a
1909 config1a = {
1910 'version': 1,
1911 'formatters': {
1912 'form1' : {
1913 'format' : '%(levelname)s ++ %(message)s',
1914 },
1915 },
1916 'handlers' : {
1917 'hand1' : {
1918 'class' : 'logging.StreamHandler',
1919 'formatter' : 'form1',
1920 'level' : 'NOTSET',
1921 'stream' : 'ext://sys.stdout',
1922 },
1923 },
1924 'loggers' : {
1925 'compiler.parser' : {
1926 'level' : 'DEBUG',
1927 },
1928 },
1929 'root' : {
1930 'level' : 'WARNING',
1931 'handlers' : ['hand1'],
1932 },
1933 }
1934
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001935 # config2 has a subtle configuration error that should be reported
1936 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001937 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001938 'formatters': {
1939 'form1' : {
1940 'format' : '%(levelname)s ++ %(message)s',
1941 },
1942 },
1943 'handlers' : {
1944 'hand1' : {
1945 'class' : 'logging.StreamHandler',
1946 'formatter' : 'form1',
1947 'level' : 'NOTSET',
1948 'stream' : 'ext://sys.stdbout',
1949 },
1950 },
1951 'loggers' : {
1952 'compiler.parser' : {
1953 'level' : 'DEBUG',
1954 'handlers' : ['hand1'],
1955 },
1956 },
1957 'root' : {
1958 'level' : 'WARNING',
1959 },
1960 }
1961
1962 #As config1 but with a misspelt level on a handler
1963 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001964 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001965 'formatters': {
1966 'form1' : {
1967 'format' : '%(levelname)s ++ %(message)s',
1968 },
1969 },
1970 'handlers' : {
1971 'hand1' : {
1972 'class' : 'logging.StreamHandler',
1973 'formatter' : 'form1',
1974 'level' : 'NTOSET',
1975 'stream' : 'ext://sys.stdout',
1976 },
1977 },
1978 'loggers' : {
1979 'compiler.parser' : {
1980 'level' : 'DEBUG',
1981 'handlers' : ['hand1'],
1982 },
1983 },
1984 'root' : {
1985 'level' : 'WARNING',
1986 },
1987 }
1988
1989
1990 #As config1 but with a misspelt level on a logger
1991 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001992 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001993 'formatters': {
1994 'form1' : {
1995 'format' : '%(levelname)s ++ %(message)s',
1996 },
1997 },
1998 'handlers' : {
1999 'hand1' : {
2000 'class' : 'logging.StreamHandler',
2001 'formatter' : 'form1',
2002 'level' : 'NOTSET',
2003 'stream' : 'ext://sys.stdout',
2004 },
2005 },
2006 'loggers' : {
2007 'compiler.parser' : {
2008 'level' : 'DEBUG',
2009 'handlers' : ['hand1'],
2010 },
2011 },
2012 'root' : {
2013 'level' : 'WRANING',
2014 },
2015 }
2016
2017 # config3 has a less subtle configuration error
2018 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002019 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002020 'formatters': {
2021 'form1' : {
2022 'format' : '%(levelname)s ++ %(message)s',
2023 },
2024 },
2025 'handlers' : {
2026 'hand1' : {
2027 'class' : 'logging.StreamHandler',
2028 'formatter' : 'misspelled_name',
2029 'level' : 'NOTSET',
2030 'stream' : 'ext://sys.stdout',
2031 },
2032 },
2033 'loggers' : {
2034 'compiler.parser' : {
2035 'level' : 'DEBUG',
2036 'handlers' : ['hand1'],
2037 },
2038 },
2039 'root' : {
2040 'level' : 'WARNING',
2041 },
2042 }
2043
2044 # config4 specifies a custom formatter class to be loaded
2045 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002046 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002047 'formatters': {
2048 'form1' : {
2049 '()' : __name__ + '.ExceptionFormatter',
2050 'format' : '%(levelname)s:%(name)s:%(message)s',
2051 },
2052 },
2053 'handlers' : {
2054 'hand1' : {
2055 'class' : 'logging.StreamHandler',
2056 'formatter' : 'form1',
2057 'level' : 'NOTSET',
2058 'stream' : 'ext://sys.stdout',
2059 },
2060 },
2061 'root' : {
2062 'level' : 'NOTSET',
2063 'handlers' : ['hand1'],
2064 },
2065 }
2066
2067 # As config4 but using an actual callable rather than a string
2068 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002069 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002070 'formatters': {
2071 'form1' : {
2072 '()' : ExceptionFormatter,
2073 'format' : '%(levelname)s:%(name)s:%(message)s',
2074 },
2075 'form2' : {
2076 '()' : __name__ + '.formatFunc',
2077 'format' : '%(levelname)s:%(name)s:%(message)s',
2078 },
2079 'form3' : {
2080 '()' : formatFunc,
2081 'format' : '%(levelname)s:%(name)s:%(message)s',
2082 },
2083 },
2084 'handlers' : {
2085 'hand1' : {
2086 'class' : 'logging.StreamHandler',
2087 'formatter' : 'form1',
2088 'level' : 'NOTSET',
2089 'stream' : 'ext://sys.stdout',
2090 },
2091 'hand2' : {
2092 '()' : handlerFunc,
2093 },
2094 },
2095 'root' : {
2096 'level' : 'NOTSET',
2097 'handlers' : ['hand1'],
2098 },
2099 }
2100
2101 # config5 specifies a custom handler class to be loaded
2102 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002103 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002104 'formatters': {
2105 'form1' : {
2106 'format' : '%(levelname)s ++ %(message)s',
2107 },
2108 },
2109 'handlers' : {
2110 'hand1' : {
2111 'class' : __name__ + '.CustomHandler',
2112 'formatter' : 'form1',
2113 'level' : 'NOTSET',
2114 'stream' : 'ext://sys.stdout',
2115 },
2116 },
2117 'loggers' : {
2118 'compiler.parser' : {
2119 'level' : 'DEBUG',
2120 'handlers' : ['hand1'],
2121 },
2122 },
2123 'root' : {
2124 'level' : 'WARNING',
2125 },
2126 }
2127
2128 # config6 specifies a custom handler class to be loaded
2129 # but has bad arguments
2130 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002131 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002132 'formatters': {
2133 'form1' : {
2134 'format' : '%(levelname)s ++ %(message)s',
2135 },
2136 },
2137 'handlers' : {
2138 'hand1' : {
2139 'class' : __name__ + '.CustomHandler',
2140 'formatter' : 'form1',
2141 'level' : 'NOTSET',
2142 'stream' : 'ext://sys.stdout',
2143 '9' : 'invalid parameter name',
2144 },
2145 },
2146 'loggers' : {
2147 'compiler.parser' : {
2148 'level' : 'DEBUG',
2149 'handlers' : ['hand1'],
2150 },
2151 },
2152 'root' : {
2153 'level' : 'WARNING',
2154 },
2155 }
2156
2157 #config 7 does not define compiler.parser but defines compiler.lexer
2158 #so compiler.parser should be disabled after applying it
2159 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002160 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002161 'formatters': {
2162 'form1' : {
2163 'format' : '%(levelname)s ++ %(message)s',
2164 },
2165 },
2166 'handlers' : {
2167 'hand1' : {
2168 'class' : 'logging.StreamHandler',
2169 'formatter' : 'form1',
2170 'level' : 'NOTSET',
2171 'stream' : 'ext://sys.stdout',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.lexer' : {
2176 'level' : 'DEBUG',
2177 'handlers' : ['hand1'],
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WARNING',
2182 },
2183 }
2184
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002185 # config8 defines both compiler and compiler.lexer
2186 # so compiler.parser should not be disabled (since
2187 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002188 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002189 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002190 'disable_existing_loggers' : False,
2191 'formatters': {
2192 'form1' : {
2193 'format' : '%(levelname)s ++ %(message)s',
2194 },
2195 },
2196 'handlers' : {
2197 'hand1' : {
2198 'class' : 'logging.StreamHandler',
2199 'formatter' : 'form1',
2200 'level' : 'NOTSET',
2201 'stream' : 'ext://sys.stdout',
2202 },
2203 },
2204 'loggers' : {
2205 'compiler' : {
2206 'level' : 'DEBUG',
2207 'handlers' : ['hand1'],
2208 },
2209 'compiler.lexer' : {
2210 },
2211 },
2212 'root' : {
2213 'level' : 'WARNING',
2214 },
2215 }
2216
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002217 # config8a disables existing loggers
2218 config8a = {
2219 'version': 1,
2220 'disable_existing_loggers' : True,
2221 'formatters': {
2222 'form1' : {
2223 'format' : '%(levelname)s ++ %(message)s',
2224 },
2225 },
2226 'handlers' : {
2227 'hand1' : {
2228 'class' : 'logging.StreamHandler',
2229 'formatter' : 'form1',
2230 'level' : 'NOTSET',
2231 'stream' : 'ext://sys.stdout',
2232 },
2233 },
2234 'loggers' : {
2235 'compiler' : {
2236 'level' : 'DEBUG',
2237 'handlers' : ['hand1'],
2238 },
2239 'compiler.lexer' : {
2240 },
2241 },
2242 'root' : {
2243 'level' : 'WARNING',
2244 },
2245 }
2246
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002247 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002248 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002249 'formatters': {
2250 'form1' : {
2251 'format' : '%(levelname)s ++ %(message)s',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : 'logging.StreamHandler',
2257 'formatter' : 'form1',
2258 'level' : 'WARNING',
2259 'stream' : 'ext://sys.stdout',
2260 },
2261 },
2262 'loggers' : {
2263 'compiler.parser' : {
2264 'level' : 'WARNING',
2265 'handlers' : ['hand1'],
2266 },
2267 },
2268 'root' : {
2269 'level' : 'NOTSET',
2270 },
2271 }
2272
2273 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002274 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 'incremental' : True,
2276 'handlers' : {
2277 'hand1' : {
2278 'level' : 'WARNING',
2279 },
2280 },
2281 'loggers' : {
2282 'compiler.parser' : {
2283 'level' : 'INFO',
2284 },
2285 },
2286 }
2287
2288 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002289 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002290 'incremental' : True,
2291 'handlers' : {
2292 'hand1' : {
2293 'level' : 'INFO',
2294 },
2295 },
2296 'loggers' : {
2297 'compiler.parser' : {
2298 'level' : 'INFO',
2299 },
2300 },
2301 }
2302
2303 #As config1 but with a filter added
2304 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002305 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002306 'formatters': {
2307 'form1' : {
2308 'format' : '%(levelname)s ++ %(message)s',
2309 },
2310 },
2311 'filters' : {
2312 'filt1' : {
2313 'name' : 'compiler.parser',
2314 },
2315 },
2316 'handlers' : {
2317 'hand1' : {
2318 'class' : 'logging.StreamHandler',
2319 'formatter' : 'form1',
2320 'level' : 'NOTSET',
2321 'stream' : 'ext://sys.stdout',
2322 'filters' : ['filt1'],
2323 },
2324 },
2325 'loggers' : {
2326 'compiler.parser' : {
2327 'level' : 'DEBUG',
2328 'filters' : ['filt1'],
2329 },
2330 },
2331 'root' : {
2332 'level' : 'WARNING',
2333 'handlers' : ['hand1'],
2334 },
2335 }
2336
2337 #As config1 but using cfg:// references
2338 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002339 'version': 1,
2340 'true_formatters': {
2341 'form1' : {
2342 'format' : '%(levelname)s ++ %(message)s',
2343 },
2344 },
2345 'handler_configs': {
2346 'hand1' : {
2347 'class' : 'logging.StreamHandler',
2348 'formatter' : 'form1',
2349 'level' : 'NOTSET',
2350 'stream' : 'ext://sys.stdout',
2351 },
2352 },
2353 'formatters' : 'cfg://true_formatters',
2354 'handlers' : {
2355 'hand1' : 'cfg://handler_configs[hand1]',
2356 },
2357 'loggers' : {
2358 'compiler.parser' : {
2359 'level' : 'DEBUG',
2360 'handlers' : ['hand1'],
2361 },
2362 },
2363 'root' : {
2364 'level' : 'WARNING',
2365 },
2366 }
2367
2368 #As config11 but missing the version key
2369 config12 = {
2370 'true_formatters': {
2371 'form1' : {
2372 'format' : '%(levelname)s ++ %(message)s',
2373 },
2374 },
2375 'handler_configs': {
2376 'hand1' : {
2377 'class' : 'logging.StreamHandler',
2378 'formatter' : 'form1',
2379 'level' : 'NOTSET',
2380 'stream' : 'ext://sys.stdout',
2381 },
2382 },
2383 'formatters' : 'cfg://true_formatters',
2384 'handlers' : {
2385 'hand1' : 'cfg://handler_configs[hand1]',
2386 },
2387 'loggers' : {
2388 'compiler.parser' : {
2389 'level' : 'DEBUG',
2390 'handlers' : ['hand1'],
2391 },
2392 },
2393 'root' : {
2394 'level' : 'WARNING',
2395 },
2396 }
2397
2398 #As config11 but using an unsupported version
2399 config13 = {
2400 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002401 'true_formatters': {
2402 'form1' : {
2403 'format' : '%(levelname)s ++ %(message)s',
2404 },
2405 },
2406 'handler_configs': {
2407 'hand1' : {
2408 'class' : 'logging.StreamHandler',
2409 'formatter' : 'form1',
2410 'level' : 'NOTSET',
2411 'stream' : 'ext://sys.stdout',
2412 },
2413 },
2414 'formatters' : 'cfg://true_formatters',
2415 'handlers' : {
2416 'hand1' : 'cfg://handler_configs[hand1]',
2417 },
2418 'loggers' : {
2419 'compiler.parser' : {
2420 'level' : 'DEBUG',
2421 'handlers' : ['hand1'],
2422 },
2423 },
2424 'root' : {
2425 'level' : 'WARNING',
2426 },
2427 }
2428
Vinay Sajip8d270232012-11-15 14:20:18 +00002429 # As config0, but with properties
2430 config14 = {
2431 'version': 1,
2432 'formatters': {
2433 'form1' : {
2434 'format' : '%(levelname)s ++ %(message)s',
2435 },
2436 },
2437 'handlers' : {
2438 'hand1' : {
2439 'class' : 'logging.StreamHandler',
2440 'formatter' : 'form1',
2441 'level' : 'NOTSET',
2442 'stream' : 'ext://sys.stdout',
2443 '.': {
2444 'foo': 'bar',
2445 'terminator': '!\n',
2446 }
2447 },
2448 },
2449 'root' : {
2450 'level' : 'WARNING',
2451 'handlers' : ['hand1'],
2452 },
2453 }
2454
Vinay Sajip3f885b52013-03-22 15:19:54 +00002455 out_of_order = {
2456 "version": 1,
2457 "formatters": {
2458 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002459 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2460 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002461 }
2462 },
2463 "handlers": {
2464 "fileGlobal": {
2465 "class": "logging.StreamHandler",
2466 "level": "DEBUG",
2467 "formatter": "mySimpleFormatter"
2468 },
2469 "bufferGlobal": {
2470 "class": "logging.handlers.MemoryHandler",
2471 "capacity": 5,
2472 "formatter": "mySimpleFormatter",
2473 "target": "fileGlobal",
2474 "level": "DEBUG"
2475 }
2476 },
2477 "loggers": {
2478 "mymodule": {
2479 "level": "DEBUG",
2480 "handlers": ["bufferGlobal"],
2481 "propagate": "true"
2482 }
2483 }
2484 }
2485
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002486 def apply_config(self, conf):
2487 logging.config.dictConfig(conf)
2488
2489 def test_config0_ok(self):
2490 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002491 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002492 self.apply_config(self.config0)
2493 logger = logging.getLogger()
2494 # Won't output anything
2495 logger.info(self.next_message())
2496 # Outputs a message
2497 logger.error(self.next_message())
2498 self.assert_log_lines([
2499 ('ERROR', '2'),
2500 ], stream=output)
2501 # Original logger output is empty.
2502 self.assert_log_lines([])
2503
2504 def test_config1_ok(self, config=config1):
2505 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002506 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002507 self.apply_config(config)
2508 logger = logging.getLogger("compiler.parser")
2509 # Both will output a message
2510 logger.info(self.next_message())
2511 logger.error(self.next_message())
2512 self.assert_log_lines([
2513 ('INFO', '1'),
2514 ('ERROR', '2'),
2515 ], stream=output)
2516 # Original logger output is empty.
2517 self.assert_log_lines([])
2518
2519 def test_config2_failure(self):
2520 # A simple config which overrides the default settings.
2521 self.assertRaises(Exception, self.apply_config, self.config2)
2522
2523 def test_config2a_failure(self):
2524 # A simple config which overrides the default settings.
2525 self.assertRaises(Exception, self.apply_config, self.config2a)
2526
2527 def test_config2b_failure(self):
2528 # A simple config which overrides the default settings.
2529 self.assertRaises(Exception, self.apply_config, self.config2b)
2530
2531 def test_config3_failure(self):
2532 # A simple config which overrides the default settings.
2533 self.assertRaises(Exception, self.apply_config, self.config3)
2534
2535 def test_config4_ok(self):
2536 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002537 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002538 self.apply_config(self.config4)
2539 #logger = logging.getLogger()
2540 try:
2541 raise RuntimeError()
2542 except RuntimeError:
2543 logging.exception("just testing")
2544 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002545 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002546 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2547 # Original logger output is empty
2548 self.assert_log_lines([])
2549
2550 def test_config4a_ok(self):
2551 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002552 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002553 self.apply_config(self.config4a)
2554 #logger = logging.getLogger()
2555 try:
2556 raise RuntimeError()
2557 except RuntimeError:
2558 logging.exception("just testing")
2559 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002560 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002561 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2562 # Original logger output is empty
2563 self.assert_log_lines([])
2564
2565 def test_config5_ok(self):
2566 self.test_config1_ok(config=self.config5)
2567
2568 def test_config6_failure(self):
2569 self.assertRaises(Exception, self.apply_config, self.config6)
2570
2571 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002572 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002573 self.apply_config(self.config1)
2574 logger = logging.getLogger("compiler.parser")
2575 # Both will output a message
2576 logger.info(self.next_message())
2577 logger.error(self.next_message())
2578 self.assert_log_lines([
2579 ('INFO', '1'),
2580 ('ERROR', '2'),
2581 ], stream=output)
2582 # Original logger output is empty.
2583 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002584 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002585 self.apply_config(self.config7)
2586 logger = logging.getLogger("compiler.parser")
2587 self.assertTrue(logger.disabled)
2588 logger = logging.getLogger("compiler.lexer")
2589 # Both will output a message
2590 logger.info(self.next_message())
2591 logger.error(self.next_message())
2592 self.assert_log_lines([
2593 ('INFO', '3'),
2594 ('ERROR', '4'),
2595 ], stream=output)
2596 # Original logger output is empty.
2597 self.assert_log_lines([])
2598
2599 #Same as test_config_7_ok but don't disable old loggers.
2600 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002601 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002602 self.apply_config(self.config1)
2603 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002604 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002605 logger.info(self.next_message())
2606 logger.error(self.next_message())
2607 self.assert_log_lines([
2608 ('INFO', '1'),
2609 ('ERROR', '2'),
2610 ], stream=output)
2611 # Original logger output is empty.
2612 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002613 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002614 self.apply_config(self.config8)
2615 logger = logging.getLogger("compiler.parser")
2616 self.assertFalse(logger.disabled)
2617 # Both will output a message
2618 logger.info(self.next_message())
2619 logger.error(self.next_message())
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 ('INFO', '5'),
2628 ('ERROR', '6'),
2629 ], stream=output)
2630 # Original logger output is empty.
2631 self.assert_log_lines([])
2632
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002633 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002634 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002635 self.apply_config(self.config1a)
2636 logger = logging.getLogger("compiler.parser")
2637 # See issue #11424. compiler-hyphenated sorts
2638 # between compiler and compiler.xyz and this
2639 # was preventing compiler.xyz from being included
2640 # in the child loggers of compiler because of an
2641 # overzealous loop termination condition.
2642 hyphenated = logging.getLogger('compiler-hyphenated')
2643 # All will output a message
2644 logger.info(self.next_message())
2645 logger.error(self.next_message())
2646 hyphenated.critical(self.next_message())
2647 self.assert_log_lines([
2648 ('INFO', '1'),
2649 ('ERROR', '2'),
2650 ('CRITICAL', '3'),
2651 ], stream=output)
2652 # Original logger output is empty.
2653 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002654 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002655 self.apply_config(self.config8a)
2656 logger = logging.getLogger("compiler.parser")
2657 self.assertFalse(logger.disabled)
2658 # Both will output a message
2659 logger.info(self.next_message())
2660 logger.error(self.next_message())
2661 logger = logging.getLogger("compiler.lexer")
2662 # Both will output a message
2663 logger.info(self.next_message())
2664 logger.error(self.next_message())
2665 # Will not appear
2666 hyphenated.critical(self.next_message())
2667 self.assert_log_lines([
2668 ('INFO', '4'),
2669 ('ERROR', '5'),
2670 ('INFO', '6'),
2671 ('ERROR', '7'),
2672 ], stream=output)
2673 # Original logger output is empty.
2674 self.assert_log_lines([])
2675
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002676 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002677 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 self.apply_config(self.config9)
2679 logger = logging.getLogger("compiler.parser")
2680 #Nothing will be output since both handler and logger are set to WARNING
2681 logger.info(self.next_message())
2682 self.assert_log_lines([], stream=output)
2683 self.apply_config(self.config9a)
2684 #Nothing will be output since both handler is still set to WARNING
2685 logger.info(self.next_message())
2686 self.assert_log_lines([], stream=output)
2687 self.apply_config(self.config9b)
2688 #Message should now be output
2689 logger.info(self.next_message())
2690 self.assert_log_lines([
2691 ('INFO', '3'),
2692 ], stream=output)
2693
2694 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002695 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002696 self.apply_config(self.config10)
2697 logger = logging.getLogger("compiler.parser")
2698 logger.warning(self.next_message())
2699 logger = logging.getLogger('compiler')
2700 #Not output, because filtered
2701 logger.warning(self.next_message())
2702 logger = logging.getLogger('compiler.lexer')
2703 #Not output, because filtered
2704 logger.warning(self.next_message())
2705 logger = logging.getLogger("compiler.parser.codegen")
2706 #Output, as not filtered
2707 logger.error(self.next_message())
2708 self.assert_log_lines([
2709 ('WARNING', '1'),
2710 ('ERROR', '4'),
2711 ], stream=output)
2712
2713 def test_config11_ok(self):
2714 self.test_config1_ok(self.config11)
2715
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002716 def test_config12_failure(self):
2717 self.assertRaises(Exception, self.apply_config, self.config12)
2718
2719 def test_config13_failure(self):
2720 self.assertRaises(Exception, self.apply_config, self.config13)
2721
Vinay Sajip8d270232012-11-15 14:20:18 +00002722 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002723 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002724 self.apply_config(self.config14)
2725 h = logging._handlers['hand1']
2726 self.assertEqual(h.foo, 'bar')
2727 self.assertEqual(h.terminator, '!\n')
2728 logging.warning('Exclamation')
2729 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2730
Victor Stinner45df8202010-04-28 22:31:17 +00002731 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002732 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002733 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002734 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002735 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002736 t.start()
2737 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002738 # Now get the port allocated
2739 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002740 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002741 try:
2742 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2743 sock.settimeout(2.0)
2744 sock.connect(('localhost', port))
2745
2746 slen = struct.pack('>L', len(text))
2747 s = slen + text
2748 sentsofar = 0
2749 left = len(s)
2750 while left > 0:
2751 sent = sock.send(s[sentsofar:])
2752 sentsofar += sent
2753 left -= sent
2754 sock.close()
2755 finally:
2756 t.ready.wait(2.0)
2757 logging.config.stopListening()
2758 t.join(2.0)
2759
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002760 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002761 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002762 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002763 self.setup_via_listener(json.dumps(self.config10))
2764 logger = logging.getLogger("compiler.parser")
2765 logger.warning(self.next_message())
2766 logger = logging.getLogger('compiler')
2767 #Not output, because filtered
2768 logger.warning(self.next_message())
2769 logger = logging.getLogger('compiler.lexer')
2770 #Not output, because filtered
2771 logger.warning(self.next_message())
2772 logger = logging.getLogger("compiler.parser.codegen")
2773 #Output, as not filtered
2774 logger.error(self.next_message())
2775 self.assert_log_lines([
2776 ('WARNING', '1'),
2777 ('ERROR', '4'),
2778 ], stream=output)
2779
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002780 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002781 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002782 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002783 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2784 logger = logging.getLogger("compiler.parser")
2785 # Both will output a message
2786 logger.info(self.next_message())
2787 logger.error(self.next_message())
2788 self.assert_log_lines([
2789 ('INFO', '1'),
2790 ('ERROR', '2'),
2791 ], stream=output)
2792 # Original logger output is empty.
2793 self.assert_log_lines([])
2794
Vinay Sajip4ded5512012-10-02 15:56:16 +01002795 @unittest.skipUnless(threading, 'Threading required for this test.')
2796 def test_listen_verify(self):
2797
2798 def verify_fail(stuff):
2799 return None
2800
2801 def verify_reverse(stuff):
2802 return stuff[::-1]
2803
2804 logger = logging.getLogger("compiler.parser")
2805 to_send = textwrap.dedent(ConfigFileTest.config1)
2806 # First, specify a verification function that will fail.
2807 # We expect to see no output, since our configuration
2808 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002809 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002810 self.setup_via_listener(to_send, verify_fail)
2811 # Both will output a message
2812 logger.info(self.next_message())
2813 logger.error(self.next_message())
2814 self.assert_log_lines([], stream=output)
2815 # Original logger output has the stuff we logged.
2816 self.assert_log_lines([
2817 ('INFO', '1'),
2818 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002819 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002820
2821 # Now, perform no verification. Our configuration
2822 # should take effect.
2823
Vinay Sajip1feedb42014-05-31 08:19:12 +01002824 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002825 self.setup_via_listener(to_send) # no verify callable specified
2826 logger = logging.getLogger("compiler.parser")
2827 # Both will output a message
2828 logger.info(self.next_message())
2829 logger.error(self.next_message())
2830 self.assert_log_lines([
2831 ('INFO', '3'),
2832 ('ERROR', '4'),
2833 ], stream=output)
2834 # Original logger output still has the stuff we logged before.
2835 self.assert_log_lines([
2836 ('INFO', '1'),
2837 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002838 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002839
2840 # Now, perform verification which transforms the bytes.
2841
Vinay Sajip1feedb42014-05-31 08:19:12 +01002842 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002843 self.setup_via_listener(to_send[::-1], verify_reverse)
2844 logger = logging.getLogger("compiler.parser")
2845 # Both will output a message
2846 logger.info(self.next_message())
2847 logger.error(self.next_message())
2848 self.assert_log_lines([
2849 ('INFO', '5'),
2850 ('ERROR', '6'),
2851 ], stream=output)
2852 # Original logger output still has the stuff we logged before.
2853 self.assert_log_lines([
2854 ('INFO', '1'),
2855 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002856 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002857
Vinay Sajip3f885b52013-03-22 15:19:54 +00002858 def test_out_of_order(self):
2859 self.apply_config(self.out_of_order)
2860 handler = logging.getLogger('mymodule').handlers[0]
2861 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002862 self.assertIsInstance(handler.formatter._style,
2863 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002864
Vinay Sajip373baef2011-04-26 20:05:24 +01002865 def test_baseconfig(self):
2866 d = {
2867 'atuple': (1, 2, 3),
2868 'alist': ['a', 'b', 'c'],
2869 'adict': {'d': 'e', 'f': 3 },
2870 'nest1': ('g', ('h', 'i'), 'j'),
2871 'nest2': ['k', ['l', 'm'], 'n'],
2872 'nest3': ['o', 'cfg://alist', 'p'],
2873 }
2874 bc = logging.config.BaseConfigurator(d)
2875 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2876 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2877 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2878 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2879 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2880 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2881 v = bc.convert('cfg://nest3')
2882 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2883 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2884 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2885 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002886
2887class ManagerTest(BaseTest):
2888 def test_manager_loggerclass(self):
2889 logged = []
2890
2891 class MyLogger(logging.Logger):
2892 def _log(self, level, msg, args, exc_info=None, extra=None):
2893 logged.append(msg)
2894
2895 man = logging.Manager(None)
2896 self.assertRaises(TypeError, man.setLoggerClass, int)
2897 man.setLoggerClass(MyLogger)
2898 logger = man.getLogger('test')
2899 logger.warning('should appear in logged')
2900 logging.warning('should not appear in logged')
2901
2902 self.assertEqual(logged, ['should appear in logged'])
2903
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002904 def test_set_log_record_factory(self):
2905 man = logging.Manager(None)
2906 expected = object()
2907 man.setLogRecordFactory(expected)
2908 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002909
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002910class ChildLoggerTest(BaseTest):
2911 def test_child_loggers(self):
2912 r = logging.getLogger()
2913 l1 = logging.getLogger('abc')
2914 l2 = logging.getLogger('def.ghi')
2915 c1 = r.getChild('xyz')
2916 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002917 self.assertIs(c1, logging.getLogger('xyz'))
2918 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002919 c1 = l1.getChild('def')
2920 c2 = c1.getChild('ghi')
2921 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002922 self.assertIs(c1, logging.getLogger('abc.def'))
2923 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2924 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002925
2926
Vinay Sajip6fac8172010-10-19 20:44:14 +00002927class DerivedLogRecord(logging.LogRecord):
2928 pass
2929
Vinay Sajip61561522010-12-03 11:50:38 +00002930class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002931
2932 def setUp(self):
2933 class CheckingFilter(logging.Filter):
2934 def __init__(self, cls):
2935 self.cls = cls
2936
2937 def filter(self, record):
2938 t = type(record)
2939 if t is not self.cls:
2940 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2941 self.cls)
2942 raise TypeError(msg)
2943 return True
2944
2945 BaseTest.setUp(self)
2946 self.filter = CheckingFilter(DerivedLogRecord)
2947 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002948 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002949
2950 def tearDown(self):
2951 self.root_logger.removeFilter(self.filter)
2952 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002953 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002954
2955 def test_logrecord_class(self):
2956 self.assertRaises(TypeError, self.root_logger.warning,
2957 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002958 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959 self.root_logger.error(self.next_message())
2960 self.assert_log_lines([
2961 ('root', 'ERROR', '2'),
2962 ])
2963
2964
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002965class QueueHandlerTest(BaseTest):
2966 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002967 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002968
2969 def setUp(self):
2970 BaseTest.setUp(self)
2971 self.queue = queue.Queue(-1)
2972 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2973 self.que_logger = logging.getLogger('que')
2974 self.que_logger.propagate = False
2975 self.que_logger.setLevel(logging.WARNING)
2976 self.que_logger.addHandler(self.que_hdlr)
2977
2978 def tearDown(self):
2979 self.que_hdlr.close()
2980 BaseTest.tearDown(self)
2981
2982 def test_queue_handler(self):
2983 self.que_logger.debug(self.next_message())
2984 self.assertRaises(queue.Empty, self.queue.get_nowait)
2985 self.que_logger.info(self.next_message())
2986 self.assertRaises(queue.Empty, self.queue.get_nowait)
2987 msg = self.next_message()
2988 self.que_logger.warning(msg)
2989 data = self.queue.get_nowait()
2990 self.assertTrue(isinstance(data, logging.LogRecord))
2991 self.assertEqual(data.name, self.que_logger.name)
2992 self.assertEqual((data.msg, data.args), (msg, None))
2993
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002994 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2995 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002996 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002997 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01002998 listener = logging.handlers.QueueListener(self.queue, handler)
2999 listener.start()
3000 try:
3001 self.que_logger.warning(self.next_message())
3002 self.que_logger.error(self.next_message())
3003 self.que_logger.critical(self.next_message())
3004 finally:
3005 listener.stop()
3006 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3007 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3008 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3009
Vinay Sajip37eb3382011-04-26 20:26:41 +01003010ZERO = datetime.timedelta(0)
3011
3012class UTC(datetime.tzinfo):
3013 def utcoffset(self, dt):
3014 return ZERO
3015
3016 dst = utcoffset
3017
3018 def tzname(self, dt):
3019 return 'UTC'
3020
3021utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003022
Vinay Sajipa39c5712010-10-25 13:57:39 +00003023class FormatterTest(unittest.TestCase):
3024 def setUp(self):
3025 self.common = {
3026 'name': 'formatter.test',
3027 'level': logging.DEBUG,
3028 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3029 'lineno': 42,
3030 'exc_info': None,
3031 'func': None,
3032 'msg': 'Message with %d %s',
3033 'args': (2, 'placeholders'),
3034 }
3035 self.variants = {
3036 }
3037
3038 def get_record(self, name=None):
3039 result = dict(self.common)
3040 if name is not None:
3041 result.update(self.variants[name])
3042 return logging.makeLogRecord(result)
3043
3044 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003045 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003046 r = self.get_record()
3047 f = logging.Formatter('${%(message)s}')
3048 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3049 f = logging.Formatter('%(random)s')
3050 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003051 self.assertFalse(f.usesTime())
3052 f = logging.Formatter('%(asctime)s')
3053 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003054 f = logging.Formatter('%(asctime)-15s')
3055 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003056 f = logging.Formatter('asctime')
3057 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003058
3059 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003060 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003061 r = self.get_record()
3062 f = logging.Formatter('$%{message}%$', style='{')
3063 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3064 f = logging.Formatter('{random}', style='{')
3065 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003066 self.assertFalse(f.usesTime())
3067 f = logging.Formatter('{asctime}', style='{')
3068 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003069 f = logging.Formatter('{asctime!s:15}', style='{')
3070 self.assertTrue(f.usesTime())
3071 f = logging.Formatter('{asctime:15}', style='{')
3072 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003073 f = logging.Formatter('asctime', style='{')
3074 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003075
3076 def test_dollars(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', style='$')
3080 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3081 f = logging.Formatter('$$%${message}%$$', style='$')
3082 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3083 f = logging.Formatter('${random}', style='$')
3084 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003085 self.assertFalse(f.usesTime())
3086 f = logging.Formatter('${asctime}', style='$')
3087 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003088 f = logging.Formatter('${asctime', style='$')
3089 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003090 f = logging.Formatter('$asctime', style='$')
3091 self.assertTrue(f.usesTime())
3092 f = logging.Formatter('asctime', style='$')
3093 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003094
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003095 def test_invalid_style(self):
3096 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3097
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003098 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003099 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003100 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3101 # We use None to indicate we want the local timezone
3102 # We're essentially converting a UTC time to local time
3103 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003104 r.msecs = 123
3105 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003106 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003107 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3108 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003109 f.format(r)
3110 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3111
3112class TestBufferingFormatter(logging.BufferingFormatter):
3113 def formatHeader(self, records):
3114 return '[(%d)' % len(records)
3115
3116 def formatFooter(self, records):
3117 return '(%d)]' % len(records)
3118
3119class BufferingFormatterTest(unittest.TestCase):
3120 def setUp(self):
3121 self.records = [
3122 logging.makeLogRecord({'msg': 'one'}),
3123 logging.makeLogRecord({'msg': 'two'}),
3124 ]
3125
3126 def test_default(self):
3127 f = logging.BufferingFormatter()
3128 self.assertEqual('', f.format([]))
3129 self.assertEqual('onetwo', f.format(self.records))
3130
3131 def test_custom(self):
3132 f = TestBufferingFormatter()
3133 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3134 lf = logging.Formatter('<%(message)s>')
3135 f = TestBufferingFormatter(lf)
3136 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003137
3138class ExceptionTest(BaseTest):
3139 def test_formatting(self):
3140 r = self.root_logger
3141 h = RecordingHandler()
3142 r.addHandler(h)
3143 try:
3144 raise RuntimeError('deliberate mistake')
3145 except:
3146 logging.exception('failed', stack_info=True)
3147 r.removeHandler(h)
3148 h.close()
3149 r = h.records[0]
3150 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3151 'call last):\n'))
3152 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3153 'deliberate mistake'))
3154 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3155 'call last):\n'))
3156 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3157 'stack_info=True)'))
3158
3159
Vinay Sajip5a27d402010-12-10 11:42:57 +00003160class LastResortTest(BaseTest):
3161 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003162 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003163 root = self.root_logger
3164 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003165 old_lastresort = logging.lastResort
3166 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003167
Vinay Sajip5a27d402010-12-10 11:42:57 +00003168 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003169 with support.captured_stderr() as stderr:
3170 root.debug('This should not appear')
3171 self.assertEqual(stderr.getvalue(), '')
3172 root.warning('Final chance!')
3173 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3174
3175 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003176 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003177 with support.captured_stderr() as stderr:
3178 root.warning('Final chance!')
3179 msg = 'No handlers could be found for logger "root"\n'
3180 self.assertEqual(stderr.getvalue(), msg)
3181
Vinay Sajip5a27d402010-12-10 11:42:57 +00003182 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003183 with support.captured_stderr() as stderr:
3184 root.warning('Final chance!')
3185 self.assertEqual(stderr.getvalue(), '')
3186
3187 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003188 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003189 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003190 with support.captured_stderr() as stderr:
3191 root.warning('Final chance!')
3192 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003193 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003194 root.addHandler(self.root_hdlr)
3195 logging.lastResort = old_lastresort
3196 logging.raiseExceptions = old_raise_exceptions
3197
3198
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003199class FakeHandler:
3200
3201 def __init__(self, identifier, called):
3202 for method in ('acquire', 'flush', 'close', 'release'):
3203 setattr(self, method, self.record_call(identifier, method, called))
3204
3205 def record_call(self, identifier, method_name, called):
3206 def inner():
3207 called.append('{} - {}'.format(identifier, method_name))
3208 return inner
3209
3210
3211class RecordingHandler(logging.NullHandler):
3212
3213 def __init__(self, *args, **kwargs):
3214 super(RecordingHandler, self).__init__(*args, **kwargs)
3215 self.records = []
3216
3217 def handle(self, record):
3218 """Keep track of all the emitted records."""
3219 self.records.append(record)
3220
3221
3222class ShutdownTest(BaseTest):
3223
Vinay Sajip5e66b162011-04-20 15:41:14 +01003224 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003225
3226 def setUp(self):
3227 super(ShutdownTest, self).setUp()
3228 self.called = []
3229
3230 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003231 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003232
3233 def raise_error(self, error):
3234 def inner():
3235 raise error()
3236 return inner
3237
3238 def test_no_failure(self):
3239 # create some fake handlers
3240 handler0 = FakeHandler(0, self.called)
3241 handler1 = FakeHandler(1, self.called)
3242 handler2 = FakeHandler(2, self.called)
3243
3244 # create live weakref to those handlers
3245 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3246
3247 logging.shutdown(handlerList=list(handlers))
3248
3249 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3250 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3251 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3252 self.assertEqual(expected, self.called)
3253
3254 def _test_with_failure_in_method(self, method, error):
3255 handler = FakeHandler(0, self.called)
3256 setattr(handler, method, self.raise_error(error))
3257 handlers = [logging.weakref.ref(handler)]
3258
3259 logging.shutdown(handlerList=list(handlers))
3260
3261 self.assertEqual('0 - release', self.called[-1])
3262
3263 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003264 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003265
3266 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003267 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003268
3269 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003270 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003271
3272 def test_with_valueerror_in_acquire(self):
3273 self._test_with_failure_in_method('acquire', ValueError)
3274
3275 def test_with_valueerror_in_flush(self):
3276 self._test_with_failure_in_method('flush', ValueError)
3277
3278 def test_with_valueerror_in_close(self):
3279 self._test_with_failure_in_method('close', ValueError)
3280
3281 def test_with_other_error_in_acquire_without_raise(self):
3282 logging.raiseExceptions = False
3283 self._test_with_failure_in_method('acquire', IndexError)
3284
3285 def test_with_other_error_in_flush_without_raise(self):
3286 logging.raiseExceptions = False
3287 self._test_with_failure_in_method('flush', IndexError)
3288
3289 def test_with_other_error_in_close_without_raise(self):
3290 logging.raiseExceptions = False
3291 self._test_with_failure_in_method('close', IndexError)
3292
3293 def test_with_other_error_in_acquire_with_raise(self):
3294 logging.raiseExceptions = True
3295 self.assertRaises(IndexError, self._test_with_failure_in_method,
3296 'acquire', IndexError)
3297
3298 def test_with_other_error_in_flush_with_raise(self):
3299 logging.raiseExceptions = True
3300 self.assertRaises(IndexError, self._test_with_failure_in_method,
3301 'flush', IndexError)
3302
3303 def test_with_other_error_in_close_with_raise(self):
3304 logging.raiseExceptions = True
3305 self.assertRaises(IndexError, self._test_with_failure_in_method,
3306 'close', IndexError)
3307
3308
3309class ModuleLevelMiscTest(BaseTest):
3310
Vinay Sajip5e66b162011-04-20 15:41:14 +01003311 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003312
3313 def test_disable(self):
3314 old_disable = logging.root.manager.disable
3315 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003316 self.assertEqual(old_disable, 0)
3317 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003318
3319 logging.disable(83)
3320 self.assertEqual(logging.root.manager.disable, 83)
3321
3322 def _test_log(self, method, level=None):
3323 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003324 support.patch(self, logging, 'basicConfig',
3325 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003326
3327 recording = RecordingHandler()
3328 logging.root.addHandler(recording)
3329
3330 log_method = getattr(logging, method)
3331 if level is not None:
3332 log_method(level, "test me: %r", recording)
3333 else:
3334 log_method("test me: %r", recording)
3335
3336 self.assertEqual(len(recording.records), 1)
3337 record = recording.records[0]
3338 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3339
3340 expected_level = level if level is not None else getattr(logging, method.upper())
3341 self.assertEqual(record.levelno, expected_level)
3342
3343 # basicConfig was not called!
3344 self.assertEqual(called, [])
3345
3346 def test_log(self):
3347 self._test_log('log', logging.ERROR)
3348
3349 def test_debug(self):
3350 self._test_log('debug')
3351
3352 def test_info(self):
3353 self._test_log('info')
3354
3355 def test_warning(self):
3356 self._test_log('warning')
3357
3358 def test_error(self):
3359 self._test_log('error')
3360
3361 def test_critical(self):
3362 self._test_log('critical')
3363
3364 def test_set_logger_class(self):
3365 self.assertRaises(TypeError, logging.setLoggerClass, object)
3366
3367 class MyLogger(logging.Logger):
3368 pass
3369
3370 logging.setLoggerClass(MyLogger)
3371 self.assertEqual(logging.getLoggerClass(), MyLogger)
3372
3373 logging.setLoggerClass(logging.Logger)
3374 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3375
Antoine Pitrou712cb732013-12-21 15:51:54 +01003376 def test_logging_at_shutdown(self):
3377 # Issue #20037
3378 code = """if 1:
3379 import logging
3380
3381 class A:
3382 def __del__(self):
3383 try:
3384 raise ValueError("some error")
3385 except Exception:
3386 logging.exception("exception in __del__")
3387
3388 a = A()"""
3389 rc, out, err = assert_python_ok("-c", code)
3390 err = err.decode()
3391 self.assertIn("exception in __del__", err)
3392 self.assertIn("ValueError: some error", err)
3393
3394
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003395class LogRecordTest(BaseTest):
3396 def test_str_rep(self):
3397 r = logging.makeLogRecord({})
3398 s = str(r)
3399 self.assertTrue(s.startswith('<LogRecord: '))
3400 self.assertTrue(s.endswith('>'))
3401
3402 def test_dict_arg(self):
3403 h = RecordingHandler()
3404 r = logging.getLogger()
3405 r.addHandler(h)
3406 d = {'less' : 'more' }
3407 logging.warning('less is %(less)s', d)
3408 self.assertIs(h.records[0].args, d)
3409 self.assertEqual(h.records[0].message, 'less is more')
3410 r.removeHandler(h)
3411 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003412
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003413 def test_multiprocessing(self):
3414 r = logging.makeLogRecord({})
3415 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003416 try:
3417 import multiprocessing as mp
3418 r = logging.makeLogRecord({})
3419 self.assertEqual(r.processName, mp.current_process().name)
3420 except ImportError:
3421 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003422
3423 def test_optional(self):
3424 r = logging.makeLogRecord({})
3425 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003426 if threading:
3427 NOT_NONE(r.thread)
3428 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003429 NOT_NONE(r.process)
3430 NOT_NONE(r.processName)
3431 log_threads = logging.logThreads
3432 log_processes = logging.logProcesses
3433 log_multiprocessing = logging.logMultiprocessing
3434 try:
3435 logging.logThreads = False
3436 logging.logProcesses = False
3437 logging.logMultiprocessing = False
3438 r = logging.makeLogRecord({})
3439 NONE = self.assertIsNone
3440 NONE(r.thread)
3441 NONE(r.threadName)
3442 NONE(r.process)
3443 NONE(r.processName)
3444 finally:
3445 logging.logThreads = log_threads
3446 logging.logProcesses = log_processes
3447 logging.logMultiprocessing = log_multiprocessing
3448
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003449class BasicConfigTest(unittest.TestCase):
3450
Vinay Sajip95bf5042011-04-20 11:50:56 +01003451 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003452
3453 def setUp(self):
3454 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003455 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003456 self.saved_handlers = logging._handlers.copy()
3457 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003458 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003459 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003460 logging.root.handlers = []
3461
3462 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003463 for h in logging.root.handlers[:]:
3464 logging.root.removeHandler(h)
3465 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003466 super(BasicConfigTest, self).tearDown()
3467
Vinay Sajip3def7e02011-04-20 10:58:06 +01003468 def cleanup(self):
3469 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003470 logging._handlers.clear()
3471 logging._handlers.update(self.saved_handlers)
3472 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003473 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003474
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003475 def test_no_kwargs(self):
3476 logging.basicConfig()
3477
3478 # handler defaults to a StreamHandler to sys.stderr
3479 self.assertEqual(len(logging.root.handlers), 1)
3480 handler = logging.root.handlers[0]
3481 self.assertIsInstance(handler, logging.StreamHandler)
3482 self.assertEqual(handler.stream, sys.stderr)
3483
3484 formatter = handler.formatter
3485 # format defaults to logging.BASIC_FORMAT
3486 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3487 # datefmt defaults to None
3488 self.assertIsNone(formatter.datefmt)
3489 # style defaults to %
3490 self.assertIsInstance(formatter._style, logging.PercentStyle)
3491
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003492 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003493 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494
Vinay Sajip1fd12022014-01-13 21:59:56 +00003495 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003496 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003497 logging.basicConfig(stream=sys.stdout, style="{")
3498 logging.error("Log an error")
3499 sys.stdout.seek(0)
3500 self.assertEqual(output.getvalue().strip(),
3501 "ERROR:root:Log an error")
3502
3503 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003504 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003505 logging.basicConfig(stream=sys.stdout, style="$")
3506 logging.error("Log an error")
3507 sys.stdout.seek(0)
3508 self.assertEqual(output.getvalue().strip(),
3509 "ERROR:root:Log an error")
3510
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003511 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003512
3513 def cleanup(h1, h2, fn):
3514 h1.close()
3515 h2.close()
3516 os.remove(fn)
3517
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518 logging.basicConfig(filename='test.log')
3519
3520 self.assertEqual(len(logging.root.handlers), 1)
3521 handler = logging.root.handlers[0]
3522 self.assertIsInstance(handler, logging.FileHandler)
3523
3524 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003525 self.assertEqual(handler.stream.mode, expected.stream.mode)
3526 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003527 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003528
3529 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003530
3531 def cleanup(h1, h2, fn):
3532 h1.close()
3533 h2.close()
3534 os.remove(fn)
3535
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003536 logging.basicConfig(filename='test.log', filemode='wb')
3537
3538 handler = logging.root.handlers[0]
3539 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003540 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003541 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003542
3543 def test_stream(self):
3544 stream = io.StringIO()
3545 self.addCleanup(stream.close)
3546 logging.basicConfig(stream=stream)
3547
3548 self.assertEqual(len(logging.root.handlers), 1)
3549 handler = logging.root.handlers[0]
3550 self.assertIsInstance(handler, logging.StreamHandler)
3551 self.assertEqual(handler.stream, stream)
3552
3553 def test_format(self):
3554 logging.basicConfig(format='foo')
3555
3556 formatter = logging.root.handlers[0].formatter
3557 self.assertEqual(formatter._style._fmt, 'foo')
3558
3559 def test_datefmt(self):
3560 logging.basicConfig(datefmt='bar')
3561
3562 formatter = logging.root.handlers[0].formatter
3563 self.assertEqual(formatter.datefmt, 'bar')
3564
3565 def test_style(self):
3566 logging.basicConfig(style='$')
3567
3568 formatter = logging.root.handlers[0].formatter
3569 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3570
3571 def test_level(self):
3572 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003573 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003574
3575 logging.basicConfig(level=57)
3576 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003577 # Test that second call has no effect
3578 logging.basicConfig(level=58)
3579 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003580
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003581 def test_incompatible(self):
3582 assertRaises = self.assertRaises
3583 handlers = [logging.StreamHandler()]
3584 stream = sys.stderr
3585 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3586 stream=stream)
3587 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3588 handlers=handlers)
3589 assertRaises(ValueError, logging.basicConfig, stream=stream,
3590 handlers=handlers)
3591
3592 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003593 handlers = [
3594 logging.StreamHandler(),
3595 logging.StreamHandler(sys.stdout),
3596 logging.StreamHandler(),
3597 ]
3598 f = logging.Formatter()
3599 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003600 logging.basicConfig(handlers=handlers)
3601 self.assertIs(handlers[0], logging.root.handlers[0])
3602 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003603 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003604 self.assertIsNotNone(handlers[0].formatter)
3605 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003606 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003607 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3608
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003609 def _test_log(self, method, level=None):
3610 # logging.root has no handlers so basicConfig should be called
3611 called = []
3612
3613 old_basic_config = logging.basicConfig
3614 def my_basic_config(*a, **kw):
3615 old_basic_config()
3616 old_level = logging.root.level
3617 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003618 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003619 called.append((a, kw))
3620
Vinay Sajip1feedb42014-05-31 08:19:12 +01003621 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003622
3623 log_method = getattr(logging, method)
3624 if level is not None:
3625 log_method(level, "test me")
3626 else:
3627 log_method("test me")
3628
3629 # basicConfig was called with no arguments
3630 self.assertEqual(called, [((), {})])
3631
3632 def test_log(self):
3633 self._test_log('log', logging.WARNING)
3634
3635 def test_debug(self):
3636 self._test_log('debug')
3637
3638 def test_info(self):
3639 self._test_log('info')
3640
3641 def test_warning(self):
3642 self._test_log('warning')
3643
3644 def test_error(self):
3645 self._test_log('error')
3646
3647 def test_critical(self):
3648 self._test_log('critical')
3649
3650
3651class LoggerAdapterTest(unittest.TestCase):
3652
3653 def setUp(self):
3654 super(LoggerAdapterTest, self).setUp()
3655 old_handler_list = logging._handlerList[:]
3656
3657 self.recording = RecordingHandler()
3658 self.logger = logging.root
3659 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003660 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003661 self.addCleanup(self.recording.close)
3662
3663 def cleanup():
3664 logging._handlerList[:] = old_handler_list
3665
3666 self.addCleanup(cleanup)
3667 self.addCleanup(logging.shutdown)
3668 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3669
3670 def test_exception(self):
3671 msg = 'testing exception: %r'
3672 exc = None
3673 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003674 1 / 0
3675 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003676 exc = e
3677 self.adapter.exception(msg, self.recording)
3678
3679 self.assertEqual(len(self.recording.records), 1)
3680 record = self.recording.records[0]
3681 self.assertEqual(record.levelno, logging.ERROR)
3682 self.assertEqual(record.msg, msg)
3683 self.assertEqual(record.args, (self.recording,))
3684 self.assertEqual(record.exc_info,
3685 (exc.__class__, exc, exc.__traceback__))
3686
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003687 def test_exception_excinfo(self):
3688 try:
3689 1 / 0
3690 except ZeroDivisionError as e:
3691 exc = e
3692
3693 self.adapter.exception('exc_info test', exc_info=exc)
3694
3695 self.assertEqual(len(self.recording.records), 1)
3696 record = self.recording.records[0]
3697 self.assertEqual(record.exc_info,
3698 (exc.__class__, exc, exc.__traceback__))
3699
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003700 def test_critical(self):
3701 msg = 'critical test! %r'
3702 self.adapter.critical(msg, self.recording)
3703
3704 self.assertEqual(len(self.recording.records), 1)
3705 record = self.recording.records[0]
3706 self.assertEqual(record.levelno, logging.CRITICAL)
3707 self.assertEqual(record.msg, msg)
3708 self.assertEqual(record.args, (self.recording,))
3709
3710 def test_is_enabled_for(self):
3711 old_disable = self.adapter.logger.manager.disable
3712 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003713 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3714 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003715 self.assertFalse(self.adapter.isEnabledFor(32))
3716
3717 def test_has_handlers(self):
3718 self.assertTrue(self.adapter.hasHandlers())
3719
3720 for handler in self.logger.handlers:
3721 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003722
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003723 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003724 self.assertFalse(self.adapter.hasHandlers())
3725
3726
3727class LoggerTest(BaseTest):
3728
3729 def setUp(self):
3730 super(LoggerTest, self).setUp()
3731 self.recording = RecordingHandler()
3732 self.logger = logging.Logger(name='blah')
3733 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003734 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003735 self.addCleanup(self.recording.close)
3736 self.addCleanup(logging.shutdown)
3737
3738 def test_set_invalid_level(self):
3739 self.assertRaises(TypeError, self.logger.setLevel, object())
3740
3741 def test_exception(self):
3742 msg = 'testing exception: %r'
3743 exc = None
3744 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003745 1 / 0
3746 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003747 exc = e
3748 self.logger.exception(msg, self.recording)
3749
3750 self.assertEqual(len(self.recording.records), 1)
3751 record = self.recording.records[0]
3752 self.assertEqual(record.levelno, logging.ERROR)
3753 self.assertEqual(record.msg, msg)
3754 self.assertEqual(record.args, (self.recording,))
3755 self.assertEqual(record.exc_info,
3756 (exc.__class__, exc, exc.__traceback__))
3757
3758 def test_log_invalid_level_with_raise(self):
3759 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003760 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003761
3762 logging.raiseExceptions = True
3763 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3764
3765 def test_log_invalid_level_no_raise(self):
3766 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003767 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003768
3769 logging.raiseExceptions = False
3770 self.logger.log('10', 'test message') # no exception happens
3771
3772 def test_find_caller_with_stack_info(self):
3773 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003774 support.patch(self, logging.traceback, 'print_stack',
3775 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003776
3777 self.logger.findCaller(stack_info=True)
3778
3779 self.assertEqual(len(called), 1)
3780 self.assertEqual('Stack (most recent call last):\n', called[0])
3781
3782 def test_make_record_with_extra_overwrite(self):
3783 name = 'my record'
3784 level = 13
3785 fn = lno = msg = args = exc_info = func = sinfo = None
3786 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3787 exc_info, func, sinfo)
3788
3789 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3790 extra = {key: 'some value'}
3791 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3792 fn, lno, msg, args, exc_info,
3793 extra=extra, sinfo=sinfo)
3794
3795 def test_make_record_with_extra_no_overwrite(self):
3796 name = 'my record'
3797 level = 13
3798 fn = lno = msg = args = exc_info = func = sinfo = None
3799 extra = {'valid_key': 'some value'}
3800 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3801 exc_info, extra=extra, sinfo=sinfo)
3802 self.assertIn('valid_key', result.__dict__)
3803
3804 def test_has_handlers(self):
3805 self.assertTrue(self.logger.hasHandlers())
3806
3807 for handler in self.logger.handlers:
3808 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003809 self.assertFalse(self.logger.hasHandlers())
3810
3811 def test_has_handlers_no_propagate(self):
3812 child_logger = logging.getLogger('blah.child')
3813 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003814 self.assertFalse(child_logger.hasHandlers())
3815
3816 def test_is_enabled_for(self):
3817 old_disable = self.logger.manager.disable
3818 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003819 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003820 self.assertFalse(self.logger.isEnabledFor(22))
3821
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003822 def test_root_logger_aliases(self):
3823 root = logging.getLogger()
3824 self.assertIs(root, logging.root)
3825 self.assertIs(root, logging.getLogger(None))
3826 self.assertIs(root, logging.getLogger(''))
3827 self.assertIs(root, logging.getLogger('foo').root)
3828 self.assertIs(root, logging.getLogger('foo.bar').root)
3829 self.assertIs(root, logging.getLogger('foo').parent)
3830
3831 self.assertIsNot(root, logging.getLogger('\0'))
3832 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3833
3834 def test_invalid_names(self):
3835 self.assertRaises(TypeError, logging.getLogger, any)
3836 self.assertRaises(TypeError, logging.getLogger, b'foo')
3837
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003838
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003839class BaseFileTest(BaseTest):
3840 "Base class for handler tests that write log files"
3841
3842 def setUp(self):
3843 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003844 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3845 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003846 self.rmfiles = []
3847
3848 def tearDown(self):
3849 for fn in self.rmfiles:
3850 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003851 if os.path.exists(self.fn):
3852 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003853 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003854
3855 def assertLogFile(self, filename):
3856 "Assert a log file is there and register it for deletion"
3857 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003858 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003859 self.rmfiles.append(filename)
3860
3861
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003862class FileHandlerTest(BaseFileTest):
3863 def test_delay(self):
3864 os.unlink(self.fn)
3865 fh = logging.FileHandler(self.fn, delay=True)
3866 self.assertIsNone(fh.stream)
3867 self.assertFalse(os.path.exists(self.fn))
3868 fh.handle(logging.makeLogRecord({}))
3869 self.assertIsNotNone(fh.stream)
3870 self.assertTrue(os.path.exists(self.fn))
3871 fh.close()
3872
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003873class RotatingFileHandlerTest(BaseFileTest):
3874 def next_rec(self):
3875 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3876 self.next_message(), None, None, None)
3877
3878 def test_should_not_rollover(self):
3879 # If maxbytes is zero rollover never occurs
3880 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3881 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003882 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003883
3884 def test_should_rollover(self):
3885 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3886 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003887 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003888
3889 def test_file_created(self):
3890 # checks that the file is created and assumes it was created
3891 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003892 rh = logging.handlers.RotatingFileHandler(self.fn)
3893 rh.emit(self.next_rec())
3894 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003895 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003896
3897 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003898 def namer(name):
3899 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003900 rh = logging.handlers.RotatingFileHandler(
3901 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003902 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003903 rh.emit(self.next_rec())
3904 self.assertLogFile(self.fn)
3905 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003906 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003907 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003908 self.assertLogFile(namer(self.fn + ".2"))
3909 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3910 rh.close()
3911
Vinay Sajip1feedb42014-05-31 08:19:12 +01003912 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003913 def test_rotator(self):
3914 def namer(name):
3915 return name + ".gz"
3916
3917 def rotator(source, dest):
3918 with open(source, "rb") as sf:
3919 data = sf.read()
3920 compressed = zlib.compress(data, 9)
3921 with open(dest, "wb") as df:
3922 df.write(compressed)
3923 os.remove(source)
3924
3925 rh = logging.handlers.RotatingFileHandler(
3926 self.fn, backupCount=2, maxBytes=1)
3927 rh.rotator = rotator
3928 rh.namer = namer
3929 m1 = self.next_rec()
3930 rh.emit(m1)
3931 self.assertLogFile(self.fn)
3932 m2 = self.next_rec()
3933 rh.emit(m2)
3934 fn = namer(self.fn + ".1")
3935 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003936 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003937 with open(fn, "rb") as f:
3938 compressed = f.read()
3939 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003940 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003941 rh.emit(self.next_rec())
3942 fn = namer(self.fn + ".2")
3943 self.assertLogFile(fn)
3944 with open(fn, "rb") as f:
3945 compressed = f.read()
3946 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003947 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003948 rh.emit(self.next_rec())
3949 fn = namer(self.fn + ".2")
3950 with open(fn, "rb") as f:
3951 compressed = f.read()
3952 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003953 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003954 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003955 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003956
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003957class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003958 # other test methods added below
3959 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003960 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3961 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003962 fmt = logging.Formatter('%(asctime)s %(message)s')
3963 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003964 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003965 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003966 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003967 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003968 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003969 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003970 fh.close()
3971 # At this point, we should have a recent rotated file which we
3972 # can test for the existence of. However, in practice, on some
3973 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003974 # in time to go to look for the log file. So, we go back a fair
3975 # bit, and stop as soon as we see a rotated file. In theory this
3976 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003977 found = False
3978 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003979 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003980 for secs in range(GO_BACK):
3981 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003982 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3983 found = os.path.exists(fn)
3984 if found:
3985 self.rmfiles.append(fn)
3986 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003987 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3988 if not found:
3989 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003990 dn, fn = os.path.split(self.fn)
3991 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003992 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3993 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003994 for f in files:
3995 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003996 path = os.path.join(dn, f)
3997 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003998 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003999 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004000
Vinay Sajip0372e102011-05-05 12:59:14 +01004001 def test_invalid(self):
4002 assertRaises = self.assertRaises
4003 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004004 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004005 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004006 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004007 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004008 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004009
Vinay Sajipa7130792013-04-12 17:04:23 +01004010 def test_compute_rollover_daily_attime(self):
4011 currentTime = 0
4012 atTime = datetime.time(12, 0, 0)
4013 rh = logging.handlers.TimedRotatingFileHandler(
4014 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4015 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004016 try:
4017 actual = rh.computeRollover(currentTime)
4018 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004019
Vinay Sajipd86ac962013-04-14 12:20:46 +01004020 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4021 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4022 finally:
4023 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004024
Vinay Sajip10e8c492013-05-18 10:19:54 -07004025 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004026 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004027 currentTime = int(time.time())
4028 today = currentTime - currentTime % 86400
4029
Vinay Sajipa7130792013-04-12 17:04:23 +01004030 atTime = datetime.time(12, 0, 0)
4031
Vinay Sajip10e8c492013-05-18 10:19:54 -07004032 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004033 for day in range(7):
4034 rh = logging.handlers.TimedRotatingFileHandler(
4035 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4036 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004037 try:
4038 if wday > day:
4039 # The rollover day has already passed this week, so we
4040 # go over into next week
4041 expected = (7 - wday + day)
4042 else:
4043 expected = (day - wday)
4044 # At this point expected is in days from now, convert to seconds
4045 expected *= 24 * 60 * 60
4046 # Add in the rollover time
4047 expected += 12 * 60 * 60
4048 # Add in adjustment for today
4049 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004050 actual = rh.computeRollover(today)
4051 if actual != expected:
4052 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004053 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004054 self.assertEqual(actual, expected)
4055 if day == wday:
4056 # goes into following week
4057 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004058 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004059 if actual != expected:
4060 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004061 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004062 self.assertEqual(actual, expected)
4063 finally:
4064 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004065
4066
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004067def secs(**kw):
4068 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4069
4070for when, exp in (('S', 1),
4071 ('M', 60),
4072 ('H', 60 * 60),
4073 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004074 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004075 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004076 ('W0', secs(days=4, hours=24)),
4077 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004078 def test_compute_rollover(self, when=when, exp=exp):
4079 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004080 self.fn, when=when, interval=1, backupCount=0, utc=True)
4081 currentTime = 0.0
4082 actual = rh.computeRollover(currentTime)
4083 if exp != actual:
4084 # Failures occur on some systems for MIDNIGHT and W0.
4085 # Print detailed calculation for MIDNIGHT so we can try to see
4086 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004087 if when == 'MIDNIGHT':
4088 try:
4089 if rh.utc:
4090 t = time.gmtime(currentTime)
4091 else:
4092 t = time.localtime(currentTime)
4093 currentHour = t[3]
4094 currentMinute = t[4]
4095 currentSecond = t[5]
4096 # r is the number of seconds left between now and midnight
4097 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4098 currentMinute) * 60 +
4099 currentSecond)
4100 result = currentTime + r
4101 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4102 print('currentHour: %s' % currentHour, file=sys.stderr)
4103 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4104 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4105 print('r: %s' % r, file=sys.stderr)
4106 print('result: %s' % result, file=sys.stderr)
4107 except Exception:
4108 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4109 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004110 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004111 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4112
Vinay Sajip60ccd822011-05-09 17:32:09 +01004113
4114@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4115class NTEventLogHandlerTest(BaseTest):
4116 def test_basic(self):
4117 logtype = 'Application'
4118 elh = win32evtlog.OpenEventLog(None, logtype)
4119 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4120 h = logging.handlers.NTEventLogHandler('test_logging')
4121 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4122 h.handle(r)
4123 h.close()
4124 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004125 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004126 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4127 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4128 found = False
4129 GO_BACK = 100
4130 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4131 for e in events:
4132 if e.SourceName != 'test_logging':
4133 continue
4134 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4135 if msg != 'Test Log Message\r\n':
4136 continue
4137 found = True
4138 break
4139 msg = 'Record not found in event log, went back %d records' % GO_BACK
4140 self.assertTrue(found, msg=msg)
4141
Christian Heimes180510d2008-03-03 19:15:45 +00004142# Set the locale to the platform-dependent default. I have no idea
4143# why the test does this, but in any case we save the current locale
4144# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004145@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004146def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004147 support.run_unittest(
4148 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4149 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4150 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4151 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4152 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4153 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4154 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4155 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4156 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4157 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
4158 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004159
Christian Heimes180510d2008-03-03 19:15:45 +00004160if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004161 test_main()