blob: 744238195a2826c37a6d92fd829ccdb3798ddb45 [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 = {}
929 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
930 sockmap)
931 server.start()
932 addr = ('localhost', 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
Vinay Sajip9ba87612011-05-21 11:32:15 +01001630 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1631MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1632zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1633aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1634AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16350tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16365LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1637piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16382z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1639i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1640PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1641E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1642rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1643/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1644-----END RSA PRIVATE KEY-----
1645-----BEGIN CERTIFICATE-----
1646MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1647BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1648EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1649xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1650l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1651vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1652BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1653S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1654BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16554f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16561c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1657IRbTpvlHWPjsSvHz0ZOH
1658-----END CERTIFICATE-----"""
1659
Vinay Sajip7367d082011-05-02 13:17:27 +01001660 def setUp(self):
1661 """Set up an HTTP server to receive log messages, and a HTTPHandler
1662 pointing to that server's address and port."""
1663 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 self.handled = threading.Event()
1665
Vinay Sajip7367d082011-05-02 13:17:27 +01001666 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001667 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001668 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001669 if self.command == 'POST':
1670 try:
1671 rlen = int(request.headers['Content-Length'])
1672 self.post_data = request.rfile.read(rlen)
1673 except:
1674 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001675 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001676 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001677 self.handled.set()
1678
1679 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001680 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001681 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001682 root_logger = self.root_logger
1683 root_logger.removeHandler(self.root_logger.handlers[0])
1684 for secure in (False, True):
1685 addr = ('localhost', 0)
1686 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001687 try:
1688 import ssl
1689 fd, fn = tempfile.mkstemp()
1690 os.close(fd)
1691 with open(fn, 'w') as f:
1692 f.write(self.PEMFILE)
1693 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1694 sslctx.load_cert_chain(fn)
1695 os.unlink(fn)
1696 except ImportError:
1697 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001698 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001699 sslctx = None
1700 self.server = server = TestHTTPServer(addr, self.handle_request,
1701 0.01, sslctx=sslctx)
1702 server.start()
1703 server.ready.wait()
1704 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001705 secure_client = secure and sslctx
1706 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1707 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001708 self.log_data = None
1709 root_logger.addHandler(self.h_hdlr)
1710
1711 for method in ('GET', 'POST'):
1712 self.h_hdlr.method = method
1713 self.handled.clear()
1714 msg = "sp\xe4m"
1715 logger.error(msg)
1716 self.handled.wait()
1717 self.assertEqual(self.log_data.path, '/frob')
1718 self.assertEqual(self.command, method)
1719 if method == 'GET':
1720 d = parse_qs(self.log_data.query)
1721 else:
1722 d = parse_qs(self.post_data.decode('utf-8'))
1723 self.assertEqual(d['name'], ['http'])
1724 self.assertEqual(d['funcName'], ['test_output'])
1725 self.assertEqual(d['msg'], [msg])
1726
1727 self.server.stop(2.0)
1728 self.root_logger.removeHandler(self.h_hdlr)
1729 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001732
Christian Heimes180510d2008-03-03 19:15:45 +00001733 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001734
Christian Heimes180510d2008-03-03 19:15:45 +00001735 def setUp(self):
1736 """Create a dict to remember potentially destroyed objects."""
1737 BaseTest.setUp(self)
1738 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001739
Christian Heimes180510d2008-03-03 19:15:45 +00001740 def _watch_for_survival(self, *args):
1741 """Watch the given objects for survival, by creating weakrefs to
1742 them."""
1743 for obj in args:
1744 key = id(obj), repr(obj)
1745 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001746
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001747 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001748 """Assert that all objects watched for survival have survived."""
1749 # Trigger cycle breaking.
1750 gc.collect()
1751 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001752 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001753 if ref() is None:
1754 dead.append(repr_)
1755 if dead:
1756 self.fail("%d objects should have survived "
1757 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001758
Christian Heimes180510d2008-03-03 19:15:45 +00001759 def test_persistent_loggers(self):
1760 # Logger objects are persistent and retain their configuration, even
1761 # if visible references are destroyed.
1762 self.root_logger.setLevel(logging.INFO)
1763 foo = logging.getLogger("foo")
1764 self._watch_for_survival(foo)
1765 foo.setLevel(logging.DEBUG)
1766 self.root_logger.debug(self.next_message())
1767 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001768 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001769 ('foo', 'DEBUG', '2'),
1770 ])
1771 del foo
1772 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001773 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001774 # foo has retained its settings.
1775 bar = logging.getLogger("foo")
1776 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001777 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001778 ('foo', 'DEBUG', '2'),
1779 ('foo', 'DEBUG', '3'),
1780 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001781
Benjamin Petersonf91df042009-02-13 02:50:59 +00001782
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001783class EncodingTest(BaseTest):
1784 def test_encoding_plain_file(self):
1785 # In Python 2.x, a plain file object is treated as having no encoding.
1786 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001787 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1788 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001789 # the non-ascii data we write to the log.
1790 data = "foo\x80"
1791 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001792 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001793 log.addHandler(handler)
1794 try:
1795 # write non-ascii data to the log.
1796 log.warning(data)
1797 finally:
1798 log.removeHandler(handler)
1799 handler.close()
1800 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001801 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001802 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001803 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001804 finally:
1805 f.close()
1806 finally:
1807 if os.path.isfile(fn):
1808 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001809
Benjamin Petersonf91df042009-02-13 02:50:59 +00001810 def test_encoding_cyrillic_unicode(self):
1811 log = logging.getLogger("test")
1812 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1813 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1814 #Ensure it's written in a Cyrillic encoding
1815 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001816 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001817 stream = io.BytesIO()
1818 writer = writer_class(stream, 'strict')
1819 handler = logging.StreamHandler(writer)
1820 log.addHandler(handler)
1821 try:
1822 log.warning(message)
1823 finally:
1824 log.removeHandler(handler)
1825 handler.close()
1826 # check we wrote exactly those bytes, ignoring trailing \n etc
1827 s = stream.getvalue()
1828 #Compare against what the data should be when encoded in CP-1251
1829 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1830
1831
Georg Brandlf9734072008-12-07 15:30:06 +00001832class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001833
Georg Brandlf9734072008-12-07 15:30:06 +00001834 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001835 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001836 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838 warnings.filterwarnings("always", category=UserWarning)
1839 stream = io.StringIO()
1840 h = logging.StreamHandler(stream)
1841 logger = logging.getLogger("py.warnings")
1842 logger.addHandler(h)
1843 warnings.warn("I'm warning you...")
1844 logger.removeHandler(h)
1845 s = stream.getvalue()
1846 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001847 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001848
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001849 #See if an explicit file uses the original implementation
1850 a_file = io.StringIO()
1851 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1852 a_file, "Dummy line")
1853 s = a_file.getvalue()
1854 a_file.close()
1855 self.assertEqual(s,
1856 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1857
1858 def test_warnings_no_handlers(self):
1859 with warnings.catch_warnings():
1860 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001861 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001862
1863 # confirm our assumption: no loggers are set
1864 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001865 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001866
1867 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001868 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001869 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001870
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001871
1872def formatFunc(format, datefmt=None):
1873 return logging.Formatter(format, datefmt)
1874
1875def handlerFunc():
1876 return logging.StreamHandler()
1877
1878class CustomHandler(logging.StreamHandler):
1879 pass
1880
1881class ConfigDictTest(BaseTest):
1882
1883 """Reading logging config from a dictionary."""
1884
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001885 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001886
1887 # config0 is a standard configuration.
1888 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001889 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001890 'formatters': {
1891 'form1' : {
1892 'format' : '%(levelname)s ++ %(message)s',
1893 },
1894 },
1895 'handlers' : {
1896 'hand1' : {
1897 'class' : 'logging.StreamHandler',
1898 'formatter' : 'form1',
1899 'level' : 'NOTSET',
1900 'stream' : 'ext://sys.stdout',
1901 },
1902 },
1903 'root' : {
1904 'level' : 'WARNING',
1905 'handlers' : ['hand1'],
1906 },
1907 }
1908
1909 # config1 adds a little to the standard configuration.
1910 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001911 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001912 'formatters': {
1913 'form1' : {
1914 'format' : '%(levelname)s ++ %(message)s',
1915 },
1916 },
1917 'handlers' : {
1918 'hand1' : {
1919 'class' : 'logging.StreamHandler',
1920 'formatter' : 'form1',
1921 'level' : 'NOTSET',
1922 'stream' : 'ext://sys.stdout',
1923 },
1924 },
1925 'loggers' : {
1926 'compiler.parser' : {
1927 'level' : 'DEBUG',
1928 'handlers' : ['hand1'],
1929 },
1930 },
1931 'root' : {
1932 'level' : 'WARNING',
1933 },
1934 }
1935
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001936 # config1a moves the handler to the root. Used with config8a
1937 config1a = {
1938 'version': 1,
1939 'formatters': {
1940 'form1' : {
1941 'format' : '%(levelname)s ++ %(message)s',
1942 },
1943 },
1944 'handlers' : {
1945 'hand1' : {
1946 'class' : 'logging.StreamHandler',
1947 'formatter' : 'form1',
1948 'level' : 'NOTSET',
1949 'stream' : 'ext://sys.stdout',
1950 },
1951 },
1952 'loggers' : {
1953 'compiler.parser' : {
1954 'level' : 'DEBUG',
1955 },
1956 },
1957 'root' : {
1958 'level' : 'WARNING',
1959 'handlers' : ['hand1'],
1960 },
1961 }
1962
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001963 # config2 has a subtle configuration error that should be reported
1964 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001965 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001966 'formatters': {
1967 'form1' : {
1968 'format' : '%(levelname)s ++ %(message)s',
1969 },
1970 },
1971 'handlers' : {
1972 'hand1' : {
1973 'class' : 'logging.StreamHandler',
1974 'formatter' : 'form1',
1975 'level' : 'NOTSET',
1976 'stream' : 'ext://sys.stdbout',
1977 },
1978 },
1979 'loggers' : {
1980 'compiler.parser' : {
1981 'level' : 'DEBUG',
1982 'handlers' : ['hand1'],
1983 },
1984 },
1985 'root' : {
1986 'level' : 'WARNING',
1987 },
1988 }
1989
1990 #As config1 but with a misspelt level on a handler
1991 config2a = {
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' : 'NTOSET',
2003 'stream' : 'ext://sys.stdout',
2004 },
2005 },
2006 'loggers' : {
2007 'compiler.parser' : {
2008 'level' : 'DEBUG',
2009 'handlers' : ['hand1'],
2010 },
2011 },
2012 'root' : {
2013 'level' : 'WARNING',
2014 },
2015 }
2016
2017
2018 #As config1 but with a misspelt level on a logger
2019 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002020 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002021 'formatters': {
2022 'form1' : {
2023 'format' : '%(levelname)s ++ %(message)s',
2024 },
2025 },
2026 'handlers' : {
2027 'hand1' : {
2028 'class' : 'logging.StreamHandler',
2029 'formatter' : 'form1',
2030 'level' : 'NOTSET',
2031 'stream' : 'ext://sys.stdout',
2032 },
2033 },
2034 'loggers' : {
2035 'compiler.parser' : {
2036 'level' : 'DEBUG',
2037 'handlers' : ['hand1'],
2038 },
2039 },
2040 'root' : {
2041 'level' : 'WRANING',
2042 },
2043 }
2044
2045 # config3 has a less subtle configuration error
2046 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002047 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002048 'formatters': {
2049 'form1' : {
2050 'format' : '%(levelname)s ++ %(message)s',
2051 },
2052 },
2053 'handlers' : {
2054 'hand1' : {
2055 'class' : 'logging.StreamHandler',
2056 'formatter' : 'misspelled_name',
2057 'level' : 'NOTSET',
2058 'stream' : 'ext://sys.stdout',
2059 },
2060 },
2061 'loggers' : {
2062 'compiler.parser' : {
2063 'level' : 'DEBUG',
2064 'handlers' : ['hand1'],
2065 },
2066 },
2067 'root' : {
2068 'level' : 'WARNING',
2069 },
2070 }
2071
2072 # config4 specifies a custom formatter class to be loaded
2073 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002074 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002075 'formatters': {
2076 'form1' : {
2077 '()' : __name__ + '.ExceptionFormatter',
2078 'format' : '%(levelname)s:%(name)s:%(message)s',
2079 },
2080 },
2081 'handlers' : {
2082 'hand1' : {
2083 'class' : 'logging.StreamHandler',
2084 'formatter' : 'form1',
2085 'level' : 'NOTSET',
2086 'stream' : 'ext://sys.stdout',
2087 },
2088 },
2089 'root' : {
2090 'level' : 'NOTSET',
2091 'handlers' : ['hand1'],
2092 },
2093 }
2094
2095 # As config4 but using an actual callable rather than a string
2096 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002097 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002098 'formatters': {
2099 'form1' : {
2100 '()' : ExceptionFormatter,
2101 'format' : '%(levelname)s:%(name)s:%(message)s',
2102 },
2103 'form2' : {
2104 '()' : __name__ + '.formatFunc',
2105 'format' : '%(levelname)s:%(name)s:%(message)s',
2106 },
2107 'form3' : {
2108 '()' : formatFunc,
2109 'format' : '%(levelname)s:%(name)s:%(message)s',
2110 },
2111 },
2112 'handlers' : {
2113 'hand1' : {
2114 'class' : 'logging.StreamHandler',
2115 'formatter' : 'form1',
2116 'level' : 'NOTSET',
2117 'stream' : 'ext://sys.stdout',
2118 },
2119 'hand2' : {
2120 '()' : handlerFunc,
2121 },
2122 },
2123 'root' : {
2124 'level' : 'NOTSET',
2125 'handlers' : ['hand1'],
2126 },
2127 }
2128
2129 # config5 specifies a custom handler class to be loaded
2130 config5 = {
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 },
2144 },
2145 'loggers' : {
2146 'compiler.parser' : {
2147 'level' : 'DEBUG',
2148 'handlers' : ['hand1'],
2149 },
2150 },
2151 'root' : {
2152 'level' : 'WARNING',
2153 },
2154 }
2155
2156 # config6 specifies a custom handler class to be loaded
2157 # but has bad arguments
2158 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002159 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002160 'formatters': {
2161 'form1' : {
2162 'format' : '%(levelname)s ++ %(message)s',
2163 },
2164 },
2165 'handlers' : {
2166 'hand1' : {
2167 'class' : __name__ + '.CustomHandler',
2168 'formatter' : 'form1',
2169 'level' : 'NOTSET',
2170 'stream' : 'ext://sys.stdout',
2171 '9' : 'invalid parameter name',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.parser' : {
2176 'level' : 'DEBUG',
2177 'handlers' : ['hand1'],
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WARNING',
2182 },
2183 }
2184
2185 #config 7 does not define compiler.parser but defines compiler.lexer
2186 #so compiler.parser should be disabled after applying it
2187 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002188 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002189 'formatters': {
2190 'form1' : {
2191 'format' : '%(levelname)s ++ %(message)s',
2192 },
2193 },
2194 'handlers' : {
2195 'hand1' : {
2196 'class' : 'logging.StreamHandler',
2197 'formatter' : 'form1',
2198 'level' : 'NOTSET',
2199 'stream' : 'ext://sys.stdout',
2200 },
2201 },
2202 'loggers' : {
2203 'compiler.lexer' : {
2204 'level' : 'DEBUG',
2205 'handlers' : ['hand1'],
2206 },
2207 },
2208 'root' : {
2209 'level' : 'WARNING',
2210 },
2211 }
2212
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002213 # config8 defines both compiler and compiler.lexer
2214 # so compiler.parser should not be disabled (since
2215 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002216 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002217 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002218 'disable_existing_loggers' : False,
2219 'formatters': {
2220 'form1' : {
2221 'format' : '%(levelname)s ++ %(message)s',
2222 },
2223 },
2224 'handlers' : {
2225 'hand1' : {
2226 'class' : 'logging.StreamHandler',
2227 'formatter' : 'form1',
2228 'level' : 'NOTSET',
2229 'stream' : 'ext://sys.stdout',
2230 },
2231 },
2232 'loggers' : {
2233 'compiler' : {
2234 'level' : 'DEBUG',
2235 'handlers' : ['hand1'],
2236 },
2237 'compiler.lexer' : {
2238 },
2239 },
2240 'root' : {
2241 'level' : 'WARNING',
2242 },
2243 }
2244
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002245 # config8a disables existing loggers
2246 config8a = {
2247 'version': 1,
2248 'disable_existing_loggers' : True,
2249 'formatters': {
2250 'form1' : {
2251 'format' : '%(levelname)s ++ %(message)s',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : 'logging.StreamHandler',
2257 'formatter' : 'form1',
2258 'level' : 'NOTSET',
2259 'stream' : 'ext://sys.stdout',
2260 },
2261 },
2262 'loggers' : {
2263 'compiler' : {
2264 'level' : 'DEBUG',
2265 'handlers' : ['hand1'],
2266 },
2267 'compiler.lexer' : {
2268 },
2269 },
2270 'root' : {
2271 'level' : 'WARNING',
2272 },
2273 }
2274
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002276 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002277 'formatters': {
2278 'form1' : {
2279 'format' : '%(levelname)s ++ %(message)s',
2280 },
2281 },
2282 'handlers' : {
2283 'hand1' : {
2284 'class' : 'logging.StreamHandler',
2285 'formatter' : 'form1',
2286 'level' : 'WARNING',
2287 'stream' : 'ext://sys.stdout',
2288 },
2289 },
2290 'loggers' : {
2291 'compiler.parser' : {
2292 'level' : 'WARNING',
2293 'handlers' : ['hand1'],
2294 },
2295 },
2296 'root' : {
2297 'level' : 'NOTSET',
2298 },
2299 }
2300
2301 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002302 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002303 'incremental' : True,
2304 'handlers' : {
2305 'hand1' : {
2306 'level' : 'WARNING',
2307 },
2308 },
2309 'loggers' : {
2310 'compiler.parser' : {
2311 'level' : 'INFO',
2312 },
2313 },
2314 }
2315
2316 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002317 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002318 'incremental' : True,
2319 'handlers' : {
2320 'hand1' : {
2321 'level' : 'INFO',
2322 },
2323 },
2324 'loggers' : {
2325 'compiler.parser' : {
2326 'level' : 'INFO',
2327 },
2328 },
2329 }
2330
2331 #As config1 but with a filter added
2332 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002333 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002334 'formatters': {
2335 'form1' : {
2336 'format' : '%(levelname)s ++ %(message)s',
2337 },
2338 },
2339 'filters' : {
2340 'filt1' : {
2341 'name' : 'compiler.parser',
2342 },
2343 },
2344 'handlers' : {
2345 'hand1' : {
2346 'class' : 'logging.StreamHandler',
2347 'formatter' : 'form1',
2348 'level' : 'NOTSET',
2349 'stream' : 'ext://sys.stdout',
2350 'filters' : ['filt1'],
2351 },
2352 },
2353 'loggers' : {
2354 'compiler.parser' : {
2355 'level' : 'DEBUG',
2356 'filters' : ['filt1'],
2357 },
2358 },
2359 'root' : {
2360 'level' : 'WARNING',
2361 'handlers' : ['hand1'],
2362 },
2363 }
2364
2365 #As config1 but using cfg:// references
2366 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002367 'version': 1,
2368 'true_formatters': {
2369 'form1' : {
2370 'format' : '%(levelname)s ++ %(message)s',
2371 },
2372 },
2373 'handler_configs': {
2374 'hand1' : {
2375 'class' : 'logging.StreamHandler',
2376 'formatter' : 'form1',
2377 'level' : 'NOTSET',
2378 'stream' : 'ext://sys.stdout',
2379 },
2380 },
2381 'formatters' : 'cfg://true_formatters',
2382 'handlers' : {
2383 'hand1' : 'cfg://handler_configs[hand1]',
2384 },
2385 'loggers' : {
2386 'compiler.parser' : {
2387 'level' : 'DEBUG',
2388 'handlers' : ['hand1'],
2389 },
2390 },
2391 'root' : {
2392 'level' : 'WARNING',
2393 },
2394 }
2395
2396 #As config11 but missing the version key
2397 config12 = {
2398 'true_formatters': {
2399 'form1' : {
2400 'format' : '%(levelname)s ++ %(message)s',
2401 },
2402 },
2403 'handler_configs': {
2404 'hand1' : {
2405 'class' : 'logging.StreamHandler',
2406 'formatter' : 'form1',
2407 'level' : 'NOTSET',
2408 'stream' : 'ext://sys.stdout',
2409 },
2410 },
2411 'formatters' : 'cfg://true_formatters',
2412 'handlers' : {
2413 'hand1' : 'cfg://handler_configs[hand1]',
2414 },
2415 'loggers' : {
2416 'compiler.parser' : {
2417 'level' : 'DEBUG',
2418 'handlers' : ['hand1'],
2419 },
2420 },
2421 'root' : {
2422 'level' : 'WARNING',
2423 },
2424 }
2425
2426 #As config11 but using an unsupported version
2427 config13 = {
2428 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002429 'true_formatters': {
2430 'form1' : {
2431 'format' : '%(levelname)s ++ %(message)s',
2432 },
2433 },
2434 'handler_configs': {
2435 'hand1' : {
2436 'class' : 'logging.StreamHandler',
2437 'formatter' : 'form1',
2438 'level' : 'NOTSET',
2439 'stream' : 'ext://sys.stdout',
2440 },
2441 },
2442 'formatters' : 'cfg://true_formatters',
2443 'handlers' : {
2444 'hand1' : 'cfg://handler_configs[hand1]',
2445 },
2446 'loggers' : {
2447 'compiler.parser' : {
2448 'level' : 'DEBUG',
2449 'handlers' : ['hand1'],
2450 },
2451 },
2452 'root' : {
2453 'level' : 'WARNING',
2454 },
2455 }
2456
Vinay Sajip8d270232012-11-15 14:20:18 +00002457 # As config0, but with properties
2458 config14 = {
2459 'version': 1,
2460 'formatters': {
2461 'form1' : {
2462 'format' : '%(levelname)s ++ %(message)s',
2463 },
2464 },
2465 'handlers' : {
2466 'hand1' : {
2467 'class' : 'logging.StreamHandler',
2468 'formatter' : 'form1',
2469 'level' : 'NOTSET',
2470 'stream' : 'ext://sys.stdout',
2471 '.': {
2472 'foo': 'bar',
2473 'terminator': '!\n',
2474 }
2475 },
2476 },
2477 'root' : {
2478 'level' : 'WARNING',
2479 'handlers' : ['hand1'],
2480 },
2481 }
2482
Vinay Sajip3f885b52013-03-22 15:19:54 +00002483 out_of_order = {
2484 "version": 1,
2485 "formatters": {
2486 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002487 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2488 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002489 }
2490 },
2491 "handlers": {
2492 "fileGlobal": {
2493 "class": "logging.StreamHandler",
2494 "level": "DEBUG",
2495 "formatter": "mySimpleFormatter"
2496 },
2497 "bufferGlobal": {
2498 "class": "logging.handlers.MemoryHandler",
2499 "capacity": 5,
2500 "formatter": "mySimpleFormatter",
2501 "target": "fileGlobal",
2502 "level": "DEBUG"
2503 }
2504 },
2505 "loggers": {
2506 "mymodule": {
2507 "level": "DEBUG",
2508 "handlers": ["bufferGlobal"],
2509 "propagate": "true"
2510 }
2511 }
2512 }
2513
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002514 def apply_config(self, conf):
2515 logging.config.dictConfig(conf)
2516
2517 def test_config0_ok(self):
2518 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002519 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002520 self.apply_config(self.config0)
2521 logger = logging.getLogger()
2522 # Won't output anything
2523 logger.info(self.next_message())
2524 # Outputs a message
2525 logger.error(self.next_message())
2526 self.assert_log_lines([
2527 ('ERROR', '2'),
2528 ], stream=output)
2529 # Original logger output is empty.
2530 self.assert_log_lines([])
2531
2532 def test_config1_ok(self, config=config1):
2533 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002534 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002535 self.apply_config(config)
2536 logger = logging.getLogger("compiler.parser")
2537 # Both will output a message
2538 logger.info(self.next_message())
2539 logger.error(self.next_message())
2540 self.assert_log_lines([
2541 ('INFO', '1'),
2542 ('ERROR', '2'),
2543 ], stream=output)
2544 # Original logger output is empty.
2545 self.assert_log_lines([])
2546
2547 def test_config2_failure(self):
2548 # A simple config which overrides the default settings.
2549 self.assertRaises(Exception, self.apply_config, self.config2)
2550
2551 def test_config2a_failure(self):
2552 # A simple config which overrides the default settings.
2553 self.assertRaises(Exception, self.apply_config, self.config2a)
2554
2555 def test_config2b_failure(self):
2556 # A simple config which overrides the default settings.
2557 self.assertRaises(Exception, self.apply_config, self.config2b)
2558
2559 def test_config3_failure(self):
2560 # A simple config which overrides the default settings.
2561 self.assertRaises(Exception, self.apply_config, self.config3)
2562
2563 def test_config4_ok(self):
2564 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002565 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002566 self.apply_config(self.config4)
2567 #logger = logging.getLogger()
2568 try:
2569 raise RuntimeError()
2570 except RuntimeError:
2571 logging.exception("just testing")
2572 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002573 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002574 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2575 # Original logger output is empty
2576 self.assert_log_lines([])
2577
2578 def test_config4a_ok(self):
2579 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002580 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002581 self.apply_config(self.config4a)
2582 #logger = logging.getLogger()
2583 try:
2584 raise RuntimeError()
2585 except RuntimeError:
2586 logging.exception("just testing")
2587 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002588 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002589 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2590 # Original logger output is empty
2591 self.assert_log_lines([])
2592
2593 def test_config5_ok(self):
2594 self.test_config1_ok(config=self.config5)
2595
2596 def test_config6_failure(self):
2597 self.assertRaises(Exception, self.apply_config, self.config6)
2598
2599 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002600 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002601 self.apply_config(self.config1)
2602 logger = logging.getLogger("compiler.parser")
2603 # Both will output a message
2604 logger.info(self.next_message())
2605 logger.error(self.next_message())
2606 self.assert_log_lines([
2607 ('INFO', '1'),
2608 ('ERROR', '2'),
2609 ], stream=output)
2610 # Original logger output is empty.
2611 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002612 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002613 self.apply_config(self.config7)
2614 logger = logging.getLogger("compiler.parser")
2615 self.assertTrue(logger.disabled)
2616 logger = logging.getLogger("compiler.lexer")
2617 # Both will output a message
2618 logger.info(self.next_message())
2619 logger.error(self.next_message())
2620 self.assert_log_lines([
2621 ('INFO', '3'),
2622 ('ERROR', '4'),
2623 ], stream=output)
2624 # Original logger output is empty.
2625 self.assert_log_lines([])
2626
2627 #Same as test_config_7_ok but don't disable old loggers.
2628 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002629 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002630 self.apply_config(self.config1)
2631 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002632 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002633 logger.info(self.next_message())
2634 logger.error(self.next_message())
2635 self.assert_log_lines([
2636 ('INFO', '1'),
2637 ('ERROR', '2'),
2638 ], stream=output)
2639 # Original logger output is empty.
2640 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002641 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002642 self.apply_config(self.config8)
2643 logger = logging.getLogger("compiler.parser")
2644 self.assertFalse(logger.disabled)
2645 # Both will output a message
2646 logger.info(self.next_message())
2647 logger.error(self.next_message())
2648 logger = logging.getLogger("compiler.lexer")
2649 # Both will output a message
2650 logger.info(self.next_message())
2651 logger.error(self.next_message())
2652 self.assert_log_lines([
2653 ('INFO', '3'),
2654 ('ERROR', '4'),
2655 ('INFO', '5'),
2656 ('ERROR', '6'),
2657 ], stream=output)
2658 # Original logger output is empty.
2659 self.assert_log_lines([])
2660
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002661 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002662 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002663 self.apply_config(self.config1a)
2664 logger = logging.getLogger("compiler.parser")
2665 # See issue #11424. compiler-hyphenated sorts
2666 # between compiler and compiler.xyz and this
2667 # was preventing compiler.xyz from being included
2668 # in the child loggers of compiler because of an
2669 # overzealous loop termination condition.
2670 hyphenated = logging.getLogger('compiler-hyphenated')
2671 # All will output a message
2672 logger.info(self.next_message())
2673 logger.error(self.next_message())
2674 hyphenated.critical(self.next_message())
2675 self.assert_log_lines([
2676 ('INFO', '1'),
2677 ('ERROR', '2'),
2678 ('CRITICAL', '3'),
2679 ], stream=output)
2680 # Original logger output is empty.
2681 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002682 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002683 self.apply_config(self.config8a)
2684 logger = logging.getLogger("compiler.parser")
2685 self.assertFalse(logger.disabled)
2686 # Both will output a message
2687 logger.info(self.next_message())
2688 logger.error(self.next_message())
2689 logger = logging.getLogger("compiler.lexer")
2690 # Both will output a message
2691 logger.info(self.next_message())
2692 logger.error(self.next_message())
2693 # Will not appear
2694 hyphenated.critical(self.next_message())
2695 self.assert_log_lines([
2696 ('INFO', '4'),
2697 ('ERROR', '5'),
2698 ('INFO', '6'),
2699 ('ERROR', '7'),
2700 ], stream=output)
2701 # Original logger output is empty.
2702 self.assert_log_lines([])
2703
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002704 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002705 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002706 self.apply_config(self.config9)
2707 logger = logging.getLogger("compiler.parser")
2708 #Nothing will be output since both handler and logger are set to WARNING
2709 logger.info(self.next_message())
2710 self.assert_log_lines([], stream=output)
2711 self.apply_config(self.config9a)
2712 #Nothing will be output since both handler is still set to WARNING
2713 logger.info(self.next_message())
2714 self.assert_log_lines([], stream=output)
2715 self.apply_config(self.config9b)
2716 #Message should now be output
2717 logger.info(self.next_message())
2718 self.assert_log_lines([
2719 ('INFO', '3'),
2720 ], stream=output)
2721
2722 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002723 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002724 self.apply_config(self.config10)
2725 logger = logging.getLogger("compiler.parser")
2726 logger.warning(self.next_message())
2727 logger = logging.getLogger('compiler')
2728 #Not output, because filtered
2729 logger.warning(self.next_message())
2730 logger = logging.getLogger('compiler.lexer')
2731 #Not output, because filtered
2732 logger.warning(self.next_message())
2733 logger = logging.getLogger("compiler.parser.codegen")
2734 #Output, as not filtered
2735 logger.error(self.next_message())
2736 self.assert_log_lines([
2737 ('WARNING', '1'),
2738 ('ERROR', '4'),
2739 ], stream=output)
2740
2741 def test_config11_ok(self):
2742 self.test_config1_ok(self.config11)
2743
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002744 def test_config12_failure(self):
2745 self.assertRaises(Exception, self.apply_config, self.config12)
2746
2747 def test_config13_failure(self):
2748 self.assertRaises(Exception, self.apply_config, self.config13)
2749
Vinay Sajip8d270232012-11-15 14:20:18 +00002750 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002751 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002752 self.apply_config(self.config14)
2753 h = logging._handlers['hand1']
2754 self.assertEqual(h.foo, 'bar')
2755 self.assertEqual(h.terminator, '!\n')
2756 logging.warning('Exclamation')
2757 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2758
Victor Stinner45df8202010-04-28 22:31:17 +00002759 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002760 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002761 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002762 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002763 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002764 t.start()
2765 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002766 # Now get the port allocated
2767 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002769 try:
2770 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2771 sock.settimeout(2.0)
2772 sock.connect(('localhost', port))
2773
2774 slen = struct.pack('>L', len(text))
2775 s = slen + text
2776 sentsofar = 0
2777 left = len(s)
2778 while left > 0:
2779 sent = sock.send(s[sentsofar:])
2780 sentsofar += sent
2781 left -= sent
2782 sock.close()
2783 finally:
2784 t.ready.wait(2.0)
2785 logging.config.stopListening()
2786 t.join(2.0)
2787
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002788 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002789 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002790 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002791 self.setup_via_listener(json.dumps(self.config10))
2792 logger = logging.getLogger("compiler.parser")
2793 logger.warning(self.next_message())
2794 logger = logging.getLogger('compiler')
2795 #Not output, because filtered
2796 logger.warning(self.next_message())
2797 logger = logging.getLogger('compiler.lexer')
2798 #Not output, because filtered
2799 logger.warning(self.next_message())
2800 logger = logging.getLogger("compiler.parser.codegen")
2801 #Output, as not filtered
2802 logger.error(self.next_message())
2803 self.assert_log_lines([
2804 ('WARNING', '1'),
2805 ('ERROR', '4'),
2806 ], stream=output)
2807
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002808 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002809 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002810 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002811 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2812 logger = logging.getLogger("compiler.parser")
2813 # Both will output a message
2814 logger.info(self.next_message())
2815 logger.error(self.next_message())
2816 self.assert_log_lines([
2817 ('INFO', '1'),
2818 ('ERROR', '2'),
2819 ], stream=output)
2820 # Original logger output is empty.
2821 self.assert_log_lines([])
2822
Vinay Sajip4ded5512012-10-02 15:56:16 +01002823 @unittest.skipUnless(threading, 'Threading required for this test.')
2824 def test_listen_verify(self):
2825
2826 def verify_fail(stuff):
2827 return None
2828
2829 def verify_reverse(stuff):
2830 return stuff[::-1]
2831
2832 logger = logging.getLogger("compiler.parser")
2833 to_send = textwrap.dedent(ConfigFileTest.config1)
2834 # First, specify a verification function that will fail.
2835 # We expect to see no output, since our configuration
2836 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002837 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002838 self.setup_via_listener(to_send, verify_fail)
2839 # Both will output a message
2840 logger.info(self.next_message())
2841 logger.error(self.next_message())
2842 self.assert_log_lines([], stream=output)
2843 # Original logger output has the stuff we logged.
2844 self.assert_log_lines([
2845 ('INFO', '1'),
2846 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002847 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002848
2849 # Now, perform no verification. Our configuration
2850 # should take effect.
2851
Vinay Sajip1feedb42014-05-31 08:19:12 +01002852 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002853 self.setup_via_listener(to_send) # no verify callable specified
2854 logger = logging.getLogger("compiler.parser")
2855 # Both will output a message
2856 logger.info(self.next_message())
2857 logger.error(self.next_message())
2858 self.assert_log_lines([
2859 ('INFO', '3'),
2860 ('ERROR', '4'),
2861 ], stream=output)
2862 # Original logger output still has the stuff we logged before.
2863 self.assert_log_lines([
2864 ('INFO', '1'),
2865 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002866 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002867
2868 # Now, perform verification which transforms the bytes.
2869
Vinay Sajip1feedb42014-05-31 08:19:12 +01002870 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002871 self.setup_via_listener(to_send[::-1], verify_reverse)
2872 logger = logging.getLogger("compiler.parser")
2873 # Both will output a message
2874 logger.info(self.next_message())
2875 logger.error(self.next_message())
2876 self.assert_log_lines([
2877 ('INFO', '5'),
2878 ('ERROR', '6'),
2879 ], stream=output)
2880 # Original logger output still has the stuff we logged before.
2881 self.assert_log_lines([
2882 ('INFO', '1'),
2883 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002884 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002885
Vinay Sajip3f885b52013-03-22 15:19:54 +00002886 def test_out_of_order(self):
2887 self.apply_config(self.out_of_order)
2888 handler = logging.getLogger('mymodule').handlers[0]
2889 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002890 self.assertIsInstance(handler.formatter._style,
2891 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002892
Vinay Sajip373baef2011-04-26 20:05:24 +01002893 def test_baseconfig(self):
2894 d = {
2895 'atuple': (1, 2, 3),
2896 'alist': ['a', 'b', 'c'],
2897 'adict': {'d': 'e', 'f': 3 },
2898 'nest1': ('g', ('h', 'i'), 'j'),
2899 'nest2': ['k', ['l', 'm'], 'n'],
2900 'nest3': ['o', 'cfg://alist', 'p'],
2901 }
2902 bc = logging.config.BaseConfigurator(d)
2903 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2904 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2905 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2906 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2907 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2908 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2909 v = bc.convert('cfg://nest3')
2910 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2911 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2912 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2913 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002914
2915class ManagerTest(BaseTest):
2916 def test_manager_loggerclass(self):
2917 logged = []
2918
2919 class MyLogger(logging.Logger):
2920 def _log(self, level, msg, args, exc_info=None, extra=None):
2921 logged.append(msg)
2922
2923 man = logging.Manager(None)
2924 self.assertRaises(TypeError, man.setLoggerClass, int)
2925 man.setLoggerClass(MyLogger)
2926 logger = man.getLogger('test')
2927 logger.warning('should appear in logged')
2928 logging.warning('should not appear in logged')
2929
2930 self.assertEqual(logged, ['should appear in logged'])
2931
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002932 def test_set_log_record_factory(self):
2933 man = logging.Manager(None)
2934 expected = object()
2935 man.setLogRecordFactory(expected)
2936 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002937
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002938class ChildLoggerTest(BaseTest):
2939 def test_child_loggers(self):
2940 r = logging.getLogger()
2941 l1 = logging.getLogger('abc')
2942 l2 = logging.getLogger('def.ghi')
2943 c1 = r.getChild('xyz')
2944 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002945 self.assertIs(c1, logging.getLogger('xyz'))
2946 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002947 c1 = l1.getChild('def')
2948 c2 = c1.getChild('ghi')
2949 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002950 self.assertIs(c1, logging.getLogger('abc.def'))
2951 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2952 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002953
2954
Vinay Sajip6fac8172010-10-19 20:44:14 +00002955class DerivedLogRecord(logging.LogRecord):
2956 pass
2957
Vinay Sajip61561522010-12-03 11:50:38 +00002958class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959
2960 def setUp(self):
2961 class CheckingFilter(logging.Filter):
2962 def __init__(self, cls):
2963 self.cls = cls
2964
2965 def filter(self, record):
2966 t = type(record)
2967 if t is not self.cls:
2968 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2969 self.cls)
2970 raise TypeError(msg)
2971 return True
2972
2973 BaseTest.setUp(self)
2974 self.filter = CheckingFilter(DerivedLogRecord)
2975 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002976 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002977
2978 def tearDown(self):
2979 self.root_logger.removeFilter(self.filter)
2980 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002981 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002982
2983 def test_logrecord_class(self):
2984 self.assertRaises(TypeError, self.root_logger.warning,
2985 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002986 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002987 self.root_logger.error(self.next_message())
2988 self.assert_log_lines([
2989 ('root', 'ERROR', '2'),
2990 ])
2991
2992
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002993class QueueHandlerTest(BaseTest):
2994 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002995 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002996
2997 def setUp(self):
2998 BaseTest.setUp(self)
2999 self.queue = queue.Queue(-1)
3000 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3001 self.que_logger = logging.getLogger('que')
3002 self.que_logger.propagate = False
3003 self.que_logger.setLevel(logging.WARNING)
3004 self.que_logger.addHandler(self.que_hdlr)
3005
3006 def tearDown(self):
3007 self.que_hdlr.close()
3008 BaseTest.tearDown(self)
3009
3010 def test_queue_handler(self):
3011 self.que_logger.debug(self.next_message())
3012 self.assertRaises(queue.Empty, self.queue.get_nowait)
3013 self.que_logger.info(self.next_message())
3014 self.assertRaises(queue.Empty, self.queue.get_nowait)
3015 msg = self.next_message()
3016 self.que_logger.warning(msg)
3017 data = self.queue.get_nowait()
3018 self.assertTrue(isinstance(data, logging.LogRecord))
3019 self.assertEqual(data.name, self.que_logger.name)
3020 self.assertEqual((data.msg, data.args), (msg, None))
3021
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003022 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3023 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003024 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003025 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003026 listener = logging.handlers.QueueListener(self.queue, handler)
3027 listener.start()
3028 try:
3029 self.que_logger.warning(self.next_message())
3030 self.que_logger.error(self.next_message())
3031 self.que_logger.critical(self.next_message())
3032 finally:
3033 listener.stop()
3034 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3035 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3036 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3037
Vinay Sajip37eb3382011-04-26 20:26:41 +01003038ZERO = datetime.timedelta(0)
3039
3040class UTC(datetime.tzinfo):
3041 def utcoffset(self, dt):
3042 return ZERO
3043
3044 dst = utcoffset
3045
3046 def tzname(self, dt):
3047 return 'UTC'
3048
3049utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003050
Vinay Sajipa39c5712010-10-25 13:57:39 +00003051class FormatterTest(unittest.TestCase):
3052 def setUp(self):
3053 self.common = {
3054 'name': 'formatter.test',
3055 'level': logging.DEBUG,
3056 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3057 'lineno': 42,
3058 'exc_info': None,
3059 'func': None,
3060 'msg': 'Message with %d %s',
3061 'args': (2, 'placeholders'),
3062 }
3063 self.variants = {
3064 }
3065
3066 def get_record(self, name=None):
3067 result = dict(self.common)
3068 if name is not None:
3069 result.update(self.variants[name])
3070 return logging.makeLogRecord(result)
3071
3072 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003073 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003074 r = self.get_record()
3075 f = logging.Formatter('${%(message)s}')
3076 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3077 f = logging.Formatter('%(random)s')
3078 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003079 self.assertFalse(f.usesTime())
3080 f = logging.Formatter('%(asctime)s')
3081 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003082 f = logging.Formatter('%(asctime)-15s')
3083 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003084 f = logging.Formatter('asctime')
3085 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003086
3087 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003088 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003089 r = self.get_record()
3090 f = logging.Formatter('$%{message}%$', style='{')
3091 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3092 f = logging.Formatter('{random}', style='{')
3093 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003094 self.assertFalse(f.usesTime())
3095 f = logging.Formatter('{asctime}', style='{')
3096 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003097 f = logging.Formatter('{asctime!s:15}', style='{')
3098 self.assertTrue(f.usesTime())
3099 f = logging.Formatter('{asctime:15}', style='{')
3100 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003101 f = logging.Formatter('asctime', style='{')
3102 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003103
3104 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003105 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003106 r = self.get_record()
3107 f = logging.Formatter('$message', style='$')
3108 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3109 f = logging.Formatter('$$%${message}%$$', style='$')
3110 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3111 f = logging.Formatter('${random}', style='$')
3112 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003113 self.assertFalse(f.usesTime())
3114 f = logging.Formatter('${asctime}', style='$')
3115 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003116 f = logging.Formatter('${asctime', style='$')
3117 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003118 f = logging.Formatter('$asctime', style='$')
3119 self.assertTrue(f.usesTime())
3120 f = logging.Formatter('asctime', style='$')
3121 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003122
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003123 def test_invalid_style(self):
3124 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3125
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003126 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003127 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003128 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3129 # We use None to indicate we want the local timezone
3130 # We're essentially converting a UTC time to local time
3131 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003132 r.msecs = 123
3133 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003134 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003135 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3136 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003137 f.format(r)
3138 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3139
3140class TestBufferingFormatter(logging.BufferingFormatter):
3141 def formatHeader(self, records):
3142 return '[(%d)' % len(records)
3143
3144 def formatFooter(self, records):
3145 return '(%d)]' % len(records)
3146
3147class BufferingFormatterTest(unittest.TestCase):
3148 def setUp(self):
3149 self.records = [
3150 logging.makeLogRecord({'msg': 'one'}),
3151 logging.makeLogRecord({'msg': 'two'}),
3152 ]
3153
3154 def test_default(self):
3155 f = logging.BufferingFormatter()
3156 self.assertEqual('', f.format([]))
3157 self.assertEqual('onetwo', f.format(self.records))
3158
3159 def test_custom(self):
3160 f = TestBufferingFormatter()
3161 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3162 lf = logging.Formatter('<%(message)s>')
3163 f = TestBufferingFormatter(lf)
3164 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003165
3166class ExceptionTest(BaseTest):
3167 def test_formatting(self):
3168 r = self.root_logger
3169 h = RecordingHandler()
3170 r.addHandler(h)
3171 try:
3172 raise RuntimeError('deliberate mistake')
3173 except:
3174 logging.exception('failed', stack_info=True)
3175 r.removeHandler(h)
3176 h.close()
3177 r = h.records[0]
3178 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3179 'call last):\n'))
3180 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3181 'deliberate mistake'))
3182 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3183 'call last):\n'))
3184 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3185 'stack_info=True)'))
3186
3187
Vinay Sajip5a27d402010-12-10 11:42:57 +00003188class LastResortTest(BaseTest):
3189 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003190 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003191 root = self.root_logger
3192 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003193 old_lastresort = logging.lastResort
3194 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003195
Vinay Sajip5a27d402010-12-10 11:42:57 +00003196 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003197 with support.captured_stderr() as stderr:
3198 root.debug('This should not appear')
3199 self.assertEqual(stderr.getvalue(), '')
3200 root.warning('Final chance!')
3201 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3202
3203 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003204 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003205 with support.captured_stderr() as stderr:
3206 root.warning('Final chance!')
3207 msg = 'No handlers could be found for logger "root"\n'
3208 self.assertEqual(stderr.getvalue(), msg)
3209
Vinay Sajip5a27d402010-12-10 11:42:57 +00003210 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003211 with support.captured_stderr() as stderr:
3212 root.warning('Final chance!')
3213 self.assertEqual(stderr.getvalue(), '')
3214
3215 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003216 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003217 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003218 with support.captured_stderr() as stderr:
3219 root.warning('Final chance!')
3220 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003221 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003222 root.addHandler(self.root_hdlr)
3223 logging.lastResort = old_lastresort
3224 logging.raiseExceptions = old_raise_exceptions
3225
3226
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003227class FakeHandler:
3228
3229 def __init__(self, identifier, called):
3230 for method in ('acquire', 'flush', 'close', 'release'):
3231 setattr(self, method, self.record_call(identifier, method, called))
3232
3233 def record_call(self, identifier, method_name, called):
3234 def inner():
3235 called.append('{} - {}'.format(identifier, method_name))
3236 return inner
3237
3238
3239class RecordingHandler(logging.NullHandler):
3240
3241 def __init__(self, *args, **kwargs):
3242 super(RecordingHandler, self).__init__(*args, **kwargs)
3243 self.records = []
3244
3245 def handle(self, record):
3246 """Keep track of all the emitted records."""
3247 self.records.append(record)
3248
3249
3250class ShutdownTest(BaseTest):
3251
Vinay Sajip5e66b162011-04-20 15:41:14 +01003252 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003253
3254 def setUp(self):
3255 super(ShutdownTest, self).setUp()
3256 self.called = []
3257
3258 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003259 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003260
3261 def raise_error(self, error):
3262 def inner():
3263 raise error()
3264 return inner
3265
3266 def test_no_failure(self):
3267 # create some fake handlers
3268 handler0 = FakeHandler(0, self.called)
3269 handler1 = FakeHandler(1, self.called)
3270 handler2 = FakeHandler(2, self.called)
3271
3272 # create live weakref to those handlers
3273 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3274
3275 logging.shutdown(handlerList=list(handlers))
3276
3277 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3278 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3279 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3280 self.assertEqual(expected, self.called)
3281
3282 def _test_with_failure_in_method(self, method, error):
3283 handler = FakeHandler(0, self.called)
3284 setattr(handler, method, self.raise_error(error))
3285 handlers = [logging.weakref.ref(handler)]
3286
3287 logging.shutdown(handlerList=list(handlers))
3288
3289 self.assertEqual('0 - release', self.called[-1])
3290
3291 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003292 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003293
3294 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003295 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003296
3297 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003298 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003299
3300 def test_with_valueerror_in_acquire(self):
3301 self._test_with_failure_in_method('acquire', ValueError)
3302
3303 def test_with_valueerror_in_flush(self):
3304 self._test_with_failure_in_method('flush', ValueError)
3305
3306 def test_with_valueerror_in_close(self):
3307 self._test_with_failure_in_method('close', ValueError)
3308
3309 def test_with_other_error_in_acquire_without_raise(self):
3310 logging.raiseExceptions = False
3311 self._test_with_failure_in_method('acquire', IndexError)
3312
3313 def test_with_other_error_in_flush_without_raise(self):
3314 logging.raiseExceptions = False
3315 self._test_with_failure_in_method('flush', IndexError)
3316
3317 def test_with_other_error_in_close_without_raise(self):
3318 logging.raiseExceptions = False
3319 self._test_with_failure_in_method('close', IndexError)
3320
3321 def test_with_other_error_in_acquire_with_raise(self):
3322 logging.raiseExceptions = True
3323 self.assertRaises(IndexError, self._test_with_failure_in_method,
3324 'acquire', IndexError)
3325
3326 def test_with_other_error_in_flush_with_raise(self):
3327 logging.raiseExceptions = True
3328 self.assertRaises(IndexError, self._test_with_failure_in_method,
3329 'flush', IndexError)
3330
3331 def test_with_other_error_in_close_with_raise(self):
3332 logging.raiseExceptions = True
3333 self.assertRaises(IndexError, self._test_with_failure_in_method,
3334 'close', IndexError)
3335
3336
3337class ModuleLevelMiscTest(BaseTest):
3338
Vinay Sajip5e66b162011-04-20 15:41:14 +01003339 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003340
3341 def test_disable(self):
3342 old_disable = logging.root.manager.disable
3343 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003344 self.assertEqual(old_disable, 0)
3345 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003346
3347 logging.disable(83)
3348 self.assertEqual(logging.root.manager.disable, 83)
3349
3350 def _test_log(self, method, level=None):
3351 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003352 support.patch(self, logging, 'basicConfig',
3353 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003354
3355 recording = RecordingHandler()
3356 logging.root.addHandler(recording)
3357
3358 log_method = getattr(logging, method)
3359 if level is not None:
3360 log_method(level, "test me: %r", recording)
3361 else:
3362 log_method("test me: %r", recording)
3363
3364 self.assertEqual(len(recording.records), 1)
3365 record = recording.records[0]
3366 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3367
3368 expected_level = level if level is not None else getattr(logging, method.upper())
3369 self.assertEqual(record.levelno, expected_level)
3370
3371 # basicConfig was not called!
3372 self.assertEqual(called, [])
3373
3374 def test_log(self):
3375 self._test_log('log', logging.ERROR)
3376
3377 def test_debug(self):
3378 self._test_log('debug')
3379
3380 def test_info(self):
3381 self._test_log('info')
3382
3383 def test_warning(self):
3384 self._test_log('warning')
3385
3386 def test_error(self):
3387 self._test_log('error')
3388
3389 def test_critical(self):
3390 self._test_log('critical')
3391
3392 def test_set_logger_class(self):
3393 self.assertRaises(TypeError, logging.setLoggerClass, object)
3394
3395 class MyLogger(logging.Logger):
3396 pass
3397
3398 logging.setLoggerClass(MyLogger)
3399 self.assertEqual(logging.getLoggerClass(), MyLogger)
3400
3401 logging.setLoggerClass(logging.Logger)
3402 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3403
Antoine Pitrou712cb732013-12-21 15:51:54 +01003404 def test_logging_at_shutdown(self):
3405 # Issue #20037
3406 code = """if 1:
3407 import logging
3408
3409 class A:
3410 def __del__(self):
3411 try:
3412 raise ValueError("some error")
3413 except Exception:
3414 logging.exception("exception in __del__")
3415
3416 a = A()"""
3417 rc, out, err = assert_python_ok("-c", code)
3418 err = err.decode()
3419 self.assertIn("exception in __del__", err)
3420 self.assertIn("ValueError: some error", err)
3421
3422
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003423class LogRecordTest(BaseTest):
3424 def test_str_rep(self):
3425 r = logging.makeLogRecord({})
3426 s = str(r)
3427 self.assertTrue(s.startswith('<LogRecord: '))
3428 self.assertTrue(s.endswith('>'))
3429
3430 def test_dict_arg(self):
3431 h = RecordingHandler()
3432 r = logging.getLogger()
3433 r.addHandler(h)
3434 d = {'less' : 'more' }
3435 logging.warning('less is %(less)s', d)
3436 self.assertIs(h.records[0].args, d)
3437 self.assertEqual(h.records[0].message, 'less is more')
3438 r.removeHandler(h)
3439 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003440
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003441 def test_multiprocessing(self):
3442 r = logging.makeLogRecord({})
3443 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003444 try:
3445 import multiprocessing as mp
3446 r = logging.makeLogRecord({})
3447 self.assertEqual(r.processName, mp.current_process().name)
3448 except ImportError:
3449 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003450
3451 def test_optional(self):
3452 r = logging.makeLogRecord({})
3453 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003454 if threading:
3455 NOT_NONE(r.thread)
3456 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003457 NOT_NONE(r.process)
3458 NOT_NONE(r.processName)
3459 log_threads = logging.logThreads
3460 log_processes = logging.logProcesses
3461 log_multiprocessing = logging.logMultiprocessing
3462 try:
3463 logging.logThreads = False
3464 logging.logProcesses = False
3465 logging.logMultiprocessing = False
3466 r = logging.makeLogRecord({})
3467 NONE = self.assertIsNone
3468 NONE(r.thread)
3469 NONE(r.threadName)
3470 NONE(r.process)
3471 NONE(r.processName)
3472 finally:
3473 logging.logThreads = log_threads
3474 logging.logProcesses = log_processes
3475 logging.logMultiprocessing = log_multiprocessing
3476
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003477class BasicConfigTest(unittest.TestCase):
3478
Vinay Sajip95bf5042011-04-20 11:50:56 +01003479 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003480
3481 def setUp(self):
3482 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003483 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003484 self.saved_handlers = logging._handlers.copy()
3485 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003486 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003487 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003488 logging.root.handlers = []
3489
3490 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003491 for h in logging.root.handlers[:]:
3492 logging.root.removeHandler(h)
3493 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494 super(BasicConfigTest, self).tearDown()
3495
Vinay Sajip3def7e02011-04-20 10:58:06 +01003496 def cleanup(self):
3497 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003498 logging._handlers.clear()
3499 logging._handlers.update(self.saved_handlers)
3500 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003501 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003502
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003503 def test_no_kwargs(self):
3504 logging.basicConfig()
3505
3506 # handler defaults to a StreamHandler to sys.stderr
3507 self.assertEqual(len(logging.root.handlers), 1)
3508 handler = logging.root.handlers[0]
3509 self.assertIsInstance(handler, logging.StreamHandler)
3510 self.assertEqual(handler.stream, sys.stderr)
3511
3512 formatter = handler.formatter
3513 # format defaults to logging.BASIC_FORMAT
3514 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3515 # datefmt defaults to None
3516 self.assertIsNone(formatter.datefmt)
3517 # style defaults to %
3518 self.assertIsInstance(formatter._style, logging.PercentStyle)
3519
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003520 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003521 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003522
Vinay Sajip1fd12022014-01-13 21:59:56 +00003523 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003524 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003525 logging.basicConfig(stream=sys.stdout, style="{")
3526 logging.error("Log an error")
3527 sys.stdout.seek(0)
3528 self.assertEqual(output.getvalue().strip(),
3529 "ERROR:root:Log an error")
3530
3531 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003532 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003533 logging.basicConfig(stream=sys.stdout, style="$")
3534 logging.error("Log an error")
3535 sys.stdout.seek(0)
3536 self.assertEqual(output.getvalue().strip(),
3537 "ERROR:root:Log an error")
3538
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003539 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003540
3541 def cleanup(h1, h2, fn):
3542 h1.close()
3543 h2.close()
3544 os.remove(fn)
3545
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003546 logging.basicConfig(filename='test.log')
3547
3548 self.assertEqual(len(logging.root.handlers), 1)
3549 handler = logging.root.handlers[0]
3550 self.assertIsInstance(handler, logging.FileHandler)
3551
3552 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003553 self.assertEqual(handler.stream.mode, expected.stream.mode)
3554 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003555 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003556
3557 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003558
3559 def cleanup(h1, h2, fn):
3560 h1.close()
3561 h2.close()
3562 os.remove(fn)
3563
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003564 logging.basicConfig(filename='test.log', filemode='wb')
3565
3566 handler = logging.root.handlers[0]
3567 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003568 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003569 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003570
3571 def test_stream(self):
3572 stream = io.StringIO()
3573 self.addCleanup(stream.close)
3574 logging.basicConfig(stream=stream)
3575
3576 self.assertEqual(len(logging.root.handlers), 1)
3577 handler = logging.root.handlers[0]
3578 self.assertIsInstance(handler, logging.StreamHandler)
3579 self.assertEqual(handler.stream, stream)
3580
3581 def test_format(self):
3582 logging.basicConfig(format='foo')
3583
3584 formatter = logging.root.handlers[0].formatter
3585 self.assertEqual(formatter._style._fmt, 'foo')
3586
3587 def test_datefmt(self):
3588 logging.basicConfig(datefmt='bar')
3589
3590 formatter = logging.root.handlers[0].formatter
3591 self.assertEqual(formatter.datefmt, 'bar')
3592
3593 def test_style(self):
3594 logging.basicConfig(style='$')
3595
3596 formatter = logging.root.handlers[0].formatter
3597 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3598
3599 def test_level(self):
3600 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003601 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003602
3603 logging.basicConfig(level=57)
3604 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003605 # Test that second call has no effect
3606 logging.basicConfig(level=58)
3607 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003608
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003609 def test_incompatible(self):
3610 assertRaises = self.assertRaises
3611 handlers = [logging.StreamHandler()]
3612 stream = sys.stderr
3613 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3614 stream=stream)
3615 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3616 handlers=handlers)
3617 assertRaises(ValueError, logging.basicConfig, stream=stream,
3618 handlers=handlers)
3619
3620 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003621 handlers = [
3622 logging.StreamHandler(),
3623 logging.StreamHandler(sys.stdout),
3624 logging.StreamHandler(),
3625 ]
3626 f = logging.Formatter()
3627 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003628 logging.basicConfig(handlers=handlers)
3629 self.assertIs(handlers[0], logging.root.handlers[0])
3630 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003631 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003632 self.assertIsNotNone(handlers[0].formatter)
3633 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003634 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003635 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3636
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003637 def _test_log(self, method, level=None):
3638 # logging.root has no handlers so basicConfig should be called
3639 called = []
3640
3641 old_basic_config = logging.basicConfig
3642 def my_basic_config(*a, **kw):
3643 old_basic_config()
3644 old_level = logging.root.level
3645 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003646 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003647 called.append((a, kw))
3648
Vinay Sajip1feedb42014-05-31 08:19:12 +01003649 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003650
3651 log_method = getattr(logging, method)
3652 if level is not None:
3653 log_method(level, "test me")
3654 else:
3655 log_method("test me")
3656
3657 # basicConfig was called with no arguments
3658 self.assertEqual(called, [((), {})])
3659
3660 def test_log(self):
3661 self._test_log('log', logging.WARNING)
3662
3663 def test_debug(self):
3664 self._test_log('debug')
3665
3666 def test_info(self):
3667 self._test_log('info')
3668
3669 def test_warning(self):
3670 self._test_log('warning')
3671
3672 def test_error(self):
3673 self._test_log('error')
3674
3675 def test_critical(self):
3676 self._test_log('critical')
3677
3678
3679class LoggerAdapterTest(unittest.TestCase):
3680
3681 def setUp(self):
3682 super(LoggerAdapterTest, self).setUp()
3683 old_handler_list = logging._handlerList[:]
3684
3685 self.recording = RecordingHandler()
3686 self.logger = logging.root
3687 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003688 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003689 self.addCleanup(self.recording.close)
3690
3691 def cleanup():
3692 logging._handlerList[:] = old_handler_list
3693
3694 self.addCleanup(cleanup)
3695 self.addCleanup(logging.shutdown)
3696 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3697
3698 def test_exception(self):
3699 msg = 'testing exception: %r'
3700 exc = None
3701 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003702 1 / 0
3703 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003704 exc = e
3705 self.adapter.exception(msg, self.recording)
3706
3707 self.assertEqual(len(self.recording.records), 1)
3708 record = self.recording.records[0]
3709 self.assertEqual(record.levelno, logging.ERROR)
3710 self.assertEqual(record.msg, msg)
3711 self.assertEqual(record.args, (self.recording,))
3712 self.assertEqual(record.exc_info,
3713 (exc.__class__, exc, exc.__traceback__))
3714
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003715 def test_exception_excinfo(self):
3716 try:
3717 1 / 0
3718 except ZeroDivisionError as e:
3719 exc = e
3720
3721 self.adapter.exception('exc_info test', exc_info=exc)
3722
3723 self.assertEqual(len(self.recording.records), 1)
3724 record = self.recording.records[0]
3725 self.assertEqual(record.exc_info,
3726 (exc.__class__, exc, exc.__traceback__))
3727
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003728 def test_critical(self):
3729 msg = 'critical test! %r'
3730 self.adapter.critical(msg, self.recording)
3731
3732 self.assertEqual(len(self.recording.records), 1)
3733 record = self.recording.records[0]
3734 self.assertEqual(record.levelno, logging.CRITICAL)
3735 self.assertEqual(record.msg, msg)
3736 self.assertEqual(record.args, (self.recording,))
3737
3738 def test_is_enabled_for(self):
3739 old_disable = self.adapter.logger.manager.disable
3740 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003741 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3742 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003743 self.assertFalse(self.adapter.isEnabledFor(32))
3744
3745 def test_has_handlers(self):
3746 self.assertTrue(self.adapter.hasHandlers())
3747
3748 for handler in self.logger.handlers:
3749 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003750
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003751 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003752 self.assertFalse(self.adapter.hasHandlers())
3753
3754
3755class LoggerTest(BaseTest):
3756
3757 def setUp(self):
3758 super(LoggerTest, self).setUp()
3759 self.recording = RecordingHandler()
3760 self.logger = logging.Logger(name='blah')
3761 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003762 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003763 self.addCleanup(self.recording.close)
3764 self.addCleanup(logging.shutdown)
3765
3766 def test_set_invalid_level(self):
3767 self.assertRaises(TypeError, self.logger.setLevel, object())
3768
3769 def test_exception(self):
3770 msg = 'testing exception: %r'
3771 exc = None
3772 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003773 1 / 0
3774 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003775 exc = e
3776 self.logger.exception(msg, self.recording)
3777
3778 self.assertEqual(len(self.recording.records), 1)
3779 record = self.recording.records[0]
3780 self.assertEqual(record.levelno, logging.ERROR)
3781 self.assertEqual(record.msg, msg)
3782 self.assertEqual(record.args, (self.recording,))
3783 self.assertEqual(record.exc_info,
3784 (exc.__class__, exc, exc.__traceback__))
3785
3786 def test_log_invalid_level_with_raise(self):
3787 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003788 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003789
3790 logging.raiseExceptions = True
3791 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3792
3793 def test_log_invalid_level_no_raise(self):
3794 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003795 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003796
3797 logging.raiseExceptions = False
3798 self.logger.log('10', 'test message') # no exception happens
3799
3800 def test_find_caller_with_stack_info(self):
3801 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003802 support.patch(self, logging.traceback, 'print_stack',
3803 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003804
3805 self.logger.findCaller(stack_info=True)
3806
3807 self.assertEqual(len(called), 1)
3808 self.assertEqual('Stack (most recent call last):\n', called[0])
3809
3810 def test_make_record_with_extra_overwrite(self):
3811 name = 'my record'
3812 level = 13
3813 fn = lno = msg = args = exc_info = func = sinfo = None
3814 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3815 exc_info, func, sinfo)
3816
3817 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3818 extra = {key: 'some value'}
3819 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3820 fn, lno, msg, args, exc_info,
3821 extra=extra, sinfo=sinfo)
3822
3823 def test_make_record_with_extra_no_overwrite(self):
3824 name = 'my record'
3825 level = 13
3826 fn = lno = msg = args = exc_info = func = sinfo = None
3827 extra = {'valid_key': 'some value'}
3828 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3829 exc_info, extra=extra, sinfo=sinfo)
3830 self.assertIn('valid_key', result.__dict__)
3831
3832 def test_has_handlers(self):
3833 self.assertTrue(self.logger.hasHandlers())
3834
3835 for handler in self.logger.handlers:
3836 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003837 self.assertFalse(self.logger.hasHandlers())
3838
3839 def test_has_handlers_no_propagate(self):
3840 child_logger = logging.getLogger('blah.child')
3841 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003842 self.assertFalse(child_logger.hasHandlers())
3843
3844 def test_is_enabled_for(self):
3845 old_disable = self.logger.manager.disable
3846 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003847 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003848 self.assertFalse(self.logger.isEnabledFor(22))
3849
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003850 def test_root_logger_aliases(self):
3851 root = logging.getLogger()
3852 self.assertIs(root, logging.root)
3853 self.assertIs(root, logging.getLogger(None))
3854 self.assertIs(root, logging.getLogger(''))
3855 self.assertIs(root, logging.getLogger('foo').root)
3856 self.assertIs(root, logging.getLogger('foo.bar').root)
3857 self.assertIs(root, logging.getLogger('foo').parent)
3858
3859 self.assertIsNot(root, logging.getLogger('\0'))
3860 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3861
3862 def test_invalid_names(self):
3863 self.assertRaises(TypeError, logging.getLogger, any)
3864 self.assertRaises(TypeError, logging.getLogger, b'foo')
3865
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003866
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003867class BaseFileTest(BaseTest):
3868 "Base class for handler tests that write log files"
3869
3870 def setUp(self):
3871 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003872 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3873 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003874 self.rmfiles = []
3875
3876 def tearDown(self):
3877 for fn in self.rmfiles:
3878 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003879 if os.path.exists(self.fn):
3880 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003881 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003882
3883 def assertLogFile(self, filename):
3884 "Assert a log file is there and register it for deletion"
3885 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003886 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003887 self.rmfiles.append(filename)
3888
3889
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003890class FileHandlerTest(BaseFileTest):
3891 def test_delay(self):
3892 os.unlink(self.fn)
3893 fh = logging.FileHandler(self.fn, delay=True)
3894 self.assertIsNone(fh.stream)
3895 self.assertFalse(os.path.exists(self.fn))
3896 fh.handle(logging.makeLogRecord({}))
3897 self.assertIsNotNone(fh.stream)
3898 self.assertTrue(os.path.exists(self.fn))
3899 fh.close()
3900
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003901class RotatingFileHandlerTest(BaseFileTest):
3902 def next_rec(self):
3903 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3904 self.next_message(), None, None, None)
3905
3906 def test_should_not_rollover(self):
3907 # If maxbytes is zero rollover never occurs
3908 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3909 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003910 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003911
3912 def test_should_rollover(self):
3913 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3914 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003915 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003916
3917 def test_file_created(self):
3918 # checks that the file is created and assumes it was created
3919 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003920 rh = logging.handlers.RotatingFileHandler(self.fn)
3921 rh.emit(self.next_rec())
3922 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003923 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003924
3925 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003926 def namer(name):
3927 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003928 rh = logging.handlers.RotatingFileHandler(
3929 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003930 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003931 rh.emit(self.next_rec())
3932 self.assertLogFile(self.fn)
3933 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003934 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003935 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003936 self.assertLogFile(namer(self.fn + ".2"))
3937 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3938 rh.close()
3939
Vinay Sajip1feedb42014-05-31 08:19:12 +01003940 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003941 def test_rotator(self):
3942 def namer(name):
3943 return name + ".gz"
3944
3945 def rotator(source, dest):
3946 with open(source, "rb") as sf:
3947 data = sf.read()
3948 compressed = zlib.compress(data, 9)
3949 with open(dest, "wb") as df:
3950 df.write(compressed)
3951 os.remove(source)
3952
3953 rh = logging.handlers.RotatingFileHandler(
3954 self.fn, backupCount=2, maxBytes=1)
3955 rh.rotator = rotator
3956 rh.namer = namer
3957 m1 = self.next_rec()
3958 rh.emit(m1)
3959 self.assertLogFile(self.fn)
3960 m2 = self.next_rec()
3961 rh.emit(m2)
3962 fn = namer(self.fn + ".1")
3963 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003964 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003965 with open(fn, "rb") as f:
3966 compressed = f.read()
3967 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003968 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003969 rh.emit(self.next_rec())
3970 fn = namer(self.fn + ".2")
3971 self.assertLogFile(fn)
3972 with open(fn, "rb") as f:
3973 compressed = f.read()
3974 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003975 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003976 rh.emit(self.next_rec())
3977 fn = namer(self.fn + ".2")
3978 with open(fn, "rb") as f:
3979 compressed = f.read()
3980 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003981 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003982 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003983 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003984
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003985class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003986 # other test methods added below
3987 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003988 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3989 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003990 fmt = logging.Formatter('%(asctime)s %(message)s')
3991 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003992 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003993 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003994 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003995 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003996 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003997 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003998 fh.close()
3999 # At this point, we should have a recent rotated file which we
4000 # can test for the existence of. However, in practice, on some
4001 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004002 # in time to go to look for the log file. So, we go back a fair
4003 # bit, and stop as soon as we see a rotated file. In theory this
4004 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004005 found = False
4006 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004007 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004008 for secs in range(GO_BACK):
4009 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004010 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4011 found = os.path.exists(fn)
4012 if found:
4013 self.rmfiles.append(fn)
4014 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004015 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4016 if not found:
4017 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004018 dn, fn = os.path.split(self.fn)
4019 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004020 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4021 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004022 for f in files:
4023 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004024 path = os.path.join(dn, f)
4025 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004026 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004027 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004028
Vinay Sajip0372e102011-05-05 12:59:14 +01004029 def test_invalid(self):
4030 assertRaises = self.assertRaises
4031 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004032 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004033 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004034 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004035 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004036 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004037
Vinay Sajipa7130792013-04-12 17:04:23 +01004038 def test_compute_rollover_daily_attime(self):
4039 currentTime = 0
4040 atTime = datetime.time(12, 0, 0)
4041 rh = logging.handlers.TimedRotatingFileHandler(
4042 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4043 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004044 try:
4045 actual = rh.computeRollover(currentTime)
4046 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004047
Vinay Sajipd86ac962013-04-14 12:20:46 +01004048 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4049 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4050 finally:
4051 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004052
Vinay Sajip10e8c492013-05-18 10:19:54 -07004053 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004054 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004055 currentTime = int(time.time())
4056 today = currentTime - currentTime % 86400
4057
Vinay Sajipa7130792013-04-12 17:04:23 +01004058 atTime = datetime.time(12, 0, 0)
4059
Vinay Sajip10e8c492013-05-18 10:19:54 -07004060 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004061 for day in range(7):
4062 rh = logging.handlers.TimedRotatingFileHandler(
4063 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4064 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004065 try:
4066 if wday > day:
4067 # The rollover day has already passed this week, so we
4068 # go over into next week
4069 expected = (7 - wday + day)
4070 else:
4071 expected = (day - wday)
4072 # At this point expected is in days from now, convert to seconds
4073 expected *= 24 * 60 * 60
4074 # Add in the rollover time
4075 expected += 12 * 60 * 60
4076 # Add in adjustment for today
4077 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004078 actual = rh.computeRollover(today)
4079 if actual != expected:
4080 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004081 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004082 self.assertEqual(actual, expected)
4083 if day == wday:
4084 # goes into following week
4085 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004086 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004087 if actual != expected:
4088 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004089 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004090 self.assertEqual(actual, expected)
4091 finally:
4092 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004093
4094
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004095def secs(**kw):
4096 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4097
4098for when, exp in (('S', 1),
4099 ('M', 60),
4100 ('H', 60 * 60),
4101 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004102 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004103 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004104 ('W0', secs(days=4, hours=24)),
4105 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004106 def test_compute_rollover(self, when=when, exp=exp):
4107 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004108 self.fn, when=when, interval=1, backupCount=0, utc=True)
4109 currentTime = 0.0
4110 actual = rh.computeRollover(currentTime)
4111 if exp != actual:
4112 # Failures occur on some systems for MIDNIGHT and W0.
4113 # Print detailed calculation for MIDNIGHT so we can try to see
4114 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004115 if when == 'MIDNIGHT':
4116 try:
4117 if rh.utc:
4118 t = time.gmtime(currentTime)
4119 else:
4120 t = time.localtime(currentTime)
4121 currentHour = t[3]
4122 currentMinute = t[4]
4123 currentSecond = t[5]
4124 # r is the number of seconds left between now and midnight
4125 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4126 currentMinute) * 60 +
4127 currentSecond)
4128 result = currentTime + r
4129 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4130 print('currentHour: %s' % currentHour, file=sys.stderr)
4131 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4132 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4133 print('r: %s' % r, file=sys.stderr)
4134 print('result: %s' % result, file=sys.stderr)
4135 except Exception:
4136 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4137 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004138 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004139 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4140
Vinay Sajip60ccd822011-05-09 17:32:09 +01004141
4142@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4143class NTEventLogHandlerTest(BaseTest):
4144 def test_basic(self):
4145 logtype = 'Application'
4146 elh = win32evtlog.OpenEventLog(None, logtype)
4147 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4148 h = logging.handlers.NTEventLogHandler('test_logging')
4149 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4150 h.handle(r)
4151 h.close()
4152 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004153 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004154 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4155 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4156 found = False
4157 GO_BACK = 100
4158 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4159 for e in events:
4160 if e.SourceName != 'test_logging':
4161 continue
4162 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4163 if msg != 'Test Log Message\r\n':
4164 continue
4165 found = True
4166 break
4167 msg = 'Record not found in event log, went back %d records' % GO_BACK
4168 self.assertTrue(found, msg=msg)
4169
Christian Heimes180510d2008-03-03 19:15:45 +00004170# Set the locale to the platform-dependent default. I have no idea
4171# why the test does this, but in any case we save the current locale
4172# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004173@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004174def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004175 support.run_unittest(
4176 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4177 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4178 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4179 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4180 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4181 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4182 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4183 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4184 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4185 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
4186 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004187
Christian Heimes180510d2008-03-03 19:15:45 +00004188if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004189 test_main()