blob: 6de8803081e517b10ea1da82474b5874d96a69bd [file] [log] [blame]
Vinay Sajipca7b5042019-06-17 17:40:52 +01001# Copyright 2001-2019 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 Sajipca7b5042019-06-17 17:40:52 +010019Copyright (C) 2001-2019 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
Pablo Galindo137b0632018-10-16 15:17:57 +010028import copy
Vinay Sajip19ec67a2010-09-17 18:57:36 +000029import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010030import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000031import pickle
32import io
33import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000034import json
Christian Heimes180510d2008-03-03 19:15:45 +000035import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000036import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010037import random
Christian Heimes180510d2008-03-03 19:15:45 +000038import re
Gregory P. Smith19003842018-09-13 22:08:31 -070039import signal
Christian Heimes180510d2008-03-03 19:15:45 +000040import socket
Christian Heimes180510d2008-03-03 19:15:45 +000041import struct
42import sys
43import tempfile
Rémi Lapeyre65f64b12019-03-15 07:53:34 +010044from test.support.script_helper import assert_python_ok, assert_python_failure
Vinay Sajip1feedb42014-05-31 08:19:12 +010045from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000046import textwrap
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020047import threading
Vinay Sajip37eb3382011-04-26 20:26:41 +010048import time
Christian Heimes180510d2008-03-03 19:15:45 +000049import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000050import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000051import weakref
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020052
53import asyncore
54from http.server import HTTPServer, BaseHTTPRequestHandler
55import smtpd
56from urllib.parse import urlparse, parse_qs
57from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
58 ThreadingTCPServer, StreamRequestHandler)
59
Vinay Sajip60ccd822011-05-09 17:32:09 +010060try:
Vinay Sajip223349c2015-10-01 20:37:54 +010061 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010062except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010063 win32evtlog = win32evtlogutil = pywintypes = None
64
Eric V. Smith851cad72012-03-11 22:46:04 -070065try:
66 import zlib
67except ImportError:
68 pass
Christian Heimes18c66892008-02-17 13:31:39 +000069
Christian Heimes180510d2008-03-03 19:15:45 +000070class BaseTest(unittest.TestCase):
71
72 """Base class for logging tests."""
73
74 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030075 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000076 message_num = 0
77
78 def setUp(self):
79 """Setup the default logging stream to an internal StringIO instance,
80 so that we can examine log output as we want."""
Victor Stinner69669602017-08-18 23:47:54 +020081 self._threading_key = support.threading_setup()
82
Christian Heimes180510d2008-03-03 19:15:45 +000083 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000084 logging._acquireLock()
85 try:
Christian Heimes180510d2008-03-03 19:15:45 +000086 self.saved_handlers = logging._handlers.copy()
87 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000088 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070089 self.saved_name_to_level = logging._nameToLevel.copy()
90 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000091 self.logger_states = logger_states = {}
92 for name in saved_loggers:
93 logger_states[name] = getattr(saved_loggers[name],
94 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000095 finally:
96 logging._releaseLock()
97
Florent Xicluna5252f9f2011-11-07 19:43:05 +010098 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000099 self.logger1 = logging.getLogger("\xab\xd7\xbb")
100 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000101
Christian Heimes180510d2008-03-03 19:15:45 +0000102 self.root_logger = logging.getLogger("")
103 self.original_logging_level = self.root_logger.getEffectiveLevel()
104
105 self.stream = io.StringIO()
106 self.root_logger.setLevel(logging.DEBUG)
107 self.root_hdlr = logging.StreamHandler(self.stream)
108 self.root_formatter = logging.Formatter(self.log_format)
109 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000110 if self.logger1.hasHandlers():
111 hlist = self.logger1.handlers + self.root_logger.handlers
112 raise AssertionError('Unexpected handlers: %s' % hlist)
113 if self.logger2.hasHandlers():
114 hlist = self.logger2.handlers + self.root_logger.handlers
115 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000116 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000117 self.assertTrue(self.logger1.hasHandlers())
118 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000119
120 def tearDown(self):
121 """Remove our logging stream, and restore the original logging
122 level."""
123 self.stream.close()
124 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000125 while self.root_logger.handlers:
126 h = self.root_logger.handlers[0]
127 self.root_logger.removeHandler(h)
128 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000129 self.root_logger.setLevel(self.original_logging_level)
130 logging._acquireLock()
131 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700132 logging._levelToName.clear()
133 logging._levelToName.update(self.saved_level_to_name)
134 logging._nameToLevel.clear()
135 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000136 logging._handlers.clear()
137 logging._handlers.update(self.saved_handlers)
138 logging._handlerList[:] = self.saved_handler_list
Avram Lubkin78c18a92017-07-30 05:36:33 -0400139 manager = logging.getLogger().manager
140 manager.disable = 0
141 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000142 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
Victor Stinner69669602017-08-18 23:47:54 +0200151 self.doCleanups()
152 support.threading_cleanup(*self._threading_key)
153
Vinay Sajip4ded5512012-10-02 15:56:16 +0100154 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000155 """Match the collected log lines against the regular expression
156 self.expected_log_pat, and compare the extracted group values to
157 the expected_values list of tuples."""
158 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100159 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300160 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100161 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000162 for actual, expected in zip(actual_lines, expected_values):
163 match = pat.search(actual)
164 if not match:
165 self.fail("Log line does not match expected pattern:\n" +
166 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000167 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000168 s = stream.read()
169 if s:
170 self.fail("Remaining output at end of log stream:\n" + s)
171
172 def next_message(self):
173 """Generate a message consisting solely of an auto-incrementing
174 integer."""
175 self.message_num += 1
176 return "%d" % self.message_num
177
178
179class BuiltinLevelsTest(BaseTest):
180 """Test builtin levels and their inheritance."""
181
182 def test_flat(self):
Mike53f7a7c2017-12-14 14:04:53 +0300183 # Logging levels in a flat logger namespace.
Christian Heimes180510d2008-03-03 19:15:45 +0000184 m = self.next_message
185
186 ERR = logging.getLogger("ERR")
187 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000188 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000189 INF.setLevel(logging.INFO)
190 DEB = logging.getLogger("DEB")
191 DEB.setLevel(logging.DEBUG)
192
193 # These should log.
194 ERR.log(logging.CRITICAL, m())
195 ERR.error(m())
196
197 INF.log(logging.CRITICAL, m())
198 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100199 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 INF.info(m())
201
202 DEB.log(logging.CRITICAL, m())
203 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100204 DEB.warning(m())
205 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000206 DEB.debug(m())
207
208 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100209 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ERR.info(m())
211 ERR.debug(m())
212
213 INF.debug(m())
214
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000215 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000216 ('ERR', 'CRITICAL', '1'),
217 ('ERR', 'ERROR', '2'),
218 ('INF', 'CRITICAL', '3'),
219 ('INF', 'ERROR', '4'),
220 ('INF', 'WARNING', '5'),
221 ('INF', 'INFO', '6'),
222 ('DEB', 'CRITICAL', '7'),
223 ('DEB', 'ERROR', '8'),
224 ('DEB', 'WARNING', '9'),
225 ('DEB', 'INFO', '10'),
226 ('DEB', 'DEBUG', '11'),
227 ])
228
229 def test_nested_explicit(self):
230 # Logging levels in a nested namespace, all explicitly set.
231 m = self.next_message
232
233 INF = logging.getLogger("INF")
234 INF.setLevel(logging.INFO)
235 INF_ERR = logging.getLogger("INF.ERR")
236 INF_ERR.setLevel(logging.ERROR)
237
238 # These should log.
239 INF_ERR.log(logging.CRITICAL, m())
240 INF_ERR.error(m())
241
242 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100243 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000244 INF_ERR.info(m())
245 INF_ERR.debug(m())
246
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000247 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000248 ('INF.ERR', 'CRITICAL', '1'),
249 ('INF.ERR', 'ERROR', '2'),
250 ])
251
252 def test_nested_inherited(self):
Mike53f7a7c2017-12-14 14:04:53 +0300253 # Logging levels in a nested namespace, inherited from parent loggers.
Christian Heimes180510d2008-03-03 19:15:45 +0000254 m = self.next_message
255
256 INF = logging.getLogger("INF")
257 INF.setLevel(logging.INFO)
258 INF_ERR = logging.getLogger("INF.ERR")
259 INF_ERR.setLevel(logging.ERROR)
260 INF_UNDEF = logging.getLogger("INF.UNDEF")
261 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
262 UNDEF = logging.getLogger("UNDEF")
263
264 # These should log.
265 INF_UNDEF.log(logging.CRITICAL, m())
266 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100267 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000268 INF_UNDEF.info(m())
269 INF_ERR_UNDEF.log(logging.CRITICAL, m())
270 INF_ERR_UNDEF.error(m())
271
272 # These should not log.
273 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100274 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000275 INF_ERR_UNDEF.info(m())
276 INF_ERR_UNDEF.debug(m())
277
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000278 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000279 ('INF.UNDEF', 'CRITICAL', '1'),
280 ('INF.UNDEF', 'ERROR', '2'),
281 ('INF.UNDEF', 'WARNING', '3'),
282 ('INF.UNDEF', 'INFO', '4'),
283 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
284 ('INF.ERR.UNDEF', 'ERROR', '6'),
285 ])
286
287 def test_nested_with_virtual_parent(self):
288 # Logging levels when some parent does not exist yet.
289 m = self.next_message
290
291 INF = logging.getLogger("INF")
292 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
293 CHILD = logging.getLogger("INF.BADPARENT")
294 INF.setLevel(logging.INFO)
295
296 # These should log.
297 GRANDCHILD.log(logging.FATAL, m())
298 GRANDCHILD.info(m())
299 CHILD.log(logging.FATAL, m())
300 CHILD.info(m())
301
302 # These should not log.
303 GRANDCHILD.debug(m())
304 CHILD.debug(m())
305
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000306 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000307 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
308 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
309 ('INF.BADPARENT', 'CRITICAL', '3'),
310 ('INF.BADPARENT', 'INFO', '4'),
311 ])
312
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100313 def test_regression_22386(self):
314 """See issue #22386 for more information."""
315 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
316 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000317
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100318 def test_issue27935(self):
319 fatal = logging.getLevelName('FATAL')
320 self.assertEqual(fatal, logging.FATAL)
321
Vinay Sajip924aaae2017-01-11 17:35:36 +0000322 def test_regression_29220(self):
323 """See issue #29220 for more information."""
324 logging.addLevelName(logging.INFO, '')
325 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
326 self.assertEqual(logging.getLevelName(logging.INFO), '')
327 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
328 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
329
Christian Heimes180510d2008-03-03 19:15:45 +0000330class BasicFilterTest(BaseTest):
331
332 """Test the bundled Filter class."""
333
334 def test_filter(self):
335 # Only messages satisfying the specified criteria pass through the
336 # filter.
337 filter_ = logging.Filter("spam.eggs")
338 handler = self.root_logger.handlers[0]
339 try:
340 handler.addFilter(filter_)
341 spam = logging.getLogger("spam")
342 spam_eggs = logging.getLogger("spam.eggs")
343 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
344 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
345
346 spam.info(self.next_message())
347 spam_eggs.info(self.next_message()) # Good.
348 spam_eggs_fish.info(self.next_message()) # Good.
349 spam_bakedbeans.info(self.next_message())
350
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000351 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000352 ('spam.eggs', 'INFO', '2'),
353 ('spam.eggs.fish', 'INFO', '3'),
354 ])
355 finally:
356 handler.removeFilter(filter_)
357
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000358 def test_callable_filter(self):
359 # Only messages satisfying the specified criteria pass through the
360 # filter.
361
362 def filterfunc(record):
363 parts = record.name.split('.')
364 prefix = '.'.join(parts[:2])
365 return prefix == 'spam.eggs'
366
367 handler = self.root_logger.handlers[0]
368 try:
369 handler.addFilter(filterfunc)
370 spam = logging.getLogger("spam")
371 spam_eggs = logging.getLogger("spam.eggs")
372 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
373 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
374
375 spam.info(self.next_message())
376 spam_eggs.info(self.next_message()) # Good.
377 spam_eggs_fish.info(self.next_message()) # Good.
378 spam_bakedbeans.info(self.next_message())
379
380 self.assert_log_lines([
381 ('spam.eggs', 'INFO', '2'),
382 ('spam.eggs.fish', 'INFO', '3'),
383 ])
384 finally:
385 handler.removeFilter(filterfunc)
386
Vinay Sajip985ef872011-04-26 19:34:04 +0100387 def test_empty_filter(self):
388 f = logging.Filter()
389 r = logging.makeLogRecord({'name': 'spam.eggs'})
390 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000391
392#
393# First, we define our levels. There can be as many as you want - the only
394# limitations are that they should be integers, the lowest should be > 0 and
395# larger values mean less information being logged. If you need specific
396# level values which do not fit into these limitations, you can use a
397# mapping dictionary to convert between your application levels and the
398# logging system.
399#
400SILENT = 120
401TACITURN = 119
402TERSE = 118
403EFFUSIVE = 117
404SOCIABLE = 116
405VERBOSE = 115
406TALKATIVE = 114
407GARRULOUS = 113
408CHATTERBOX = 112
409BORING = 111
410
411LEVEL_RANGE = range(BORING, SILENT + 1)
412
413#
414# Next, we define names for our levels. You don't need to do this - in which
415# case the system will use "Level n" to denote the text for the level.
416#
417my_logging_levels = {
418 SILENT : 'Silent',
419 TACITURN : 'Taciturn',
420 TERSE : 'Terse',
421 EFFUSIVE : 'Effusive',
422 SOCIABLE : 'Sociable',
423 VERBOSE : 'Verbose',
424 TALKATIVE : 'Talkative',
425 GARRULOUS : 'Garrulous',
426 CHATTERBOX : 'Chatterbox',
427 BORING : 'Boring',
428}
429
430class GarrulousFilter(logging.Filter):
431
432 """A filter which blocks garrulous messages."""
433
434 def filter(self, record):
435 return record.levelno != GARRULOUS
436
437class VerySpecificFilter(logging.Filter):
438
439 """A filter which blocks sociable and taciturn messages."""
440
441 def filter(self, record):
442 return record.levelno not in [SOCIABLE, TACITURN]
443
444
445class CustomLevelsAndFiltersTest(BaseTest):
446
447 """Test various filtering possibilities with custom logging levels."""
448
449 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300450 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000451
452 def setUp(self):
453 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000454 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000455 logging.addLevelName(k, v)
456
457 def log_at_all_levels(self, logger):
458 for lvl in LEVEL_RANGE:
459 logger.log(lvl, self.next_message())
460
461 def test_logger_filter(self):
462 # Filter at logger level.
463 self.root_logger.setLevel(VERBOSE)
464 # Levels >= 'Verbose' 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 ('Verbose', '5'),
468 ('Sociable', '6'),
469 ('Effusive', '7'),
470 ('Terse', '8'),
471 ('Taciturn', '9'),
472 ('Silent', '10'),
473 ])
474
475 def test_handler_filter(self):
476 # Filter at handler level.
477 self.root_logger.handlers[0].setLevel(SOCIABLE)
478 try:
479 # Levels >= 'Sociable' are good.
480 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000481 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000482 ('Sociable', '6'),
483 ('Effusive', '7'),
484 ('Terse', '8'),
485 ('Taciturn', '9'),
486 ('Silent', '10'),
487 ])
488 finally:
489 self.root_logger.handlers[0].setLevel(logging.NOTSET)
490
491 def test_specific_filters(self):
492 # Set a specific filter object on the handler, and then add another
493 # filter object on the logger itself.
494 handler = self.root_logger.handlers[0]
495 specific_filter = None
496 garr = GarrulousFilter()
497 handler.addFilter(garr)
498 try:
499 self.log_at_all_levels(self.root_logger)
500 first_lines = [
501 # Notice how 'Garrulous' is missing
502 ('Boring', '1'),
503 ('Chatterbox', '2'),
504 ('Talkative', '4'),
505 ('Verbose', '5'),
506 ('Sociable', '6'),
507 ('Effusive', '7'),
508 ('Terse', '8'),
509 ('Taciturn', '9'),
510 ('Silent', '10'),
511 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000512 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000513
514 specific_filter = VerySpecificFilter()
515 self.root_logger.addFilter(specific_filter)
516 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000517 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000518 # Not only 'Garrulous' is still missing, but also 'Sociable'
519 # and 'Taciturn'
520 ('Boring', '11'),
521 ('Chatterbox', '12'),
522 ('Talkative', '14'),
523 ('Verbose', '15'),
524 ('Effusive', '17'),
525 ('Terse', '18'),
526 ('Silent', '20'),
527 ])
528 finally:
529 if specific_filter:
530 self.root_logger.removeFilter(specific_filter)
531 handler.removeFilter(garr)
532
533
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100534class HandlerTest(BaseTest):
535 def test_name(self):
536 h = logging.Handler()
537 h.name = 'generic'
538 self.assertEqual(h.name, 'generic')
539 h.name = 'anothergeneric'
540 self.assertEqual(h.name, 'anothergeneric')
541 self.assertRaises(NotImplementedError, h.emit, None)
542
Vinay Sajip5a35b062011-04-27 11:31:14 +0100543 def test_builtin_handlers(self):
544 # We can't actually *use* too many handlers in the tests,
545 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200546 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 for existing in (True, False):
548 fd, fn = tempfile.mkstemp()
549 os.close(fd)
550 if not existing:
551 os.unlink(fn)
552 h = logging.handlers.WatchedFileHandler(fn, delay=True)
553 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100554 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100555 self.assertEqual(dev, -1)
556 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100557 r = logging.makeLogRecord({'msg': 'Test'})
558 h.handle(r)
559 # Now remove the file.
560 os.unlink(fn)
561 self.assertFalse(os.path.exists(fn))
562 # The next call should recreate the file.
563 h.handle(r)
564 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100565 else:
566 self.assertEqual(h.dev, -1)
567 self.assertEqual(h.ino, -1)
568 h.close()
569 if existing:
570 os.unlink(fn)
571 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100572 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100573 else:
574 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100575 try:
576 h = logging.handlers.SysLogHandler(sockname)
577 self.assertEqual(h.facility, h.LOG_USER)
578 self.assertTrue(h.unixsocket)
579 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200580 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100581 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100582 for method in ('GET', 'POST', 'PUT'):
583 if method == 'PUT':
584 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
585 'localhost', '/log', method)
586 else:
587 h = logging.handlers.HTTPHandler('localhost', '/log', method)
588 h.close()
589 h = logging.handlers.BufferingHandler(0)
590 r = logging.makeLogRecord({})
591 self.assertTrue(h.shouldFlush(r))
592 h.close()
593 h = logging.handlers.BufferingHandler(1)
594 self.assertFalse(h.shouldFlush(r))
595 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100596
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100597 def test_path_objects(self):
598 """
599 Test that Path objects are accepted as filename arguments to handlers.
600
601 See Issue #27493.
602 """
603 fd, fn = tempfile.mkstemp()
604 os.close(fd)
605 os.unlink(fn)
606 pfn = pathlib.Path(fn)
607 cases = (
608 (logging.FileHandler, (pfn, 'w')),
609 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
610 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
611 )
612 if sys.platform in ('linux', 'darwin'):
613 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
614 for cls, args in cases:
615 h = cls(*args)
616 self.assertTrue(os.path.exists(fn))
617 h.close()
618 os.unlink(fn)
619
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100620 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100621 def test_race(self):
622 # Issue #14632 refers.
623 def remove_loop(fname, tries):
624 for _ in range(tries):
625 try:
626 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000627 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100628 except OSError:
629 pass
630 time.sleep(0.004 * random.randint(0, 4))
631
Vinay Sajipc94871a2012-04-25 10:51:35 +0100632 del_count = 500
633 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100634
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000635 self.handle_time = None
636 self.deletion_time = None
637
Vinay Sajipa5798de2012-04-24 23:33:33 +0100638 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100639 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
640 os.close(fd)
641 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
642 remover.daemon = True
643 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100644 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100645 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
646 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100647 try:
648 for _ in range(log_count):
649 time.sleep(0.005)
650 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000651 try:
652 self.handle_time = time.time()
653 h.handle(r)
654 except Exception:
655 print('Deleted at %s, '
656 'opened at %s' % (self.deletion_time,
657 self.handle_time))
658 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100659 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100660 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100661 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100662 if os.path.exists(fn):
663 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100664
Gregory P. Smith19003842018-09-13 22:08:31 -0700665 # The implementation relies on os.register_at_fork existing, but we test
666 # based on os.fork existing because that is what users and this test use.
667 # This helps ensure that when fork exists (the important concept) that the
668 # register_at_fork mechanism is also present and used.
669 @unittest.skipIf(not hasattr(os, 'fork'), 'Test requires os.fork().')
670 def test_post_fork_child_no_deadlock(self):
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400671 """Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
672 class _OurHandler(logging.Handler):
673 def __init__(self):
674 super().__init__()
675 self.sub_handler = logging.StreamHandler(
676 stream=open('/dev/null', 'wt'))
677
678 def emit(self, record):
679 self.sub_handler.acquire()
680 try:
681 self.sub_handler.emit(record)
682 finally:
683 self.sub_handler.release()
684
685 self.assertEqual(len(logging._handlers), 0)
686 refed_h = _OurHandler()
Xtreak2c105382019-05-13 20:18:52 +0530687 self.addCleanup(refed_h.sub_handler.stream.close)
Gregory P. Smith19003842018-09-13 22:08:31 -0700688 refed_h.name = 'because we need at least one for this test'
689 self.assertGreater(len(logging._handlers), 0)
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400690 self.assertGreater(len(logging._at_fork_reinit_lock_weakset), 1)
691 test_logger = logging.getLogger('test_post_fork_child_no_deadlock')
692 test_logger.addHandler(refed_h)
693 test_logger.setLevel(logging.DEBUG)
Gregory P. Smith19003842018-09-13 22:08:31 -0700694
695 locks_held__ready_to_fork = threading.Event()
696 fork_happened__release_locks_and_end_thread = threading.Event()
697
698 def lock_holder_thread_fn():
699 logging._acquireLock()
700 try:
701 refed_h.acquire()
702 try:
703 # Tell the main thread to do the fork.
704 locks_held__ready_to_fork.set()
705
706 # If the deadlock bug exists, the fork will happen
707 # without dealing with the locks we hold, deadlocking
708 # the child.
709
710 # Wait for a successful fork or an unreasonable amount of
711 # time before releasing our locks. To avoid a timing based
712 # test we'd need communication from os.fork() as to when it
713 # has actually happened. Given this is a regression test
714 # for a fixed issue, potentially less reliably detecting
715 # regression via timing is acceptable for simplicity.
716 # The test will always take at least this long. :(
717 fork_happened__release_locks_and_end_thread.wait(0.5)
718 finally:
719 refed_h.release()
720 finally:
721 logging._releaseLock()
722
723 lock_holder_thread = threading.Thread(
724 target=lock_holder_thread_fn,
725 name='test_post_fork_child_no_deadlock lock holder')
726 lock_holder_thread.start()
727
728 locks_held__ready_to_fork.wait()
729 pid = os.fork()
730 if pid == 0: # Child.
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400731 try:
732 test_logger.info(r'Child process did not deadlock. \o/')
733 finally:
734 os._exit(0)
Gregory P. Smith19003842018-09-13 22:08:31 -0700735 else: # Parent.
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400736 test_logger.info(r'Parent process returned from fork. \o/')
Gregory P. Smith19003842018-09-13 22:08:31 -0700737 fork_happened__release_locks_and_end_thread.set()
738 lock_holder_thread.join()
739 start_time = time.monotonic()
740 while True:
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400741 test_logger.debug('Waiting for child process.')
Gregory P. Smith19003842018-09-13 22:08:31 -0700742 waited_pid, status = os.waitpid(pid, os.WNOHANG)
743 if waited_pid == pid:
744 break # child process exited.
745 if time.monotonic() - start_time > 7:
746 break # so long? implies child deadlock.
747 time.sleep(0.05)
Gregory P. Smith64aa6d22019-05-07 12:18:20 -0400748 test_logger.debug('Done waiting.')
Gregory P. Smith19003842018-09-13 22:08:31 -0700749 if waited_pid != pid:
750 os.kill(pid, signal.SIGKILL)
751 waited_pid, status = os.waitpid(pid, 0)
752 self.fail("child process deadlocked.")
753 self.assertEqual(status, 0, msg="child process error")
754
Vinay Sajipa5798de2012-04-24 23:33:33 +0100755
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100756class BadStream(object):
757 def write(self, data):
758 raise RuntimeError('deliberate mistake')
759
760class TestStreamHandler(logging.StreamHandler):
761 def handleError(self, record):
762 self.error_record = record
763
Riccardo Magliocchettica87eeb2019-05-07 23:36:39 +0200764class StreamWithIntName(object):
765 level = logging.NOTSET
766 name = 2
767
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100768class StreamHandlerTest(BaseTest):
769 def test_error_handling(self):
770 h = TestStreamHandler(BadStream())
771 r = logging.makeLogRecord({})
772 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100773
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100774 try:
775 h.handle(r)
776 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100777
Vinay Sajip985ef872011-04-26 19:34:04 +0100778 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100779 with support.captured_stderr() as stderr:
780 h.handle(r)
781 msg = '\nRuntimeError: deliberate mistake\n'
782 self.assertIn(msg, stderr.getvalue())
783
Vinay Sajip985ef872011-04-26 19:34:04 +0100784 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100785 with support.captured_stderr() as stderr:
786 h.handle(r)
787 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100788 finally:
789 logging.raiseExceptions = old_raise
790
Vinay Sajip2543f502017-07-30 10:41:45 +0100791 def test_stream_setting(self):
792 """
793 Test setting the handler's stream
794 """
795 h = logging.StreamHandler()
796 stream = io.StringIO()
797 old = h.setStream(stream)
798 self.assertIs(old, sys.stderr)
799 actual = h.setStream(old)
800 self.assertIs(actual, stream)
801 # test that setting to existing value returns None
802 actual = h.setStream(old)
803 self.assertIsNone(actual)
804
Riccardo Magliocchettica87eeb2019-05-07 23:36:39 +0200805 def test_can_represent_stream_with_int_name(self):
806 h = logging.StreamHandler(StreamWithIntName())
807 self.assertEqual(repr(h), '<StreamHandler 2 (NOTSET)>')
808
Vinay Sajip7367d082011-05-02 13:17:27 +0100809# -- The following section could be moved into a server_helper.py module
810# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100811
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200812class TestSMTPServer(smtpd.SMTPServer):
813 """
814 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100815
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200816 :param addr: A (host, port) tuple which the server listens on.
817 You can specify a port value of zero: the server's
818 *port* attribute will hold the actual port number
819 used, which can be used in client connections.
820 :param handler: A callable which will be called to process
821 incoming messages. The handler will be passed
822 the client address tuple, who the message is from,
823 a list of recipients and the message data.
824 :param poll_interval: The interval, in seconds, used in the underlying
825 :func:`select` or :func:`poll` call by
826 :func:`asyncore.loop`.
827 :param sockmap: A dictionary which will be used to hold
828 :class:`asyncore.dispatcher` instances used by
829 :func:`asyncore.loop`. This avoids changing the
830 :mod:`asyncore` module's global state.
831 """
832
833 def __init__(self, addr, handler, poll_interval, sockmap):
834 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
835 decode_data=True)
836 self.port = self.socket.getsockname()[1]
837 self._handler = handler
838 self._thread = None
839 self.poll_interval = poll_interval
840
841 def process_message(self, peer, mailfrom, rcpttos, data):
842 """
843 Delegates to the handler passed in to the server's constructor.
844
845 Typically, this will be a test case method.
846 :param peer: The client (host, port) tuple.
847 :param mailfrom: The address of the sender.
848 :param rcpttos: The addresses of the recipients.
849 :param data: The message.
850 """
851 self._handler(peer, mailfrom, rcpttos, data)
852
853 def start(self):
854 """
855 Start the server running on a separate daemon thread.
856 """
857 self._thread = t = threading.Thread(target=self.serve_forever,
858 args=(self.poll_interval,))
859 t.setDaemon(True)
860 t.start()
861
862 def serve_forever(self, poll_interval):
863 """
864 Run the :mod:`asyncore` loop until normal termination
865 conditions arise.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100866 :param poll_interval: The interval, in seconds, used in the underlying
867 :func:`select` or :func:`poll` call by
868 :func:`asyncore.loop`.
869 """
Victor Stinner13ff2452018-01-22 18:32:50 +0100870 asyncore.loop(poll_interval, map=self._map)
Vinay Sajipce7c9782011-05-17 07:15:53 +0100871
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200872 def stop(self, timeout=None):
873 """
874 Stop the thread by closing the server instance.
875 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100876
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200877 :param timeout: How long to wait for the server thread
878 to terminate.
879 """
880 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700881 support.join_thread(self._thread, timeout)
882 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200883 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100884
Vinay Sajip7367d082011-05-02 13:17:27 +0100885
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200886class ControlMixin(object):
887 """
888 This mixin is used to start a server on a separate thread, and
889 shut it down programmatically. Request handling is simplified - instead
890 of needing to derive a suitable RequestHandler subclass, you just
891 provide a callable which will be passed each received request to be
892 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100893
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200894 :param handler: A handler callable which will be called with a
895 single parameter - the request - in order to
896 process the request. This handler is called on the
897 server thread, effectively meaning that requests are
898 processed serially. While not quite Web scale ;-),
899 this should be fine for testing applications.
900 :param poll_interval: The polling interval in seconds.
901 """
902 def __init__(self, handler, poll_interval):
903 self._thread = None
904 self.poll_interval = poll_interval
905 self._handler = handler
906 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200908 def start(self):
909 """
910 Create a daemon thread to run the server, and start it.
911 """
912 self._thread = t = threading.Thread(target=self.serve_forever,
913 args=(self.poll_interval,))
914 t.setDaemon(True)
915 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100916
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200917 def serve_forever(self, poll_interval):
918 """
919 Run the server. Set the ready flag before entering the
920 service loop.
921 """
922 self.ready.set()
923 super(ControlMixin, self).serve_forever(poll_interval)
924
925 def stop(self, timeout=None):
926 """
927 Tell the server thread to stop, and wait for it to do so.
928
929 :param timeout: How long to wait for the server thread
930 to terminate.
931 """
932 self.shutdown()
933 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700934 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100935 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200936 self.server_close()
937 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100938
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200939class TestHTTPServer(ControlMixin, HTTPServer):
940 """
941 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100942
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200943 :param addr: A tuple with the IP address and port to listen on.
944 :param handler: A handler callable which will be called with a
945 single parameter - the request - in order to
946 process the request.
947 :param poll_interval: The polling interval in seconds.
948 :param log: Pass ``True`` to enable log messages.
949 """
950 def __init__(self, addr, handler, poll_interval=0.5,
951 log=False, sslctx=None):
952 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
953 def __getattr__(self, name, default=None):
954 if name.startswith('do_'):
955 return self.process_request
956 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100957
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200958 def process_request(self):
959 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100960
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200961 def log_message(self, format, *args):
962 if log:
963 super(DelegatingHTTPRequestHandler,
964 self).log_message(format, *args)
965 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
966 ControlMixin.__init__(self, handler, poll_interval)
967 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100968
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200969 def get_request(self):
970 try:
971 sock, addr = self.socket.accept()
972 if self.sslctx:
973 sock = self.sslctx.wrap_socket(sock, server_side=True)
974 except OSError as e:
975 # socket errors are silenced by the caller, print them here
976 sys.stderr.write("Got an error:\n%s\n" % e)
977 raise
978 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100979
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200980class TestTCPServer(ControlMixin, ThreadingTCPServer):
981 """
982 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100983
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200984 :param addr: A tuple with the IP address and port to listen on.
985 :param handler: A handler callable which will be called with a single
986 parameter - the request - in order to process the request.
987 :param poll_interval: The polling interval in seconds.
988 :bind_and_activate: If True (the default), binds the server and starts it
989 listening. If False, you need to call
990 :meth:`server_bind` and :meth:`server_activate` at
991 some later time before calling :meth:`start`, so that
992 the server will set up the socket and listen on it.
993 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100994
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200995 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100996
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200997 def __init__(self, addr, handler, poll_interval=0.5,
998 bind_and_activate=True):
999 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +01001000
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001001 def handle(self):
1002 self.server._handler(self)
1003 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
1004 bind_and_activate)
1005 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +01001006
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001007 def server_bind(self):
1008 super(TestTCPServer, self).server_bind()
1009 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +01001010
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001011class TestUDPServer(ControlMixin, ThreadingUDPServer):
1012 """
1013 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +01001014
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001015 :param addr: A tuple with the IP address and port to listen on.
1016 :param handler: A handler callable which will be called with a
1017 single parameter - the request - in order to
1018 process the request.
1019 :param poll_interval: The polling interval for shutdown requests,
1020 in seconds.
1021 :bind_and_activate: If True (the default), binds the server and
1022 starts it listening. If False, you need to
1023 call :meth:`server_bind` and
1024 :meth:`server_activate` at some later time
1025 before calling :meth:`start`, so that the server will
1026 set up the socket and listen on it.
1027 """
1028 def __init__(self, addr, handler, poll_interval=0.5,
1029 bind_and_activate=True):
1030 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +01001031
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001032 def handle(self):
1033 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001034
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001035 def finish(self):
1036 data = self.wfile.getvalue()
1037 if data:
1038 try:
1039 super(DelegatingUDPRequestHandler, self).finish()
1040 except OSError:
1041 if not self.server._closed:
1042 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +01001043
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001044 ThreadingUDPServer.__init__(self, addr,
1045 DelegatingUDPRequestHandler,
1046 bind_and_activate)
1047 ControlMixin.__init__(self, handler, poll_interval)
1048 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +01001049
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001050 def server_bind(self):
1051 super(TestUDPServer, self).server_bind()
1052 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +01001053
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001054 def server_close(self):
1055 super(TestUDPServer, self).server_close()
1056 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +01001057
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001058if hasattr(socket, "AF_UNIX"):
1059 class TestUnixStreamServer(TestTCPServer):
1060 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +01001061
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001062 class TestUnixDatagramServer(TestUDPServer):
1063 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +01001064
Vinay Sajip7367d082011-05-02 13:17:27 +01001065# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +01001066
1067class SMTPHandlerTest(BaseTest):
Victor Stinner31b50b82018-07-11 12:35:38 +02001068 # bpo-14314, bpo-19665, bpo-34092: don't wait forever, timeout of 1 minute
1069 TIMEOUT = 60.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02001070
Vinay Sajipa463d252011-04-30 21:52:48 +01001071 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +01001072 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -08001073 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +01001074 sockmap)
1075 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -08001076 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001077 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
1078 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001079 self.assertEqual(h.toaddrs, ['you'])
1080 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001081 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001082 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001083 h.handle(r)
Victor Stinner31b50b82018-07-11 12:35:38 +02001084 self.handled.wait(self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001085 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001086 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001087 self.assertEqual(len(self.messages), 1)
1088 peer, mailfrom, rcpttos, data = self.messages[0]
1089 self.assertEqual(mailfrom, 'me')
1090 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001091 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001092 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001093 h.close()
1094
1095 def process_message(self, *args):
1096 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001097 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001098
Christian Heimes180510d2008-03-03 19:15:45 +00001099class MemoryHandlerTest(BaseTest):
1100
1101 """Tests for the MemoryHandler."""
1102
1103 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001104 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001105
1106 def setUp(self):
1107 BaseTest.setUp(self)
1108 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001109 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001110 self.mem_logger = logging.getLogger('mem')
1111 self.mem_logger.propagate = 0
1112 self.mem_logger.addHandler(self.mem_hdlr)
1113
1114 def tearDown(self):
1115 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001116 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001117
1118 def test_flush(self):
1119 # The memory handler flushes to its target handler based on specific
1120 # criteria (message count and message level).
1121 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001122 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001123 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001124 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001125 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001126 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001127 lines = [
1128 ('DEBUG', '1'),
1129 ('INFO', '2'),
1130 ('WARNING', '3'),
1131 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001132 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001133 for n in (4, 14):
1134 for i in range(9):
1135 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001136 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001137 # This will flush because it's the 10th message since the last
1138 # flush.
1139 self.mem_logger.debug(self.next_message())
1140 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001141 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001142
1143 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001144 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001145
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001146 def test_flush_on_close(self):
1147 """
1148 Test that the flush-on-close configuration works as expected.
1149 """
1150 self.mem_logger.debug(self.next_message())
1151 self.assert_log_lines([])
1152 self.mem_logger.info(self.next_message())
1153 self.assert_log_lines([])
1154 self.mem_logger.removeHandler(self.mem_hdlr)
1155 # Default behaviour is to flush on close. Check that it happens.
1156 self.mem_hdlr.close()
1157 lines = [
1158 ('DEBUG', '1'),
1159 ('INFO', '2'),
1160 ]
1161 self.assert_log_lines(lines)
1162 # Now configure for flushing not to be done on close.
1163 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1164 self.root_hdlr,
1165 False)
1166 self.mem_logger.addHandler(self.mem_hdlr)
1167 self.mem_logger.debug(self.next_message())
1168 self.assert_log_lines(lines) # no change
1169 self.mem_logger.info(self.next_message())
1170 self.assert_log_lines(lines) # no change
1171 self.mem_logger.removeHandler(self.mem_hdlr)
1172 self.mem_hdlr.close()
1173 # assert that no new lines have been added
1174 self.assert_log_lines(lines) # no change
1175
Christian Heimes180510d2008-03-03 19:15:45 +00001176
1177class ExceptionFormatter(logging.Formatter):
1178 """A special exception formatter."""
1179 def formatException(self, ei):
1180 return "Got a [%s]" % ei[0].__name__
1181
1182
1183class ConfigFileTest(BaseTest):
1184
1185 """Reading logging config from a .ini-style config file."""
1186
Xtreak087570a2018-07-02 14:27:46 +05301187 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001188 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001189
1190 # config0 is a standard configuration.
1191 config0 = """
1192 [loggers]
1193 keys=root
1194
1195 [handlers]
1196 keys=hand1
1197
1198 [formatters]
1199 keys=form1
1200
1201 [logger_root]
1202 level=WARNING
1203 handlers=hand1
1204
1205 [handler_hand1]
1206 class=StreamHandler
1207 level=NOTSET
1208 formatter=form1
1209 args=(sys.stdout,)
1210
1211 [formatter_form1]
1212 format=%(levelname)s ++ %(message)s
1213 datefmt=
1214 """
1215
1216 # config1 adds a little to the standard configuration.
1217 config1 = """
1218 [loggers]
1219 keys=root,parser
1220
1221 [handlers]
1222 keys=hand1
1223
1224 [formatters]
1225 keys=form1
1226
1227 [logger_root]
1228 level=WARNING
1229 handlers=
1230
1231 [logger_parser]
1232 level=DEBUG
1233 handlers=hand1
1234 propagate=1
1235 qualname=compiler.parser
1236
1237 [handler_hand1]
1238 class=StreamHandler
1239 level=NOTSET
1240 formatter=form1
1241 args=(sys.stdout,)
1242
1243 [formatter_form1]
1244 format=%(levelname)s ++ %(message)s
1245 datefmt=
1246 """
1247
Vinay Sajip3f84b072011-03-07 17:49:33 +00001248 # config1a moves the handler to the root.
1249 config1a = """
1250 [loggers]
1251 keys=root,parser
1252
1253 [handlers]
1254 keys=hand1
1255
1256 [formatters]
1257 keys=form1
1258
1259 [logger_root]
1260 level=WARNING
1261 handlers=hand1
1262
1263 [logger_parser]
1264 level=DEBUG
1265 handlers=
1266 propagate=1
1267 qualname=compiler.parser
1268
1269 [handler_hand1]
1270 class=StreamHandler
1271 level=NOTSET
1272 formatter=form1
1273 args=(sys.stdout,)
1274
1275 [formatter_form1]
1276 format=%(levelname)s ++ %(message)s
1277 datefmt=
1278 """
1279
Christian Heimes180510d2008-03-03 19:15:45 +00001280 # config2 has a subtle configuration error that should be reported
1281 config2 = config1.replace("sys.stdout", "sys.stbout")
1282
1283 # config3 has a less subtle configuration error
1284 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1285
1286 # config4 specifies a custom formatter class to be loaded
1287 config4 = """
1288 [loggers]
1289 keys=root
1290
1291 [handlers]
1292 keys=hand1
1293
1294 [formatters]
1295 keys=form1
1296
1297 [logger_root]
1298 level=NOTSET
1299 handlers=hand1
1300
1301 [handler_hand1]
1302 class=StreamHandler
1303 level=NOTSET
1304 formatter=form1
1305 args=(sys.stdout,)
1306
1307 [formatter_form1]
1308 class=""" + __name__ + """.ExceptionFormatter
1309 format=%(levelname)s:%(name)s:%(message)s
1310 datefmt=
1311 """
1312
Georg Brandl3dbca812008-07-23 16:10:53 +00001313 # config5 specifies a custom handler class to be loaded
1314 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1315
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001316 # config6 uses ', ' delimiters in the handlers and formatters sections
1317 config6 = """
1318 [loggers]
1319 keys=root,parser
1320
1321 [handlers]
1322 keys=hand1, hand2
1323
1324 [formatters]
1325 keys=form1, form2
1326
1327 [logger_root]
1328 level=WARNING
1329 handlers=
1330
1331 [logger_parser]
1332 level=DEBUG
1333 handlers=hand1
1334 propagate=1
1335 qualname=compiler.parser
1336
1337 [handler_hand1]
1338 class=StreamHandler
1339 level=NOTSET
1340 formatter=form1
1341 args=(sys.stdout,)
1342
1343 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001344 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001345 level=NOTSET
1346 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001347 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001348
1349 [formatter_form1]
1350 format=%(levelname)s ++ %(message)s
1351 datefmt=
1352
1353 [formatter_form2]
1354 format=%(message)s
1355 datefmt=
1356 """
1357
Preston Landers6ea56d22017-08-02 15:44:28 -05001358 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001359 config7 = """
1360 [loggers]
1361 keys=root,parser,compiler
1362
1363 [handlers]
1364 keys=hand1
1365
1366 [formatters]
1367 keys=form1
1368
1369 [logger_root]
1370 level=WARNING
1371 handlers=hand1
1372
1373 [logger_compiler]
1374 level=DEBUG
1375 handlers=
1376 propagate=1
1377 qualname=compiler
1378
1379 [logger_parser]
1380 level=DEBUG
1381 handlers=
1382 propagate=1
1383 qualname=compiler.parser
1384
1385 [handler_hand1]
1386 class=StreamHandler
1387 level=NOTSET
1388 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001389 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001390
1391 [formatter_form1]
1392 format=%(levelname)s ++ %(message)s
1393 datefmt=
1394 """
1395
Xtreak087570a2018-07-02 14:27:46 +05301396 # config 8, check for resource warning
1397 config8 = r"""
1398 [loggers]
1399 keys=root
1400
1401 [handlers]
1402 keys=file
1403
1404 [formatters]
1405 keys=
1406
1407 [logger_root]
1408 level=DEBUG
1409 handlers=file
1410
1411 [handler_file]
1412 class=FileHandler
1413 level=DEBUG
1414 args=("{tempfile}",)
1415 """
1416
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001417 disable_test = """
1418 [loggers]
1419 keys=root
1420
1421 [handlers]
1422 keys=screen
1423
1424 [formatters]
1425 keys=
1426
1427 [logger_root]
1428 level=DEBUG
1429 handlers=screen
1430
1431 [handler_screen]
1432 level=DEBUG
1433 class=StreamHandler
1434 args=(sys.stdout,)
1435 formatter=
1436 """
1437
1438 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001439 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001440 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001441
1442 def test_config0_ok(self):
1443 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001444 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001445 self.apply_config(self.config0)
1446 logger = logging.getLogger()
1447 # Won't output anything
1448 logger.info(self.next_message())
1449 # Outputs a message
1450 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001451 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001452 ('ERROR', '2'),
1453 ], stream=output)
1454 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001455 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001456
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001457 def test_config0_using_cp_ok(self):
1458 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001459 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001460 file = io.StringIO(textwrap.dedent(self.config0))
1461 cp = configparser.ConfigParser()
1462 cp.read_file(file)
1463 logging.config.fileConfig(cp)
1464 logger = logging.getLogger()
1465 # Won't output anything
1466 logger.info(self.next_message())
1467 # Outputs a message
1468 logger.error(self.next_message())
1469 self.assert_log_lines([
1470 ('ERROR', '2'),
1471 ], stream=output)
1472 # Original logger output is empty.
1473 self.assert_log_lines([])
1474
Georg Brandl3dbca812008-07-23 16:10:53 +00001475 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001476 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001477 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001478 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001479 logger = logging.getLogger("compiler.parser")
1480 # Both will output a message
1481 logger.info(self.next_message())
1482 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001483 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001484 ('INFO', '1'),
1485 ('ERROR', '2'),
1486 ], stream=output)
1487 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001488 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001489
1490 def test_config2_failure(self):
1491 # A simple config file which overrides the default settings.
1492 self.assertRaises(Exception, self.apply_config, self.config2)
1493
1494 def test_config3_failure(self):
1495 # A simple config file which overrides the default settings.
1496 self.assertRaises(Exception, self.apply_config, self.config3)
1497
1498 def test_config4_ok(self):
1499 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001500 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001501 self.apply_config(self.config4)
1502 logger = logging.getLogger()
1503 try:
1504 raise RuntimeError()
1505 except RuntimeError:
1506 logging.exception("just testing")
1507 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001508 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001509 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1510 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001511 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001512
Georg Brandl3dbca812008-07-23 16:10:53 +00001513 def test_config5_ok(self):
1514 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001515
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001516 def test_config6_ok(self):
1517 self.test_config1_ok(config=self.config6)
1518
Vinay Sajip3f84b072011-03-07 17:49:33 +00001519 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001520 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001521 self.apply_config(self.config1a)
1522 logger = logging.getLogger("compiler.parser")
1523 # See issue #11424. compiler-hyphenated sorts
1524 # between compiler and compiler.xyz and this
1525 # was preventing compiler.xyz from being included
1526 # in the child loggers of compiler because of an
1527 # overzealous loop termination condition.
1528 hyphenated = logging.getLogger('compiler-hyphenated')
1529 # All will output a message
1530 logger.info(self.next_message())
1531 logger.error(self.next_message())
1532 hyphenated.critical(self.next_message())
1533 self.assert_log_lines([
1534 ('INFO', '1'),
1535 ('ERROR', '2'),
1536 ('CRITICAL', '3'),
1537 ], stream=output)
1538 # Original logger output is empty.
1539 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001540 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001541 self.apply_config(self.config7)
1542 logger = logging.getLogger("compiler.parser")
1543 self.assertFalse(logger.disabled)
1544 # Both will output a message
1545 logger.info(self.next_message())
1546 logger.error(self.next_message())
1547 logger = logging.getLogger("compiler.lexer")
1548 # Both will output a message
1549 logger.info(self.next_message())
1550 logger.error(self.next_message())
1551 # Will not appear
1552 hyphenated.critical(self.next_message())
1553 self.assert_log_lines([
1554 ('INFO', '4'),
1555 ('ERROR', '5'),
1556 ('INFO', '6'),
1557 ('ERROR', '7'),
1558 ], stream=output)
1559 # Original logger output is empty.
1560 self.assert_log_lines([])
1561
Xtreak087570a2018-07-02 14:27:46 +05301562 def test_config8_ok(self):
1563
1564 def cleanup(h1, fn):
1565 h1.close()
1566 os.remove(fn)
1567
1568 with self.check_no_resource_warning():
1569 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1570 os.close(fd)
1571
1572 # Replace single backslash with double backslash in windows
1573 # to avoid unicode error during string formatting
1574 if os.name == "nt":
1575 fn = fn.replace("\\", "\\\\")
1576
1577 config8 = self.config8.format(tempfile=fn)
1578
1579 self.apply_config(config8)
1580 self.apply_config(config8)
1581
1582 handler = logging.root.handlers[0]
1583 self.addCleanup(cleanup, handler, fn)
1584
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001585 def test_logger_disabling(self):
1586 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001587 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001588 self.assertFalse(logger.disabled)
1589 self.apply_config(self.disable_test)
1590 self.assertTrue(logger.disabled)
1591 self.apply_config(self.disable_test, disable_existing_loggers=False)
1592 self.assertFalse(logger.disabled)
1593
Lucas Cimonb15100f2019-10-31 09:06:25 +01001594 def test_config_set_handler_names(self):
1595 test_config = """
1596 [loggers]
1597 keys=root
1598
1599 [handlers]
1600 keys=hand1
1601
1602 [formatters]
1603 keys=form1
1604
1605 [logger_root]
1606 handlers=hand1
1607
1608 [handler_hand1]
1609 class=StreamHandler
1610 formatter=form1
1611
1612 [formatter_form1]
1613 format=%(levelname)s ++ %(message)s
1614 """
1615 self.apply_config(test_config)
1616 self.assertEquals(logging.getLogger().handlers[0].name, 'hand1')
1617
Łukasz Langa214f18e2018-06-08 04:02:48 -07001618 def test_defaults_do_no_interpolation(self):
1619 """bpo-33802 defaults should not get interpolated"""
1620 ini = textwrap.dedent("""
1621 [formatters]
1622 keys=default
1623
1624 [formatter_default]
1625
1626 [handlers]
1627 keys=console
1628
1629 [handler_console]
1630 class=logging.StreamHandler
1631 args=tuple()
1632
1633 [loggers]
1634 keys=root
1635
1636 [logger_root]
1637 formatter=default
1638 handlers=console
1639 """).strip()
1640 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1641 try:
1642 os.write(fd, ini.encode('ascii'))
1643 os.close(fd)
1644 logging.config.fileConfig(
1645 fn,
1646 defaults=dict(
1647 version=1,
1648 disable_existing_loggers=False,
1649 formatters={
1650 "generic": {
1651 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1652 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1653 "class": "logging.Formatter"
1654 },
1655 },
1656 )
1657 )
1658 finally:
1659 os.unlink(fn)
1660
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001661
Christian Heimes180510d2008-03-03 19:15:45 +00001662class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001663
Christian Heimes180510d2008-03-03 19:15:45 +00001664 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001665
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001666 server_class = TestTCPServer
1667 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001668
Christian Heimes180510d2008-03-03 19:15:45 +00001669 def setUp(self):
1670 """Set up a TCP server to receive log messages, and a SocketHandler
1671 pointing to that server's address and port."""
1672 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001673 # Issue #29177: deal with errors that happen during setup
1674 self.server = self.sock_hdlr = self.server_exception = None
1675 try:
1676 self.server = server = self.server_class(self.address,
1677 self.handle_socket, 0.01)
1678 server.start()
1679 # Uncomment next line to test error recovery in setUp()
1680 # raise OSError('dummy error raised')
1681 except OSError as e:
1682 self.server_exception = e
1683 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001684 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001685 hcls = logging.handlers.SocketHandler
1686 if isinstance(server.server_address, tuple):
1687 self.sock_hdlr = hcls('localhost', server.port)
1688 else:
1689 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001690 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001691 self.root_logger.removeHandler(self.root_logger.handlers[0])
1692 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001693 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001694
Christian Heimes180510d2008-03-03 19:15:45 +00001695 def tearDown(self):
1696 """Shutdown the TCP server."""
1697 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001698 if self.sock_hdlr:
1699 self.root_logger.removeHandler(self.sock_hdlr)
1700 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001701 if self.server:
1702 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001703 finally:
1704 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001705
Vinay Sajip7367d082011-05-02 13:17:27 +01001706 def handle_socket(self, request):
1707 conn = request.connection
1708 while True:
1709 chunk = conn.recv(4)
1710 if len(chunk) < 4:
1711 break
1712 slen = struct.unpack(">L", chunk)[0]
1713 chunk = conn.recv(slen)
1714 while len(chunk) < slen:
1715 chunk = chunk + conn.recv(slen - len(chunk))
1716 obj = pickle.loads(chunk)
1717 record = logging.makeLogRecord(obj)
1718 self.log_output += record.msg + '\n'
1719 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001720
Christian Heimes180510d2008-03-03 19:15:45 +00001721 def test_output(self):
1722 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001723 if self.server_exception:
1724 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001725 logger = logging.getLogger("tcp")
1726 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001727 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001728 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001729 self.handled.acquire()
1730 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001731
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001732 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001733 if self.server_exception:
1734 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001735 # Avoid timing-related failures due to SocketHandler's own hard-wired
1736 # one-second timeout on socket.create_connection() (issue #16264).
1737 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001738 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001739 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001740 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001741 try:
1742 raise RuntimeError('Deliberate mistake')
1743 except RuntimeError:
1744 self.root_logger.exception('Never sent')
1745 self.root_logger.error('Never sent, either')
1746 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001747 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001748 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1749 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001750
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001751def _get_temp_domain_socket():
1752 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1753 os.close(fd)
1754 # just need a name - file can't be present, or we'll get an
1755 # 'address already in use' error.
1756 os.remove(fn)
1757 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001758
Victor Stinnerec5a8602014-06-02 14:41:51 +02001759@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001760class UnixSocketHandlerTest(SocketHandlerTest):
1761
1762 """Test for SocketHandler with unix sockets."""
1763
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001764 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001765 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001766
1767 def setUp(self):
1768 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001769 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001770 SocketHandlerTest.setUp(self)
1771
1772 def tearDown(self):
1773 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001774 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001775
Vinay Sajip7367d082011-05-02 13:17:27 +01001776class DatagramHandlerTest(BaseTest):
1777
1778 """Test for DatagramHandler."""
1779
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001780 server_class = TestUDPServer
1781 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001782
Vinay Sajip7367d082011-05-02 13:17:27 +01001783 def setUp(self):
1784 """Set up a UDP server to receive log messages, and a DatagramHandler
1785 pointing to that server's address and port."""
1786 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001787 # Issue #29177: deal with errors that happen during setup
1788 self.server = self.sock_hdlr = self.server_exception = None
1789 try:
1790 self.server = server = self.server_class(self.address,
1791 self.handle_datagram, 0.01)
1792 server.start()
1793 # Uncomment next line to test error recovery in setUp()
1794 # raise OSError('dummy error raised')
1795 except OSError as e:
1796 self.server_exception = e
1797 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001798 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001799 hcls = logging.handlers.DatagramHandler
1800 if isinstance(server.server_address, tuple):
1801 self.sock_hdlr = hcls('localhost', server.port)
1802 else:
1803 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001804 self.log_output = ''
1805 self.root_logger.removeHandler(self.root_logger.handlers[0])
1806 self.root_logger.addHandler(self.sock_hdlr)
1807 self.handled = threading.Event()
1808
1809 def tearDown(self):
1810 """Shutdown the UDP server."""
1811 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001812 if self.server:
1813 self.server.stop(2.0)
1814 if self.sock_hdlr:
1815 self.root_logger.removeHandler(self.sock_hdlr)
1816 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001817 finally:
1818 BaseTest.tearDown(self)
1819
1820 def handle_datagram(self, request):
1821 slen = struct.pack('>L', 0) # length of prefix
1822 packet = request.packet[len(slen):]
1823 obj = pickle.loads(packet)
1824 record = logging.makeLogRecord(obj)
1825 self.log_output += record.msg + '\n'
1826 self.handled.set()
1827
1828 def test_output(self):
1829 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001830 if self.server_exception:
1831 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001832 logger = logging.getLogger("udp")
1833 logger.error("spam")
1834 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001835 self.handled.clear()
1836 logger.error("eggs")
1837 self.handled.wait()
1838 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001839
Victor Stinnerec5a8602014-06-02 14:41:51 +02001840@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001841class UnixDatagramHandlerTest(DatagramHandlerTest):
1842
1843 """Test for DatagramHandler using Unix sockets."""
1844
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001845 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001846 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001847
1848 def setUp(self):
1849 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001850 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001851 DatagramHandlerTest.setUp(self)
1852
1853 def tearDown(self):
1854 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001855 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001856
Vinay Sajip7367d082011-05-02 13:17:27 +01001857class SysLogHandlerTest(BaseTest):
1858
1859 """Test for SysLogHandler using UDP."""
1860
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001861 server_class = TestUDPServer
1862 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001863
Vinay Sajip7367d082011-05-02 13:17:27 +01001864 def setUp(self):
1865 """Set up a UDP server to receive log messages, and a SysLogHandler
1866 pointing to that server's address and port."""
1867 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001868 # Issue #29177: deal with errors that happen during setup
1869 self.server = self.sl_hdlr = self.server_exception = None
1870 try:
1871 self.server = server = self.server_class(self.address,
1872 self.handle_datagram, 0.01)
1873 server.start()
1874 # Uncomment next line to test error recovery in setUp()
1875 # raise OSError('dummy error raised')
1876 except OSError as e:
1877 self.server_exception = e
1878 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001879 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001880 hcls = logging.handlers.SysLogHandler
1881 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001882 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001883 else:
1884 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001885 self.log_output = ''
1886 self.root_logger.removeHandler(self.root_logger.handlers[0])
1887 self.root_logger.addHandler(self.sl_hdlr)
1888 self.handled = threading.Event()
1889
1890 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001891 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001892 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001893 if self.server:
1894 self.server.stop(2.0)
1895 if self.sl_hdlr:
1896 self.root_logger.removeHandler(self.sl_hdlr)
1897 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001898 finally:
1899 BaseTest.tearDown(self)
1900
1901 def handle_datagram(self, request):
1902 self.log_output = request.packet
1903 self.handled.set()
1904
1905 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001906 if self.server_exception:
1907 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001908 # The log message sent to the SysLogHandler is properly received.
1909 logger = logging.getLogger("slh")
1910 logger.error("sp\xe4m")
1911 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001912 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001913 self.handled.clear()
1914 self.sl_hdlr.append_nul = False
1915 logger.error("sp\xe4m")
1916 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001917 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001918 self.handled.clear()
1919 self.sl_hdlr.ident = "h\xe4m-"
1920 logger.error("sp\xe4m")
1921 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001922 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001923
Victor Stinnerec5a8602014-06-02 14:41:51 +02001924@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001925class UnixSysLogHandlerTest(SysLogHandlerTest):
1926
1927 """Test for SysLogHandler with Unix sockets."""
1928
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001929 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001930 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001931
1932 def setUp(self):
1933 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001934 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001935 SysLogHandlerTest.setUp(self)
1936
1937 def tearDown(self):
1938 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001939 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001940
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001941@unittest.skipUnless(support.IPV6_ENABLED,
1942 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001943class IPv6SysLogHandlerTest(SysLogHandlerTest):
1944
1945 """Test for SysLogHandler with IPv6 host."""
1946
1947 server_class = TestUDPServer
1948 address = ('::1', 0)
1949
1950 def setUp(self):
1951 self.server_class.address_family = socket.AF_INET6
1952 super(IPv6SysLogHandlerTest, self).setUp()
1953
1954 def tearDown(self):
1955 self.server_class.address_family = socket.AF_INET
1956 super(IPv6SysLogHandlerTest, self).tearDown()
1957
Vinay Sajip7367d082011-05-02 13:17:27 +01001958class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001959 """Test for HTTPHandler."""
1960
1961 def setUp(self):
1962 """Set up an HTTP server to receive log messages, and a HTTPHandler
1963 pointing to that server's address and port."""
1964 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001965 self.handled = threading.Event()
1966
Vinay Sajip7367d082011-05-02 13:17:27 +01001967 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001968 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001969 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001970 if self.command == 'POST':
1971 try:
1972 rlen = int(request.headers['Content-Length'])
1973 self.post_data = request.rfile.read(rlen)
1974 except:
1975 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001976 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001977 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001978 self.handled.set()
1979
1980 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001981 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001982 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001983 root_logger = self.root_logger
1984 root_logger.removeHandler(self.root_logger.handlers[0])
1985 for secure in (False, True):
1986 addr = ('localhost', 0)
1987 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001988 try:
1989 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001990 except ImportError:
1991 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001992 else:
1993 here = os.path.dirname(__file__)
1994 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001995 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001996 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001997
1998 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001999 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01002000 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06002001 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01002002 self.server = server = TestHTTPServer(addr, self.handle_request,
2003 0.01, sslctx=sslctx)
2004 server.start()
2005 server.ready.wait()
2006 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01002007 secure_client = secure and sslctx
2008 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06002009 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01002010 context=context,
2011 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01002012 self.log_data = None
2013 root_logger.addHandler(self.h_hdlr)
2014
2015 for method in ('GET', 'POST'):
2016 self.h_hdlr.method = method
2017 self.handled.clear()
2018 msg = "sp\xe4m"
2019 logger.error(msg)
2020 self.handled.wait()
2021 self.assertEqual(self.log_data.path, '/frob')
2022 self.assertEqual(self.command, method)
2023 if method == 'GET':
2024 d = parse_qs(self.log_data.query)
2025 else:
2026 d = parse_qs(self.post_data.decode('utf-8'))
2027 self.assertEqual(d['name'], ['http'])
2028 self.assertEqual(d['funcName'], ['test_output'])
2029 self.assertEqual(d['msg'], [msg])
2030
2031 self.server.stop(2.0)
2032 self.root_logger.removeHandler(self.h_hdlr)
2033 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01002034
Christian Heimes180510d2008-03-03 19:15:45 +00002035class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002036
Christian Heimes180510d2008-03-03 19:15:45 +00002037 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002038
Christian Heimes180510d2008-03-03 19:15:45 +00002039 def setUp(self):
2040 """Create a dict to remember potentially destroyed objects."""
2041 BaseTest.setUp(self)
2042 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002043
Christian Heimes180510d2008-03-03 19:15:45 +00002044 def _watch_for_survival(self, *args):
2045 """Watch the given objects for survival, by creating weakrefs to
2046 them."""
2047 for obj in args:
2048 key = id(obj), repr(obj)
2049 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002050
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002051 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00002052 """Assert that all objects watched for survival have survived."""
2053 # Trigger cycle breaking.
2054 gc.collect()
2055 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002056 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00002057 if ref() is None:
2058 dead.append(repr_)
2059 if dead:
2060 self.fail("%d objects should have survived "
2061 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002062
Christian Heimes180510d2008-03-03 19:15:45 +00002063 def test_persistent_loggers(self):
2064 # Logger objects are persistent and retain their configuration, even
2065 # if visible references are destroyed.
2066 self.root_logger.setLevel(logging.INFO)
2067 foo = logging.getLogger("foo")
2068 self._watch_for_survival(foo)
2069 foo.setLevel(logging.DEBUG)
2070 self.root_logger.debug(self.next_message())
2071 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002072 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002073 ('foo', 'DEBUG', '2'),
2074 ])
2075 del foo
2076 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002077 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00002078 # foo has retained its settings.
2079 bar = logging.getLogger("foo")
2080 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002081 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002082 ('foo', 'DEBUG', '2'),
2083 ('foo', 'DEBUG', '3'),
2084 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002085
Benjamin Petersonf91df042009-02-13 02:50:59 +00002086
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002087class EncodingTest(BaseTest):
2088 def test_encoding_plain_file(self):
2089 # In Python 2.x, a plain file object is treated as having no encoding.
2090 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00002091 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
2092 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002093 # the non-ascii data we write to the log.
2094 data = "foo\x80"
2095 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002097 log.addHandler(handler)
2098 try:
2099 # write non-ascii data to the log.
2100 log.warning(data)
2101 finally:
2102 log.removeHandler(handler)
2103 handler.close()
2104 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002105 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002106 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002107 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002108 finally:
2109 f.close()
2110 finally:
2111 if os.path.isfile(fn):
2112 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002113
Benjamin Petersonf91df042009-02-13 02:50:59 +00002114 def test_encoding_cyrillic_unicode(self):
2115 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03002116 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00002117 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03002118 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00002119 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00002120 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00002121 stream = io.BytesIO()
2122 writer = writer_class(stream, 'strict')
2123 handler = logging.StreamHandler(writer)
2124 log.addHandler(handler)
2125 try:
2126 log.warning(message)
2127 finally:
2128 log.removeHandler(handler)
2129 handler.close()
2130 # check we wrote exactly those bytes, ignoring trailing \n etc
2131 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03002132 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00002133 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
2134
2135
Georg Brandlf9734072008-12-07 15:30:06 +00002136class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00002137
Georg Brandlf9734072008-12-07 15:30:06 +00002138 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00002139 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00002140 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002141 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002142 warnings.filterwarnings("always", category=UserWarning)
2143 stream = io.StringIO()
2144 h = logging.StreamHandler(stream)
2145 logger = logging.getLogger("py.warnings")
2146 logger.addHandler(h)
2147 warnings.warn("I'm warning you...")
2148 logger.removeHandler(h)
2149 s = stream.getvalue()
2150 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002151 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00002152
Mike53f7a7c2017-12-14 14:04:53 +03002153 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002154 a_file = io.StringIO()
2155 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
2156 a_file, "Dummy line")
2157 s = a_file.getvalue()
2158 a_file.close()
2159 self.assertEqual(s,
2160 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
2161
2162 def test_warnings_no_handlers(self):
2163 with warnings.catch_warnings():
2164 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002165 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002166
2167 # confirm our assumption: no loggers are set
2168 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002169 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002170
2171 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002172 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002173 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002174
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002175
2176def formatFunc(format, datefmt=None):
2177 return logging.Formatter(format, datefmt)
2178
BNMetrics18fb1fb2018-10-15 19:41:36 +01002179class myCustomFormatter:
2180 def __init__(self, fmt, datefmt=None):
2181 pass
2182
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002183def handlerFunc():
2184 return logging.StreamHandler()
2185
2186class CustomHandler(logging.StreamHandler):
2187 pass
2188
2189class ConfigDictTest(BaseTest):
2190
2191 """Reading logging config from a dictionary."""
2192
Xtreak087570a2018-07-02 14:27:46 +05302193 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002194 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002195
2196 # config0 is a standard configuration.
2197 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002198 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002199 'formatters': {
2200 'form1' : {
2201 'format' : '%(levelname)s ++ %(message)s',
2202 },
2203 },
2204 'handlers' : {
2205 'hand1' : {
2206 'class' : 'logging.StreamHandler',
2207 'formatter' : 'form1',
2208 'level' : 'NOTSET',
2209 'stream' : 'ext://sys.stdout',
2210 },
2211 },
2212 'root' : {
2213 'level' : 'WARNING',
2214 'handlers' : ['hand1'],
2215 },
2216 }
2217
2218 # config1 adds a little to the standard configuration.
2219 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002220 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002221 'formatters': {
2222 'form1' : {
2223 'format' : '%(levelname)s ++ %(message)s',
2224 },
2225 },
2226 'handlers' : {
2227 'hand1' : {
2228 'class' : 'logging.StreamHandler',
2229 'formatter' : 'form1',
2230 'level' : 'NOTSET',
2231 'stream' : 'ext://sys.stdout',
2232 },
2233 },
2234 'loggers' : {
2235 'compiler.parser' : {
2236 'level' : 'DEBUG',
2237 'handlers' : ['hand1'],
2238 },
2239 },
2240 'root' : {
2241 'level' : 'WARNING',
2242 },
2243 }
2244
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002245 # config1a moves the handler to the root. Used with config8a
2246 config1a = {
2247 'version': 1,
2248 'formatters': {
2249 'form1' : {
2250 'format' : '%(levelname)s ++ %(message)s',
2251 },
2252 },
2253 'handlers' : {
2254 'hand1' : {
2255 'class' : 'logging.StreamHandler',
2256 'formatter' : 'form1',
2257 'level' : 'NOTSET',
2258 'stream' : 'ext://sys.stdout',
2259 },
2260 },
2261 'loggers' : {
2262 'compiler.parser' : {
2263 'level' : 'DEBUG',
2264 },
2265 },
2266 'root' : {
2267 'level' : 'WARNING',
2268 'handlers' : ['hand1'],
2269 },
2270 }
2271
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002272 # config2 has a subtle configuration error that should be reported
2273 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002274 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 'formatters': {
2276 'form1' : {
2277 'format' : '%(levelname)s ++ %(message)s',
2278 },
2279 },
2280 'handlers' : {
2281 'hand1' : {
2282 'class' : 'logging.StreamHandler',
2283 'formatter' : 'form1',
2284 'level' : 'NOTSET',
2285 'stream' : 'ext://sys.stdbout',
2286 },
2287 },
2288 'loggers' : {
2289 'compiler.parser' : {
2290 'level' : 'DEBUG',
2291 'handlers' : ['hand1'],
2292 },
2293 },
2294 'root' : {
2295 'level' : 'WARNING',
2296 },
2297 }
2298
Mike53f7a7c2017-12-14 14:04:53 +03002299 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002300 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002301 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002302 'formatters': {
2303 'form1' : {
2304 'format' : '%(levelname)s ++ %(message)s',
2305 },
2306 },
2307 'handlers' : {
2308 'hand1' : {
2309 'class' : 'logging.StreamHandler',
2310 'formatter' : 'form1',
2311 'level' : 'NTOSET',
2312 'stream' : 'ext://sys.stdout',
2313 },
2314 },
2315 'loggers' : {
2316 'compiler.parser' : {
2317 'level' : 'DEBUG',
2318 'handlers' : ['hand1'],
2319 },
2320 },
2321 'root' : {
2322 'level' : 'WARNING',
2323 },
2324 }
2325
2326
Mike53f7a7c2017-12-14 14:04:53 +03002327 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002328 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002329 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002330 'formatters': {
2331 'form1' : {
2332 'format' : '%(levelname)s ++ %(message)s',
2333 },
2334 },
2335 'handlers' : {
2336 'hand1' : {
2337 'class' : 'logging.StreamHandler',
2338 'formatter' : 'form1',
2339 'level' : 'NOTSET',
2340 'stream' : 'ext://sys.stdout',
2341 },
2342 },
2343 'loggers' : {
2344 'compiler.parser' : {
2345 'level' : 'DEBUG',
2346 'handlers' : ['hand1'],
2347 },
2348 },
2349 'root' : {
2350 'level' : 'WRANING',
2351 },
2352 }
2353
2354 # config3 has a less subtle configuration error
2355 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002356 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002357 'formatters': {
2358 'form1' : {
2359 'format' : '%(levelname)s ++ %(message)s',
2360 },
2361 },
2362 'handlers' : {
2363 'hand1' : {
2364 'class' : 'logging.StreamHandler',
2365 'formatter' : 'misspelled_name',
2366 'level' : 'NOTSET',
2367 'stream' : 'ext://sys.stdout',
2368 },
2369 },
2370 'loggers' : {
2371 'compiler.parser' : {
2372 'level' : 'DEBUG',
2373 'handlers' : ['hand1'],
2374 },
2375 },
2376 'root' : {
2377 'level' : 'WARNING',
2378 },
2379 }
2380
2381 # config4 specifies a custom formatter class to be loaded
2382 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002383 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002384 'formatters': {
2385 'form1' : {
2386 '()' : __name__ + '.ExceptionFormatter',
2387 'format' : '%(levelname)s:%(name)s:%(message)s',
2388 },
2389 },
2390 'handlers' : {
2391 'hand1' : {
2392 'class' : 'logging.StreamHandler',
2393 'formatter' : 'form1',
2394 'level' : 'NOTSET',
2395 'stream' : 'ext://sys.stdout',
2396 },
2397 },
2398 'root' : {
2399 'level' : 'NOTSET',
2400 'handlers' : ['hand1'],
2401 },
2402 }
2403
2404 # As config4 but using an actual callable rather than a string
2405 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002406 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002407 'formatters': {
2408 'form1' : {
2409 '()' : ExceptionFormatter,
2410 'format' : '%(levelname)s:%(name)s:%(message)s',
2411 },
2412 'form2' : {
2413 '()' : __name__ + '.formatFunc',
2414 'format' : '%(levelname)s:%(name)s:%(message)s',
2415 },
2416 'form3' : {
2417 '()' : formatFunc,
2418 'format' : '%(levelname)s:%(name)s:%(message)s',
2419 },
2420 },
2421 'handlers' : {
2422 'hand1' : {
2423 'class' : 'logging.StreamHandler',
2424 'formatter' : 'form1',
2425 'level' : 'NOTSET',
2426 'stream' : 'ext://sys.stdout',
2427 },
2428 'hand2' : {
2429 '()' : handlerFunc,
2430 },
2431 },
2432 'root' : {
2433 'level' : 'NOTSET',
2434 'handlers' : ['hand1'],
2435 },
2436 }
2437
2438 # config5 specifies a custom handler class to be loaded
2439 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002440 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002441 'formatters': {
2442 'form1' : {
2443 'format' : '%(levelname)s ++ %(message)s',
2444 },
2445 },
2446 'handlers' : {
2447 'hand1' : {
2448 'class' : __name__ + '.CustomHandler',
2449 'formatter' : 'form1',
2450 'level' : 'NOTSET',
2451 'stream' : 'ext://sys.stdout',
2452 },
2453 },
2454 'loggers' : {
2455 'compiler.parser' : {
2456 'level' : 'DEBUG',
2457 'handlers' : ['hand1'],
2458 },
2459 },
2460 'root' : {
2461 'level' : 'WARNING',
2462 },
2463 }
2464
2465 # config6 specifies a custom handler class to be loaded
2466 # but has bad arguments
2467 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002468 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002469 'formatters': {
2470 'form1' : {
2471 'format' : '%(levelname)s ++ %(message)s',
2472 },
2473 },
2474 'handlers' : {
2475 'hand1' : {
2476 'class' : __name__ + '.CustomHandler',
2477 'formatter' : 'form1',
2478 'level' : 'NOTSET',
2479 'stream' : 'ext://sys.stdout',
2480 '9' : 'invalid parameter name',
2481 },
2482 },
2483 'loggers' : {
2484 'compiler.parser' : {
2485 'level' : 'DEBUG',
2486 'handlers' : ['hand1'],
2487 },
2488 },
2489 'root' : {
2490 'level' : 'WARNING',
2491 },
2492 }
2493
Mike53f7a7c2017-12-14 14:04:53 +03002494 # config 7 does not define compiler.parser but defines compiler.lexer
2495 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002496 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002497 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002498 'formatters': {
2499 'form1' : {
2500 'format' : '%(levelname)s ++ %(message)s',
2501 },
2502 },
2503 'handlers' : {
2504 'hand1' : {
2505 'class' : 'logging.StreamHandler',
2506 'formatter' : 'form1',
2507 'level' : 'NOTSET',
2508 'stream' : 'ext://sys.stdout',
2509 },
2510 },
2511 'loggers' : {
2512 'compiler.lexer' : {
2513 'level' : 'DEBUG',
2514 'handlers' : ['hand1'],
2515 },
2516 },
2517 'root' : {
2518 'level' : 'WARNING',
2519 },
2520 }
2521
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002522 # config8 defines both compiler and compiler.lexer
2523 # so compiler.parser should not be disabled (since
2524 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002525 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002526 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002527 'disable_existing_loggers' : False,
2528 'formatters': {
2529 'form1' : {
2530 'format' : '%(levelname)s ++ %(message)s',
2531 },
2532 },
2533 'handlers' : {
2534 'hand1' : {
2535 'class' : 'logging.StreamHandler',
2536 'formatter' : 'form1',
2537 'level' : 'NOTSET',
2538 'stream' : 'ext://sys.stdout',
2539 },
2540 },
2541 'loggers' : {
2542 'compiler' : {
2543 'level' : 'DEBUG',
2544 'handlers' : ['hand1'],
2545 },
2546 'compiler.lexer' : {
2547 },
2548 },
2549 'root' : {
2550 'level' : 'WARNING',
2551 },
2552 }
2553
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002554 # config8a disables existing loggers
2555 config8a = {
2556 'version': 1,
2557 'disable_existing_loggers' : True,
2558 'formatters': {
2559 'form1' : {
2560 'format' : '%(levelname)s ++ %(message)s',
2561 },
2562 },
2563 'handlers' : {
2564 'hand1' : {
2565 'class' : 'logging.StreamHandler',
2566 'formatter' : 'form1',
2567 'level' : 'NOTSET',
2568 'stream' : 'ext://sys.stdout',
2569 },
2570 },
2571 'loggers' : {
2572 'compiler' : {
2573 'level' : 'DEBUG',
2574 'handlers' : ['hand1'],
2575 },
2576 'compiler.lexer' : {
2577 },
2578 },
2579 'root' : {
2580 'level' : 'WARNING',
2581 },
2582 }
2583
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002584 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002585 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002586 'formatters': {
2587 'form1' : {
2588 'format' : '%(levelname)s ++ %(message)s',
2589 },
2590 },
2591 'handlers' : {
2592 'hand1' : {
2593 'class' : 'logging.StreamHandler',
2594 'formatter' : 'form1',
2595 'level' : 'WARNING',
2596 'stream' : 'ext://sys.stdout',
2597 },
2598 },
2599 'loggers' : {
2600 'compiler.parser' : {
2601 'level' : 'WARNING',
2602 'handlers' : ['hand1'],
2603 },
2604 },
2605 'root' : {
2606 'level' : 'NOTSET',
2607 },
2608 }
2609
2610 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002611 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002612 'incremental' : True,
2613 'handlers' : {
2614 'hand1' : {
2615 'level' : 'WARNING',
2616 },
2617 },
2618 'loggers' : {
2619 'compiler.parser' : {
2620 'level' : 'INFO',
2621 },
2622 },
2623 }
2624
2625 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002626 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002627 'incremental' : True,
2628 'handlers' : {
2629 'hand1' : {
2630 'level' : 'INFO',
2631 },
2632 },
2633 'loggers' : {
2634 'compiler.parser' : {
2635 'level' : 'INFO',
2636 },
2637 },
2638 }
2639
Mike53f7a7c2017-12-14 14:04:53 +03002640 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002641 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002642 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002643 'formatters': {
2644 'form1' : {
2645 'format' : '%(levelname)s ++ %(message)s',
2646 },
2647 },
2648 'filters' : {
2649 'filt1' : {
2650 'name' : 'compiler.parser',
2651 },
2652 },
2653 'handlers' : {
2654 'hand1' : {
2655 'class' : 'logging.StreamHandler',
2656 'formatter' : 'form1',
2657 'level' : 'NOTSET',
2658 'stream' : 'ext://sys.stdout',
2659 'filters' : ['filt1'],
2660 },
2661 },
2662 'loggers' : {
2663 'compiler.parser' : {
2664 'level' : 'DEBUG',
2665 'filters' : ['filt1'],
2666 },
2667 },
2668 'root' : {
2669 'level' : 'WARNING',
2670 'handlers' : ['hand1'],
2671 },
2672 }
2673
Mike53f7a7c2017-12-14 14:04:53 +03002674 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002675 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002676 'version': 1,
2677 'true_formatters': {
2678 'form1' : {
2679 'format' : '%(levelname)s ++ %(message)s',
2680 },
2681 },
2682 'handler_configs': {
2683 'hand1' : {
2684 'class' : 'logging.StreamHandler',
2685 'formatter' : 'form1',
2686 'level' : 'NOTSET',
2687 'stream' : 'ext://sys.stdout',
2688 },
2689 },
2690 'formatters' : 'cfg://true_formatters',
2691 'handlers' : {
2692 'hand1' : 'cfg://handler_configs[hand1]',
2693 },
2694 'loggers' : {
2695 'compiler.parser' : {
2696 'level' : 'DEBUG',
2697 'handlers' : ['hand1'],
2698 },
2699 },
2700 'root' : {
2701 'level' : 'WARNING',
2702 },
2703 }
2704
Mike53f7a7c2017-12-14 14:04:53 +03002705 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002706 config12 = {
2707 'true_formatters': {
2708 'form1' : {
2709 'format' : '%(levelname)s ++ %(message)s',
2710 },
2711 },
2712 'handler_configs': {
2713 'hand1' : {
2714 'class' : 'logging.StreamHandler',
2715 'formatter' : 'form1',
2716 'level' : 'NOTSET',
2717 'stream' : 'ext://sys.stdout',
2718 },
2719 },
2720 'formatters' : 'cfg://true_formatters',
2721 'handlers' : {
2722 'hand1' : 'cfg://handler_configs[hand1]',
2723 },
2724 'loggers' : {
2725 'compiler.parser' : {
2726 'level' : 'DEBUG',
2727 'handlers' : ['hand1'],
2728 },
2729 },
2730 'root' : {
2731 'level' : 'WARNING',
2732 },
2733 }
2734
Mike53f7a7c2017-12-14 14:04:53 +03002735 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002736 config13 = {
2737 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002738 'true_formatters': {
2739 'form1' : {
2740 'format' : '%(levelname)s ++ %(message)s',
2741 },
2742 },
2743 'handler_configs': {
2744 'hand1' : {
2745 'class' : 'logging.StreamHandler',
2746 'formatter' : 'form1',
2747 'level' : 'NOTSET',
2748 'stream' : 'ext://sys.stdout',
2749 },
2750 },
2751 'formatters' : 'cfg://true_formatters',
2752 'handlers' : {
2753 'hand1' : 'cfg://handler_configs[hand1]',
2754 },
2755 'loggers' : {
2756 'compiler.parser' : {
2757 'level' : 'DEBUG',
2758 'handlers' : ['hand1'],
2759 },
2760 },
2761 'root' : {
2762 'level' : 'WARNING',
2763 },
2764 }
2765
Vinay Sajip8d270232012-11-15 14:20:18 +00002766 # As config0, but with properties
2767 config14 = {
2768 'version': 1,
2769 'formatters': {
2770 'form1' : {
2771 'format' : '%(levelname)s ++ %(message)s',
2772 },
2773 },
2774 'handlers' : {
2775 'hand1' : {
2776 'class' : 'logging.StreamHandler',
2777 'formatter' : 'form1',
2778 'level' : 'NOTSET',
2779 'stream' : 'ext://sys.stdout',
2780 '.': {
2781 'foo': 'bar',
2782 'terminator': '!\n',
2783 }
2784 },
2785 },
2786 'root' : {
2787 'level' : 'WARNING',
2788 'handlers' : ['hand1'],
2789 },
2790 }
2791
Vinay Sajip3f885b52013-03-22 15:19:54 +00002792 out_of_order = {
2793 "version": 1,
2794 "formatters": {
2795 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002796 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2797 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002798 }
2799 },
2800 "handlers": {
2801 "fileGlobal": {
2802 "class": "logging.StreamHandler",
2803 "level": "DEBUG",
2804 "formatter": "mySimpleFormatter"
2805 },
2806 "bufferGlobal": {
2807 "class": "logging.handlers.MemoryHandler",
2808 "capacity": 5,
2809 "formatter": "mySimpleFormatter",
2810 "target": "fileGlobal",
2811 "level": "DEBUG"
2812 }
2813 },
2814 "loggers": {
2815 "mymodule": {
2816 "level": "DEBUG",
2817 "handlers": ["bufferGlobal"],
2818 "propagate": "true"
2819 }
2820 }
2821 }
2822
BNMetrics18fb1fb2018-10-15 19:41:36 +01002823 # Configuration with custom logging.Formatter subclass as '()' key and 'validate' set to False
2824 custom_formatter_class_validate = {
2825 'version': 1,
2826 'formatters': {
2827 'form1': {
2828 '()': __name__ + '.ExceptionFormatter',
2829 'format': '%(levelname)s:%(name)s:%(message)s',
2830 'validate': False,
2831 },
2832 },
2833 'handlers' : {
2834 'hand1' : {
2835 'class': 'logging.StreamHandler',
2836 'formatter': 'form1',
2837 'level': 'NOTSET',
2838 'stream': 'ext://sys.stdout',
2839 },
2840 },
2841 "loggers": {
2842 "my_test_logger_custom_formatter": {
2843 "level": "DEBUG",
2844 "handlers": ["hand1"],
2845 "propagate": "true"
2846 }
2847 }
2848 }
2849
2850 # Configuration with custom logging.Formatter subclass as 'class' key and 'validate' set to False
2851 custom_formatter_class_validate2 = {
2852 'version': 1,
2853 'formatters': {
2854 'form1': {
2855 'class': __name__ + '.ExceptionFormatter',
2856 'format': '%(levelname)s:%(name)s:%(message)s',
2857 'validate': False,
2858 },
2859 },
2860 'handlers' : {
2861 'hand1' : {
2862 'class': 'logging.StreamHandler',
2863 'formatter': 'form1',
2864 'level': 'NOTSET',
2865 'stream': 'ext://sys.stdout',
2866 },
2867 },
2868 "loggers": {
2869 "my_test_logger_custom_formatter": {
2870 "level": "DEBUG",
2871 "handlers": ["hand1"],
2872 "propagate": "true"
2873 }
2874 }
2875 }
2876
2877 # Configuration with custom class that is not inherited from logging.Formatter
2878 custom_formatter_class_validate3 = {
2879 'version': 1,
2880 'formatters': {
2881 'form1': {
2882 'class': __name__ + '.myCustomFormatter',
2883 'format': '%(levelname)s:%(name)s:%(message)s',
2884 'validate': False,
2885 },
2886 },
2887 'handlers' : {
2888 'hand1' : {
2889 'class': 'logging.StreamHandler',
2890 'formatter': 'form1',
2891 'level': 'NOTSET',
2892 'stream': 'ext://sys.stdout',
2893 },
2894 },
2895 "loggers": {
2896 "my_test_logger_custom_formatter": {
2897 "level": "DEBUG",
2898 "handlers": ["hand1"],
2899 "propagate": "true"
2900 }
2901 }
2902 }
2903
2904 # Configuration with custom function and 'validate' set to False
2905 custom_formatter_with_function = {
2906 'version': 1,
2907 'formatters': {
2908 'form1': {
2909 '()': formatFunc,
2910 'format': '%(levelname)s:%(name)s:%(message)s',
2911 'validate': False,
2912 },
2913 },
2914 'handlers' : {
2915 'hand1' : {
2916 'class': 'logging.StreamHandler',
2917 'formatter': 'form1',
2918 'level': 'NOTSET',
2919 'stream': 'ext://sys.stdout',
2920 },
2921 },
2922 "loggers": {
2923 "my_test_logger_custom_formatter": {
2924 "level": "DEBUG",
2925 "handlers": ["hand1"],
2926 "propagate": "true"
2927 }
2928 }
2929 }
2930
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002931 def apply_config(self, conf):
2932 logging.config.dictConfig(conf)
2933
2934 def test_config0_ok(self):
2935 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002936 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002937 self.apply_config(self.config0)
2938 logger = logging.getLogger()
2939 # Won't output anything
2940 logger.info(self.next_message())
2941 # Outputs a message
2942 logger.error(self.next_message())
2943 self.assert_log_lines([
2944 ('ERROR', '2'),
2945 ], stream=output)
2946 # Original logger output is empty.
2947 self.assert_log_lines([])
2948
2949 def test_config1_ok(self, config=config1):
2950 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002951 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002952 self.apply_config(config)
2953 logger = logging.getLogger("compiler.parser")
2954 # Both will output a message
2955 logger.info(self.next_message())
2956 logger.error(self.next_message())
2957 self.assert_log_lines([
2958 ('INFO', '1'),
2959 ('ERROR', '2'),
2960 ], stream=output)
2961 # Original logger output is empty.
2962 self.assert_log_lines([])
2963
2964 def test_config2_failure(self):
2965 # A simple config which overrides the default settings.
2966 self.assertRaises(Exception, self.apply_config, self.config2)
2967
2968 def test_config2a_failure(self):
2969 # A simple config which overrides the default settings.
2970 self.assertRaises(Exception, self.apply_config, self.config2a)
2971
2972 def test_config2b_failure(self):
2973 # A simple config which overrides the default settings.
2974 self.assertRaises(Exception, self.apply_config, self.config2b)
2975
2976 def test_config3_failure(self):
2977 # A simple config which overrides the default settings.
2978 self.assertRaises(Exception, self.apply_config, self.config3)
2979
2980 def test_config4_ok(self):
2981 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002982 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002983 self.apply_config(self.config4)
2984 #logger = logging.getLogger()
2985 try:
2986 raise RuntimeError()
2987 except RuntimeError:
2988 logging.exception("just testing")
2989 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002990 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002991 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2992 # Original logger output is empty
2993 self.assert_log_lines([])
2994
2995 def test_config4a_ok(self):
2996 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002997 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002998 self.apply_config(self.config4a)
2999 #logger = logging.getLogger()
3000 try:
3001 raise RuntimeError()
3002 except RuntimeError:
3003 logging.exception("just testing")
3004 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00003005 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003006 "ERROR:root:just testing\nGot a [RuntimeError]\n")
3007 # Original logger output is empty
3008 self.assert_log_lines([])
3009
3010 def test_config5_ok(self):
3011 self.test_config1_ok(config=self.config5)
3012
3013 def test_config6_failure(self):
3014 self.assertRaises(Exception, self.apply_config, self.config6)
3015
3016 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003017 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003018 self.apply_config(self.config1)
3019 logger = logging.getLogger("compiler.parser")
3020 # Both will output a message
3021 logger.info(self.next_message())
3022 logger.error(self.next_message())
3023 self.assert_log_lines([
3024 ('INFO', '1'),
3025 ('ERROR', '2'),
3026 ], stream=output)
3027 # Original logger output is empty.
3028 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003029 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003030 self.apply_config(self.config7)
3031 logger = logging.getLogger("compiler.parser")
3032 self.assertTrue(logger.disabled)
3033 logger = logging.getLogger("compiler.lexer")
3034 # Both will output a message
3035 logger.info(self.next_message())
3036 logger.error(self.next_message())
3037 self.assert_log_lines([
3038 ('INFO', '3'),
3039 ('ERROR', '4'),
3040 ], stream=output)
3041 # Original logger output is empty.
3042 self.assert_log_lines([])
3043
Mike53f7a7c2017-12-14 14:04:53 +03003044 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003045 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003046 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003047 self.apply_config(self.config1)
3048 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003049 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003050 logger.info(self.next_message())
3051 logger.error(self.next_message())
3052 self.assert_log_lines([
3053 ('INFO', '1'),
3054 ('ERROR', '2'),
3055 ], stream=output)
3056 # Original logger output is empty.
3057 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003058 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003059 self.apply_config(self.config8)
3060 logger = logging.getLogger("compiler.parser")
3061 self.assertFalse(logger.disabled)
3062 # Both will output a message
3063 logger.info(self.next_message())
3064 logger.error(self.next_message())
3065 logger = logging.getLogger("compiler.lexer")
3066 # Both will output a message
3067 logger.info(self.next_message())
3068 logger.error(self.next_message())
3069 self.assert_log_lines([
3070 ('INFO', '3'),
3071 ('ERROR', '4'),
3072 ('INFO', '5'),
3073 ('ERROR', '6'),
3074 ], stream=output)
3075 # Original logger output is empty.
3076 self.assert_log_lines([])
3077
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003078 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003079 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003080 self.apply_config(self.config1a)
3081 logger = logging.getLogger("compiler.parser")
3082 # See issue #11424. compiler-hyphenated sorts
3083 # between compiler and compiler.xyz and this
3084 # was preventing compiler.xyz from being included
3085 # in the child loggers of compiler because of an
3086 # overzealous loop termination condition.
3087 hyphenated = logging.getLogger('compiler-hyphenated')
3088 # All will output a message
3089 logger.info(self.next_message())
3090 logger.error(self.next_message())
3091 hyphenated.critical(self.next_message())
3092 self.assert_log_lines([
3093 ('INFO', '1'),
3094 ('ERROR', '2'),
3095 ('CRITICAL', '3'),
3096 ], stream=output)
3097 # Original logger output is empty.
3098 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003099 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003100 self.apply_config(self.config8a)
3101 logger = logging.getLogger("compiler.parser")
3102 self.assertFalse(logger.disabled)
3103 # Both will output a message
3104 logger.info(self.next_message())
3105 logger.error(self.next_message())
3106 logger = logging.getLogger("compiler.lexer")
3107 # Both will output a message
3108 logger.info(self.next_message())
3109 logger.error(self.next_message())
3110 # Will not appear
3111 hyphenated.critical(self.next_message())
3112 self.assert_log_lines([
3113 ('INFO', '4'),
3114 ('ERROR', '5'),
3115 ('INFO', '6'),
3116 ('ERROR', '7'),
3117 ], stream=output)
3118 # Original logger output is empty.
3119 self.assert_log_lines([])
3120
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003121 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003122 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003123 self.apply_config(self.config9)
3124 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03003125 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003126 logger.info(self.next_message())
3127 self.assert_log_lines([], stream=output)
3128 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03003129 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003130 logger.info(self.next_message())
3131 self.assert_log_lines([], stream=output)
3132 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03003133 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003134 logger.info(self.next_message())
3135 self.assert_log_lines([
3136 ('INFO', '3'),
3137 ], stream=output)
3138
3139 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003140 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003141 self.apply_config(self.config10)
3142 logger = logging.getLogger("compiler.parser")
3143 logger.warning(self.next_message())
3144 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003145 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003146 logger.warning(self.next_message())
3147 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003148 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003149 logger.warning(self.next_message())
3150 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003151 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003152 logger.error(self.next_message())
3153 self.assert_log_lines([
3154 ('WARNING', '1'),
3155 ('ERROR', '4'),
3156 ], stream=output)
3157
3158 def test_config11_ok(self):
3159 self.test_config1_ok(self.config11)
3160
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003161 def test_config12_failure(self):
3162 self.assertRaises(Exception, self.apply_config, self.config12)
3163
3164 def test_config13_failure(self):
3165 self.assertRaises(Exception, self.apply_config, self.config13)
3166
Vinay Sajip8d270232012-11-15 14:20:18 +00003167 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003168 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00003169 self.apply_config(self.config14)
3170 h = logging._handlers['hand1']
3171 self.assertEqual(h.foo, 'bar')
3172 self.assertEqual(h.terminator, '!\n')
3173 logging.warning('Exclamation')
3174 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
3175
Xtreak087570a2018-07-02 14:27:46 +05303176 def test_config15_ok(self):
3177
3178 def cleanup(h1, fn):
3179 h1.close()
3180 os.remove(fn)
3181
3182 with self.check_no_resource_warning():
3183 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
3184 os.close(fd)
3185
3186 config = {
3187 "version": 1,
3188 "handlers": {
3189 "file": {
3190 "class": "logging.FileHandler",
3191 "filename": fn
3192 }
3193 },
3194 "root": {
3195 "handlers": ["file"]
3196 }
3197 }
3198
3199 self.apply_config(config)
3200 self.apply_config(config)
3201
3202 handler = logging.root.handlers[0]
3203 self.addCleanup(cleanup, handler, fn)
3204
Vinay Sajip4ded5512012-10-02 15:56:16 +01003205 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003206 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00003207 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01003208 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003209 t.start()
3210 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00003211 # Now get the port allocated
3212 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003213 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003214 try:
3215 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3216 sock.settimeout(2.0)
3217 sock.connect(('localhost', port))
3218
3219 slen = struct.pack('>L', len(text))
3220 s = slen + text
3221 sentsofar = 0
3222 left = len(s)
3223 while left > 0:
3224 sent = sock.send(s[sentsofar:])
3225 sentsofar += sent
3226 left -= sent
3227 sock.close()
3228 finally:
3229 t.ready.wait(2.0)
3230 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07003231 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003232
3233 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003234 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003235 self.setup_via_listener(json.dumps(self.config10))
3236 logger = logging.getLogger("compiler.parser")
3237 logger.warning(self.next_message())
3238 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003239 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003240 logger.warning(self.next_message())
3241 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003242 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003243 logger.warning(self.next_message())
3244 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003245 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003246 logger.error(self.next_message())
3247 self.assert_log_lines([
3248 ('WARNING', '1'),
3249 ('ERROR', '4'),
3250 ], stream=output)
3251
3252 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003253 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003254 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
3255 logger = logging.getLogger("compiler.parser")
3256 # Both will output a message
3257 logger.info(self.next_message())
3258 logger.error(self.next_message())
3259 self.assert_log_lines([
3260 ('INFO', '1'),
3261 ('ERROR', '2'),
3262 ], stream=output)
3263 # Original logger output is empty.
3264 self.assert_log_lines([])
3265
Vinay Sajip4ded5512012-10-02 15:56:16 +01003266 def test_listen_verify(self):
3267
3268 def verify_fail(stuff):
3269 return None
3270
3271 def verify_reverse(stuff):
3272 return stuff[::-1]
3273
3274 logger = logging.getLogger("compiler.parser")
3275 to_send = textwrap.dedent(ConfigFileTest.config1)
3276 # First, specify a verification function that will fail.
3277 # We expect to see no output, since our configuration
3278 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01003279 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003280 self.setup_via_listener(to_send, verify_fail)
3281 # Both will output a message
3282 logger.info(self.next_message())
3283 logger.error(self.next_message())
3284 self.assert_log_lines([], stream=output)
3285 # Original logger output has the stuff we logged.
3286 self.assert_log_lines([
3287 ('INFO', '1'),
3288 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003289 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003290
3291 # Now, perform no verification. Our configuration
3292 # should take effect.
3293
Vinay Sajip1feedb42014-05-31 08:19:12 +01003294 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003295 self.setup_via_listener(to_send) # no verify callable specified
3296 logger = logging.getLogger("compiler.parser")
3297 # Both will output a message
3298 logger.info(self.next_message())
3299 logger.error(self.next_message())
3300 self.assert_log_lines([
3301 ('INFO', '3'),
3302 ('ERROR', '4'),
3303 ], stream=output)
3304 # Original logger output still has the stuff we logged before.
3305 self.assert_log_lines([
3306 ('INFO', '1'),
3307 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003308 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003309
3310 # Now, perform verification which transforms the bytes.
3311
Vinay Sajip1feedb42014-05-31 08:19:12 +01003312 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003313 self.setup_via_listener(to_send[::-1], verify_reverse)
3314 logger = logging.getLogger("compiler.parser")
3315 # Both will output a message
3316 logger.info(self.next_message())
3317 logger.error(self.next_message())
3318 self.assert_log_lines([
3319 ('INFO', '5'),
3320 ('ERROR', '6'),
3321 ], stream=output)
3322 # Original logger output still has the stuff we logged before.
3323 self.assert_log_lines([
3324 ('INFO', '1'),
3325 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003326 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003327
Vinay Sajip3f885b52013-03-22 15:19:54 +00003328 def test_out_of_order(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01003329 self.assertRaises(ValueError, self.apply_config, self.out_of_order)
3330
3331 def test_out_of_order_with_dollar_style(self):
Pablo Galindo137b0632018-10-16 15:17:57 +01003332 config = copy.deepcopy(self.out_of_order)
BNMetrics18fb1fb2018-10-15 19:41:36 +01003333 config['formatters']['mySimpleFormatter']['format'] = "${asctime} (${name}) ${levelname}: ${message}"
3334
3335 self.apply_config(config)
Vinay Sajip3f885b52013-03-22 15:19:54 +00003336 handler = logging.getLogger('mymodule').handlers[0]
3337 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003338 self.assertIsInstance(handler.formatter._style,
3339 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003340
BNMetrics18fb1fb2018-10-15 19:41:36 +01003341 def test_custom_formatter_class_with_validate(self):
3342 self.apply_config(self.custom_formatter_class_validate)
3343 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3344 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3345
3346 def test_custom_formatter_class_with_validate2(self):
3347 self.apply_config(self.custom_formatter_class_validate2)
3348 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3349 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3350
3351 def test_custom_formatter_class_with_validate2_with_wrong_fmt(self):
3352 config = self.custom_formatter_class_validate.copy()
3353 config['formatters']['form1']['style'] = "$"
3354
3355 # Exception should not be raise as we have configured 'validate' to False
3356 self.apply_config(config)
3357 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3358 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3359
3360 def test_custom_formatter_class_with_validate3(self):
3361 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_class_validate3)
3362
3363 def test_custom_formatter_function_with_validate(self):
3364 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_function)
3365
Vinay Sajip373baef2011-04-26 20:05:24 +01003366 def test_baseconfig(self):
3367 d = {
3368 'atuple': (1, 2, 3),
3369 'alist': ['a', 'b', 'c'],
3370 'adict': {'d': 'e', 'f': 3 },
3371 'nest1': ('g', ('h', 'i'), 'j'),
3372 'nest2': ['k', ['l', 'm'], 'n'],
3373 'nest3': ['o', 'cfg://alist', 'p'],
3374 }
3375 bc = logging.config.BaseConfigurator(d)
3376 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3377 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3378 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3379 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3380 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3381 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3382 v = bc.convert('cfg://nest3')
3383 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3384 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3385 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3386 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003387
3388class ManagerTest(BaseTest):
3389 def test_manager_loggerclass(self):
3390 logged = []
3391
3392 class MyLogger(logging.Logger):
3393 def _log(self, level, msg, args, exc_info=None, extra=None):
3394 logged.append(msg)
3395
3396 man = logging.Manager(None)
3397 self.assertRaises(TypeError, man.setLoggerClass, int)
3398 man.setLoggerClass(MyLogger)
3399 logger = man.getLogger('test')
3400 logger.warning('should appear in logged')
3401 logging.warning('should not appear in logged')
3402
3403 self.assertEqual(logged, ['should appear in logged'])
3404
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003405 def test_set_log_record_factory(self):
3406 man = logging.Manager(None)
3407 expected = object()
3408 man.setLogRecordFactory(expected)
3409 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003410
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003411class ChildLoggerTest(BaseTest):
3412 def test_child_loggers(self):
3413 r = logging.getLogger()
3414 l1 = logging.getLogger('abc')
3415 l2 = logging.getLogger('def.ghi')
3416 c1 = r.getChild('xyz')
3417 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003418 self.assertIs(c1, logging.getLogger('xyz'))
3419 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003420 c1 = l1.getChild('def')
3421 c2 = c1.getChild('ghi')
3422 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003423 self.assertIs(c1, logging.getLogger('abc.def'))
3424 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3425 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003426
3427
Vinay Sajip6fac8172010-10-19 20:44:14 +00003428class DerivedLogRecord(logging.LogRecord):
3429 pass
3430
Vinay Sajip61561522010-12-03 11:50:38 +00003431class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003432
3433 def setUp(self):
3434 class CheckingFilter(logging.Filter):
3435 def __init__(self, cls):
3436 self.cls = cls
3437
3438 def filter(self, record):
3439 t = type(record)
3440 if t is not self.cls:
3441 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3442 self.cls)
3443 raise TypeError(msg)
3444 return True
3445
3446 BaseTest.setUp(self)
3447 self.filter = CheckingFilter(DerivedLogRecord)
3448 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003449 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003450
3451 def tearDown(self):
3452 self.root_logger.removeFilter(self.filter)
3453 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003454 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003455
3456 def test_logrecord_class(self):
3457 self.assertRaises(TypeError, self.root_logger.warning,
3458 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003459 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003460 self.root_logger.error(self.next_message())
3461 self.assert_log_lines([
3462 ('root', 'ERROR', '2'),
3463 ])
3464
3465
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003466class QueueHandlerTest(BaseTest):
3467 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003468 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003469
3470 def setUp(self):
3471 BaseTest.setUp(self)
3472 self.queue = queue.Queue(-1)
3473 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003474 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003475 self.que_logger = logging.getLogger('que')
3476 self.que_logger.propagate = False
3477 self.que_logger.setLevel(logging.WARNING)
3478 self.que_logger.addHandler(self.que_hdlr)
3479
3480 def tearDown(self):
3481 self.que_hdlr.close()
3482 BaseTest.tearDown(self)
3483
3484 def test_queue_handler(self):
3485 self.que_logger.debug(self.next_message())
3486 self.assertRaises(queue.Empty, self.queue.get_nowait)
3487 self.que_logger.info(self.next_message())
3488 self.assertRaises(queue.Empty, self.queue.get_nowait)
3489 msg = self.next_message()
3490 self.que_logger.warning(msg)
3491 data = self.queue.get_nowait()
3492 self.assertTrue(isinstance(data, logging.LogRecord))
3493 self.assertEqual(data.name, self.que_logger.name)
3494 self.assertEqual((data.msg, data.args), (msg, None))
3495
favlladfe3442017-08-01 20:12:26 +02003496 def test_formatting(self):
3497 msg = self.next_message()
3498 levelname = logging.getLevelName(logging.WARNING)
3499 log_format_str = '{name} -> {levelname}: {message}'
3500 formatted_msg = log_format_str.format(name=self.name,
3501 levelname=levelname, message=msg)
3502 formatter = logging.Formatter(self.log_format)
3503 self.que_hdlr.setFormatter(formatter)
3504 self.que_logger.warning(msg)
3505 log_record = self.queue.get_nowait()
3506 self.assertEqual(formatted_msg, log_record.msg)
3507 self.assertEqual(formatted_msg, log_record.message)
3508
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003509 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3510 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003511 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003512 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003513 listener = logging.handlers.QueueListener(self.queue, handler)
3514 listener.start()
3515 try:
3516 self.que_logger.warning(self.next_message())
3517 self.que_logger.error(self.next_message())
3518 self.que_logger.critical(self.next_message())
3519 finally:
3520 listener.stop()
3521 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3522 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3523 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003524 handler.close()
3525
3526 # Now test with respect_handler_level set
3527
3528 handler = support.TestHandler(support.Matcher())
3529 handler.setLevel(logging.CRITICAL)
3530 listener = logging.handlers.QueueListener(self.queue, handler,
3531 respect_handler_level=True)
3532 listener.start()
3533 try:
3534 self.que_logger.warning(self.next_message())
3535 self.que_logger.error(self.next_message())
3536 self.que_logger.critical(self.next_message())
3537 finally:
3538 listener.stop()
3539 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3540 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3541 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
Cheryl Sabellad345bb42018-09-25 19:00:08 -04003542 handler.close()
3543
3544 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3545 'logging.handlers.QueueListener required for this test')
3546 def test_queue_listener_with_StreamHandler(self):
3547 # Test that traceback only appends once (bpo-34334).
3548 listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
3549 listener.start()
3550 try:
3551 1 / 0
3552 except ZeroDivisionError as e:
3553 exc = e
3554 self.que_logger.exception(self.next_message(), exc_info=exc)
3555 listener.stop()
3556 self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
Vinay Sajip365701a2015-02-09 19:49:00 +00003557
Xtreak2dad9602019-04-07 13:21:27 +05303558 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3559 'logging.handlers.QueueListener required for this test')
3560 def test_queue_listener_with_multiple_handlers(self):
3561 # Test that queue handler format doesn't affect other handler formats (bpo-35726).
3562 self.que_hdlr.setFormatter(self.root_formatter)
3563 self.que_logger.addHandler(self.root_hdlr)
3564
3565 listener = logging.handlers.QueueListener(self.queue, self.que_hdlr)
3566 listener.start()
3567 self.que_logger.error("error")
3568 listener.stop()
3569 self.assertEqual(self.stream.getvalue().strip(), "que -> ERROR: error")
3570
Vinay Sajipd61910c2016-09-08 01:13:39 +01003571if hasattr(logging.handlers, 'QueueListener'):
3572 import multiprocessing
3573 from unittest.mock import patch
3574
3575 class QueueListenerTest(BaseTest):
3576 """
3577 Tests based on patch submitted for issue #27930. Ensure that
3578 QueueListener handles all log messages.
3579 """
3580
3581 repeat = 20
3582
3583 @staticmethod
3584 def setup_and_log(log_queue, ident):
3585 """
3586 Creates a logger with a QueueHandler that logs to a queue read by a
3587 QueueListener. Starts the listener, logs five messages, and stops
3588 the listener.
3589 """
3590 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3591 logger.setLevel(logging.DEBUG)
3592 handler = logging.handlers.QueueHandler(log_queue)
3593 logger.addHandler(handler)
3594 listener = logging.handlers.QueueListener(log_queue)
3595 listener.start()
3596
3597 logger.info('one')
3598 logger.info('two')
3599 logger.info('three')
3600 logger.info('four')
3601 logger.info('five')
3602
3603 listener.stop()
3604 logger.removeHandler(handler)
3605 handler.close()
3606
3607 @patch.object(logging.handlers.QueueListener, 'handle')
3608 def test_handle_called_with_queue_queue(self, mock_handle):
3609 for i in range(self.repeat):
3610 log_queue = queue.Queue()
3611 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3612 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3613 'correct number of handled log messages')
3614
3615 @patch.object(logging.handlers.QueueListener, 'handle')
3616 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003617 # Issue 28668: The multiprocessing (mp) module is not functional
3618 # when the mp.synchronize module cannot be imported.
3619 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003620 for i in range(self.repeat):
3621 log_queue = multiprocessing.Queue()
3622 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003623 log_queue.close()
3624 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003625 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3626 'correct number of handled log messages')
3627
3628 @staticmethod
3629 def get_all_from_queue(log_queue):
3630 try:
3631 while True:
3632 yield log_queue.get_nowait()
3633 except queue.Empty:
3634 return []
3635
3636 def test_no_messages_in_queue_after_stop(self):
3637 """
3638 Five messages are logged then the QueueListener is stopped. This
3639 test then gets everything off the queue. Failure of this test
3640 indicates that messages were not registered on the queue until
3641 _after_ the QueueListener stopped.
3642 """
xdegayebf2b65e2017-12-01 08:08:49 +01003643 # Issue 28668: The multiprocessing (mp) module is not functional
3644 # when the mp.synchronize module cannot be imported.
3645 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003646 for i in range(self.repeat):
3647 queue = multiprocessing.Queue()
3648 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3649 # time.sleep(1)
3650 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003651 queue.close()
3652 queue.join_thread()
3653
Vinay Sajipd61910c2016-09-08 01:13:39 +01003654 expected = [[], [logging.handlers.QueueListener._sentinel]]
3655 self.assertIn(items, expected,
3656 'Found unexpected messages in queue: %s' % (
3657 [m.msg if isinstance(m, logging.LogRecord)
3658 else m for m in items]))
3659
Bar Harel6b282e12019-06-01 12:19:09 +03003660 def test_calls_task_done_after_stop(self):
3661 # Issue 36813: Make sure queue.join does not deadlock.
3662 log_queue = queue.Queue()
3663 listener = logging.handlers.QueueListener(log_queue)
3664 listener.start()
3665 listener.stop()
3666 with self.assertRaises(ValueError):
3667 # Make sure all tasks are done and .join won't block.
3668 log_queue.task_done()
3669
Vinay Sajipe723e962011-04-15 22:27:17 +01003670
Vinay Sajip37eb3382011-04-26 20:26:41 +01003671ZERO = datetime.timedelta(0)
3672
3673class UTC(datetime.tzinfo):
3674 def utcoffset(self, dt):
3675 return ZERO
3676
3677 dst = utcoffset
3678
3679 def tzname(self, dt):
3680 return 'UTC'
3681
3682utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003683
Vinay Sajipa39c5712010-10-25 13:57:39 +00003684class FormatterTest(unittest.TestCase):
3685 def setUp(self):
3686 self.common = {
3687 'name': 'formatter.test',
3688 'level': logging.DEBUG,
3689 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3690 'lineno': 42,
3691 'exc_info': None,
3692 'func': None,
3693 'msg': 'Message with %d %s',
3694 'args': (2, 'placeholders'),
3695 }
3696 self.variants = {
3697 }
3698
3699 def get_record(self, name=None):
3700 result = dict(self.common)
3701 if name is not None:
3702 result.update(self.variants[name])
3703 return logging.makeLogRecord(result)
3704
BNMetrics18fb1fb2018-10-15 19:41:36 +01003705 def assert_error_message(self, exception, message, *args, **kwargs):
3706 try:
3707 self.assertRaises(exception, *args, **kwargs)
3708 except exception as e:
3709 self.assertEqual(message, e.message)
3710
Vinay Sajipa39c5712010-10-25 13:57:39 +00003711 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003712 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003713 r = self.get_record()
3714 f = logging.Formatter('${%(message)s}')
3715 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3716 f = logging.Formatter('%(random)s')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003717 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003718 self.assertFalse(f.usesTime())
3719 f = logging.Formatter('%(asctime)s')
3720 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003721 f = logging.Formatter('%(asctime)-15s')
3722 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003723 f = logging.Formatter('%(asctime)#15s')
3724 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003725
3726 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003727 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003728 r = self.get_record()
3729 f = logging.Formatter('$%{message}%$', style='{')
3730 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3731 f = logging.Formatter('{random}', style='{')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003732 self.assertRaises(ValueError, f.format, r)
3733 f = logging.Formatter("{message}", style='{')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003734 self.assertFalse(f.usesTime())
3735 f = logging.Formatter('{asctime}', style='{')
3736 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003737 f = logging.Formatter('{asctime!s:15}', style='{')
3738 self.assertTrue(f.usesTime())
3739 f = logging.Formatter('{asctime:15}', style='{')
3740 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003741
3742 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003743 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003744 r = self.get_record()
BNMetrics18fb1fb2018-10-15 19:41:36 +01003745 f = logging.Formatter('${message}', style='$')
3746 self.assertEqual(f.format(r), 'Message with 2 placeholders')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003747 f = logging.Formatter('$message', style='$')
3748 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3749 f = logging.Formatter('$$%${message}%$$', style='$')
3750 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3751 f = logging.Formatter('${random}', style='$')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003752 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003753 self.assertFalse(f.usesTime())
3754 f = logging.Formatter('${asctime}', style='$')
3755 self.assertTrue(f.usesTime())
3756 f = logging.Formatter('$asctime', style='$')
3757 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003758 f = logging.Formatter('${message}', style='$')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003759 self.assertFalse(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003760 f = logging.Formatter('${asctime}--', style='$')
3761 self.assertTrue(f.usesTime())
3762
3763 def test_format_validate(self):
3764 # Check correct formatting
3765 # Percentage style
3766 f = logging.Formatter("%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3767 self.assertEqual(f._fmt, "%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3768 f = logging.Formatter("%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3769 self.assertEqual(f._fmt, "%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3770 f = logging.Formatter("%(process)#+027.23X")
3771 self.assertEqual(f._fmt, "%(process)#+027.23X")
3772 f = logging.Formatter("%(foo)#.*g")
3773 self.assertEqual(f._fmt, "%(foo)#.*g")
3774
3775 # StrFormat Style
3776 f = logging.Formatter("$%{message}%$ - {asctime!a:15} - {customfield['key']}", style="{")
3777 self.assertEqual(f._fmt, "$%{message}%$ - {asctime!a:15} - {customfield['key']}")
3778 f = logging.Formatter("{process:.2f} - {custom.f:.4f}", style="{")
3779 self.assertEqual(f._fmt, "{process:.2f} - {custom.f:.4f}")
3780 f = logging.Formatter("{customfield!s:#<30}", style="{")
3781 self.assertEqual(f._fmt, "{customfield!s:#<30}")
3782 f = logging.Formatter("{message!r}", style="{")
3783 self.assertEqual(f._fmt, "{message!r}")
3784 f = logging.Formatter("{message!s}", style="{")
3785 self.assertEqual(f._fmt, "{message!s}")
3786 f = logging.Formatter("{message!a}", style="{")
3787 self.assertEqual(f._fmt, "{message!a}")
3788 f = logging.Formatter("{process!r:4.2}", style="{")
3789 self.assertEqual(f._fmt, "{process!r:4.2}")
3790 f = logging.Formatter("{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}", style="{")
3791 self.assertEqual(f._fmt, "{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}")
3792 f = logging.Formatter("{process!s:{w},.{p}}", style="{")
3793 self.assertEqual(f._fmt, "{process!s:{w},.{p}}")
3794 f = logging.Formatter("{foo:12.{p}}", style="{")
3795 self.assertEqual(f._fmt, "{foo:12.{p}}")
3796 f = logging.Formatter("{foo:{w}.6}", style="{")
3797 self.assertEqual(f._fmt, "{foo:{w}.6}")
3798 f = logging.Formatter("{foo[0].bar[1].baz}", style="{")
3799 self.assertEqual(f._fmt, "{foo[0].bar[1].baz}")
3800 f = logging.Formatter("{foo[k1].bar[k2].baz}", style="{")
3801 self.assertEqual(f._fmt, "{foo[k1].bar[k2].baz}")
3802 f = logging.Formatter("{12[k1].bar[k2].baz}", style="{")
3803 self.assertEqual(f._fmt, "{12[k1].bar[k2].baz}")
3804
3805 # Dollar style
3806 f = logging.Formatter("${asctime} - $message", style="$")
3807 self.assertEqual(f._fmt, "${asctime} - $message")
3808 f = logging.Formatter("$bar $$", style="$")
3809 self.assertEqual(f._fmt, "$bar $$")
3810 f = logging.Formatter("$bar $$$$", style="$")
3811 self.assertEqual(f._fmt, "$bar $$$$") # this would print two $($$)
3812
3813 # Testing when ValueError being raised from incorrect format
3814 # Percentage Style
3815 self.assertRaises(ValueError, logging.Formatter, "%(asctime)Z")
3816 self.assertRaises(ValueError, logging.Formatter, "%(asctime)b")
3817 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*")
3818 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*3s")
3819 self.assertRaises(ValueError, logging.Formatter, "%(asctime)_")
3820 self.assertRaises(ValueError, logging.Formatter, '{asctime}')
3821 self.assertRaises(ValueError, logging.Formatter, '${message}')
3822 self.assertRaises(ValueError, logging.Formatter, '%(foo)#12.3*f') # with both * and decimal number as precision
3823 self.assertRaises(ValueError, logging.Formatter, '%(foo)0*.8*f')
3824
3825 # StrFormat Style
3826 # Testing failure for '-' in field name
3827 self.assert_error_message(
3828 ValueError,
3829 "invalid field name/expression: 'name-thing'",
3830 logging.Formatter, "{name-thing}", style="{"
3831 )
3832 # Testing failure for style mismatch
3833 self.assert_error_message(
3834 ValueError,
3835 "invalid format: no fields",
3836 logging.Formatter, '%(asctime)s', style='{'
3837 )
3838 # Testing failure for invalid conversion
3839 self.assert_error_message(
3840 ValueError,
3841 "invalid conversion: 'Z'"
3842 )
3843 self.assertRaises(ValueError, logging.Formatter, '{asctime!s:#30,15f}', style='{')
3844 self.assert_error_message(
3845 ValueError,
3846 "invalid format: expected ':' after conversion specifier",
3847 logging.Formatter, '{asctime!aa:15}', style='{'
3848 )
3849 # Testing failure for invalid spec
3850 self.assert_error_message(
3851 ValueError,
3852 "bad specifier: '.2ff'",
3853 logging.Formatter, '{process:.2ff}', style='{'
3854 )
3855 self.assertRaises(ValueError, logging.Formatter, '{process:.2Z}', style='{')
3856 self.assertRaises(ValueError, logging.Formatter, '{process!s:<##30,12g}', style='{')
3857 self.assertRaises(ValueError, logging.Formatter, '{process!s:<#30#,12g}', style='{')
3858 self.assertRaises(ValueError, logging.Formatter, '{process!s:{{w}},{{p}}}', style='{')
3859 # Testing failure for mismatch braces
3860 self.assert_error_message(
3861 ValueError,
3862 "invalid format: unmatched '{' in format spec",
3863 logging.Formatter, '{process', style='{'
3864 )
3865 self.assert_error_message(
3866 ValueError,
3867 "invalid format: unmatched '{' in format spec",
3868 logging.Formatter, 'process}', style='{'
3869 )
3870 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}', style='{')
3871 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}}', style='{')
3872 self.assertRaises(ValueError, logging.Formatter, '{foo/bar}', style='{')
3873 self.assertRaises(ValueError, logging.Formatter, '{foo:{{w}}.{{p}}}}', style='{')
3874 self.assertRaises(ValueError, logging.Formatter, '{foo!X:{{w}}.{{p}}}', style='{')
3875 self.assertRaises(ValueError, logging.Formatter, '{foo!a:random}', style='{')
3876 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{dom}', style='{')
3877 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{d}om}', style='{')
3878 self.assertRaises(ValueError, logging.Formatter, '{foo.!a:d}', style='{')
3879
3880 # Dollar style
3881 # Testing failure for mismatch bare $
3882 self.assert_error_message(
3883 ValueError,
3884 "invalid format: bare \'$\' not allowed",
3885 logging.Formatter, '$bar $$$', style='$'
3886 )
3887 self.assert_error_message(
3888 ValueError,
3889 "invalid format: bare \'$\' not allowed",
3890 logging.Formatter, 'bar $', style='$'
3891 )
3892 self.assert_error_message(
3893 ValueError,
3894 "invalid format: bare \'$\' not allowed",
3895 logging.Formatter, 'foo $.', style='$'
3896 )
3897 # Testing failure for mismatch style
3898 self.assert_error_message(
3899 ValueError,
3900 "invalid format: no fields",
3901 logging.Formatter, '{asctime}', style='$'
3902 )
3903 self.assertRaises(ValueError, logging.Formatter, '%(asctime)s', style='$')
3904
3905 # Testing failure for incorrect fields
3906 self.assert_error_message(
3907 ValueError,
3908 "invalid format: no fields",
3909 logging.Formatter, 'foo', style='$'
3910 )
3911 self.assertRaises(ValueError, logging.Formatter, '${asctime', style='$')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003912
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003913 def test_invalid_style(self):
3914 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3915
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003916 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003917 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003918 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3919 # We use None to indicate we want the local timezone
3920 # We're essentially converting a UTC time to local time
3921 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003922 r.msecs = 123
3923 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003924 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003925 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3926 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003927 f.format(r)
3928 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3929
3930class TestBufferingFormatter(logging.BufferingFormatter):
3931 def formatHeader(self, records):
3932 return '[(%d)' % len(records)
3933
3934 def formatFooter(self, records):
3935 return '(%d)]' % len(records)
3936
3937class BufferingFormatterTest(unittest.TestCase):
3938 def setUp(self):
3939 self.records = [
3940 logging.makeLogRecord({'msg': 'one'}),
3941 logging.makeLogRecord({'msg': 'two'}),
3942 ]
3943
3944 def test_default(self):
3945 f = logging.BufferingFormatter()
3946 self.assertEqual('', f.format([]))
3947 self.assertEqual('onetwo', f.format(self.records))
3948
3949 def test_custom(self):
3950 f = TestBufferingFormatter()
3951 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3952 lf = logging.Formatter('<%(message)s>')
3953 f = TestBufferingFormatter(lf)
3954 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003955
3956class ExceptionTest(BaseTest):
3957 def test_formatting(self):
3958 r = self.root_logger
3959 h = RecordingHandler()
3960 r.addHandler(h)
3961 try:
3962 raise RuntimeError('deliberate mistake')
3963 except:
3964 logging.exception('failed', stack_info=True)
3965 r.removeHandler(h)
3966 h.close()
3967 r = h.records[0]
3968 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3969 'call last):\n'))
3970 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3971 'deliberate mistake'))
3972 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3973 'call last):\n'))
3974 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3975 'stack_info=True)'))
3976
3977
Vinay Sajip5a27d402010-12-10 11:42:57 +00003978class LastResortTest(BaseTest):
3979 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003980 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003981 root = self.root_logger
3982 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003983 old_lastresort = logging.lastResort
3984 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003985
Vinay Sajip5a27d402010-12-10 11:42:57 +00003986 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003987 with support.captured_stderr() as stderr:
3988 root.debug('This should not appear')
3989 self.assertEqual(stderr.getvalue(), '')
3990 root.warning('Final chance!')
3991 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3992
3993 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003994 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003995 with support.captured_stderr() as stderr:
3996 root.warning('Final chance!')
3997 msg = 'No handlers could be found for logger "root"\n'
3998 self.assertEqual(stderr.getvalue(), msg)
3999
Vinay Sajip5a27d402010-12-10 11:42:57 +00004000 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01004001 with support.captured_stderr() as stderr:
4002 root.warning('Final chance!')
4003 self.assertEqual(stderr.getvalue(), '')
4004
4005 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00004006 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00004007 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01004008 with support.captured_stderr() as stderr:
4009 root.warning('Final chance!')
4010 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00004011 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00004012 root.addHandler(self.root_hdlr)
4013 logging.lastResort = old_lastresort
4014 logging.raiseExceptions = old_raise_exceptions
4015
4016
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004017class FakeHandler:
4018
4019 def __init__(self, identifier, called):
4020 for method in ('acquire', 'flush', 'close', 'release'):
4021 setattr(self, method, self.record_call(identifier, method, called))
4022
4023 def record_call(self, identifier, method_name, called):
4024 def inner():
4025 called.append('{} - {}'.format(identifier, method_name))
4026 return inner
4027
4028
4029class RecordingHandler(logging.NullHandler):
4030
4031 def __init__(self, *args, **kwargs):
4032 super(RecordingHandler, self).__init__(*args, **kwargs)
4033 self.records = []
4034
4035 def handle(self, record):
4036 """Keep track of all the emitted records."""
4037 self.records.append(record)
4038
4039
4040class ShutdownTest(BaseTest):
4041
Vinay Sajip5e66b162011-04-20 15:41:14 +01004042 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004043
4044 def setUp(self):
4045 super(ShutdownTest, self).setUp()
4046 self.called = []
4047
4048 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004049 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004050
4051 def raise_error(self, error):
4052 def inner():
4053 raise error()
4054 return inner
4055
4056 def test_no_failure(self):
4057 # create some fake handlers
4058 handler0 = FakeHandler(0, self.called)
4059 handler1 = FakeHandler(1, self.called)
4060 handler2 = FakeHandler(2, self.called)
4061
4062 # create live weakref to those handlers
4063 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
4064
4065 logging.shutdown(handlerList=list(handlers))
4066
4067 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
4068 '1 - acquire', '1 - flush', '1 - close', '1 - release',
4069 '0 - acquire', '0 - flush', '0 - close', '0 - release']
4070 self.assertEqual(expected, self.called)
4071
4072 def _test_with_failure_in_method(self, method, error):
4073 handler = FakeHandler(0, self.called)
4074 setattr(handler, method, self.raise_error(error))
4075 handlers = [logging.weakref.ref(handler)]
4076
4077 logging.shutdown(handlerList=list(handlers))
4078
4079 self.assertEqual('0 - release', self.called[-1])
4080
4081 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004082 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004083
4084 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004085 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004086
4087 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004088 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004089
4090 def test_with_valueerror_in_acquire(self):
4091 self._test_with_failure_in_method('acquire', ValueError)
4092
4093 def test_with_valueerror_in_flush(self):
4094 self._test_with_failure_in_method('flush', ValueError)
4095
4096 def test_with_valueerror_in_close(self):
4097 self._test_with_failure_in_method('close', ValueError)
4098
4099 def test_with_other_error_in_acquire_without_raise(self):
4100 logging.raiseExceptions = False
4101 self._test_with_failure_in_method('acquire', IndexError)
4102
4103 def test_with_other_error_in_flush_without_raise(self):
4104 logging.raiseExceptions = False
4105 self._test_with_failure_in_method('flush', IndexError)
4106
4107 def test_with_other_error_in_close_without_raise(self):
4108 logging.raiseExceptions = False
4109 self._test_with_failure_in_method('close', IndexError)
4110
4111 def test_with_other_error_in_acquire_with_raise(self):
4112 logging.raiseExceptions = True
4113 self.assertRaises(IndexError, self._test_with_failure_in_method,
4114 'acquire', IndexError)
4115
4116 def test_with_other_error_in_flush_with_raise(self):
4117 logging.raiseExceptions = True
4118 self.assertRaises(IndexError, self._test_with_failure_in_method,
4119 'flush', IndexError)
4120
4121 def test_with_other_error_in_close_with_raise(self):
4122 logging.raiseExceptions = True
4123 self.assertRaises(IndexError, self._test_with_failure_in_method,
4124 'close', IndexError)
4125
4126
4127class ModuleLevelMiscTest(BaseTest):
4128
Vinay Sajip5e66b162011-04-20 15:41:14 +01004129 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004130
4131 def test_disable(self):
4132 old_disable = logging.root.manager.disable
4133 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004134 self.assertEqual(old_disable, 0)
4135 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004136
4137 logging.disable(83)
4138 self.assertEqual(logging.root.manager.disable, 83)
4139
Vinay Sajipd489ac92016-12-31 11:40:11 +00004140 # test the default value introduced in 3.7
4141 # (Issue #28524)
4142 logging.disable()
4143 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
4144
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004145 def _test_log(self, method, level=None):
4146 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004147 support.patch(self, logging, 'basicConfig',
4148 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004149
4150 recording = RecordingHandler()
4151 logging.root.addHandler(recording)
4152
4153 log_method = getattr(logging, method)
4154 if level is not None:
4155 log_method(level, "test me: %r", recording)
4156 else:
4157 log_method("test me: %r", recording)
4158
4159 self.assertEqual(len(recording.records), 1)
4160 record = recording.records[0]
4161 self.assertEqual(record.getMessage(), "test me: %r" % recording)
4162
4163 expected_level = level if level is not None else getattr(logging, method.upper())
4164 self.assertEqual(record.levelno, expected_level)
4165
4166 # basicConfig was not called!
4167 self.assertEqual(called, [])
4168
4169 def test_log(self):
4170 self._test_log('log', logging.ERROR)
4171
4172 def test_debug(self):
4173 self._test_log('debug')
4174
4175 def test_info(self):
4176 self._test_log('info')
4177
4178 def test_warning(self):
4179 self._test_log('warning')
4180
4181 def test_error(self):
4182 self._test_log('error')
4183
4184 def test_critical(self):
4185 self._test_log('critical')
4186
4187 def test_set_logger_class(self):
4188 self.assertRaises(TypeError, logging.setLoggerClass, object)
4189
4190 class MyLogger(logging.Logger):
4191 pass
4192
4193 logging.setLoggerClass(MyLogger)
4194 self.assertEqual(logging.getLoggerClass(), MyLogger)
4195
4196 logging.setLoggerClass(logging.Logger)
4197 self.assertEqual(logging.getLoggerClass(), logging.Logger)
4198
Vinay Sajip01500012019-06-19 11:46:53 +01004199 def test_subclass_logger_cache(self):
4200 # bpo-37258
4201 message = []
4202
4203 class MyLogger(logging.getLoggerClass()):
4204 def __init__(self, name='MyLogger', level=logging.NOTSET):
4205 super().__init__(name, level)
4206 message.append('initialized')
4207
4208 logging.setLoggerClass(MyLogger)
4209 logger = logging.getLogger('just_some_logger')
4210 self.assertEqual(message, ['initialized'])
4211 stream = io.StringIO()
4212 h = logging.StreamHandler(stream)
4213 logger.addHandler(h)
4214 try:
4215 logger.setLevel(logging.DEBUG)
4216 logger.debug("hello")
4217 self.assertEqual(stream.getvalue().strip(), "hello")
4218
4219 stream.truncate(0)
4220 stream.seek(0)
4221
4222 logger.setLevel(logging.INFO)
4223 logger.debug("hello")
4224 self.assertEqual(stream.getvalue(), "")
4225 finally:
4226 logger.removeHandler(h)
4227 h.close()
4228 logging.setLoggerClass(logging.Logger)
4229
Serhiy Storchakaa7930372016-07-03 22:27:26 +03004230 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01004231 def test_logging_at_shutdown(self):
4232 # Issue #20037
4233 code = """if 1:
4234 import logging
4235
4236 class A:
4237 def __del__(self):
4238 try:
4239 raise ValueError("some error")
4240 except Exception:
4241 logging.exception("exception in __del__")
4242
4243 a = A()"""
4244 rc, out, err = assert_python_ok("-c", code)
4245 err = err.decode()
4246 self.assertIn("exception in __del__", err)
4247 self.assertIn("ValueError: some error", err)
4248
Rémi Lapeyre65f64b12019-03-15 07:53:34 +01004249 def test_recursion_error(self):
4250 # Issue 36272
4251 code = """if 1:
4252 import logging
4253
4254 def rec():
4255 logging.error("foo")
4256 rec()
4257
4258 rec()"""
4259 rc, out, err = assert_python_failure("-c", code)
4260 err = err.decode()
4261 self.assertNotIn("Cannot recover from stack overflow.", err)
4262 self.assertEqual(rc, 1)
4263
Antoine Pitrou712cb732013-12-21 15:51:54 +01004264
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004265class LogRecordTest(BaseTest):
4266 def test_str_rep(self):
4267 r = logging.makeLogRecord({})
4268 s = str(r)
4269 self.assertTrue(s.startswith('<LogRecord: '))
4270 self.assertTrue(s.endswith('>'))
4271
4272 def test_dict_arg(self):
4273 h = RecordingHandler()
4274 r = logging.getLogger()
4275 r.addHandler(h)
4276 d = {'less' : 'more' }
4277 logging.warning('less is %(less)s', d)
4278 self.assertIs(h.records[0].args, d)
4279 self.assertEqual(h.records[0].message, 'less is more')
4280 r.removeHandler(h)
4281 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004282
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004283 def test_multiprocessing(self):
4284 r = logging.makeLogRecord({})
4285 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01004286 try:
4287 import multiprocessing as mp
4288 r = logging.makeLogRecord({})
4289 self.assertEqual(r.processName, mp.current_process().name)
4290 except ImportError:
4291 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004292
4293 def test_optional(self):
4294 r = logging.makeLogRecord({})
4295 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004296 NOT_NONE(r.thread)
4297 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004298 NOT_NONE(r.process)
4299 NOT_NONE(r.processName)
4300 log_threads = logging.logThreads
4301 log_processes = logging.logProcesses
4302 log_multiprocessing = logging.logMultiprocessing
4303 try:
4304 logging.logThreads = False
4305 logging.logProcesses = False
4306 logging.logMultiprocessing = False
4307 r = logging.makeLogRecord({})
4308 NONE = self.assertIsNone
4309 NONE(r.thread)
4310 NONE(r.threadName)
4311 NONE(r.process)
4312 NONE(r.processName)
4313 finally:
4314 logging.logThreads = log_threads
4315 logging.logProcesses = log_processes
4316 logging.logMultiprocessing = log_multiprocessing
4317
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004318class BasicConfigTest(unittest.TestCase):
4319
Vinay Sajip95bf5042011-04-20 11:50:56 +01004320 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004321
4322 def setUp(self):
4323 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01004324 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01004325 self.saved_handlers = logging._handlers.copy()
4326 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01004327 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01004328 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004329 logging.root.handlers = []
4330
4331 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01004332 for h in logging.root.handlers[:]:
4333 logging.root.removeHandler(h)
4334 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004335 super(BasicConfigTest, self).tearDown()
4336
Vinay Sajip3def7e02011-04-20 10:58:06 +01004337 def cleanup(self):
4338 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01004339 logging._handlers.clear()
4340 logging._handlers.update(self.saved_handlers)
4341 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1d094af2019-09-22 03:51:51 +01004342 logging.root.setLevel(self.original_logging_level)
Vinay Sajip3def7e02011-04-20 10:58:06 +01004343
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004344 def test_no_kwargs(self):
4345 logging.basicConfig()
4346
4347 # handler defaults to a StreamHandler to sys.stderr
4348 self.assertEqual(len(logging.root.handlers), 1)
4349 handler = logging.root.handlers[0]
4350 self.assertIsInstance(handler, logging.StreamHandler)
4351 self.assertEqual(handler.stream, sys.stderr)
4352
4353 formatter = handler.formatter
4354 # format defaults to logging.BASIC_FORMAT
4355 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
4356 # datefmt defaults to None
4357 self.assertIsNone(formatter.datefmt)
4358 # style defaults to %
4359 self.assertIsInstance(formatter._style, logging.PercentStyle)
4360
Florent Xiclunae41f0de2011-11-11 19:39:25 +01004361 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01004362 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004363
Vinay Sajip1fd12022014-01-13 21:59:56 +00004364 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004365 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004366 logging.basicConfig(stream=sys.stdout, style="{")
4367 logging.error("Log an error")
4368 sys.stdout.seek(0)
4369 self.assertEqual(output.getvalue().strip(),
4370 "ERROR:root:Log an error")
4371
4372 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004373 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004374 logging.basicConfig(stream=sys.stdout, style="$")
4375 logging.error("Log an error")
4376 sys.stdout.seek(0)
4377 self.assertEqual(output.getvalue().strip(),
4378 "ERROR:root:Log an error")
4379
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004380 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004381
4382 def cleanup(h1, h2, fn):
4383 h1.close()
4384 h2.close()
4385 os.remove(fn)
4386
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004387 logging.basicConfig(filename='test.log')
4388
4389 self.assertEqual(len(logging.root.handlers), 1)
4390 handler = logging.root.handlers[0]
4391 self.assertIsInstance(handler, logging.FileHandler)
4392
4393 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004394 self.assertEqual(handler.stream.mode, expected.stream.mode)
4395 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004396 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004397
4398 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004399
4400 def cleanup(h1, h2, fn):
4401 h1.close()
4402 h2.close()
4403 os.remove(fn)
4404
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004405 logging.basicConfig(filename='test.log', filemode='wb')
4406
4407 handler = logging.root.handlers[0]
4408 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004409 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004410 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004411
4412 def test_stream(self):
4413 stream = io.StringIO()
4414 self.addCleanup(stream.close)
4415 logging.basicConfig(stream=stream)
4416
4417 self.assertEqual(len(logging.root.handlers), 1)
4418 handler = logging.root.handlers[0]
4419 self.assertIsInstance(handler, logging.StreamHandler)
4420 self.assertEqual(handler.stream, stream)
4421
4422 def test_format(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01004423 logging.basicConfig(format='%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004424
4425 formatter = logging.root.handlers[0].formatter
BNMetrics18fb1fb2018-10-15 19:41:36 +01004426 self.assertEqual(formatter._style._fmt, '%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004427
4428 def test_datefmt(self):
4429 logging.basicConfig(datefmt='bar')
4430
4431 formatter = logging.root.handlers[0].formatter
4432 self.assertEqual(formatter.datefmt, 'bar')
4433
4434 def test_style(self):
4435 logging.basicConfig(style='$')
4436
4437 formatter = logging.root.handlers[0].formatter
4438 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
4439
4440 def test_level(self):
4441 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004442 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004443
4444 logging.basicConfig(level=57)
4445 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004446 # Test that second call has no effect
4447 logging.basicConfig(level=58)
4448 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004449
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004450 def test_incompatible(self):
4451 assertRaises = self.assertRaises
4452 handlers = [logging.StreamHandler()]
4453 stream = sys.stderr
4454 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004455 stream=stream)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004456 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004457 handlers=handlers)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004458 assertRaises(ValueError, logging.basicConfig, stream=stream,
BNMetrics18fb1fb2018-10-15 19:41:36 +01004459 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00004460 # Issue 23207: test for invalid kwargs
4461 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
4462 # Should pop both filename and filemode even if filename is None
4463 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004464
4465 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004466 handlers = [
4467 logging.StreamHandler(),
4468 logging.StreamHandler(sys.stdout),
4469 logging.StreamHandler(),
4470 ]
4471 f = logging.Formatter()
4472 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004473 logging.basicConfig(handlers=handlers)
4474 self.assertIs(handlers[0], logging.root.handlers[0])
4475 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004476 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004477 self.assertIsNotNone(handlers[0].formatter)
4478 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004479 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004480 self.assertIs(handlers[0].formatter, handlers[1].formatter)
4481
Dong-hee Nacf67d6a2018-06-25 13:11:09 +09004482 def test_force(self):
4483 old_string_io = io.StringIO()
4484 new_string_io = io.StringIO()
4485 old_handlers = [logging.StreamHandler(old_string_io)]
4486 new_handlers = [logging.StreamHandler(new_string_io)]
4487 logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
4488 logging.warning('warn')
4489 logging.info('info')
4490 logging.debug('debug')
4491 self.assertEqual(len(logging.root.handlers), 1)
4492 logging.basicConfig(level=logging.INFO, handlers=new_handlers,
4493 force=True)
4494 logging.warning('warn')
4495 logging.info('info')
4496 logging.debug('debug')
4497 self.assertEqual(len(logging.root.handlers), 1)
4498 self.assertEqual(old_string_io.getvalue().strip(),
4499 'WARNING:root:warn')
4500 self.assertEqual(new_string_io.getvalue().strip(),
4501 'WARNING:root:warn\nINFO:root:info')
4502
Vinay Sajipca7b5042019-06-17 17:40:52 +01004503 def test_encoding(self):
4504 try:
4505 encoding = 'utf-8'
4506 logging.basicConfig(filename='test.log', encoding=encoding,
4507 errors='strict',
4508 format='%(message)s', level=logging.DEBUG)
4509
4510 self.assertEqual(len(logging.root.handlers), 1)
4511 handler = logging.root.handlers[0]
4512 self.assertIsInstance(handler, logging.FileHandler)
4513 self.assertEqual(handler.encoding, encoding)
4514 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4515 finally:
4516 handler.close()
4517 with open('test.log', encoding='utf-8') as f:
4518 data = f.read().strip()
4519 os.remove('test.log')
4520 self.assertEqual(data,
4521 'The Øresund Bridge joins Copenhagen to Malmö')
4522
4523 def test_encoding_errors(self):
4524 try:
4525 encoding = 'ascii'
4526 logging.basicConfig(filename='test.log', encoding=encoding,
4527 errors='ignore',
4528 format='%(message)s', level=logging.DEBUG)
4529
4530 self.assertEqual(len(logging.root.handlers), 1)
4531 handler = logging.root.handlers[0]
4532 self.assertIsInstance(handler, logging.FileHandler)
4533 self.assertEqual(handler.encoding, encoding)
4534 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4535 finally:
4536 handler.close()
4537 with open('test.log', encoding='utf-8') as f:
4538 data = f.read().strip()
4539 os.remove('test.log')
4540 self.assertEqual(data, 'The resund Bridge joins Copenhagen to Malm')
4541
4542 def test_encoding_errors_default(self):
4543 try:
4544 encoding = 'ascii'
4545 logging.basicConfig(filename='test.log', encoding=encoding,
4546 format='%(message)s', level=logging.DEBUG)
4547
4548 self.assertEqual(len(logging.root.handlers), 1)
4549 handler = logging.root.handlers[0]
4550 self.assertIsInstance(handler, logging.FileHandler)
4551 self.assertEqual(handler.encoding, encoding)
4552 self.assertEqual(handler.errors, 'backslashreplace')
4553 logging.debug('😂: ☃️: The Øresund Bridge joins Copenhagen to Malmö')
4554 finally:
4555 handler.close()
4556 with open('test.log', encoding='utf-8') as f:
4557 data = f.read().strip()
4558 os.remove('test.log')
4559 self.assertEqual(data, r'\U0001f602: \u2603\ufe0f: The \xd8resund '
4560 r'Bridge joins Copenhagen to Malm\xf6')
4561
4562 def test_encoding_errors_none(self):
4563 # Specifying None should behave as 'strict'
4564 try:
4565 encoding = 'ascii'
4566 logging.basicConfig(filename='test.log', encoding=encoding,
4567 errors=None,
4568 format='%(message)s', level=logging.DEBUG)
4569
4570 self.assertEqual(len(logging.root.handlers), 1)
4571 handler = logging.root.handlers[0]
4572 self.assertIsInstance(handler, logging.FileHandler)
4573 self.assertEqual(handler.encoding, encoding)
4574 self.assertIsNone(handler.errors)
4575
4576 message = []
4577
4578 def dummy_handle_error(record):
4579 _, v, _ = sys.exc_info()
4580 message.append(str(v))
4581
4582 handler.handleError = dummy_handle_error
4583 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4584 self.assertTrue(message)
4585 self.assertIn("'ascii' codec can't encode "
4586 "character '\\xd8' in position 4:", message[0])
4587 finally:
4588 handler.close()
4589 with open('test.log', encoding='utf-8') as f:
4590 data = f.read().strip()
4591 os.remove('test.log')
4592 # didn't write anything due to the encoding error
4593 self.assertEqual(data, r'')
4594
4595
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004596 def _test_log(self, method, level=None):
4597 # logging.root has no handlers so basicConfig should be called
4598 called = []
4599
4600 old_basic_config = logging.basicConfig
4601 def my_basic_config(*a, **kw):
4602 old_basic_config()
4603 old_level = logging.root.level
4604 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004605 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004606 called.append((a, kw))
4607
Vinay Sajip1feedb42014-05-31 08:19:12 +01004608 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004609
4610 log_method = getattr(logging, method)
4611 if level is not None:
4612 log_method(level, "test me")
4613 else:
4614 log_method("test me")
4615
4616 # basicConfig was called with no arguments
4617 self.assertEqual(called, [((), {})])
4618
4619 def test_log(self):
4620 self._test_log('log', logging.WARNING)
4621
4622 def test_debug(self):
4623 self._test_log('debug')
4624
4625 def test_info(self):
4626 self._test_log('info')
4627
4628 def test_warning(self):
4629 self._test_log('warning')
4630
4631 def test_error(self):
4632 self._test_log('error')
4633
4634 def test_critical(self):
4635 self._test_log('critical')
4636
4637
4638class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004639 def setUp(self):
4640 super(LoggerAdapterTest, self).setUp()
4641 old_handler_list = logging._handlerList[:]
4642
4643 self.recording = RecordingHandler()
4644 self.logger = logging.root
4645 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004646 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004647 self.addCleanup(self.recording.close)
4648
4649 def cleanup():
4650 logging._handlerList[:] = old_handler_list
4651
4652 self.addCleanup(cleanup)
4653 self.addCleanup(logging.shutdown)
4654 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4655
4656 def test_exception(self):
4657 msg = 'testing exception: %r'
4658 exc = None
4659 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004660 1 / 0
4661 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004662 exc = e
4663 self.adapter.exception(msg, self.recording)
4664
4665 self.assertEqual(len(self.recording.records), 1)
4666 record = self.recording.records[0]
4667 self.assertEqual(record.levelno, logging.ERROR)
4668 self.assertEqual(record.msg, msg)
4669 self.assertEqual(record.args, (self.recording,))
4670 self.assertEqual(record.exc_info,
4671 (exc.__class__, exc, exc.__traceback__))
4672
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004673 def test_exception_excinfo(self):
4674 try:
4675 1 / 0
4676 except ZeroDivisionError as e:
4677 exc = e
4678
4679 self.adapter.exception('exc_info test', exc_info=exc)
4680
4681 self.assertEqual(len(self.recording.records), 1)
4682 record = self.recording.records[0]
4683 self.assertEqual(record.exc_info,
4684 (exc.__class__, exc, exc.__traceback__))
4685
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004686 def test_critical(self):
4687 msg = 'critical test! %r'
4688 self.adapter.critical(msg, self.recording)
4689
4690 self.assertEqual(len(self.recording.records), 1)
4691 record = self.recording.records[0]
4692 self.assertEqual(record.levelno, logging.CRITICAL)
4693 self.assertEqual(record.msg, msg)
4694 self.assertEqual(record.args, (self.recording,))
4695
4696 def test_is_enabled_for(self):
4697 old_disable = self.adapter.logger.manager.disable
4698 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004699 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4700 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004701 self.assertFalse(self.adapter.isEnabledFor(32))
4702
4703 def test_has_handlers(self):
4704 self.assertTrue(self.adapter.hasHandlers())
4705
4706 for handler in self.logger.handlers:
4707 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004708
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004709 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004710 self.assertFalse(self.adapter.hasHandlers())
4711
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004712 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004713 class Adapter(logging.LoggerAdapter):
4714 prefix = 'Adapter'
4715
4716 def process(self, msg, kwargs):
4717 return f"{self.prefix} {msg}", kwargs
4718
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004719 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004720 adapter = Adapter(logger=self.logger, extra=None)
4721 adapter_adapter = Adapter(logger=adapter, extra=None)
4722 adapter_adapter.prefix = 'AdapterAdapter'
4723 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004724 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004725 self.assertEqual(len(self.recording.records), 1)
4726 record = self.recording.records[0]
4727 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004728 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004729 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004730 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004731 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004732 self.assertIs(self.logger.manager, orig_manager)
4733 temp_manager = object()
4734 try:
4735 adapter_adapter.manager = temp_manager
4736 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004737 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004738 self.assertIs(self.logger.manager, temp_manager)
4739 finally:
4740 adapter_adapter.manager = orig_manager
4741 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004742 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004743 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004744
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004745
4746class LoggerTest(BaseTest):
4747
4748 def setUp(self):
4749 super(LoggerTest, self).setUp()
4750 self.recording = RecordingHandler()
4751 self.logger = logging.Logger(name='blah')
4752 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004753 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004754 self.addCleanup(self.recording.close)
4755 self.addCleanup(logging.shutdown)
4756
4757 def test_set_invalid_level(self):
4758 self.assertRaises(TypeError, self.logger.setLevel, object())
4759
4760 def test_exception(self):
4761 msg = 'testing exception: %r'
4762 exc = None
4763 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004764 1 / 0
4765 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004766 exc = e
4767 self.logger.exception(msg, self.recording)
4768
4769 self.assertEqual(len(self.recording.records), 1)
4770 record = self.recording.records[0]
4771 self.assertEqual(record.levelno, logging.ERROR)
4772 self.assertEqual(record.msg, msg)
4773 self.assertEqual(record.args, (self.recording,))
4774 self.assertEqual(record.exc_info,
4775 (exc.__class__, exc, exc.__traceback__))
4776
4777 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004778 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004779 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004780
4781 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004782 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004783 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004784
4785 def test_find_caller_with_stack_info(self):
4786 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004787 support.patch(self, logging.traceback, 'print_stack',
4788 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004789
4790 self.logger.findCaller(stack_info=True)
4791
4792 self.assertEqual(len(called), 1)
4793 self.assertEqual('Stack (most recent call last):\n', called[0])
4794
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004795 def test_find_caller_with_stacklevel(self):
4796 the_level = 1
4797
4798 def innermost():
4799 self.logger.warning('test', stacklevel=the_level)
4800
4801 def inner():
4802 innermost()
4803
4804 def outer():
4805 inner()
4806
4807 records = self.recording.records
4808 outer()
4809 self.assertEqual(records[-1].funcName, 'innermost')
4810 lineno = records[-1].lineno
4811 the_level += 1
4812 outer()
4813 self.assertEqual(records[-1].funcName, 'inner')
4814 self.assertGreater(records[-1].lineno, lineno)
4815 lineno = records[-1].lineno
4816 the_level += 1
4817 outer()
4818 self.assertEqual(records[-1].funcName, 'outer')
4819 self.assertGreater(records[-1].lineno, lineno)
4820 lineno = records[-1].lineno
4821 the_level += 1
4822 outer()
4823 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4824 self.assertGreater(records[-1].lineno, lineno)
4825
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004826 def test_make_record_with_extra_overwrite(self):
4827 name = 'my record'
4828 level = 13
4829 fn = lno = msg = args = exc_info = func = sinfo = None
4830 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4831 exc_info, func, sinfo)
4832
4833 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4834 extra = {key: 'some value'}
4835 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4836 fn, lno, msg, args, exc_info,
4837 extra=extra, sinfo=sinfo)
4838
4839 def test_make_record_with_extra_no_overwrite(self):
4840 name = 'my record'
4841 level = 13
4842 fn = lno = msg = args = exc_info = func = sinfo = None
4843 extra = {'valid_key': 'some value'}
4844 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4845 exc_info, extra=extra, sinfo=sinfo)
4846 self.assertIn('valid_key', result.__dict__)
4847
4848 def test_has_handlers(self):
4849 self.assertTrue(self.logger.hasHandlers())
4850
4851 for handler in self.logger.handlers:
4852 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004853 self.assertFalse(self.logger.hasHandlers())
4854
4855 def test_has_handlers_no_propagate(self):
4856 child_logger = logging.getLogger('blah.child')
4857 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004858 self.assertFalse(child_logger.hasHandlers())
4859
4860 def test_is_enabled_for(self):
4861 old_disable = self.logger.manager.disable
4862 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004863 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004864 self.assertFalse(self.logger.isEnabledFor(22))
4865
Timo Furrer6e3ca642018-06-01 09:29:46 +02004866 def test_is_enabled_for_disabled_logger(self):
4867 old_disabled = self.logger.disabled
4868 old_disable = self.logger.manager.disable
4869
4870 self.logger.disabled = True
4871 self.logger.manager.disable = 21
4872
4873 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4874 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4875
4876 self.assertFalse(self.logger.isEnabledFor(22))
4877
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004878 def test_root_logger_aliases(self):
4879 root = logging.getLogger()
4880 self.assertIs(root, logging.root)
4881 self.assertIs(root, logging.getLogger(None))
4882 self.assertIs(root, logging.getLogger(''))
Vinay Sajipcb65b3a2019-08-02 16:53:00 +01004883 self.assertIs(root, logging.getLogger('root'))
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004884 self.assertIs(root, logging.getLogger('foo').root)
4885 self.assertIs(root, logging.getLogger('foo.bar').root)
4886 self.assertIs(root, logging.getLogger('foo').parent)
4887
4888 self.assertIsNot(root, logging.getLogger('\0'))
4889 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4890
4891 def test_invalid_names(self):
4892 self.assertRaises(TypeError, logging.getLogger, any)
4893 self.assertRaises(TypeError, logging.getLogger, b'foo')
4894
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004895 def test_pickling(self):
4896 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4897 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4898 logger = logging.getLogger(name)
4899 s = pickle.dumps(logger, proto)
4900 unpickled = pickle.loads(s)
4901 self.assertIs(unpickled, logger)
4902
Avram Lubkin78c18a92017-07-30 05:36:33 -04004903 def test_caching(self):
4904 root = self.root_logger
4905 logger1 = logging.getLogger("abc")
4906 logger2 = logging.getLogger("abc.def")
4907
4908 # Set root logger level and ensure cache is empty
4909 root.setLevel(logging.ERROR)
4910 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4911 self.assertEqual(logger2._cache, {})
4912
4913 # Ensure cache is populated and calls are consistent
4914 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4915 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4916 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4917 self.assertEqual(root._cache, {})
4918 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4919
4920 # Ensure root cache gets populated
4921 self.assertEqual(root._cache, {})
4922 self.assertTrue(root.isEnabledFor(logging.ERROR))
4923 self.assertEqual(root._cache, {logging.ERROR: True})
4924
4925 # Set parent logger level and ensure caches are emptied
4926 logger1.setLevel(logging.CRITICAL)
4927 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4928 self.assertEqual(logger2._cache, {})
4929
4930 # Ensure logger2 uses parent logger's effective level
4931 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4932
4933 # Set level to NOTSET and ensure caches are empty
4934 logger2.setLevel(logging.NOTSET)
4935 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4936 self.assertEqual(logger2._cache, {})
4937 self.assertEqual(logger1._cache, {})
4938 self.assertEqual(root._cache, {})
4939
4940 # Verify logger2 follows parent and not root
4941 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4942 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4943 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4944 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4945 self.assertTrue(root.isEnabledFor(logging.ERROR))
4946
4947 # Disable logging in manager and ensure caches are clear
4948 logging.disable()
4949 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4950 self.assertEqual(logger2._cache, {})
4951 self.assertEqual(logger1._cache, {})
4952 self.assertEqual(root._cache, {})
4953
4954 # Ensure no loggers are enabled
4955 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4956 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4957 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4958
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004959
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004960class BaseFileTest(BaseTest):
4961 "Base class for handler tests that write log files"
4962
4963 def setUp(self):
4964 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004965 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4966 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004967 self.rmfiles = []
4968
4969 def tearDown(self):
4970 for fn in self.rmfiles:
4971 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004972 if os.path.exists(self.fn):
4973 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004974 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004975
4976 def assertLogFile(self, filename):
4977 "Assert a log file is there and register it for deletion"
4978 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004979 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004980 self.rmfiles.append(filename)
4981
4982
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004983class FileHandlerTest(BaseFileTest):
4984 def test_delay(self):
4985 os.unlink(self.fn)
4986 fh = logging.FileHandler(self.fn, delay=True)
4987 self.assertIsNone(fh.stream)
4988 self.assertFalse(os.path.exists(self.fn))
4989 fh.handle(logging.makeLogRecord({}))
4990 self.assertIsNotNone(fh.stream)
4991 self.assertTrue(os.path.exists(self.fn))
4992 fh.close()
4993
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004994class RotatingFileHandlerTest(BaseFileTest):
4995 def next_rec(self):
4996 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4997 self.next_message(), None, None, None)
4998
4999 def test_should_not_rollover(self):
5000 # If maxbytes is zero rollover never occurs
5001 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
5002 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00005003 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005004
5005 def test_should_rollover(self):
5006 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
5007 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00005008 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005009
5010 def test_file_created(self):
5011 # checks that the file is created and assumes it was created
5012 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005013 rh = logging.handlers.RotatingFileHandler(self.fn)
5014 rh.emit(self.next_rec())
5015 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00005016 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005017
5018 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00005019 def namer(name):
5020 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005021 rh = logging.handlers.RotatingFileHandler(
5022 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005023 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005024 rh.emit(self.next_rec())
5025 self.assertLogFile(self.fn)
5026 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005027 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005028 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005029 self.assertLogFile(namer(self.fn + ".2"))
5030 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
5031 rh.close()
5032
l0rb519cb872019-11-06 22:21:40 +01005033 def test_namer_rotator_inheritance(self):
5034 class HandlerWithNamerAndRotator(logging.handlers.RotatingFileHandler):
5035 def namer(self, name):
5036 return name + ".test"
5037
5038 def rotator(self, source, dest):
5039 if os.path.exists(source):
5040 os.rename(source, dest + ".rotated")
5041
5042 rh = HandlerWithNamerAndRotator(
5043 self.fn, backupCount=2, maxBytes=1)
5044 self.assertEqual(rh.namer(self.fn), self.fn + ".test")
5045 rh.emit(self.next_rec())
5046 self.assertLogFile(self.fn)
5047 rh.emit(self.next_rec())
5048 self.assertLogFile(rh.namer(self.fn + ".1") + ".rotated")
5049 self.assertFalse(os.path.exists(rh.namer(self.fn + ".1")))
5050 rh.close()
5051
Vinay Sajip1feedb42014-05-31 08:19:12 +01005052 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00005053 def test_rotator(self):
5054 def namer(name):
5055 return name + ".gz"
5056
5057 def rotator(source, dest):
5058 with open(source, "rb") as sf:
5059 data = sf.read()
5060 compressed = zlib.compress(data, 9)
5061 with open(dest, "wb") as df:
5062 df.write(compressed)
5063 os.remove(source)
5064
5065 rh = logging.handlers.RotatingFileHandler(
5066 self.fn, backupCount=2, maxBytes=1)
5067 rh.rotator = rotator
5068 rh.namer = namer
5069 m1 = self.next_rec()
5070 rh.emit(m1)
5071 self.assertLogFile(self.fn)
5072 m2 = self.next_rec()
5073 rh.emit(m2)
5074 fn = namer(self.fn + ".1")
5075 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005076 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00005077 with open(fn, "rb") as f:
5078 compressed = f.read()
5079 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005080 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005081 rh.emit(self.next_rec())
5082 fn = namer(self.fn + ".2")
5083 self.assertLogFile(fn)
5084 with open(fn, "rb") as f:
5085 compressed = f.read()
5086 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005087 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005088 rh.emit(self.next_rec())
5089 fn = namer(self.fn + ".2")
5090 with open(fn, "rb") as f:
5091 compressed = f.read()
5092 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005093 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005094 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00005095 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005096
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005097class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01005098 # other test methods added below
5099 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01005100 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
5101 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00005102 fmt = logging.Formatter('%(asctime)s %(message)s')
5103 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005104 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005105 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01005106 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005107 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00005108 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005109 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01005110 fh.close()
5111 # At this point, we should have a recent rotated file which we
5112 # can test for the existence of. However, in practice, on some
5113 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01005114 # in time to go to look for the log file. So, we go back a fair
5115 # bit, and stop as soon as we see a rotated file. In theory this
5116 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01005117 found = False
5118 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01005119 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01005120 for secs in range(GO_BACK):
5121 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01005122 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
5123 found = os.path.exists(fn)
5124 if found:
5125 self.rmfiles.append(fn)
5126 break
Vinay Sajip672c5812011-05-13 07:09:40 +01005127 msg = 'No rotated files found, went back %d seconds' % GO_BACK
5128 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03005129 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01005130 dn, fn = os.path.split(self.fn)
5131 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02005132 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
5133 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00005134 for f in files:
5135 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00005136 path = os.path.join(dn, f)
5137 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00005138 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01005139 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005140
Vinay Sajip0372e102011-05-05 12:59:14 +01005141 def test_invalid(self):
5142 assertRaises = self.assertRaises
5143 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005144 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005145 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005146 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005147 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005148 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005149
Vinay Sajipa7130792013-04-12 17:04:23 +01005150 def test_compute_rollover_daily_attime(self):
5151 currentTime = 0
5152 atTime = datetime.time(12, 0, 0)
5153 rh = logging.handlers.TimedRotatingFileHandler(
5154 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
5155 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005156 try:
5157 actual = rh.computeRollover(currentTime)
5158 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01005159
Vinay Sajipd86ac962013-04-14 12:20:46 +01005160 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
5161 self.assertEqual(actual, currentTime + 36 * 60 * 60)
5162 finally:
5163 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005164
Vinay Sajip10e8c492013-05-18 10:19:54 -07005165 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01005166 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01005167 currentTime = int(time.time())
5168 today = currentTime - currentTime % 86400
5169
Vinay Sajipa7130792013-04-12 17:04:23 +01005170 atTime = datetime.time(12, 0, 0)
5171
Vinay Sajip10e8c492013-05-18 10:19:54 -07005172 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01005173 for day in range(7):
5174 rh = logging.handlers.TimedRotatingFileHandler(
5175 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
5176 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005177 try:
5178 if wday > day:
5179 # The rollover day has already passed this week, so we
5180 # go over into next week
5181 expected = (7 - wday + day)
5182 else:
5183 expected = (day - wday)
5184 # At this point expected is in days from now, convert to seconds
5185 expected *= 24 * 60 * 60
5186 # Add in the rollover time
5187 expected += 12 * 60 * 60
5188 # Add in adjustment for today
5189 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01005190 actual = rh.computeRollover(today)
5191 if actual != expected:
5192 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005193 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005194 self.assertEqual(actual, expected)
5195 if day == wday:
5196 # goes into following week
5197 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01005198 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01005199 if actual != expected:
5200 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005201 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005202 self.assertEqual(actual, expected)
5203 finally:
5204 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005205
5206
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005207def secs(**kw):
5208 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
5209
5210for when, exp in (('S', 1),
5211 ('M', 60),
5212 ('H', 60 * 60),
5213 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00005214 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005215 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00005216 ('W0', secs(days=4, hours=24)),
5217 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005218 def test_compute_rollover(self, when=when, exp=exp):
5219 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00005220 self.fn, when=when, interval=1, backupCount=0, utc=True)
5221 currentTime = 0.0
5222 actual = rh.computeRollover(currentTime)
5223 if exp != actual:
5224 # Failures occur on some systems for MIDNIGHT and W0.
5225 # Print detailed calculation for MIDNIGHT so we can try to see
5226 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00005227 if when == 'MIDNIGHT':
5228 try:
5229 if rh.utc:
5230 t = time.gmtime(currentTime)
5231 else:
5232 t = time.localtime(currentTime)
5233 currentHour = t[3]
5234 currentMinute = t[4]
5235 currentSecond = t[5]
5236 # r is the number of seconds left between now and midnight
5237 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
5238 currentMinute) * 60 +
5239 currentSecond)
5240 result = currentTime + r
5241 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
5242 print('currentHour: %s' % currentHour, file=sys.stderr)
5243 print('currentMinute: %s' % currentMinute, file=sys.stderr)
5244 print('currentSecond: %s' % currentSecond, file=sys.stderr)
5245 print('r: %s' % r, file=sys.stderr)
5246 print('result: %s' % result, file=sys.stderr)
5247 except Exception:
5248 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
5249 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00005250 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005251 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
5252
Vinay Sajip60ccd822011-05-09 17:32:09 +01005253
Vinay Sajip223349c2015-10-01 20:37:54 +01005254@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01005255class NTEventLogHandlerTest(BaseTest):
5256 def test_basic(self):
5257 logtype = 'Application'
5258 elh = win32evtlog.OpenEventLog(None, logtype)
5259 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01005260
5261 try:
5262 h = logging.handlers.NTEventLogHandler('test_logging')
5263 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05005264 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01005265 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05005266 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01005267
Vinay Sajip60ccd822011-05-09 17:32:09 +01005268 r = logging.makeLogRecord({'msg': 'Test Log Message'})
5269 h.handle(r)
5270 h.close()
5271 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02005272 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01005273 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
5274 win32evtlog.EVENTLOG_SEQUENTIAL_READ
5275 found = False
5276 GO_BACK = 100
5277 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
5278 for e in events:
5279 if e.SourceName != 'test_logging':
5280 continue
5281 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
5282 if msg != 'Test Log Message\r\n':
5283 continue
5284 found = True
5285 break
5286 msg = 'Record not found in event log, went back %d records' % GO_BACK
5287 self.assertTrue(found, msg=msg)
5288
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005289
5290class MiscTestCase(unittest.TestCase):
5291 def test__all__(self):
5292 blacklist = {'logThreads', 'logMultiprocessing',
5293 'logProcesses', 'currentframe',
5294 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
5295 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00005296 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005297 support.check__all__(self, logging, blacklist=blacklist)
5298
5299
Christian Heimes180510d2008-03-03 19:15:45 +00005300# Set the locale to the platform-dependent default. I have no idea
5301# why the test does this, but in any case we save the current locale
5302# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01005303@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00005304def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01005305 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01005306 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
5307 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
5308 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
5309 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
5310 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
5311 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
5312 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
5313 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08005314 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01005315 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01005316 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005317 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01005318 ]
5319 if hasattr(logging.handlers, 'QueueListener'):
5320 tests.append(QueueListenerTest)
5321 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00005322
Christian Heimes180510d2008-03-03 19:15:45 +00005323if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00005324 test_main()