blob: e223522cc7eccc204d9c6995204e2efcd3b79992 [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
Victor Stinnerbbc8b792019-12-10 20:41:23 +0100872 def stop(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200873 """
874 Stop the thread by closing the server instance.
875 Wait for the server thread to terminate.
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200876 """
877 self.close()
Victor Stinnerbbc8b792019-12-10 20:41:23 +0100878 support.join_thread(self._thread)
Victor Stinnerb9b69002017-09-14 14:40:56 -0700879 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200880 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100881
Vinay Sajip7367d082011-05-02 13:17:27 +0100882
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200883class ControlMixin(object):
884 """
885 This mixin is used to start a server on a separate thread, and
886 shut it down programmatically. Request handling is simplified - instead
887 of needing to derive a suitable RequestHandler subclass, you just
888 provide a callable which will be passed each received request to be
889 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100890
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200891 :param handler: A handler callable which will be called with a
892 single parameter - the request - in order to
893 process the request. This handler is called on the
894 server thread, effectively meaning that requests are
895 processed serially. While not quite Web scale ;-),
896 this should be fine for testing applications.
897 :param poll_interval: The polling interval in seconds.
898 """
899 def __init__(self, handler, poll_interval):
900 self._thread = None
901 self.poll_interval = poll_interval
902 self._handler = handler
903 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100904
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200905 def start(self):
906 """
907 Create a daemon thread to run the server, and start it.
908 """
909 self._thread = t = threading.Thread(target=self.serve_forever,
910 args=(self.poll_interval,))
911 t.setDaemon(True)
912 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100913
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200914 def serve_forever(self, poll_interval):
915 """
916 Run the server. Set the ready flag before entering the
917 service loop.
918 """
919 self.ready.set()
920 super(ControlMixin, self).serve_forever(poll_interval)
921
Victor Stinnerbbc8b792019-12-10 20:41:23 +0100922 def stop(self):
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200923 """
924 Tell the server thread to stop, and wait for it to do so.
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200925 """
926 self.shutdown()
927 if self._thread is not None:
Victor Stinnerbbc8b792019-12-10 20:41:23 +0100928 support.join_thread(self._thread)
Vinay Sajip7367d082011-05-02 13:17:27 +0100929 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200930 self.server_close()
931 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100932
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200933class TestHTTPServer(ControlMixin, HTTPServer):
934 """
935 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100936
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200937 :param addr: A tuple with the IP address and port to listen on.
938 :param handler: A handler callable which will be called with a
939 single parameter - the request - in order to
940 process the request.
941 :param poll_interval: The polling interval in seconds.
942 :param log: Pass ``True`` to enable log messages.
943 """
944 def __init__(self, addr, handler, poll_interval=0.5,
945 log=False, sslctx=None):
946 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
947 def __getattr__(self, name, default=None):
948 if name.startswith('do_'):
949 return self.process_request
950 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100951
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200952 def process_request(self):
953 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100954
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200955 def log_message(self, format, *args):
956 if log:
957 super(DelegatingHTTPRequestHandler,
958 self).log_message(format, *args)
959 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
960 ControlMixin.__init__(self, handler, poll_interval)
961 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100962
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200963 def get_request(self):
964 try:
965 sock, addr = self.socket.accept()
966 if self.sslctx:
967 sock = self.sslctx.wrap_socket(sock, server_side=True)
968 except OSError as e:
969 # socket errors are silenced by the caller, print them here
970 sys.stderr.write("Got an error:\n%s\n" % e)
971 raise
972 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100973
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200974class TestTCPServer(ControlMixin, ThreadingTCPServer):
975 """
976 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100977
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200978 :param addr: A tuple with the IP address and port to listen on.
979 :param handler: A handler callable which will be called with a single
980 parameter - the request - in order to process the request.
981 :param poll_interval: The polling interval in seconds.
982 :bind_and_activate: If True (the default), binds the server and starts it
983 listening. If False, you need to call
984 :meth:`server_bind` and :meth:`server_activate` at
985 some later time before calling :meth:`start`, so that
986 the server will set up the socket and listen on it.
987 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100988
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200989 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100990
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200991 def __init__(self, addr, handler, poll_interval=0.5,
992 bind_and_activate=True):
993 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100994
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200995 def handle(self):
996 self.server._handler(self)
997 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
998 bind_and_activate)
999 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +01001000
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001001 def server_bind(self):
1002 super(TestTCPServer, self).server_bind()
1003 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +01001004
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001005class TestUDPServer(ControlMixin, ThreadingUDPServer):
1006 """
1007 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +01001008
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001009 :param addr: A tuple with the IP address and port to listen on.
1010 :param handler: A handler callable which will be called with a
1011 single parameter - the request - in order to
1012 process the request.
1013 :param poll_interval: The polling interval for shutdown requests,
1014 in seconds.
1015 :bind_and_activate: If True (the default), binds the server and
1016 starts it listening. If False, you need to
1017 call :meth:`server_bind` and
1018 :meth:`server_activate` at some later time
1019 before calling :meth:`start`, so that the server will
1020 set up the socket and listen on it.
1021 """
1022 def __init__(self, addr, handler, poll_interval=0.5,
1023 bind_and_activate=True):
1024 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +01001025
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001026 def handle(self):
1027 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001028
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001029 def finish(self):
1030 data = self.wfile.getvalue()
1031 if data:
1032 try:
1033 super(DelegatingUDPRequestHandler, self).finish()
1034 except OSError:
1035 if not self.server._closed:
1036 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +01001037
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001038 ThreadingUDPServer.__init__(self, addr,
1039 DelegatingUDPRequestHandler,
1040 bind_and_activate)
1041 ControlMixin.__init__(self, handler, poll_interval)
1042 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +01001043
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001044 def server_bind(self):
1045 super(TestUDPServer, self).server_bind()
1046 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +01001047
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001048 def server_close(self):
1049 super(TestUDPServer, self).server_close()
1050 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +01001051
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001052if hasattr(socket, "AF_UNIX"):
1053 class TestUnixStreamServer(TestTCPServer):
1054 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +01001055
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001056 class TestUnixDatagramServer(TestUDPServer):
1057 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +01001058
Vinay Sajip7367d082011-05-02 13:17:27 +01001059# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +01001060
1061class SMTPHandlerTest(BaseTest):
Victor Stinnerc98b0192019-12-10 21:12:26 +01001062 # bpo-14314, bpo-19665, bpo-34092: don't wait forever
1063 TIMEOUT = support.LONG_TIMEOUT
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02001064
Vinay Sajipa463d252011-04-30 21:52:48 +01001065 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +01001066 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -08001067 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +01001068 sockmap)
1069 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -08001070 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001071 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
1072 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001073 self.assertEqual(h.toaddrs, ['you'])
1074 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001075 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001076 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001077 h.handle(r)
Victor Stinner31b50b82018-07-11 12:35:38 +02001078 self.handled.wait(self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001079 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001080 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001081 self.assertEqual(len(self.messages), 1)
1082 peer, mailfrom, rcpttos, data = self.messages[0]
1083 self.assertEqual(mailfrom, 'me')
1084 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001085 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001086 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001087 h.close()
1088
1089 def process_message(self, *args):
1090 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001091 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001092
Christian Heimes180510d2008-03-03 19:15:45 +00001093class MemoryHandlerTest(BaseTest):
1094
1095 """Tests for the MemoryHandler."""
1096
1097 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001098 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001099
1100 def setUp(self):
1101 BaseTest.setUp(self)
1102 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001103 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001104 self.mem_logger = logging.getLogger('mem')
1105 self.mem_logger.propagate = 0
1106 self.mem_logger.addHandler(self.mem_hdlr)
1107
1108 def tearDown(self):
1109 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001110 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001111
1112 def test_flush(self):
1113 # The memory handler flushes to its target handler based on specific
1114 # criteria (message count and message level).
1115 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001116 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001117 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001118 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001119 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001120 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001121 lines = [
1122 ('DEBUG', '1'),
1123 ('INFO', '2'),
1124 ('WARNING', '3'),
1125 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001126 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001127 for n in (4, 14):
1128 for i in range(9):
1129 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001130 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001131 # This will flush because it's the 10th message since the last
1132 # flush.
1133 self.mem_logger.debug(self.next_message())
1134 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001135 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001136
1137 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001138 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001139
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001140 def test_flush_on_close(self):
1141 """
1142 Test that the flush-on-close configuration works as expected.
1143 """
1144 self.mem_logger.debug(self.next_message())
1145 self.assert_log_lines([])
1146 self.mem_logger.info(self.next_message())
1147 self.assert_log_lines([])
1148 self.mem_logger.removeHandler(self.mem_hdlr)
1149 # Default behaviour is to flush on close. Check that it happens.
1150 self.mem_hdlr.close()
1151 lines = [
1152 ('DEBUG', '1'),
1153 ('INFO', '2'),
1154 ]
1155 self.assert_log_lines(lines)
1156 # Now configure for flushing not to be done on close.
1157 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1158 self.root_hdlr,
1159 False)
1160 self.mem_logger.addHandler(self.mem_hdlr)
1161 self.mem_logger.debug(self.next_message())
1162 self.assert_log_lines(lines) # no change
1163 self.mem_logger.info(self.next_message())
1164 self.assert_log_lines(lines) # no change
1165 self.mem_logger.removeHandler(self.mem_hdlr)
1166 self.mem_hdlr.close()
1167 # assert that no new lines have been added
1168 self.assert_log_lines(lines) # no change
1169
Christian Heimes180510d2008-03-03 19:15:45 +00001170
1171class ExceptionFormatter(logging.Formatter):
1172 """A special exception formatter."""
1173 def formatException(self, ei):
1174 return "Got a [%s]" % ei[0].__name__
1175
1176
1177class ConfigFileTest(BaseTest):
1178
1179 """Reading logging config from a .ini-style config file."""
1180
Xtreak087570a2018-07-02 14:27:46 +05301181 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001182 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001183
1184 # config0 is a standard configuration.
1185 config0 = """
1186 [loggers]
1187 keys=root
1188
1189 [handlers]
1190 keys=hand1
1191
1192 [formatters]
1193 keys=form1
1194
1195 [logger_root]
1196 level=WARNING
1197 handlers=hand1
1198
1199 [handler_hand1]
1200 class=StreamHandler
1201 level=NOTSET
1202 formatter=form1
1203 args=(sys.stdout,)
1204
1205 [formatter_form1]
1206 format=%(levelname)s ++ %(message)s
1207 datefmt=
1208 """
1209
1210 # config1 adds a little to the standard configuration.
1211 config1 = """
1212 [loggers]
1213 keys=root,parser
1214
1215 [handlers]
1216 keys=hand1
1217
1218 [formatters]
1219 keys=form1
1220
1221 [logger_root]
1222 level=WARNING
1223 handlers=
1224
1225 [logger_parser]
1226 level=DEBUG
1227 handlers=hand1
1228 propagate=1
1229 qualname=compiler.parser
1230
1231 [handler_hand1]
1232 class=StreamHandler
1233 level=NOTSET
1234 formatter=form1
1235 args=(sys.stdout,)
1236
1237 [formatter_form1]
1238 format=%(levelname)s ++ %(message)s
1239 datefmt=
1240 """
1241
Vinay Sajip3f84b072011-03-07 17:49:33 +00001242 # config1a moves the handler to the root.
1243 config1a = """
1244 [loggers]
1245 keys=root,parser
1246
1247 [handlers]
1248 keys=hand1
1249
1250 [formatters]
1251 keys=form1
1252
1253 [logger_root]
1254 level=WARNING
1255 handlers=hand1
1256
1257 [logger_parser]
1258 level=DEBUG
1259 handlers=
1260 propagate=1
1261 qualname=compiler.parser
1262
1263 [handler_hand1]
1264 class=StreamHandler
1265 level=NOTSET
1266 formatter=form1
1267 args=(sys.stdout,)
1268
1269 [formatter_form1]
1270 format=%(levelname)s ++ %(message)s
1271 datefmt=
1272 """
1273
Christian Heimes180510d2008-03-03 19:15:45 +00001274 # config2 has a subtle configuration error that should be reported
1275 config2 = config1.replace("sys.stdout", "sys.stbout")
1276
1277 # config3 has a less subtle configuration error
1278 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1279
1280 # config4 specifies a custom formatter class to be loaded
1281 config4 = """
1282 [loggers]
1283 keys=root
1284
1285 [handlers]
1286 keys=hand1
1287
1288 [formatters]
1289 keys=form1
1290
1291 [logger_root]
1292 level=NOTSET
1293 handlers=hand1
1294
1295 [handler_hand1]
1296 class=StreamHandler
1297 level=NOTSET
1298 formatter=form1
1299 args=(sys.stdout,)
1300
1301 [formatter_form1]
1302 class=""" + __name__ + """.ExceptionFormatter
1303 format=%(levelname)s:%(name)s:%(message)s
1304 datefmt=
1305 """
1306
Georg Brandl3dbca812008-07-23 16:10:53 +00001307 # config5 specifies a custom handler class to be loaded
1308 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1309
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001310 # config6 uses ', ' delimiters in the handlers and formatters sections
1311 config6 = """
1312 [loggers]
1313 keys=root,parser
1314
1315 [handlers]
1316 keys=hand1, hand2
1317
1318 [formatters]
1319 keys=form1, form2
1320
1321 [logger_root]
1322 level=WARNING
1323 handlers=
1324
1325 [logger_parser]
1326 level=DEBUG
1327 handlers=hand1
1328 propagate=1
1329 qualname=compiler.parser
1330
1331 [handler_hand1]
1332 class=StreamHandler
1333 level=NOTSET
1334 formatter=form1
1335 args=(sys.stdout,)
1336
1337 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001338 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001339 level=NOTSET
1340 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001341 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001342
1343 [formatter_form1]
1344 format=%(levelname)s ++ %(message)s
1345 datefmt=
1346
1347 [formatter_form2]
1348 format=%(message)s
1349 datefmt=
1350 """
1351
Preston Landers6ea56d22017-08-02 15:44:28 -05001352 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001353 config7 = """
1354 [loggers]
1355 keys=root,parser,compiler
1356
1357 [handlers]
1358 keys=hand1
1359
1360 [formatters]
1361 keys=form1
1362
1363 [logger_root]
1364 level=WARNING
1365 handlers=hand1
1366
1367 [logger_compiler]
1368 level=DEBUG
1369 handlers=
1370 propagate=1
1371 qualname=compiler
1372
1373 [logger_parser]
1374 level=DEBUG
1375 handlers=
1376 propagate=1
1377 qualname=compiler.parser
1378
1379 [handler_hand1]
1380 class=StreamHandler
1381 level=NOTSET
1382 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001383 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001384
1385 [formatter_form1]
1386 format=%(levelname)s ++ %(message)s
1387 datefmt=
1388 """
1389
Xtreak087570a2018-07-02 14:27:46 +05301390 # config 8, check for resource warning
1391 config8 = r"""
1392 [loggers]
1393 keys=root
1394
1395 [handlers]
1396 keys=file
1397
1398 [formatters]
1399 keys=
1400
1401 [logger_root]
1402 level=DEBUG
1403 handlers=file
1404
1405 [handler_file]
1406 class=FileHandler
1407 level=DEBUG
1408 args=("{tempfile}",)
1409 """
1410
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001411 disable_test = """
1412 [loggers]
1413 keys=root
1414
1415 [handlers]
1416 keys=screen
1417
1418 [formatters]
1419 keys=
1420
1421 [logger_root]
1422 level=DEBUG
1423 handlers=screen
1424
1425 [handler_screen]
1426 level=DEBUG
1427 class=StreamHandler
1428 args=(sys.stdout,)
1429 formatter=
1430 """
1431
1432 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001433 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001434 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001435
1436 def test_config0_ok(self):
1437 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001438 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001439 self.apply_config(self.config0)
1440 logger = logging.getLogger()
1441 # Won't output anything
1442 logger.info(self.next_message())
1443 # Outputs a message
1444 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001445 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001446 ('ERROR', '2'),
1447 ], stream=output)
1448 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001449 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001450
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001451 def test_config0_using_cp_ok(self):
1452 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001453 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001454 file = io.StringIO(textwrap.dedent(self.config0))
1455 cp = configparser.ConfigParser()
1456 cp.read_file(file)
1457 logging.config.fileConfig(cp)
1458 logger = logging.getLogger()
1459 # Won't output anything
1460 logger.info(self.next_message())
1461 # Outputs a message
1462 logger.error(self.next_message())
1463 self.assert_log_lines([
1464 ('ERROR', '2'),
1465 ], stream=output)
1466 # Original logger output is empty.
1467 self.assert_log_lines([])
1468
Georg Brandl3dbca812008-07-23 16:10:53 +00001469 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001470 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001471 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001472 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001473 logger = logging.getLogger("compiler.parser")
1474 # Both will output a message
1475 logger.info(self.next_message())
1476 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001477 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001478 ('INFO', '1'),
1479 ('ERROR', '2'),
1480 ], stream=output)
1481 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001482 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001483
1484 def test_config2_failure(self):
1485 # A simple config file which overrides the default settings.
1486 self.assertRaises(Exception, self.apply_config, self.config2)
1487
1488 def test_config3_failure(self):
1489 # A simple config file which overrides the default settings.
1490 self.assertRaises(Exception, self.apply_config, self.config3)
1491
1492 def test_config4_ok(self):
1493 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001494 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001495 self.apply_config(self.config4)
1496 logger = logging.getLogger()
1497 try:
1498 raise RuntimeError()
1499 except RuntimeError:
1500 logging.exception("just testing")
1501 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001502 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001503 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1504 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001505 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001506
Georg Brandl3dbca812008-07-23 16:10:53 +00001507 def test_config5_ok(self):
1508 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001509
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001510 def test_config6_ok(self):
1511 self.test_config1_ok(config=self.config6)
1512
Vinay Sajip3f84b072011-03-07 17:49:33 +00001513 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001514 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001515 self.apply_config(self.config1a)
1516 logger = logging.getLogger("compiler.parser")
1517 # See issue #11424. compiler-hyphenated sorts
1518 # between compiler and compiler.xyz and this
1519 # was preventing compiler.xyz from being included
1520 # in the child loggers of compiler because of an
1521 # overzealous loop termination condition.
1522 hyphenated = logging.getLogger('compiler-hyphenated')
1523 # All will output a message
1524 logger.info(self.next_message())
1525 logger.error(self.next_message())
1526 hyphenated.critical(self.next_message())
1527 self.assert_log_lines([
1528 ('INFO', '1'),
1529 ('ERROR', '2'),
1530 ('CRITICAL', '3'),
1531 ], stream=output)
1532 # Original logger output is empty.
1533 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001534 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001535 self.apply_config(self.config7)
1536 logger = logging.getLogger("compiler.parser")
1537 self.assertFalse(logger.disabled)
1538 # Both will output a message
1539 logger.info(self.next_message())
1540 logger.error(self.next_message())
1541 logger = logging.getLogger("compiler.lexer")
1542 # Both will output a message
1543 logger.info(self.next_message())
1544 logger.error(self.next_message())
1545 # Will not appear
1546 hyphenated.critical(self.next_message())
1547 self.assert_log_lines([
1548 ('INFO', '4'),
1549 ('ERROR', '5'),
1550 ('INFO', '6'),
1551 ('ERROR', '7'),
1552 ], stream=output)
1553 # Original logger output is empty.
1554 self.assert_log_lines([])
1555
Xtreak087570a2018-07-02 14:27:46 +05301556 def test_config8_ok(self):
1557
1558 def cleanup(h1, fn):
1559 h1.close()
1560 os.remove(fn)
1561
1562 with self.check_no_resource_warning():
1563 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1564 os.close(fd)
1565
1566 # Replace single backslash with double backslash in windows
1567 # to avoid unicode error during string formatting
1568 if os.name == "nt":
1569 fn = fn.replace("\\", "\\\\")
1570
1571 config8 = self.config8.format(tempfile=fn)
1572
1573 self.apply_config(config8)
1574 self.apply_config(config8)
1575
1576 handler = logging.root.handlers[0]
1577 self.addCleanup(cleanup, handler, fn)
1578
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001579 def test_logger_disabling(self):
1580 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001581 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001582 self.assertFalse(logger.disabled)
1583 self.apply_config(self.disable_test)
1584 self.assertTrue(logger.disabled)
1585 self.apply_config(self.disable_test, disable_existing_loggers=False)
1586 self.assertFalse(logger.disabled)
1587
Lucas Cimonb15100f2019-10-31 09:06:25 +01001588 def test_config_set_handler_names(self):
1589 test_config = """
1590 [loggers]
1591 keys=root
1592
1593 [handlers]
1594 keys=hand1
1595
1596 [formatters]
1597 keys=form1
1598
1599 [logger_root]
1600 handlers=hand1
1601
1602 [handler_hand1]
1603 class=StreamHandler
1604 formatter=form1
1605
1606 [formatter_form1]
1607 format=%(levelname)s ++ %(message)s
1608 """
1609 self.apply_config(test_config)
l0rb991b02d2019-11-07 11:13:36 +01001610 self.assertEqual(logging.getLogger().handlers[0].name, 'hand1')
Lucas Cimonb15100f2019-10-31 09:06:25 +01001611
Łukasz Langa214f18e2018-06-08 04:02:48 -07001612 def test_defaults_do_no_interpolation(self):
1613 """bpo-33802 defaults should not get interpolated"""
1614 ini = textwrap.dedent("""
1615 [formatters]
1616 keys=default
1617
1618 [formatter_default]
1619
1620 [handlers]
1621 keys=console
1622
1623 [handler_console]
1624 class=logging.StreamHandler
1625 args=tuple()
1626
1627 [loggers]
1628 keys=root
1629
1630 [logger_root]
1631 formatter=default
1632 handlers=console
1633 """).strip()
1634 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1635 try:
1636 os.write(fd, ini.encode('ascii'))
1637 os.close(fd)
1638 logging.config.fileConfig(
1639 fn,
1640 defaults=dict(
1641 version=1,
1642 disable_existing_loggers=False,
1643 formatters={
1644 "generic": {
1645 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1646 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1647 "class": "logging.Formatter"
1648 },
1649 },
1650 )
1651 )
1652 finally:
1653 os.unlink(fn)
1654
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001655
Christian Heimes180510d2008-03-03 19:15:45 +00001656class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001657
Christian Heimes180510d2008-03-03 19:15:45 +00001658 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001659
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001660 server_class = TestTCPServer
1661 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001662
Christian Heimes180510d2008-03-03 19:15:45 +00001663 def setUp(self):
1664 """Set up a TCP server to receive log messages, and a SocketHandler
1665 pointing to that server's address and port."""
1666 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001667 # Issue #29177: deal with errors that happen during setup
1668 self.server = self.sock_hdlr = self.server_exception = None
1669 try:
1670 self.server = server = self.server_class(self.address,
1671 self.handle_socket, 0.01)
1672 server.start()
1673 # Uncomment next line to test error recovery in setUp()
1674 # raise OSError('dummy error raised')
1675 except OSError as e:
1676 self.server_exception = e
1677 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001678 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001679 hcls = logging.handlers.SocketHandler
1680 if isinstance(server.server_address, tuple):
1681 self.sock_hdlr = hcls('localhost', server.port)
1682 else:
1683 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001684 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001685 self.root_logger.removeHandler(self.root_logger.handlers[0])
1686 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001687 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001688
Christian Heimes180510d2008-03-03 19:15:45 +00001689 def tearDown(self):
1690 """Shutdown the TCP server."""
1691 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001692 if self.sock_hdlr:
1693 self.root_logger.removeHandler(self.sock_hdlr)
1694 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001695 if self.server:
Victor Stinnerbbc8b792019-12-10 20:41:23 +01001696 self.server.stop()
Christian Heimes180510d2008-03-03 19:15:45 +00001697 finally:
1698 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001699
Vinay Sajip7367d082011-05-02 13:17:27 +01001700 def handle_socket(self, request):
1701 conn = request.connection
1702 while True:
1703 chunk = conn.recv(4)
1704 if len(chunk) < 4:
1705 break
1706 slen = struct.unpack(">L", chunk)[0]
1707 chunk = conn.recv(slen)
1708 while len(chunk) < slen:
1709 chunk = chunk + conn.recv(slen - len(chunk))
1710 obj = pickle.loads(chunk)
1711 record = logging.makeLogRecord(obj)
1712 self.log_output += record.msg + '\n'
1713 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001714
Christian Heimes180510d2008-03-03 19:15:45 +00001715 def test_output(self):
1716 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001717 if self.server_exception:
1718 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001719 logger = logging.getLogger("tcp")
1720 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001721 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001722 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001723 self.handled.acquire()
1724 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001725
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001726 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001727 if self.server_exception:
1728 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001729 # Avoid timing-related failures due to SocketHandler's own hard-wired
1730 # one-second timeout on socket.create_connection() (issue #16264).
1731 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001732 # Kill the server
Victor Stinnerbbc8b792019-12-10 20:41:23 +01001733 self.server.stop()
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001734 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001735 try:
1736 raise RuntimeError('Deliberate mistake')
1737 except RuntimeError:
1738 self.root_logger.exception('Never sent')
1739 self.root_logger.error('Never sent, either')
1740 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001741 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001742 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1743 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001744
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001745def _get_temp_domain_socket():
1746 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1747 os.close(fd)
1748 # just need a name - file can't be present, or we'll get an
1749 # 'address already in use' error.
1750 os.remove(fn)
1751 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001752
Victor Stinnerec5a8602014-06-02 14:41:51 +02001753@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001754class UnixSocketHandlerTest(SocketHandlerTest):
1755
1756 """Test for SocketHandler with unix sockets."""
1757
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001758 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001759 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001760
1761 def setUp(self):
1762 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001763 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001764 SocketHandlerTest.setUp(self)
1765
1766 def tearDown(self):
1767 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001768 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001769
Vinay Sajip7367d082011-05-02 13:17:27 +01001770class DatagramHandlerTest(BaseTest):
1771
1772 """Test for DatagramHandler."""
1773
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001774 server_class = TestUDPServer
1775 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001776
Vinay Sajip7367d082011-05-02 13:17:27 +01001777 def setUp(self):
1778 """Set up a UDP server to receive log messages, and a DatagramHandler
1779 pointing to that server's address and port."""
1780 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001781 # Issue #29177: deal with errors that happen during setup
1782 self.server = self.sock_hdlr = self.server_exception = None
1783 try:
1784 self.server = server = self.server_class(self.address,
1785 self.handle_datagram, 0.01)
1786 server.start()
1787 # Uncomment next line to test error recovery in setUp()
1788 # raise OSError('dummy error raised')
1789 except OSError as e:
1790 self.server_exception = e
1791 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001792 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001793 hcls = logging.handlers.DatagramHandler
1794 if isinstance(server.server_address, tuple):
1795 self.sock_hdlr = hcls('localhost', server.port)
1796 else:
1797 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001798 self.log_output = ''
1799 self.root_logger.removeHandler(self.root_logger.handlers[0])
1800 self.root_logger.addHandler(self.sock_hdlr)
1801 self.handled = threading.Event()
1802
1803 def tearDown(self):
1804 """Shutdown the UDP server."""
1805 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001806 if self.server:
Victor Stinnerbbc8b792019-12-10 20:41:23 +01001807 self.server.stop()
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001808 if self.sock_hdlr:
1809 self.root_logger.removeHandler(self.sock_hdlr)
1810 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001811 finally:
1812 BaseTest.tearDown(self)
1813
1814 def handle_datagram(self, request):
1815 slen = struct.pack('>L', 0) # length of prefix
1816 packet = request.packet[len(slen):]
1817 obj = pickle.loads(packet)
1818 record = logging.makeLogRecord(obj)
1819 self.log_output += record.msg + '\n'
1820 self.handled.set()
1821
1822 def test_output(self):
1823 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001824 if self.server_exception:
1825 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001826 logger = logging.getLogger("udp")
1827 logger.error("spam")
1828 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001829 self.handled.clear()
1830 logger.error("eggs")
1831 self.handled.wait()
1832 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001833
Victor Stinnerec5a8602014-06-02 14:41:51 +02001834@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001835class UnixDatagramHandlerTest(DatagramHandlerTest):
1836
1837 """Test for DatagramHandler using Unix sockets."""
1838
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001839 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001840 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001841
1842 def setUp(self):
1843 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001844 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001845 DatagramHandlerTest.setUp(self)
1846
1847 def tearDown(self):
1848 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001849 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001850
Vinay Sajip7367d082011-05-02 13:17:27 +01001851class SysLogHandlerTest(BaseTest):
1852
1853 """Test for SysLogHandler using UDP."""
1854
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001855 server_class = TestUDPServer
1856 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001857
Vinay Sajip7367d082011-05-02 13:17:27 +01001858 def setUp(self):
1859 """Set up a UDP server to receive log messages, and a SysLogHandler
1860 pointing to that server's address and port."""
1861 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001862 # Issue #29177: deal with errors that happen during setup
1863 self.server = self.sl_hdlr = self.server_exception = None
1864 try:
1865 self.server = server = self.server_class(self.address,
1866 self.handle_datagram, 0.01)
1867 server.start()
1868 # Uncomment next line to test error recovery in setUp()
1869 # raise OSError('dummy error raised')
1870 except OSError as e:
1871 self.server_exception = e
1872 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001873 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001874 hcls = logging.handlers.SysLogHandler
1875 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001876 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001877 else:
1878 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001879 self.log_output = ''
1880 self.root_logger.removeHandler(self.root_logger.handlers[0])
1881 self.root_logger.addHandler(self.sl_hdlr)
1882 self.handled = threading.Event()
1883
1884 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001885 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001886 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001887 if self.server:
Victor Stinnerbbc8b792019-12-10 20:41:23 +01001888 self.server.stop()
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001889 if self.sl_hdlr:
1890 self.root_logger.removeHandler(self.sl_hdlr)
1891 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001892 finally:
1893 BaseTest.tearDown(self)
1894
1895 def handle_datagram(self, request):
1896 self.log_output = request.packet
1897 self.handled.set()
1898
1899 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001900 if self.server_exception:
1901 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001902 # The log message sent to the SysLogHandler is properly received.
1903 logger = logging.getLogger("slh")
1904 logger.error("sp\xe4m")
1905 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001906 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001907 self.handled.clear()
1908 self.sl_hdlr.append_nul = False
1909 logger.error("sp\xe4m")
1910 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001911 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001912 self.handled.clear()
1913 self.sl_hdlr.ident = "h\xe4m-"
1914 logger.error("sp\xe4m")
1915 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001916 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001917
Victor Stinnerec5a8602014-06-02 14:41:51 +02001918@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001919class UnixSysLogHandlerTest(SysLogHandlerTest):
1920
1921 """Test for SysLogHandler with Unix sockets."""
1922
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001923 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001924 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001925
1926 def setUp(self):
1927 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001928 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001929 SysLogHandlerTest.setUp(self)
1930
1931 def tearDown(self):
1932 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001933 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001934
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001935@unittest.skipUnless(support.IPV6_ENABLED,
1936 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001937class IPv6SysLogHandlerTest(SysLogHandlerTest):
1938
1939 """Test for SysLogHandler with IPv6 host."""
1940
1941 server_class = TestUDPServer
1942 address = ('::1', 0)
1943
1944 def setUp(self):
1945 self.server_class.address_family = socket.AF_INET6
1946 super(IPv6SysLogHandlerTest, self).setUp()
1947
1948 def tearDown(self):
1949 self.server_class.address_family = socket.AF_INET
1950 super(IPv6SysLogHandlerTest, self).tearDown()
1951
Vinay Sajip7367d082011-05-02 13:17:27 +01001952class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001953 """Test for HTTPHandler."""
1954
1955 def setUp(self):
1956 """Set up an HTTP server to receive log messages, and a HTTPHandler
1957 pointing to that server's address and port."""
1958 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001959 self.handled = threading.Event()
1960
Vinay Sajip7367d082011-05-02 13:17:27 +01001961 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001962 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001963 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001964 if self.command == 'POST':
1965 try:
1966 rlen = int(request.headers['Content-Length'])
1967 self.post_data = request.rfile.read(rlen)
1968 except:
1969 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001970 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001971 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001972 self.handled.set()
1973
1974 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001975 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001976 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001977 root_logger = self.root_logger
1978 root_logger.removeHandler(self.root_logger.handlers[0])
1979 for secure in (False, True):
1980 addr = ('localhost', 0)
1981 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001982 try:
1983 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001984 except ImportError:
1985 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001986 else:
1987 here = os.path.dirname(__file__)
1988 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001989 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001990 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001991
1992 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001993 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001994 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001995 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001996 self.server = server = TestHTTPServer(addr, self.handle_request,
1997 0.01, sslctx=sslctx)
1998 server.start()
1999 server.ready.wait()
2000 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01002001 secure_client = secure and sslctx
2002 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06002003 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01002004 context=context,
2005 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01002006 self.log_data = None
2007 root_logger.addHandler(self.h_hdlr)
2008
2009 for method in ('GET', 'POST'):
2010 self.h_hdlr.method = method
2011 self.handled.clear()
2012 msg = "sp\xe4m"
2013 logger.error(msg)
2014 self.handled.wait()
2015 self.assertEqual(self.log_data.path, '/frob')
2016 self.assertEqual(self.command, method)
2017 if method == 'GET':
2018 d = parse_qs(self.log_data.query)
2019 else:
2020 d = parse_qs(self.post_data.decode('utf-8'))
2021 self.assertEqual(d['name'], ['http'])
2022 self.assertEqual(d['funcName'], ['test_output'])
2023 self.assertEqual(d['msg'], [msg])
2024
Victor Stinnerbbc8b792019-12-10 20:41:23 +01002025 self.server.stop()
Vinay Sajip9ba87612011-05-21 11:32:15 +01002026 self.root_logger.removeHandler(self.h_hdlr)
2027 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01002028
Christian Heimes180510d2008-03-03 19:15:45 +00002029class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002030
Christian Heimes180510d2008-03-03 19:15:45 +00002031 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002032
Christian Heimes180510d2008-03-03 19:15:45 +00002033 def setUp(self):
2034 """Create a dict to remember potentially destroyed objects."""
2035 BaseTest.setUp(self)
2036 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002037
Christian Heimes180510d2008-03-03 19:15:45 +00002038 def _watch_for_survival(self, *args):
2039 """Watch the given objects for survival, by creating weakrefs to
2040 them."""
2041 for obj in args:
2042 key = id(obj), repr(obj)
2043 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002044
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002045 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00002046 """Assert that all objects watched for survival have survived."""
2047 # Trigger cycle breaking.
2048 gc.collect()
2049 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002050 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00002051 if ref() is None:
2052 dead.append(repr_)
2053 if dead:
2054 self.fail("%d objects should have survived "
2055 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002056
Christian Heimes180510d2008-03-03 19:15:45 +00002057 def test_persistent_loggers(self):
2058 # Logger objects are persistent and retain their configuration, even
2059 # if visible references are destroyed.
2060 self.root_logger.setLevel(logging.INFO)
2061 foo = logging.getLogger("foo")
2062 self._watch_for_survival(foo)
2063 foo.setLevel(logging.DEBUG)
2064 self.root_logger.debug(self.next_message())
2065 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002066 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002067 ('foo', 'DEBUG', '2'),
2068 ])
2069 del foo
2070 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002071 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00002072 # foo has retained its settings.
2073 bar = logging.getLogger("foo")
2074 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002075 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002076 ('foo', 'DEBUG', '2'),
2077 ('foo', 'DEBUG', '3'),
2078 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002079
Benjamin Petersonf91df042009-02-13 02:50:59 +00002080
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002081class EncodingTest(BaseTest):
2082 def test_encoding_plain_file(self):
2083 # In Python 2.x, a plain file object is treated as having no encoding.
2084 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00002085 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
2086 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002087 # the non-ascii data we write to the log.
2088 data = "foo\x80"
2089 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002090 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002091 log.addHandler(handler)
2092 try:
2093 # write non-ascii data to the log.
2094 log.warning(data)
2095 finally:
2096 log.removeHandler(handler)
2097 handler.close()
2098 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002099 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002100 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002101 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002102 finally:
2103 f.close()
2104 finally:
2105 if os.path.isfile(fn):
2106 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002107
Benjamin Petersonf91df042009-02-13 02:50:59 +00002108 def test_encoding_cyrillic_unicode(self):
2109 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03002110 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00002111 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03002112 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00002113 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00002114 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00002115 stream = io.BytesIO()
2116 writer = writer_class(stream, 'strict')
2117 handler = logging.StreamHandler(writer)
2118 log.addHandler(handler)
2119 try:
2120 log.warning(message)
2121 finally:
2122 log.removeHandler(handler)
2123 handler.close()
2124 # check we wrote exactly those bytes, ignoring trailing \n etc
2125 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03002126 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00002127 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
2128
2129
Georg Brandlf9734072008-12-07 15:30:06 +00002130class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00002131
Georg Brandlf9734072008-12-07 15:30:06 +00002132 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00002133 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00002134 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002135 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002136 warnings.filterwarnings("always", category=UserWarning)
2137 stream = io.StringIO()
2138 h = logging.StreamHandler(stream)
2139 logger = logging.getLogger("py.warnings")
2140 logger.addHandler(h)
2141 warnings.warn("I'm warning you...")
2142 logger.removeHandler(h)
2143 s = stream.getvalue()
2144 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002145 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00002146
Mike53f7a7c2017-12-14 14:04:53 +03002147 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002148 a_file = io.StringIO()
2149 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
2150 a_file, "Dummy line")
2151 s = a_file.getvalue()
2152 a_file.close()
2153 self.assertEqual(s,
2154 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
2155
2156 def test_warnings_no_handlers(self):
2157 with warnings.catch_warnings():
2158 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002159 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002160
2161 # confirm our assumption: no loggers are set
2162 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002163 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002164
2165 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002166 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002167 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002168
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002169
2170def formatFunc(format, datefmt=None):
2171 return logging.Formatter(format, datefmt)
2172
BNMetrics18fb1fb2018-10-15 19:41:36 +01002173class myCustomFormatter:
2174 def __init__(self, fmt, datefmt=None):
2175 pass
2176
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002177def handlerFunc():
2178 return logging.StreamHandler()
2179
2180class CustomHandler(logging.StreamHandler):
2181 pass
2182
2183class ConfigDictTest(BaseTest):
2184
2185 """Reading logging config from a dictionary."""
2186
Xtreak087570a2018-07-02 14:27:46 +05302187 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002188 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002189
2190 # config0 is a standard configuration.
2191 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002192 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002193 'formatters': {
2194 'form1' : {
2195 'format' : '%(levelname)s ++ %(message)s',
2196 },
2197 },
2198 'handlers' : {
2199 'hand1' : {
2200 'class' : 'logging.StreamHandler',
2201 'formatter' : 'form1',
2202 'level' : 'NOTSET',
2203 'stream' : 'ext://sys.stdout',
2204 },
2205 },
2206 'root' : {
2207 'level' : 'WARNING',
2208 'handlers' : ['hand1'],
2209 },
2210 }
2211
2212 # config1 adds a little to the standard configuration.
2213 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002214 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002215 'formatters': {
2216 'form1' : {
2217 'format' : '%(levelname)s ++ %(message)s',
2218 },
2219 },
2220 'handlers' : {
2221 'hand1' : {
2222 'class' : 'logging.StreamHandler',
2223 'formatter' : 'form1',
2224 'level' : 'NOTSET',
2225 'stream' : 'ext://sys.stdout',
2226 },
2227 },
2228 'loggers' : {
2229 'compiler.parser' : {
2230 'level' : 'DEBUG',
2231 'handlers' : ['hand1'],
2232 },
2233 },
2234 'root' : {
2235 'level' : 'WARNING',
2236 },
2237 }
2238
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002239 # config1a moves the handler to the root. Used with config8a
2240 config1a = {
2241 'version': 1,
2242 'formatters': {
2243 'form1' : {
2244 'format' : '%(levelname)s ++ %(message)s',
2245 },
2246 },
2247 'handlers' : {
2248 'hand1' : {
2249 'class' : 'logging.StreamHandler',
2250 'formatter' : 'form1',
2251 'level' : 'NOTSET',
2252 'stream' : 'ext://sys.stdout',
2253 },
2254 },
2255 'loggers' : {
2256 'compiler.parser' : {
2257 'level' : 'DEBUG',
2258 },
2259 },
2260 'root' : {
2261 'level' : 'WARNING',
2262 'handlers' : ['hand1'],
2263 },
2264 }
2265
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002266 # config2 has a subtle configuration error that should be reported
2267 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002268 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002269 'formatters': {
2270 'form1' : {
2271 'format' : '%(levelname)s ++ %(message)s',
2272 },
2273 },
2274 'handlers' : {
2275 'hand1' : {
2276 'class' : 'logging.StreamHandler',
2277 'formatter' : 'form1',
2278 'level' : 'NOTSET',
2279 'stream' : 'ext://sys.stdbout',
2280 },
2281 },
2282 'loggers' : {
2283 'compiler.parser' : {
2284 'level' : 'DEBUG',
2285 'handlers' : ['hand1'],
2286 },
2287 },
2288 'root' : {
2289 'level' : 'WARNING',
2290 },
2291 }
2292
Mike53f7a7c2017-12-14 14:04:53 +03002293 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002294 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002295 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002296 'formatters': {
2297 'form1' : {
2298 'format' : '%(levelname)s ++ %(message)s',
2299 },
2300 },
2301 'handlers' : {
2302 'hand1' : {
2303 'class' : 'logging.StreamHandler',
2304 'formatter' : 'form1',
2305 'level' : 'NTOSET',
2306 'stream' : 'ext://sys.stdout',
2307 },
2308 },
2309 'loggers' : {
2310 'compiler.parser' : {
2311 'level' : 'DEBUG',
2312 'handlers' : ['hand1'],
2313 },
2314 },
2315 'root' : {
2316 'level' : 'WARNING',
2317 },
2318 }
2319
2320
Mike53f7a7c2017-12-14 14:04:53 +03002321 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002322 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002323 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002324 'formatters': {
2325 'form1' : {
2326 'format' : '%(levelname)s ++ %(message)s',
2327 },
2328 },
2329 'handlers' : {
2330 'hand1' : {
2331 'class' : 'logging.StreamHandler',
2332 'formatter' : 'form1',
2333 'level' : 'NOTSET',
2334 'stream' : 'ext://sys.stdout',
2335 },
2336 },
2337 'loggers' : {
2338 'compiler.parser' : {
2339 'level' : 'DEBUG',
2340 'handlers' : ['hand1'],
2341 },
2342 },
2343 'root' : {
2344 'level' : 'WRANING',
2345 },
2346 }
2347
2348 # config3 has a less subtle configuration error
2349 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002350 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002351 'formatters': {
2352 'form1' : {
2353 'format' : '%(levelname)s ++ %(message)s',
2354 },
2355 },
2356 'handlers' : {
2357 'hand1' : {
2358 'class' : 'logging.StreamHandler',
2359 'formatter' : 'misspelled_name',
2360 'level' : 'NOTSET',
2361 'stream' : 'ext://sys.stdout',
2362 },
2363 },
2364 'loggers' : {
2365 'compiler.parser' : {
2366 'level' : 'DEBUG',
2367 'handlers' : ['hand1'],
2368 },
2369 },
2370 'root' : {
2371 'level' : 'WARNING',
2372 },
2373 }
2374
2375 # config4 specifies a custom formatter class to be loaded
2376 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002377 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002378 'formatters': {
2379 'form1' : {
2380 '()' : __name__ + '.ExceptionFormatter',
2381 'format' : '%(levelname)s:%(name)s:%(message)s',
2382 },
2383 },
2384 'handlers' : {
2385 'hand1' : {
2386 'class' : 'logging.StreamHandler',
2387 'formatter' : 'form1',
2388 'level' : 'NOTSET',
2389 'stream' : 'ext://sys.stdout',
2390 },
2391 },
2392 'root' : {
2393 'level' : 'NOTSET',
2394 'handlers' : ['hand1'],
2395 },
2396 }
2397
2398 # As config4 but using an actual callable rather than a string
2399 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002400 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002401 'formatters': {
2402 'form1' : {
2403 '()' : ExceptionFormatter,
2404 'format' : '%(levelname)s:%(name)s:%(message)s',
2405 },
2406 'form2' : {
2407 '()' : __name__ + '.formatFunc',
2408 'format' : '%(levelname)s:%(name)s:%(message)s',
2409 },
2410 'form3' : {
2411 '()' : formatFunc,
2412 'format' : '%(levelname)s:%(name)s:%(message)s',
2413 },
2414 },
2415 'handlers' : {
2416 'hand1' : {
2417 'class' : 'logging.StreamHandler',
2418 'formatter' : 'form1',
2419 'level' : 'NOTSET',
2420 'stream' : 'ext://sys.stdout',
2421 },
2422 'hand2' : {
2423 '()' : handlerFunc,
2424 },
2425 },
2426 'root' : {
2427 'level' : 'NOTSET',
2428 'handlers' : ['hand1'],
2429 },
2430 }
2431
2432 # config5 specifies a custom handler class to be loaded
2433 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002434 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002435 'formatters': {
2436 'form1' : {
2437 'format' : '%(levelname)s ++ %(message)s',
2438 },
2439 },
2440 'handlers' : {
2441 'hand1' : {
2442 'class' : __name__ + '.CustomHandler',
2443 'formatter' : 'form1',
2444 'level' : 'NOTSET',
2445 'stream' : 'ext://sys.stdout',
2446 },
2447 },
2448 'loggers' : {
2449 'compiler.parser' : {
2450 'level' : 'DEBUG',
2451 'handlers' : ['hand1'],
2452 },
2453 },
2454 'root' : {
2455 'level' : 'WARNING',
2456 },
2457 }
2458
2459 # config6 specifies a custom handler class to be loaded
2460 # but has bad arguments
2461 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002462 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002463 'formatters': {
2464 'form1' : {
2465 'format' : '%(levelname)s ++ %(message)s',
2466 },
2467 },
2468 'handlers' : {
2469 'hand1' : {
2470 'class' : __name__ + '.CustomHandler',
2471 'formatter' : 'form1',
2472 'level' : 'NOTSET',
2473 'stream' : 'ext://sys.stdout',
2474 '9' : 'invalid parameter name',
2475 },
2476 },
2477 'loggers' : {
2478 'compiler.parser' : {
2479 'level' : 'DEBUG',
2480 'handlers' : ['hand1'],
2481 },
2482 },
2483 'root' : {
2484 'level' : 'WARNING',
2485 },
2486 }
2487
Mike53f7a7c2017-12-14 14:04:53 +03002488 # config 7 does not define compiler.parser but defines compiler.lexer
2489 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002490 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002491 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002492 'formatters': {
2493 'form1' : {
2494 'format' : '%(levelname)s ++ %(message)s',
2495 },
2496 },
2497 'handlers' : {
2498 'hand1' : {
2499 'class' : 'logging.StreamHandler',
2500 'formatter' : 'form1',
2501 'level' : 'NOTSET',
2502 'stream' : 'ext://sys.stdout',
2503 },
2504 },
2505 'loggers' : {
2506 'compiler.lexer' : {
2507 'level' : 'DEBUG',
2508 'handlers' : ['hand1'],
2509 },
2510 },
2511 'root' : {
2512 'level' : 'WARNING',
2513 },
2514 }
2515
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002516 # config8 defines both compiler and compiler.lexer
2517 # so compiler.parser should not be disabled (since
2518 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002519 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002520 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002521 'disable_existing_loggers' : False,
2522 'formatters': {
2523 'form1' : {
2524 'format' : '%(levelname)s ++ %(message)s',
2525 },
2526 },
2527 'handlers' : {
2528 'hand1' : {
2529 'class' : 'logging.StreamHandler',
2530 'formatter' : 'form1',
2531 'level' : 'NOTSET',
2532 'stream' : 'ext://sys.stdout',
2533 },
2534 },
2535 'loggers' : {
2536 'compiler' : {
2537 'level' : 'DEBUG',
2538 'handlers' : ['hand1'],
2539 },
2540 'compiler.lexer' : {
2541 },
2542 },
2543 'root' : {
2544 'level' : 'WARNING',
2545 },
2546 }
2547
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002548 # config8a disables existing loggers
2549 config8a = {
2550 'version': 1,
2551 'disable_existing_loggers' : True,
2552 'formatters': {
2553 'form1' : {
2554 'format' : '%(levelname)s ++ %(message)s',
2555 },
2556 },
2557 'handlers' : {
2558 'hand1' : {
2559 'class' : 'logging.StreamHandler',
2560 'formatter' : 'form1',
2561 'level' : 'NOTSET',
2562 'stream' : 'ext://sys.stdout',
2563 },
2564 },
2565 'loggers' : {
2566 'compiler' : {
2567 'level' : 'DEBUG',
2568 'handlers' : ['hand1'],
2569 },
2570 'compiler.lexer' : {
2571 },
2572 },
2573 'root' : {
2574 'level' : 'WARNING',
2575 },
2576 }
2577
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002578 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002579 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002580 'formatters': {
2581 'form1' : {
2582 'format' : '%(levelname)s ++ %(message)s',
2583 },
2584 },
2585 'handlers' : {
2586 'hand1' : {
2587 'class' : 'logging.StreamHandler',
2588 'formatter' : 'form1',
2589 'level' : 'WARNING',
2590 'stream' : 'ext://sys.stdout',
2591 },
2592 },
2593 'loggers' : {
2594 'compiler.parser' : {
2595 'level' : 'WARNING',
2596 'handlers' : ['hand1'],
2597 },
2598 },
2599 'root' : {
2600 'level' : 'NOTSET',
2601 },
2602 }
2603
2604 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002605 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002606 'incremental' : True,
2607 'handlers' : {
2608 'hand1' : {
2609 'level' : 'WARNING',
2610 },
2611 },
2612 'loggers' : {
2613 'compiler.parser' : {
2614 'level' : 'INFO',
2615 },
2616 },
2617 }
2618
2619 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002620 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002621 'incremental' : True,
2622 'handlers' : {
2623 'hand1' : {
2624 'level' : 'INFO',
2625 },
2626 },
2627 'loggers' : {
2628 'compiler.parser' : {
2629 'level' : 'INFO',
2630 },
2631 },
2632 }
2633
Mike53f7a7c2017-12-14 14:04:53 +03002634 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002635 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002636 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002637 'formatters': {
2638 'form1' : {
2639 'format' : '%(levelname)s ++ %(message)s',
2640 },
2641 },
2642 'filters' : {
2643 'filt1' : {
2644 'name' : 'compiler.parser',
2645 },
2646 },
2647 'handlers' : {
2648 'hand1' : {
2649 'class' : 'logging.StreamHandler',
2650 'formatter' : 'form1',
2651 'level' : 'NOTSET',
2652 'stream' : 'ext://sys.stdout',
2653 'filters' : ['filt1'],
2654 },
2655 },
2656 'loggers' : {
2657 'compiler.parser' : {
2658 'level' : 'DEBUG',
2659 'filters' : ['filt1'],
2660 },
2661 },
2662 'root' : {
2663 'level' : 'WARNING',
2664 'handlers' : ['hand1'],
2665 },
2666 }
2667
Mike53f7a7c2017-12-14 14:04:53 +03002668 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002669 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002670 'version': 1,
2671 'true_formatters': {
2672 'form1' : {
2673 'format' : '%(levelname)s ++ %(message)s',
2674 },
2675 },
2676 'handler_configs': {
2677 'hand1' : {
2678 'class' : 'logging.StreamHandler',
2679 'formatter' : 'form1',
2680 'level' : 'NOTSET',
2681 'stream' : 'ext://sys.stdout',
2682 },
2683 },
2684 'formatters' : 'cfg://true_formatters',
2685 'handlers' : {
2686 'hand1' : 'cfg://handler_configs[hand1]',
2687 },
2688 'loggers' : {
2689 'compiler.parser' : {
2690 'level' : 'DEBUG',
2691 'handlers' : ['hand1'],
2692 },
2693 },
2694 'root' : {
2695 'level' : 'WARNING',
2696 },
2697 }
2698
Mike53f7a7c2017-12-14 14:04:53 +03002699 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002700 config12 = {
2701 'true_formatters': {
2702 'form1' : {
2703 'format' : '%(levelname)s ++ %(message)s',
2704 },
2705 },
2706 'handler_configs': {
2707 'hand1' : {
2708 'class' : 'logging.StreamHandler',
2709 'formatter' : 'form1',
2710 'level' : 'NOTSET',
2711 'stream' : 'ext://sys.stdout',
2712 },
2713 },
2714 'formatters' : 'cfg://true_formatters',
2715 'handlers' : {
2716 'hand1' : 'cfg://handler_configs[hand1]',
2717 },
2718 'loggers' : {
2719 'compiler.parser' : {
2720 'level' : 'DEBUG',
2721 'handlers' : ['hand1'],
2722 },
2723 },
2724 'root' : {
2725 'level' : 'WARNING',
2726 },
2727 }
2728
Mike53f7a7c2017-12-14 14:04:53 +03002729 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002730 config13 = {
2731 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002732 'true_formatters': {
2733 'form1' : {
2734 'format' : '%(levelname)s ++ %(message)s',
2735 },
2736 },
2737 'handler_configs': {
2738 'hand1' : {
2739 'class' : 'logging.StreamHandler',
2740 'formatter' : 'form1',
2741 'level' : 'NOTSET',
2742 'stream' : 'ext://sys.stdout',
2743 },
2744 },
2745 'formatters' : 'cfg://true_formatters',
2746 'handlers' : {
2747 'hand1' : 'cfg://handler_configs[hand1]',
2748 },
2749 'loggers' : {
2750 'compiler.parser' : {
2751 'level' : 'DEBUG',
2752 'handlers' : ['hand1'],
2753 },
2754 },
2755 'root' : {
2756 'level' : 'WARNING',
2757 },
2758 }
2759
Vinay Sajip8d270232012-11-15 14:20:18 +00002760 # As config0, but with properties
2761 config14 = {
2762 'version': 1,
2763 'formatters': {
2764 'form1' : {
2765 'format' : '%(levelname)s ++ %(message)s',
2766 },
2767 },
2768 'handlers' : {
2769 'hand1' : {
2770 'class' : 'logging.StreamHandler',
2771 'formatter' : 'form1',
2772 'level' : 'NOTSET',
2773 'stream' : 'ext://sys.stdout',
2774 '.': {
2775 'foo': 'bar',
2776 'terminator': '!\n',
2777 }
2778 },
2779 },
2780 'root' : {
2781 'level' : 'WARNING',
2782 'handlers' : ['hand1'],
2783 },
2784 }
2785
Vinay Sajip3f885b52013-03-22 15:19:54 +00002786 out_of_order = {
2787 "version": 1,
2788 "formatters": {
2789 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002790 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2791 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002792 }
2793 },
2794 "handlers": {
2795 "fileGlobal": {
2796 "class": "logging.StreamHandler",
2797 "level": "DEBUG",
2798 "formatter": "mySimpleFormatter"
2799 },
2800 "bufferGlobal": {
2801 "class": "logging.handlers.MemoryHandler",
2802 "capacity": 5,
2803 "formatter": "mySimpleFormatter",
2804 "target": "fileGlobal",
2805 "level": "DEBUG"
2806 }
2807 },
2808 "loggers": {
2809 "mymodule": {
2810 "level": "DEBUG",
2811 "handlers": ["bufferGlobal"],
2812 "propagate": "true"
2813 }
2814 }
2815 }
2816
BNMetrics18fb1fb2018-10-15 19:41:36 +01002817 # Configuration with custom logging.Formatter subclass as '()' key and 'validate' set to False
2818 custom_formatter_class_validate = {
2819 'version': 1,
2820 'formatters': {
2821 'form1': {
2822 '()': __name__ + '.ExceptionFormatter',
2823 'format': '%(levelname)s:%(name)s:%(message)s',
2824 'validate': False,
2825 },
2826 },
2827 'handlers' : {
2828 'hand1' : {
2829 'class': 'logging.StreamHandler',
2830 'formatter': 'form1',
2831 'level': 'NOTSET',
2832 'stream': 'ext://sys.stdout',
2833 },
2834 },
2835 "loggers": {
2836 "my_test_logger_custom_formatter": {
2837 "level": "DEBUG",
2838 "handlers": ["hand1"],
2839 "propagate": "true"
2840 }
2841 }
2842 }
2843
2844 # Configuration with custom logging.Formatter subclass as 'class' key and 'validate' set to False
2845 custom_formatter_class_validate2 = {
2846 'version': 1,
2847 'formatters': {
2848 'form1': {
2849 'class': __name__ + '.ExceptionFormatter',
2850 'format': '%(levelname)s:%(name)s:%(message)s',
2851 'validate': False,
2852 },
2853 },
2854 'handlers' : {
2855 'hand1' : {
2856 'class': 'logging.StreamHandler',
2857 'formatter': 'form1',
2858 'level': 'NOTSET',
2859 'stream': 'ext://sys.stdout',
2860 },
2861 },
2862 "loggers": {
2863 "my_test_logger_custom_formatter": {
2864 "level": "DEBUG",
2865 "handlers": ["hand1"],
2866 "propagate": "true"
2867 }
2868 }
2869 }
2870
2871 # Configuration with custom class that is not inherited from logging.Formatter
2872 custom_formatter_class_validate3 = {
2873 'version': 1,
2874 'formatters': {
2875 'form1': {
2876 'class': __name__ + '.myCustomFormatter',
2877 'format': '%(levelname)s:%(name)s:%(message)s',
2878 'validate': False,
2879 },
2880 },
2881 'handlers' : {
2882 'hand1' : {
2883 'class': 'logging.StreamHandler',
2884 'formatter': 'form1',
2885 'level': 'NOTSET',
2886 'stream': 'ext://sys.stdout',
2887 },
2888 },
2889 "loggers": {
2890 "my_test_logger_custom_formatter": {
2891 "level": "DEBUG",
2892 "handlers": ["hand1"],
2893 "propagate": "true"
2894 }
2895 }
2896 }
2897
2898 # Configuration with custom function and 'validate' set to False
2899 custom_formatter_with_function = {
2900 'version': 1,
2901 'formatters': {
2902 'form1': {
2903 '()': formatFunc,
2904 'format': '%(levelname)s:%(name)s:%(message)s',
2905 'validate': False,
2906 },
2907 },
2908 'handlers' : {
2909 'hand1' : {
2910 'class': 'logging.StreamHandler',
2911 'formatter': 'form1',
2912 'level': 'NOTSET',
2913 'stream': 'ext://sys.stdout',
2914 },
2915 },
2916 "loggers": {
2917 "my_test_logger_custom_formatter": {
2918 "level": "DEBUG",
2919 "handlers": ["hand1"],
2920 "propagate": "true"
2921 }
2922 }
2923 }
2924
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002925 def apply_config(self, conf):
2926 logging.config.dictConfig(conf)
2927
2928 def test_config0_ok(self):
2929 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002930 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002931 self.apply_config(self.config0)
2932 logger = logging.getLogger()
2933 # Won't output anything
2934 logger.info(self.next_message())
2935 # Outputs a message
2936 logger.error(self.next_message())
2937 self.assert_log_lines([
2938 ('ERROR', '2'),
2939 ], stream=output)
2940 # Original logger output is empty.
2941 self.assert_log_lines([])
2942
2943 def test_config1_ok(self, config=config1):
2944 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002945 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002946 self.apply_config(config)
2947 logger = logging.getLogger("compiler.parser")
2948 # Both will output a message
2949 logger.info(self.next_message())
2950 logger.error(self.next_message())
2951 self.assert_log_lines([
2952 ('INFO', '1'),
2953 ('ERROR', '2'),
2954 ], stream=output)
2955 # Original logger output is empty.
2956 self.assert_log_lines([])
2957
2958 def test_config2_failure(self):
2959 # A simple config which overrides the default settings.
2960 self.assertRaises(Exception, self.apply_config, self.config2)
2961
2962 def test_config2a_failure(self):
2963 # A simple config which overrides the default settings.
2964 self.assertRaises(Exception, self.apply_config, self.config2a)
2965
2966 def test_config2b_failure(self):
2967 # A simple config which overrides the default settings.
2968 self.assertRaises(Exception, self.apply_config, self.config2b)
2969
2970 def test_config3_failure(self):
2971 # A simple config which overrides the default settings.
2972 self.assertRaises(Exception, self.apply_config, self.config3)
2973
2974 def test_config4_ok(self):
2975 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002976 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002977 self.apply_config(self.config4)
2978 #logger = logging.getLogger()
2979 try:
2980 raise RuntimeError()
2981 except RuntimeError:
2982 logging.exception("just testing")
2983 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002984 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002985 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2986 # Original logger output is empty
2987 self.assert_log_lines([])
2988
2989 def test_config4a_ok(self):
2990 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002991 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002992 self.apply_config(self.config4a)
2993 #logger = logging.getLogger()
2994 try:
2995 raise RuntimeError()
2996 except RuntimeError:
2997 logging.exception("just testing")
2998 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002999 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003000 "ERROR:root:just testing\nGot a [RuntimeError]\n")
3001 # Original logger output is empty
3002 self.assert_log_lines([])
3003
3004 def test_config5_ok(self):
3005 self.test_config1_ok(config=self.config5)
3006
3007 def test_config6_failure(self):
3008 self.assertRaises(Exception, self.apply_config, self.config6)
3009
3010 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003011 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003012 self.apply_config(self.config1)
3013 logger = logging.getLogger("compiler.parser")
3014 # Both will output a message
3015 logger.info(self.next_message())
3016 logger.error(self.next_message())
3017 self.assert_log_lines([
3018 ('INFO', '1'),
3019 ('ERROR', '2'),
3020 ], stream=output)
3021 # Original logger output is empty.
3022 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003023 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003024 self.apply_config(self.config7)
3025 logger = logging.getLogger("compiler.parser")
3026 self.assertTrue(logger.disabled)
3027 logger = logging.getLogger("compiler.lexer")
3028 # Both will output a message
3029 logger.info(self.next_message())
3030 logger.error(self.next_message())
3031 self.assert_log_lines([
3032 ('INFO', '3'),
3033 ('ERROR', '4'),
3034 ], stream=output)
3035 # Original logger output is empty.
3036 self.assert_log_lines([])
3037
Mike53f7a7c2017-12-14 14:04:53 +03003038 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003039 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003040 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003041 self.apply_config(self.config1)
3042 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003043 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003044 logger.info(self.next_message())
3045 logger.error(self.next_message())
3046 self.assert_log_lines([
3047 ('INFO', '1'),
3048 ('ERROR', '2'),
3049 ], stream=output)
3050 # Original logger output is empty.
3051 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003052 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003053 self.apply_config(self.config8)
3054 logger = logging.getLogger("compiler.parser")
3055 self.assertFalse(logger.disabled)
3056 # Both will output a message
3057 logger.info(self.next_message())
3058 logger.error(self.next_message())
3059 logger = logging.getLogger("compiler.lexer")
3060 # Both will output a message
3061 logger.info(self.next_message())
3062 logger.error(self.next_message())
3063 self.assert_log_lines([
3064 ('INFO', '3'),
3065 ('ERROR', '4'),
3066 ('INFO', '5'),
3067 ('ERROR', '6'),
3068 ], stream=output)
3069 # Original logger output is empty.
3070 self.assert_log_lines([])
3071
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003072 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003073 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003074 self.apply_config(self.config1a)
3075 logger = logging.getLogger("compiler.parser")
3076 # See issue #11424. compiler-hyphenated sorts
3077 # between compiler and compiler.xyz and this
3078 # was preventing compiler.xyz from being included
3079 # in the child loggers of compiler because of an
3080 # overzealous loop termination condition.
3081 hyphenated = logging.getLogger('compiler-hyphenated')
3082 # All will output a message
3083 logger.info(self.next_message())
3084 logger.error(self.next_message())
3085 hyphenated.critical(self.next_message())
3086 self.assert_log_lines([
3087 ('INFO', '1'),
3088 ('ERROR', '2'),
3089 ('CRITICAL', '3'),
3090 ], stream=output)
3091 # Original logger output is empty.
3092 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003093 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003094 self.apply_config(self.config8a)
3095 logger = logging.getLogger("compiler.parser")
3096 self.assertFalse(logger.disabled)
3097 # Both will output a message
3098 logger.info(self.next_message())
3099 logger.error(self.next_message())
3100 logger = logging.getLogger("compiler.lexer")
3101 # Both will output a message
3102 logger.info(self.next_message())
3103 logger.error(self.next_message())
3104 # Will not appear
3105 hyphenated.critical(self.next_message())
3106 self.assert_log_lines([
3107 ('INFO', '4'),
3108 ('ERROR', '5'),
3109 ('INFO', '6'),
3110 ('ERROR', '7'),
3111 ], stream=output)
3112 # Original logger output is empty.
3113 self.assert_log_lines([])
3114
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003115 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003116 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003117 self.apply_config(self.config9)
3118 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03003119 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003120 logger.info(self.next_message())
3121 self.assert_log_lines([], stream=output)
3122 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03003123 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003124 logger.info(self.next_message())
3125 self.assert_log_lines([], stream=output)
3126 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03003127 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003128 logger.info(self.next_message())
3129 self.assert_log_lines([
3130 ('INFO', '3'),
3131 ], stream=output)
3132
3133 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003134 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003135 self.apply_config(self.config10)
3136 logger = logging.getLogger("compiler.parser")
3137 logger.warning(self.next_message())
3138 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003139 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003140 logger.warning(self.next_message())
3141 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003142 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003143 logger.warning(self.next_message())
3144 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003145 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003146 logger.error(self.next_message())
3147 self.assert_log_lines([
3148 ('WARNING', '1'),
3149 ('ERROR', '4'),
3150 ], stream=output)
3151
3152 def test_config11_ok(self):
3153 self.test_config1_ok(self.config11)
3154
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003155 def test_config12_failure(self):
3156 self.assertRaises(Exception, self.apply_config, self.config12)
3157
3158 def test_config13_failure(self):
3159 self.assertRaises(Exception, self.apply_config, self.config13)
3160
Vinay Sajip8d270232012-11-15 14:20:18 +00003161 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003162 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00003163 self.apply_config(self.config14)
3164 h = logging._handlers['hand1']
3165 self.assertEqual(h.foo, 'bar')
3166 self.assertEqual(h.terminator, '!\n')
3167 logging.warning('Exclamation')
3168 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
3169
Xtreak087570a2018-07-02 14:27:46 +05303170 def test_config15_ok(self):
3171
3172 def cleanup(h1, fn):
3173 h1.close()
3174 os.remove(fn)
3175
3176 with self.check_no_resource_warning():
3177 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
3178 os.close(fd)
3179
3180 config = {
3181 "version": 1,
3182 "handlers": {
3183 "file": {
3184 "class": "logging.FileHandler",
3185 "filename": fn
3186 }
3187 },
3188 "root": {
3189 "handlers": ["file"]
3190 }
3191 }
3192
3193 self.apply_config(config)
3194 self.apply_config(config)
3195
3196 handler = logging.root.handlers[0]
3197 self.addCleanup(cleanup, handler, fn)
3198
Vinay Sajip4ded5512012-10-02 15:56:16 +01003199 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003200 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00003201 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01003202 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003203 t.start()
3204 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00003205 # Now get the port allocated
3206 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003207 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003208 try:
3209 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3210 sock.settimeout(2.0)
3211 sock.connect(('localhost', port))
3212
3213 slen = struct.pack('>L', len(text))
3214 s = slen + text
3215 sentsofar = 0
3216 left = len(s)
3217 while left > 0:
3218 sent = sock.send(s[sentsofar:])
3219 sentsofar += sent
3220 left -= sent
3221 sock.close()
3222 finally:
3223 t.ready.wait(2.0)
3224 logging.config.stopListening()
Victor Stinnerbbc8b792019-12-10 20:41:23 +01003225 support.join_thread(t)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003226
3227 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003228 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003229 self.setup_via_listener(json.dumps(self.config10))
3230 logger = logging.getLogger("compiler.parser")
3231 logger.warning(self.next_message())
3232 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003233 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003234 logger.warning(self.next_message())
3235 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003236 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003237 logger.warning(self.next_message())
3238 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003239 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003240 logger.error(self.next_message())
3241 self.assert_log_lines([
3242 ('WARNING', '1'),
3243 ('ERROR', '4'),
3244 ], stream=output)
3245
3246 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003247 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003248 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
3249 logger = logging.getLogger("compiler.parser")
3250 # Both will output a message
3251 logger.info(self.next_message())
3252 logger.error(self.next_message())
3253 self.assert_log_lines([
3254 ('INFO', '1'),
3255 ('ERROR', '2'),
3256 ], stream=output)
3257 # Original logger output is empty.
3258 self.assert_log_lines([])
3259
Vinay Sajip4ded5512012-10-02 15:56:16 +01003260 def test_listen_verify(self):
3261
3262 def verify_fail(stuff):
3263 return None
3264
3265 def verify_reverse(stuff):
3266 return stuff[::-1]
3267
3268 logger = logging.getLogger("compiler.parser")
3269 to_send = textwrap.dedent(ConfigFileTest.config1)
3270 # First, specify a verification function that will fail.
3271 # We expect to see no output, since our configuration
3272 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01003273 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003274 self.setup_via_listener(to_send, verify_fail)
3275 # Both will output a message
3276 logger.info(self.next_message())
3277 logger.error(self.next_message())
3278 self.assert_log_lines([], stream=output)
3279 # Original logger output has the stuff we logged.
3280 self.assert_log_lines([
3281 ('INFO', '1'),
3282 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003283 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003284
3285 # Now, perform no verification. Our configuration
3286 # should take effect.
3287
Vinay Sajip1feedb42014-05-31 08:19:12 +01003288 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003289 self.setup_via_listener(to_send) # no verify callable specified
3290 logger = logging.getLogger("compiler.parser")
3291 # Both will output a message
3292 logger.info(self.next_message())
3293 logger.error(self.next_message())
3294 self.assert_log_lines([
3295 ('INFO', '3'),
3296 ('ERROR', '4'),
3297 ], stream=output)
3298 # Original logger output still has the stuff we logged before.
3299 self.assert_log_lines([
3300 ('INFO', '1'),
3301 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003302 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003303
3304 # Now, perform verification which transforms the bytes.
3305
Vinay Sajip1feedb42014-05-31 08:19:12 +01003306 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003307 self.setup_via_listener(to_send[::-1], verify_reverse)
3308 logger = logging.getLogger("compiler.parser")
3309 # Both will output a message
3310 logger.info(self.next_message())
3311 logger.error(self.next_message())
3312 self.assert_log_lines([
3313 ('INFO', '5'),
3314 ('ERROR', '6'),
3315 ], stream=output)
3316 # Original logger output still has the stuff we logged before.
3317 self.assert_log_lines([
3318 ('INFO', '1'),
3319 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003320 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003321
Vinay Sajip3f885b52013-03-22 15:19:54 +00003322 def test_out_of_order(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01003323 self.assertRaises(ValueError, self.apply_config, self.out_of_order)
3324
3325 def test_out_of_order_with_dollar_style(self):
Pablo Galindo137b0632018-10-16 15:17:57 +01003326 config = copy.deepcopy(self.out_of_order)
BNMetrics18fb1fb2018-10-15 19:41:36 +01003327 config['formatters']['mySimpleFormatter']['format'] = "${asctime} (${name}) ${levelname}: ${message}"
3328
3329 self.apply_config(config)
Vinay Sajip3f885b52013-03-22 15:19:54 +00003330 handler = logging.getLogger('mymodule').handlers[0]
3331 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003332 self.assertIsInstance(handler.formatter._style,
3333 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003334
BNMetrics18fb1fb2018-10-15 19:41:36 +01003335 def test_custom_formatter_class_with_validate(self):
3336 self.apply_config(self.custom_formatter_class_validate)
3337 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3338 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3339
3340 def test_custom_formatter_class_with_validate2(self):
3341 self.apply_config(self.custom_formatter_class_validate2)
3342 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3343 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3344
3345 def test_custom_formatter_class_with_validate2_with_wrong_fmt(self):
3346 config = self.custom_formatter_class_validate.copy()
3347 config['formatters']['form1']['style'] = "$"
3348
3349 # Exception should not be raise as we have configured 'validate' to False
3350 self.apply_config(config)
3351 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3352 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3353
3354 def test_custom_formatter_class_with_validate3(self):
3355 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_class_validate3)
3356
3357 def test_custom_formatter_function_with_validate(self):
3358 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_function)
3359
Vinay Sajip373baef2011-04-26 20:05:24 +01003360 def test_baseconfig(self):
3361 d = {
3362 'atuple': (1, 2, 3),
3363 'alist': ['a', 'b', 'c'],
3364 'adict': {'d': 'e', 'f': 3 },
3365 'nest1': ('g', ('h', 'i'), 'j'),
3366 'nest2': ['k', ['l', 'm'], 'n'],
3367 'nest3': ['o', 'cfg://alist', 'p'],
3368 }
3369 bc = logging.config.BaseConfigurator(d)
3370 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3371 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3372 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3373 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3374 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3375 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3376 v = bc.convert('cfg://nest3')
3377 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3378 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3379 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3380 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003381
Vinay Sajip46abfc12020-01-01 19:32:11 +00003382 def test_namedtuple(self):
3383 # see bpo-39142
3384 from collections import namedtuple
3385
3386 class MyHandler(logging.StreamHandler):
3387 def __init__(self, resource, *args, **kwargs):
3388 super().__init__(*args, **kwargs)
3389 self.resource: namedtuple = resource
3390
3391 def emit(self, record):
3392 record.msg += f' {self.resource.type}'
3393 return super().emit(record)
3394
3395 Resource = namedtuple('Resource', ['type', 'labels'])
3396 resource = Resource(type='my_type', labels=['a'])
3397
3398 config = {
3399 'version': 1,
3400 'handlers': {
3401 'myhandler': {
3402 '()': MyHandler,
3403 'resource': resource
3404 }
3405 },
3406 'root': {'level': 'INFO', 'handlers': ['myhandler']},
3407 }
3408 with support.captured_stderr() as stderr:
3409 self.apply_config(config)
3410 logging.info('some log')
3411 self.assertEqual(stderr.getvalue(), 'some log my_type\n')
3412
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003413class ManagerTest(BaseTest):
3414 def test_manager_loggerclass(self):
3415 logged = []
3416
3417 class MyLogger(logging.Logger):
3418 def _log(self, level, msg, args, exc_info=None, extra=None):
3419 logged.append(msg)
3420
3421 man = logging.Manager(None)
3422 self.assertRaises(TypeError, man.setLoggerClass, int)
3423 man.setLoggerClass(MyLogger)
3424 logger = man.getLogger('test')
3425 logger.warning('should appear in logged')
3426 logging.warning('should not appear in logged')
3427
3428 self.assertEqual(logged, ['should appear in logged'])
3429
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003430 def test_set_log_record_factory(self):
3431 man = logging.Manager(None)
3432 expected = object()
3433 man.setLogRecordFactory(expected)
3434 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003435
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003436class ChildLoggerTest(BaseTest):
3437 def test_child_loggers(self):
3438 r = logging.getLogger()
3439 l1 = logging.getLogger('abc')
3440 l2 = logging.getLogger('def.ghi')
3441 c1 = r.getChild('xyz')
3442 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003443 self.assertIs(c1, logging.getLogger('xyz'))
3444 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003445 c1 = l1.getChild('def')
3446 c2 = c1.getChild('ghi')
3447 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003448 self.assertIs(c1, logging.getLogger('abc.def'))
3449 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3450 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003451
3452
Vinay Sajip6fac8172010-10-19 20:44:14 +00003453class DerivedLogRecord(logging.LogRecord):
3454 pass
3455
Vinay Sajip61561522010-12-03 11:50:38 +00003456class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003457
3458 def setUp(self):
3459 class CheckingFilter(logging.Filter):
3460 def __init__(self, cls):
3461 self.cls = cls
3462
3463 def filter(self, record):
3464 t = type(record)
3465 if t is not self.cls:
3466 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3467 self.cls)
3468 raise TypeError(msg)
3469 return True
3470
3471 BaseTest.setUp(self)
3472 self.filter = CheckingFilter(DerivedLogRecord)
3473 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003474 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003475
3476 def tearDown(self):
3477 self.root_logger.removeFilter(self.filter)
3478 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003479 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003480
3481 def test_logrecord_class(self):
3482 self.assertRaises(TypeError, self.root_logger.warning,
3483 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003484 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003485 self.root_logger.error(self.next_message())
3486 self.assert_log_lines([
3487 ('root', 'ERROR', '2'),
3488 ])
3489
3490
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003491class QueueHandlerTest(BaseTest):
3492 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003493 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003494
3495 def setUp(self):
3496 BaseTest.setUp(self)
3497 self.queue = queue.Queue(-1)
3498 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003499 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003500 self.que_logger = logging.getLogger('que')
3501 self.que_logger.propagate = False
3502 self.que_logger.setLevel(logging.WARNING)
3503 self.que_logger.addHandler(self.que_hdlr)
3504
3505 def tearDown(self):
3506 self.que_hdlr.close()
3507 BaseTest.tearDown(self)
3508
3509 def test_queue_handler(self):
3510 self.que_logger.debug(self.next_message())
3511 self.assertRaises(queue.Empty, self.queue.get_nowait)
3512 self.que_logger.info(self.next_message())
3513 self.assertRaises(queue.Empty, self.queue.get_nowait)
3514 msg = self.next_message()
3515 self.que_logger.warning(msg)
3516 data = self.queue.get_nowait()
3517 self.assertTrue(isinstance(data, logging.LogRecord))
3518 self.assertEqual(data.name, self.que_logger.name)
3519 self.assertEqual((data.msg, data.args), (msg, None))
3520
favlladfe3442017-08-01 20:12:26 +02003521 def test_formatting(self):
3522 msg = self.next_message()
3523 levelname = logging.getLevelName(logging.WARNING)
3524 log_format_str = '{name} -> {levelname}: {message}'
3525 formatted_msg = log_format_str.format(name=self.name,
3526 levelname=levelname, message=msg)
3527 formatter = logging.Formatter(self.log_format)
3528 self.que_hdlr.setFormatter(formatter)
3529 self.que_logger.warning(msg)
3530 log_record = self.queue.get_nowait()
3531 self.assertEqual(formatted_msg, log_record.msg)
3532 self.assertEqual(formatted_msg, log_record.message)
3533
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003534 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3535 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003536 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003537 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003538 listener = logging.handlers.QueueListener(self.queue, handler)
3539 listener.start()
3540 try:
3541 self.que_logger.warning(self.next_message())
3542 self.que_logger.error(self.next_message())
3543 self.que_logger.critical(self.next_message())
3544 finally:
3545 listener.stop()
3546 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3547 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3548 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003549 handler.close()
3550
3551 # Now test with respect_handler_level set
3552
3553 handler = support.TestHandler(support.Matcher())
3554 handler.setLevel(logging.CRITICAL)
3555 listener = logging.handlers.QueueListener(self.queue, handler,
3556 respect_handler_level=True)
3557 listener.start()
3558 try:
3559 self.que_logger.warning(self.next_message())
3560 self.que_logger.error(self.next_message())
3561 self.que_logger.critical(self.next_message())
3562 finally:
3563 listener.stop()
3564 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3565 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3566 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
Cheryl Sabellad345bb42018-09-25 19:00:08 -04003567 handler.close()
3568
3569 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3570 'logging.handlers.QueueListener required for this test')
3571 def test_queue_listener_with_StreamHandler(self):
3572 # Test that traceback only appends once (bpo-34334).
3573 listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
3574 listener.start()
3575 try:
3576 1 / 0
3577 except ZeroDivisionError as e:
3578 exc = e
3579 self.que_logger.exception(self.next_message(), exc_info=exc)
3580 listener.stop()
3581 self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
Vinay Sajip365701a2015-02-09 19:49:00 +00003582
Xtreak2dad9602019-04-07 13:21:27 +05303583 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3584 'logging.handlers.QueueListener required for this test')
3585 def test_queue_listener_with_multiple_handlers(self):
3586 # Test that queue handler format doesn't affect other handler formats (bpo-35726).
3587 self.que_hdlr.setFormatter(self.root_formatter)
3588 self.que_logger.addHandler(self.root_hdlr)
3589
3590 listener = logging.handlers.QueueListener(self.queue, self.que_hdlr)
3591 listener.start()
3592 self.que_logger.error("error")
3593 listener.stop()
3594 self.assertEqual(self.stream.getvalue().strip(), "que -> ERROR: error")
3595
Vinay Sajipd61910c2016-09-08 01:13:39 +01003596if hasattr(logging.handlers, 'QueueListener'):
3597 import multiprocessing
3598 from unittest.mock import patch
3599
3600 class QueueListenerTest(BaseTest):
3601 """
3602 Tests based on patch submitted for issue #27930. Ensure that
3603 QueueListener handles all log messages.
3604 """
3605
3606 repeat = 20
3607
3608 @staticmethod
3609 def setup_and_log(log_queue, ident):
3610 """
3611 Creates a logger with a QueueHandler that logs to a queue read by a
3612 QueueListener. Starts the listener, logs five messages, and stops
3613 the listener.
3614 """
3615 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3616 logger.setLevel(logging.DEBUG)
3617 handler = logging.handlers.QueueHandler(log_queue)
3618 logger.addHandler(handler)
3619 listener = logging.handlers.QueueListener(log_queue)
3620 listener.start()
3621
3622 logger.info('one')
3623 logger.info('two')
3624 logger.info('three')
3625 logger.info('four')
3626 logger.info('five')
3627
3628 listener.stop()
3629 logger.removeHandler(handler)
3630 handler.close()
3631
3632 @patch.object(logging.handlers.QueueListener, 'handle')
3633 def test_handle_called_with_queue_queue(self, mock_handle):
3634 for i in range(self.repeat):
3635 log_queue = queue.Queue()
3636 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3637 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3638 'correct number of handled log messages')
3639
3640 @patch.object(logging.handlers.QueueListener, 'handle')
3641 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003642 # Issue 28668: The multiprocessing (mp) module is not functional
3643 # when the mp.synchronize module cannot be imported.
3644 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003645 for i in range(self.repeat):
3646 log_queue = multiprocessing.Queue()
3647 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003648 log_queue.close()
3649 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003650 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3651 'correct number of handled log messages')
3652
3653 @staticmethod
3654 def get_all_from_queue(log_queue):
3655 try:
3656 while True:
3657 yield log_queue.get_nowait()
3658 except queue.Empty:
3659 return []
3660
3661 def test_no_messages_in_queue_after_stop(self):
3662 """
3663 Five messages are logged then the QueueListener is stopped. This
3664 test then gets everything off the queue. Failure of this test
3665 indicates that messages were not registered on the queue until
3666 _after_ the QueueListener stopped.
3667 """
xdegayebf2b65e2017-12-01 08:08:49 +01003668 # Issue 28668: The multiprocessing (mp) module is not functional
3669 # when the mp.synchronize module cannot be imported.
3670 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003671 for i in range(self.repeat):
3672 queue = multiprocessing.Queue()
3673 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3674 # time.sleep(1)
3675 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003676 queue.close()
3677 queue.join_thread()
3678
Vinay Sajipd61910c2016-09-08 01:13:39 +01003679 expected = [[], [logging.handlers.QueueListener._sentinel]]
3680 self.assertIn(items, expected,
3681 'Found unexpected messages in queue: %s' % (
3682 [m.msg if isinstance(m, logging.LogRecord)
3683 else m for m in items]))
3684
Bar Harel6b282e12019-06-01 12:19:09 +03003685 def test_calls_task_done_after_stop(self):
3686 # Issue 36813: Make sure queue.join does not deadlock.
3687 log_queue = queue.Queue()
3688 listener = logging.handlers.QueueListener(log_queue)
3689 listener.start()
3690 listener.stop()
3691 with self.assertRaises(ValueError):
3692 # Make sure all tasks are done and .join won't block.
3693 log_queue.task_done()
3694
Vinay Sajipe723e962011-04-15 22:27:17 +01003695
Vinay Sajip37eb3382011-04-26 20:26:41 +01003696ZERO = datetime.timedelta(0)
3697
3698class UTC(datetime.tzinfo):
3699 def utcoffset(self, dt):
3700 return ZERO
3701
3702 dst = utcoffset
3703
3704 def tzname(self, dt):
3705 return 'UTC'
3706
3707utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003708
Vinay Sajipa39c5712010-10-25 13:57:39 +00003709class FormatterTest(unittest.TestCase):
3710 def setUp(self):
3711 self.common = {
3712 'name': 'formatter.test',
3713 'level': logging.DEBUG,
3714 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3715 'lineno': 42,
3716 'exc_info': None,
3717 'func': None,
3718 'msg': 'Message with %d %s',
3719 'args': (2, 'placeholders'),
3720 }
3721 self.variants = {
3722 }
3723
3724 def get_record(self, name=None):
3725 result = dict(self.common)
3726 if name is not None:
3727 result.update(self.variants[name])
3728 return logging.makeLogRecord(result)
3729
BNMetrics18fb1fb2018-10-15 19:41:36 +01003730 def assert_error_message(self, exception, message, *args, **kwargs):
3731 try:
3732 self.assertRaises(exception, *args, **kwargs)
3733 except exception as e:
3734 self.assertEqual(message, e.message)
3735
Vinay Sajipa39c5712010-10-25 13:57:39 +00003736 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003737 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003738 r = self.get_record()
3739 f = logging.Formatter('${%(message)s}')
3740 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3741 f = logging.Formatter('%(random)s')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003742 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003743 self.assertFalse(f.usesTime())
3744 f = logging.Formatter('%(asctime)s')
3745 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003746 f = logging.Formatter('%(asctime)-15s')
3747 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003748 f = logging.Formatter('%(asctime)#15s')
3749 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003750
3751 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003752 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003753 r = self.get_record()
3754 f = logging.Formatter('$%{message}%$', style='{')
3755 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3756 f = logging.Formatter('{random}', style='{')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003757 self.assertRaises(ValueError, f.format, r)
3758 f = logging.Formatter("{message}", style='{')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003759 self.assertFalse(f.usesTime())
3760 f = logging.Formatter('{asctime}', style='{')
3761 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003762 f = logging.Formatter('{asctime!s:15}', style='{')
3763 self.assertTrue(f.usesTime())
3764 f = logging.Formatter('{asctime:15}', style='{')
3765 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003766
3767 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003768 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003769 r = self.get_record()
BNMetrics18fb1fb2018-10-15 19:41:36 +01003770 f = logging.Formatter('${message}', style='$')
3771 self.assertEqual(f.format(r), 'Message with 2 placeholders')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003772 f = logging.Formatter('$message', style='$')
3773 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3774 f = logging.Formatter('$$%${message}%$$', style='$')
3775 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3776 f = logging.Formatter('${random}', style='$')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003777 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003778 self.assertFalse(f.usesTime())
3779 f = logging.Formatter('${asctime}', style='$')
3780 self.assertTrue(f.usesTime())
3781 f = logging.Formatter('$asctime', style='$')
3782 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003783 f = logging.Formatter('${message}', style='$')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003784 self.assertFalse(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003785 f = logging.Formatter('${asctime}--', style='$')
3786 self.assertTrue(f.usesTime())
3787
3788 def test_format_validate(self):
3789 # Check correct formatting
3790 # Percentage style
3791 f = logging.Formatter("%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3792 self.assertEqual(f._fmt, "%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3793 f = logging.Formatter("%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3794 self.assertEqual(f._fmt, "%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3795 f = logging.Formatter("%(process)#+027.23X")
3796 self.assertEqual(f._fmt, "%(process)#+027.23X")
3797 f = logging.Formatter("%(foo)#.*g")
3798 self.assertEqual(f._fmt, "%(foo)#.*g")
3799
3800 # StrFormat Style
3801 f = logging.Formatter("$%{message}%$ - {asctime!a:15} - {customfield['key']}", style="{")
3802 self.assertEqual(f._fmt, "$%{message}%$ - {asctime!a:15} - {customfield['key']}")
3803 f = logging.Formatter("{process:.2f} - {custom.f:.4f}", style="{")
3804 self.assertEqual(f._fmt, "{process:.2f} - {custom.f:.4f}")
3805 f = logging.Formatter("{customfield!s:#<30}", style="{")
3806 self.assertEqual(f._fmt, "{customfield!s:#<30}")
3807 f = logging.Formatter("{message!r}", style="{")
3808 self.assertEqual(f._fmt, "{message!r}")
3809 f = logging.Formatter("{message!s}", style="{")
3810 self.assertEqual(f._fmt, "{message!s}")
3811 f = logging.Formatter("{message!a}", style="{")
3812 self.assertEqual(f._fmt, "{message!a}")
3813 f = logging.Formatter("{process!r:4.2}", style="{")
3814 self.assertEqual(f._fmt, "{process!r:4.2}")
3815 f = logging.Formatter("{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}", style="{")
3816 self.assertEqual(f._fmt, "{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}")
3817 f = logging.Formatter("{process!s:{w},.{p}}", style="{")
3818 self.assertEqual(f._fmt, "{process!s:{w},.{p}}")
3819 f = logging.Formatter("{foo:12.{p}}", style="{")
3820 self.assertEqual(f._fmt, "{foo:12.{p}}")
3821 f = logging.Formatter("{foo:{w}.6}", style="{")
3822 self.assertEqual(f._fmt, "{foo:{w}.6}")
3823 f = logging.Formatter("{foo[0].bar[1].baz}", style="{")
3824 self.assertEqual(f._fmt, "{foo[0].bar[1].baz}")
3825 f = logging.Formatter("{foo[k1].bar[k2].baz}", style="{")
3826 self.assertEqual(f._fmt, "{foo[k1].bar[k2].baz}")
3827 f = logging.Formatter("{12[k1].bar[k2].baz}", style="{")
3828 self.assertEqual(f._fmt, "{12[k1].bar[k2].baz}")
3829
3830 # Dollar style
3831 f = logging.Formatter("${asctime} - $message", style="$")
3832 self.assertEqual(f._fmt, "${asctime} - $message")
3833 f = logging.Formatter("$bar $$", style="$")
3834 self.assertEqual(f._fmt, "$bar $$")
3835 f = logging.Formatter("$bar $$$$", style="$")
3836 self.assertEqual(f._fmt, "$bar $$$$") # this would print two $($$)
3837
3838 # Testing when ValueError being raised from incorrect format
3839 # Percentage Style
3840 self.assertRaises(ValueError, logging.Formatter, "%(asctime)Z")
3841 self.assertRaises(ValueError, logging.Formatter, "%(asctime)b")
3842 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*")
3843 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*3s")
3844 self.assertRaises(ValueError, logging.Formatter, "%(asctime)_")
3845 self.assertRaises(ValueError, logging.Formatter, '{asctime}')
3846 self.assertRaises(ValueError, logging.Formatter, '${message}')
3847 self.assertRaises(ValueError, logging.Formatter, '%(foo)#12.3*f') # with both * and decimal number as precision
3848 self.assertRaises(ValueError, logging.Formatter, '%(foo)0*.8*f')
3849
3850 # StrFormat Style
3851 # Testing failure for '-' in field name
3852 self.assert_error_message(
3853 ValueError,
3854 "invalid field name/expression: 'name-thing'",
3855 logging.Formatter, "{name-thing}", style="{"
3856 )
3857 # Testing failure for style mismatch
3858 self.assert_error_message(
3859 ValueError,
3860 "invalid format: no fields",
3861 logging.Formatter, '%(asctime)s', style='{'
3862 )
3863 # Testing failure for invalid conversion
3864 self.assert_error_message(
3865 ValueError,
3866 "invalid conversion: 'Z'"
3867 )
3868 self.assertRaises(ValueError, logging.Formatter, '{asctime!s:#30,15f}', style='{')
3869 self.assert_error_message(
3870 ValueError,
3871 "invalid format: expected ':' after conversion specifier",
3872 logging.Formatter, '{asctime!aa:15}', style='{'
3873 )
3874 # Testing failure for invalid spec
3875 self.assert_error_message(
3876 ValueError,
3877 "bad specifier: '.2ff'",
3878 logging.Formatter, '{process:.2ff}', style='{'
3879 )
3880 self.assertRaises(ValueError, logging.Formatter, '{process:.2Z}', style='{')
3881 self.assertRaises(ValueError, logging.Formatter, '{process!s:<##30,12g}', style='{')
3882 self.assertRaises(ValueError, logging.Formatter, '{process!s:<#30#,12g}', style='{')
3883 self.assertRaises(ValueError, logging.Formatter, '{process!s:{{w}},{{p}}}', style='{')
3884 # Testing failure for mismatch braces
3885 self.assert_error_message(
3886 ValueError,
3887 "invalid format: unmatched '{' in format spec",
3888 logging.Formatter, '{process', style='{'
3889 )
3890 self.assert_error_message(
3891 ValueError,
3892 "invalid format: unmatched '{' in format spec",
3893 logging.Formatter, 'process}', style='{'
3894 )
3895 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}', style='{')
3896 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}}', style='{')
3897 self.assertRaises(ValueError, logging.Formatter, '{foo/bar}', style='{')
3898 self.assertRaises(ValueError, logging.Formatter, '{foo:{{w}}.{{p}}}}', style='{')
3899 self.assertRaises(ValueError, logging.Formatter, '{foo!X:{{w}}.{{p}}}', style='{')
3900 self.assertRaises(ValueError, logging.Formatter, '{foo!a:random}', style='{')
3901 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{dom}', style='{')
3902 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{d}om}', style='{')
3903 self.assertRaises(ValueError, logging.Formatter, '{foo.!a:d}', style='{')
3904
3905 # Dollar style
3906 # Testing failure for mismatch bare $
3907 self.assert_error_message(
3908 ValueError,
3909 "invalid format: bare \'$\' not allowed",
3910 logging.Formatter, '$bar $$$', style='$'
3911 )
3912 self.assert_error_message(
3913 ValueError,
3914 "invalid format: bare \'$\' not allowed",
3915 logging.Formatter, 'bar $', style='$'
3916 )
3917 self.assert_error_message(
3918 ValueError,
3919 "invalid format: bare \'$\' not allowed",
3920 logging.Formatter, 'foo $.', style='$'
3921 )
3922 # Testing failure for mismatch style
3923 self.assert_error_message(
3924 ValueError,
3925 "invalid format: no fields",
3926 logging.Formatter, '{asctime}', style='$'
3927 )
3928 self.assertRaises(ValueError, logging.Formatter, '%(asctime)s', style='$')
3929
3930 # Testing failure for incorrect fields
3931 self.assert_error_message(
3932 ValueError,
3933 "invalid format: no fields",
3934 logging.Formatter, 'foo', style='$'
3935 )
3936 self.assertRaises(ValueError, logging.Formatter, '${asctime', style='$')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003937
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003938 def test_invalid_style(self):
3939 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3940
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003941 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003942 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003943 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3944 # We use None to indicate we want the local timezone
3945 # We're essentially converting a UTC time to local time
3946 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003947 r.msecs = 123
3948 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003949 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003950 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3951 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003952 f.format(r)
3953 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3954
3955class TestBufferingFormatter(logging.BufferingFormatter):
3956 def formatHeader(self, records):
3957 return '[(%d)' % len(records)
3958
3959 def formatFooter(self, records):
3960 return '(%d)]' % len(records)
3961
3962class BufferingFormatterTest(unittest.TestCase):
3963 def setUp(self):
3964 self.records = [
3965 logging.makeLogRecord({'msg': 'one'}),
3966 logging.makeLogRecord({'msg': 'two'}),
3967 ]
3968
3969 def test_default(self):
3970 f = logging.BufferingFormatter()
3971 self.assertEqual('', f.format([]))
3972 self.assertEqual('onetwo', f.format(self.records))
3973
3974 def test_custom(self):
3975 f = TestBufferingFormatter()
3976 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3977 lf = logging.Formatter('<%(message)s>')
3978 f = TestBufferingFormatter(lf)
3979 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003980
3981class ExceptionTest(BaseTest):
3982 def test_formatting(self):
3983 r = self.root_logger
3984 h = RecordingHandler()
3985 r.addHandler(h)
3986 try:
3987 raise RuntimeError('deliberate mistake')
3988 except:
3989 logging.exception('failed', stack_info=True)
3990 r.removeHandler(h)
3991 h.close()
3992 r = h.records[0]
3993 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3994 'call last):\n'))
3995 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3996 'deliberate mistake'))
3997 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3998 'call last):\n'))
3999 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
4000 'stack_info=True)'))
4001
4002
Vinay Sajip5a27d402010-12-10 11:42:57 +00004003class LastResortTest(BaseTest):
4004 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00004005 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00004006 root = self.root_logger
4007 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00004008 old_lastresort = logging.lastResort
4009 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01004010
Vinay Sajip5a27d402010-12-10 11:42:57 +00004011 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01004012 with support.captured_stderr() as stderr:
4013 root.debug('This should not appear')
4014 self.assertEqual(stderr.getvalue(), '')
4015 root.warning('Final chance!')
4016 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
4017
4018 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00004019 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01004020 with support.captured_stderr() as stderr:
4021 root.warning('Final chance!')
4022 msg = 'No handlers could be found for logger "root"\n'
4023 self.assertEqual(stderr.getvalue(), msg)
4024
Vinay Sajip5a27d402010-12-10 11:42:57 +00004025 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01004026 with support.captured_stderr() as stderr:
4027 root.warning('Final chance!')
4028 self.assertEqual(stderr.getvalue(), '')
4029
4030 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00004031 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00004032 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01004033 with support.captured_stderr() as stderr:
4034 root.warning('Final chance!')
4035 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00004036 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00004037 root.addHandler(self.root_hdlr)
4038 logging.lastResort = old_lastresort
4039 logging.raiseExceptions = old_raise_exceptions
4040
4041
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004042class FakeHandler:
4043
4044 def __init__(self, identifier, called):
4045 for method in ('acquire', 'flush', 'close', 'release'):
4046 setattr(self, method, self.record_call(identifier, method, called))
4047
4048 def record_call(self, identifier, method_name, called):
4049 def inner():
4050 called.append('{} - {}'.format(identifier, method_name))
4051 return inner
4052
4053
4054class RecordingHandler(logging.NullHandler):
4055
4056 def __init__(self, *args, **kwargs):
4057 super(RecordingHandler, self).__init__(*args, **kwargs)
4058 self.records = []
4059
4060 def handle(self, record):
4061 """Keep track of all the emitted records."""
4062 self.records.append(record)
4063
4064
4065class ShutdownTest(BaseTest):
4066
Vinay Sajip5e66b162011-04-20 15:41:14 +01004067 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004068
4069 def setUp(self):
4070 super(ShutdownTest, self).setUp()
4071 self.called = []
4072
4073 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004074 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004075
4076 def raise_error(self, error):
4077 def inner():
4078 raise error()
4079 return inner
4080
4081 def test_no_failure(self):
4082 # create some fake handlers
4083 handler0 = FakeHandler(0, self.called)
4084 handler1 = FakeHandler(1, self.called)
4085 handler2 = FakeHandler(2, self.called)
4086
4087 # create live weakref to those handlers
4088 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
4089
4090 logging.shutdown(handlerList=list(handlers))
4091
4092 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
4093 '1 - acquire', '1 - flush', '1 - close', '1 - release',
4094 '0 - acquire', '0 - flush', '0 - close', '0 - release']
4095 self.assertEqual(expected, self.called)
4096
4097 def _test_with_failure_in_method(self, method, error):
4098 handler = FakeHandler(0, self.called)
4099 setattr(handler, method, self.raise_error(error))
4100 handlers = [logging.weakref.ref(handler)]
4101
4102 logging.shutdown(handlerList=list(handlers))
4103
4104 self.assertEqual('0 - release', self.called[-1])
4105
4106 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004107 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004108
4109 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004110 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004111
4112 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004113 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004114
4115 def test_with_valueerror_in_acquire(self):
4116 self._test_with_failure_in_method('acquire', ValueError)
4117
4118 def test_with_valueerror_in_flush(self):
4119 self._test_with_failure_in_method('flush', ValueError)
4120
4121 def test_with_valueerror_in_close(self):
4122 self._test_with_failure_in_method('close', ValueError)
4123
4124 def test_with_other_error_in_acquire_without_raise(self):
4125 logging.raiseExceptions = False
4126 self._test_with_failure_in_method('acquire', IndexError)
4127
4128 def test_with_other_error_in_flush_without_raise(self):
4129 logging.raiseExceptions = False
4130 self._test_with_failure_in_method('flush', IndexError)
4131
4132 def test_with_other_error_in_close_without_raise(self):
4133 logging.raiseExceptions = False
4134 self._test_with_failure_in_method('close', IndexError)
4135
4136 def test_with_other_error_in_acquire_with_raise(self):
4137 logging.raiseExceptions = True
4138 self.assertRaises(IndexError, self._test_with_failure_in_method,
4139 'acquire', IndexError)
4140
4141 def test_with_other_error_in_flush_with_raise(self):
4142 logging.raiseExceptions = True
4143 self.assertRaises(IndexError, self._test_with_failure_in_method,
4144 'flush', IndexError)
4145
4146 def test_with_other_error_in_close_with_raise(self):
4147 logging.raiseExceptions = True
4148 self.assertRaises(IndexError, self._test_with_failure_in_method,
4149 'close', IndexError)
4150
4151
4152class ModuleLevelMiscTest(BaseTest):
4153
Vinay Sajip5e66b162011-04-20 15:41:14 +01004154 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004155
4156 def test_disable(self):
4157 old_disable = logging.root.manager.disable
4158 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004159 self.assertEqual(old_disable, 0)
4160 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004161
4162 logging.disable(83)
4163 self.assertEqual(logging.root.manager.disable, 83)
4164
Vinay Sajipd489ac92016-12-31 11:40:11 +00004165 # test the default value introduced in 3.7
4166 # (Issue #28524)
4167 logging.disable()
4168 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
4169
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004170 def _test_log(self, method, level=None):
4171 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004172 support.patch(self, logging, 'basicConfig',
4173 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004174
4175 recording = RecordingHandler()
4176 logging.root.addHandler(recording)
4177
4178 log_method = getattr(logging, method)
4179 if level is not None:
4180 log_method(level, "test me: %r", recording)
4181 else:
4182 log_method("test me: %r", recording)
4183
4184 self.assertEqual(len(recording.records), 1)
4185 record = recording.records[0]
4186 self.assertEqual(record.getMessage(), "test me: %r" % recording)
4187
4188 expected_level = level if level is not None else getattr(logging, method.upper())
4189 self.assertEqual(record.levelno, expected_level)
4190
4191 # basicConfig was not called!
4192 self.assertEqual(called, [])
4193
4194 def test_log(self):
4195 self._test_log('log', logging.ERROR)
4196
4197 def test_debug(self):
4198 self._test_log('debug')
4199
4200 def test_info(self):
4201 self._test_log('info')
4202
4203 def test_warning(self):
4204 self._test_log('warning')
4205
4206 def test_error(self):
4207 self._test_log('error')
4208
4209 def test_critical(self):
4210 self._test_log('critical')
4211
4212 def test_set_logger_class(self):
4213 self.assertRaises(TypeError, logging.setLoggerClass, object)
4214
4215 class MyLogger(logging.Logger):
4216 pass
4217
4218 logging.setLoggerClass(MyLogger)
4219 self.assertEqual(logging.getLoggerClass(), MyLogger)
4220
4221 logging.setLoggerClass(logging.Logger)
4222 self.assertEqual(logging.getLoggerClass(), logging.Logger)
4223
Vinay Sajip01500012019-06-19 11:46:53 +01004224 def test_subclass_logger_cache(self):
4225 # bpo-37258
4226 message = []
4227
4228 class MyLogger(logging.getLoggerClass()):
4229 def __init__(self, name='MyLogger', level=logging.NOTSET):
4230 super().__init__(name, level)
4231 message.append('initialized')
4232
4233 logging.setLoggerClass(MyLogger)
4234 logger = logging.getLogger('just_some_logger')
4235 self.assertEqual(message, ['initialized'])
4236 stream = io.StringIO()
4237 h = logging.StreamHandler(stream)
4238 logger.addHandler(h)
4239 try:
4240 logger.setLevel(logging.DEBUG)
4241 logger.debug("hello")
4242 self.assertEqual(stream.getvalue().strip(), "hello")
4243
4244 stream.truncate(0)
4245 stream.seek(0)
4246
4247 logger.setLevel(logging.INFO)
4248 logger.debug("hello")
4249 self.assertEqual(stream.getvalue(), "")
4250 finally:
4251 logger.removeHandler(h)
4252 h.close()
4253 logging.setLoggerClass(logging.Logger)
4254
Antoine Pitrou712cb732013-12-21 15:51:54 +01004255 def test_logging_at_shutdown(self):
4256 # Issue #20037
4257 code = """if 1:
4258 import logging
4259
4260 class A:
4261 def __del__(self):
4262 try:
4263 raise ValueError("some error")
4264 except Exception:
4265 logging.exception("exception in __del__")
4266
4267 a = A()"""
4268 rc, out, err = assert_python_ok("-c", code)
4269 err = err.decode()
4270 self.assertIn("exception in __del__", err)
4271 self.assertIn("ValueError: some error", err)
4272
Rémi Lapeyre65f64b12019-03-15 07:53:34 +01004273 def test_recursion_error(self):
4274 # Issue 36272
4275 code = """if 1:
4276 import logging
4277
4278 def rec():
4279 logging.error("foo")
4280 rec()
4281
4282 rec()"""
4283 rc, out, err = assert_python_failure("-c", code)
4284 err = err.decode()
4285 self.assertNotIn("Cannot recover from stack overflow.", err)
4286 self.assertEqual(rc, 1)
4287
Antoine Pitrou712cb732013-12-21 15:51:54 +01004288
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004289class LogRecordTest(BaseTest):
4290 def test_str_rep(self):
4291 r = logging.makeLogRecord({})
4292 s = str(r)
4293 self.assertTrue(s.startswith('<LogRecord: '))
4294 self.assertTrue(s.endswith('>'))
4295
4296 def test_dict_arg(self):
4297 h = RecordingHandler()
4298 r = logging.getLogger()
4299 r.addHandler(h)
4300 d = {'less' : 'more' }
4301 logging.warning('less is %(less)s', d)
4302 self.assertIs(h.records[0].args, d)
4303 self.assertEqual(h.records[0].message, 'less is more')
4304 r.removeHandler(h)
4305 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004306
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004307 def test_multiprocessing(self):
4308 r = logging.makeLogRecord({})
4309 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01004310 try:
4311 import multiprocessing as mp
4312 r = logging.makeLogRecord({})
4313 self.assertEqual(r.processName, mp.current_process().name)
4314 except ImportError:
4315 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004316
4317 def test_optional(self):
4318 r = logging.makeLogRecord({})
4319 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004320 NOT_NONE(r.thread)
4321 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004322 NOT_NONE(r.process)
4323 NOT_NONE(r.processName)
4324 log_threads = logging.logThreads
4325 log_processes = logging.logProcesses
4326 log_multiprocessing = logging.logMultiprocessing
4327 try:
4328 logging.logThreads = False
4329 logging.logProcesses = False
4330 logging.logMultiprocessing = False
4331 r = logging.makeLogRecord({})
4332 NONE = self.assertIsNone
4333 NONE(r.thread)
4334 NONE(r.threadName)
4335 NONE(r.process)
4336 NONE(r.processName)
4337 finally:
4338 logging.logThreads = log_threads
4339 logging.logProcesses = log_processes
4340 logging.logMultiprocessing = log_multiprocessing
4341
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004342class BasicConfigTest(unittest.TestCase):
4343
Vinay Sajip95bf5042011-04-20 11:50:56 +01004344 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004345
4346 def setUp(self):
4347 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01004348 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01004349 self.saved_handlers = logging._handlers.copy()
4350 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01004351 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01004352 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004353 logging.root.handlers = []
4354
4355 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01004356 for h in logging.root.handlers[:]:
4357 logging.root.removeHandler(h)
4358 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004359 super(BasicConfigTest, self).tearDown()
4360
Vinay Sajip3def7e02011-04-20 10:58:06 +01004361 def cleanup(self):
4362 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01004363 logging._handlers.clear()
4364 logging._handlers.update(self.saved_handlers)
4365 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1d094af2019-09-22 03:51:51 +01004366 logging.root.setLevel(self.original_logging_level)
Vinay Sajip3def7e02011-04-20 10:58:06 +01004367
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004368 def test_no_kwargs(self):
4369 logging.basicConfig()
4370
4371 # handler defaults to a StreamHandler to sys.stderr
4372 self.assertEqual(len(logging.root.handlers), 1)
4373 handler = logging.root.handlers[0]
4374 self.assertIsInstance(handler, logging.StreamHandler)
4375 self.assertEqual(handler.stream, sys.stderr)
4376
4377 formatter = handler.formatter
4378 # format defaults to logging.BASIC_FORMAT
4379 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
4380 # datefmt defaults to None
4381 self.assertIsNone(formatter.datefmt)
4382 # style defaults to %
4383 self.assertIsInstance(formatter._style, logging.PercentStyle)
4384
Florent Xiclunae41f0de2011-11-11 19:39:25 +01004385 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01004386 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004387
Vinay Sajip1fd12022014-01-13 21:59:56 +00004388 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004389 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004390 logging.basicConfig(stream=sys.stdout, style="{")
4391 logging.error("Log an error")
4392 sys.stdout.seek(0)
4393 self.assertEqual(output.getvalue().strip(),
4394 "ERROR:root:Log an error")
4395
4396 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004397 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004398 logging.basicConfig(stream=sys.stdout, style="$")
4399 logging.error("Log an error")
4400 sys.stdout.seek(0)
4401 self.assertEqual(output.getvalue().strip(),
4402 "ERROR:root:Log an error")
4403
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004404 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004405
4406 def cleanup(h1, h2, fn):
4407 h1.close()
4408 h2.close()
4409 os.remove(fn)
4410
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004411 logging.basicConfig(filename='test.log')
4412
4413 self.assertEqual(len(logging.root.handlers), 1)
4414 handler = logging.root.handlers[0]
4415 self.assertIsInstance(handler, logging.FileHandler)
4416
4417 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004418 self.assertEqual(handler.stream.mode, expected.stream.mode)
4419 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004420 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004421
4422 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004423
4424 def cleanup(h1, h2, fn):
4425 h1.close()
4426 h2.close()
4427 os.remove(fn)
4428
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004429 logging.basicConfig(filename='test.log', filemode='wb')
4430
4431 handler = logging.root.handlers[0]
4432 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004433 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004434 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004435
4436 def test_stream(self):
4437 stream = io.StringIO()
4438 self.addCleanup(stream.close)
4439 logging.basicConfig(stream=stream)
4440
4441 self.assertEqual(len(logging.root.handlers), 1)
4442 handler = logging.root.handlers[0]
4443 self.assertIsInstance(handler, logging.StreamHandler)
4444 self.assertEqual(handler.stream, stream)
4445
4446 def test_format(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01004447 logging.basicConfig(format='%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004448
4449 formatter = logging.root.handlers[0].formatter
BNMetrics18fb1fb2018-10-15 19:41:36 +01004450 self.assertEqual(formatter._style._fmt, '%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004451
4452 def test_datefmt(self):
4453 logging.basicConfig(datefmt='bar')
4454
4455 formatter = logging.root.handlers[0].formatter
4456 self.assertEqual(formatter.datefmt, 'bar')
4457
4458 def test_style(self):
4459 logging.basicConfig(style='$')
4460
4461 formatter = logging.root.handlers[0].formatter
4462 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
4463
4464 def test_level(self):
4465 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004466 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004467
4468 logging.basicConfig(level=57)
4469 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004470 # Test that second call has no effect
4471 logging.basicConfig(level=58)
4472 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004473
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004474 def test_incompatible(self):
4475 assertRaises = self.assertRaises
4476 handlers = [logging.StreamHandler()]
4477 stream = sys.stderr
4478 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004479 stream=stream)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004480 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004481 handlers=handlers)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004482 assertRaises(ValueError, logging.basicConfig, stream=stream,
BNMetrics18fb1fb2018-10-15 19:41:36 +01004483 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00004484 # Issue 23207: test for invalid kwargs
4485 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
4486 # Should pop both filename and filemode even if filename is None
4487 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004488
4489 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004490 handlers = [
4491 logging.StreamHandler(),
4492 logging.StreamHandler(sys.stdout),
4493 logging.StreamHandler(),
4494 ]
4495 f = logging.Formatter()
4496 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004497 logging.basicConfig(handlers=handlers)
4498 self.assertIs(handlers[0], logging.root.handlers[0])
4499 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004500 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004501 self.assertIsNotNone(handlers[0].formatter)
4502 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004503 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004504 self.assertIs(handlers[0].formatter, handlers[1].formatter)
4505
Dong-hee Nacf67d6a2018-06-25 13:11:09 +09004506 def test_force(self):
4507 old_string_io = io.StringIO()
4508 new_string_io = io.StringIO()
4509 old_handlers = [logging.StreamHandler(old_string_io)]
4510 new_handlers = [logging.StreamHandler(new_string_io)]
4511 logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
4512 logging.warning('warn')
4513 logging.info('info')
4514 logging.debug('debug')
4515 self.assertEqual(len(logging.root.handlers), 1)
4516 logging.basicConfig(level=logging.INFO, handlers=new_handlers,
4517 force=True)
4518 logging.warning('warn')
4519 logging.info('info')
4520 logging.debug('debug')
4521 self.assertEqual(len(logging.root.handlers), 1)
4522 self.assertEqual(old_string_io.getvalue().strip(),
4523 'WARNING:root:warn')
4524 self.assertEqual(new_string_io.getvalue().strip(),
4525 'WARNING:root:warn\nINFO:root:info')
4526
Vinay Sajipca7b5042019-06-17 17:40:52 +01004527 def test_encoding(self):
4528 try:
4529 encoding = 'utf-8'
4530 logging.basicConfig(filename='test.log', encoding=encoding,
4531 errors='strict',
4532 format='%(message)s', level=logging.DEBUG)
4533
4534 self.assertEqual(len(logging.root.handlers), 1)
4535 handler = logging.root.handlers[0]
4536 self.assertIsInstance(handler, logging.FileHandler)
4537 self.assertEqual(handler.encoding, encoding)
4538 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4539 finally:
4540 handler.close()
4541 with open('test.log', encoding='utf-8') as f:
4542 data = f.read().strip()
4543 os.remove('test.log')
4544 self.assertEqual(data,
4545 'The Øresund Bridge joins Copenhagen to Malmö')
4546
4547 def test_encoding_errors(self):
4548 try:
4549 encoding = 'ascii'
4550 logging.basicConfig(filename='test.log', encoding=encoding,
4551 errors='ignore',
4552 format='%(message)s', level=logging.DEBUG)
4553
4554 self.assertEqual(len(logging.root.handlers), 1)
4555 handler = logging.root.handlers[0]
4556 self.assertIsInstance(handler, logging.FileHandler)
4557 self.assertEqual(handler.encoding, encoding)
4558 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4559 finally:
4560 handler.close()
4561 with open('test.log', encoding='utf-8') as f:
4562 data = f.read().strip()
4563 os.remove('test.log')
4564 self.assertEqual(data, 'The resund Bridge joins Copenhagen to Malm')
4565
4566 def test_encoding_errors_default(self):
4567 try:
4568 encoding = 'ascii'
4569 logging.basicConfig(filename='test.log', encoding=encoding,
4570 format='%(message)s', level=logging.DEBUG)
4571
4572 self.assertEqual(len(logging.root.handlers), 1)
4573 handler = logging.root.handlers[0]
4574 self.assertIsInstance(handler, logging.FileHandler)
4575 self.assertEqual(handler.encoding, encoding)
4576 self.assertEqual(handler.errors, 'backslashreplace')
4577 logging.debug('😂: ☃️: The Øresund Bridge joins Copenhagen to Malmö')
4578 finally:
4579 handler.close()
4580 with open('test.log', encoding='utf-8') as f:
4581 data = f.read().strip()
4582 os.remove('test.log')
4583 self.assertEqual(data, r'\U0001f602: \u2603\ufe0f: The \xd8resund '
4584 r'Bridge joins Copenhagen to Malm\xf6')
4585
4586 def test_encoding_errors_none(self):
4587 # Specifying None should behave as 'strict'
4588 try:
4589 encoding = 'ascii'
4590 logging.basicConfig(filename='test.log', encoding=encoding,
4591 errors=None,
4592 format='%(message)s', level=logging.DEBUG)
4593
4594 self.assertEqual(len(logging.root.handlers), 1)
4595 handler = logging.root.handlers[0]
4596 self.assertIsInstance(handler, logging.FileHandler)
4597 self.assertEqual(handler.encoding, encoding)
4598 self.assertIsNone(handler.errors)
4599
4600 message = []
4601
4602 def dummy_handle_error(record):
4603 _, v, _ = sys.exc_info()
4604 message.append(str(v))
4605
4606 handler.handleError = dummy_handle_error
4607 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4608 self.assertTrue(message)
4609 self.assertIn("'ascii' codec can't encode "
4610 "character '\\xd8' in position 4:", message[0])
4611 finally:
4612 handler.close()
4613 with open('test.log', encoding='utf-8') as f:
4614 data = f.read().strip()
4615 os.remove('test.log')
4616 # didn't write anything due to the encoding error
4617 self.assertEqual(data, r'')
4618
4619
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004620 def _test_log(self, method, level=None):
4621 # logging.root has no handlers so basicConfig should be called
4622 called = []
4623
4624 old_basic_config = logging.basicConfig
4625 def my_basic_config(*a, **kw):
4626 old_basic_config()
4627 old_level = logging.root.level
4628 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004629 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004630 called.append((a, kw))
4631
Vinay Sajip1feedb42014-05-31 08:19:12 +01004632 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004633
4634 log_method = getattr(logging, method)
4635 if level is not None:
4636 log_method(level, "test me")
4637 else:
4638 log_method("test me")
4639
4640 # basicConfig was called with no arguments
4641 self.assertEqual(called, [((), {})])
4642
4643 def test_log(self):
4644 self._test_log('log', logging.WARNING)
4645
4646 def test_debug(self):
4647 self._test_log('debug')
4648
4649 def test_info(self):
4650 self._test_log('info')
4651
4652 def test_warning(self):
4653 self._test_log('warning')
4654
4655 def test_error(self):
4656 self._test_log('error')
4657
4658 def test_critical(self):
4659 self._test_log('critical')
4660
4661
4662class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004663 def setUp(self):
4664 super(LoggerAdapterTest, self).setUp()
4665 old_handler_list = logging._handlerList[:]
4666
4667 self.recording = RecordingHandler()
4668 self.logger = logging.root
4669 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004670 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004671 self.addCleanup(self.recording.close)
4672
4673 def cleanup():
4674 logging._handlerList[:] = old_handler_list
4675
4676 self.addCleanup(cleanup)
4677 self.addCleanup(logging.shutdown)
4678 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4679
4680 def test_exception(self):
4681 msg = 'testing exception: %r'
4682 exc = None
4683 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004684 1 / 0
4685 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004686 exc = e
4687 self.adapter.exception(msg, self.recording)
4688
4689 self.assertEqual(len(self.recording.records), 1)
4690 record = self.recording.records[0]
4691 self.assertEqual(record.levelno, logging.ERROR)
4692 self.assertEqual(record.msg, msg)
4693 self.assertEqual(record.args, (self.recording,))
4694 self.assertEqual(record.exc_info,
4695 (exc.__class__, exc, exc.__traceback__))
4696
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004697 def test_exception_excinfo(self):
4698 try:
4699 1 / 0
4700 except ZeroDivisionError as e:
4701 exc = e
4702
4703 self.adapter.exception('exc_info test', exc_info=exc)
4704
4705 self.assertEqual(len(self.recording.records), 1)
4706 record = self.recording.records[0]
4707 self.assertEqual(record.exc_info,
4708 (exc.__class__, exc, exc.__traceback__))
4709
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004710 def test_critical(self):
4711 msg = 'critical test! %r'
4712 self.adapter.critical(msg, self.recording)
4713
4714 self.assertEqual(len(self.recording.records), 1)
4715 record = self.recording.records[0]
4716 self.assertEqual(record.levelno, logging.CRITICAL)
4717 self.assertEqual(record.msg, msg)
4718 self.assertEqual(record.args, (self.recording,))
4719
4720 def test_is_enabled_for(self):
4721 old_disable = self.adapter.logger.manager.disable
4722 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004723 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4724 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004725 self.assertFalse(self.adapter.isEnabledFor(32))
4726
4727 def test_has_handlers(self):
4728 self.assertTrue(self.adapter.hasHandlers())
4729
4730 for handler in self.logger.handlers:
4731 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004732
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004733 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004734 self.assertFalse(self.adapter.hasHandlers())
4735
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004736 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004737 class Adapter(logging.LoggerAdapter):
4738 prefix = 'Adapter'
4739
4740 def process(self, msg, kwargs):
4741 return f"{self.prefix} {msg}", kwargs
4742
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004743 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004744 adapter = Adapter(logger=self.logger, extra=None)
4745 adapter_adapter = Adapter(logger=adapter, extra=None)
4746 adapter_adapter.prefix = 'AdapterAdapter'
4747 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004748 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004749 self.assertEqual(len(self.recording.records), 1)
4750 record = self.recording.records[0]
4751 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004752 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004753 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004754 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004755 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004756 self.assertIs(self.logger.manager, orig_manager)
4757 temp_manager = object()
4758 try:
4759 adapter_adapter.manager = temp_manager
4760 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004761 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004762 self.assertIs(self.logger.manager, temp_manager)
4763 finally:
4764 adapter_adapter.manager = orig_manager
4765 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004766 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004767 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004768
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004769
4770class LoggerTest(BaseTest):
4771
4772 def setUp(self):
4773 super(LoggerTest, self).setUp()
4774 self.recording = RecordingHandler()
4775 self.logger = logging.Logger(name='blah')
4776 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004777 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004778 self.addCleanup(self.recording.close)
4779 self.addCleanup(logging.shutdown)
4780
4781 def test_set_invalid_level(self):
4782 self.assertRaises(TypeError, self.logger.setLevel, object())
4783
4784 def test_exception(self):
4785 msg = 'testing exception: %r'
4786 exc = None
4787 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004788 1 / 0
4789 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004790 exc = e
4791 self.logger.exception(msg, self.recording)
4792
4793 self.assertEqual(len(self.recording.records), 1)
4794 record = self.recording.records[0]
4795 self.assertEqual(record.levelno, logging.ERROR)
4796 self.assertEqual(record.msg, msg)
4797 self.assertEqual(record.args, (self.recording,))
4798 self.assertEqual(record.exc_info,
4799 (exc.__class__, exc, exc.__traceback__))
4800
4801 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004802 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004803 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004804
4805 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004806 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004807 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004808
4809 def test_find_caller_with_stack_info(self):
4810 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004811 support.patch(self, logging.traceback, 'print_stack',
4812 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004813
4814 self.logger.findCaller(stack_info=True)
4815
4816 self.assertEqual(len(called), 1)
4817 self.assertEqual('Stack (most recent call last):\n', called[0])
4818
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004819 def test_find_caller_with_stacklevel(self):
4820 the_level = 1
4821
4822 def innermost():
4823 self.logger.warning('test', stacklevel=the_level)
4824
4825 def inner():
4826 innermost()
4827
4828 def outer():
4829 inner()
4830
4831 records = self.recording.records
4832 outer()
4833 self.assertEqual(records[-1].funcName, 'innermost')
4834 lineno = records[-1].lineno
4835 the_level += 1
4836 outer()
4837 self.assertEqual(records[-1].funcName, 'inner')
4838 self.assertGreater(records[-1].lineno, lineno)
4839 lineno = records[-1].lineno
4840 the_level += 1
4841 outer()
4842 self.assertEqual(records[-1].funcName, 'outer')
4843 self.assertGreater(records[-1].lineno, lineno)
4844 lineno = records[-1].lineno
4845 the_level += 1
4846 outer()
4847 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4848 self.assertGreater(records[-1].lineno, lineno)
4849
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004850 def test_make_record_with_extra_overwrite(self):
4851 name = 'my record'
4852 level = 13
4853 fn = lno = msg = args = exc_info = func = sinfo = None
4854 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4855 exc_info, func, sinfo)
4856
4857 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4858 extra = {key: 'some value'}
4859 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4860 fn, lno, msg, args, exc_info,
4861 extra=extra, sinfo=sinfo)
4862
4863 def test_make_record_with_extra_no_overwrite(self):
4864 name = 'my record'
4865 level = 13
4866 fn = lno = msg = args = exc_info = func = sinfo = None
4867 extra = {'valid_key': 'some value'}
4868 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4869 exc_info, extra=extra, sinfo=sinfo)
4870 self.assertIn('valid_key', result.__dict__)
4871
4872 def test_has_handlers(self):
4873 self.assertTrue(self.logger.hasHandlers())
4874
4875 for handler in self.logger.handlers:
4876 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004877 self.assertFalse(self.logger.hasHandlers())
4878
4879 def test_has_handlers_no_propagate(self):
4880 child_logger = logging.getLogger('blah.child')
4881 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004882 self.assertFalse(child_logger.hasHandlers())
4883
4884 def test_is_enabled_for(self):
4885 old_disable = self.logger.manager.disable
4886 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004887 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004888 self.assertFalse(self.logger.isEnabledFor(22))
4889
Timo Furrer6e3ca642018-06-01 09:29:46 +02004890 def test_is_enabled_for_disabled_logger(self):
4891 old_disabled = self.logger.disabled
4892 old_disable = self.logger.manager.disable
4893
4894 self.logger.disabled = True
4895 self.logger.manager.disable = 21
4896
4897 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4898 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4899
4900 self.assertFalse(self.logger.isEnabledFor(22))
4901
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004902 def test_root_logger_aliases(self):
4903 root = logging.getLogger()
4904 self.assertIs(root, logging.root)
4905 self.assertIs(root, logging.getLogger(None))
4906 self.assertIs(root, logging.getLogger(''))
Vinay Sajipcb65b3a2019-08-02 16:53:00 +01004907 self.assertIs(root, logging.getLogger('root'))
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004908 self.assertIs(root, logging.getLogger('foo').root)
4909 self.assertIs(root, logging.getLogger('foo.bar').root)
4910 self.assertIs(root, logging.getLogger('foo').parent)
4911
4912 self.assertIsNot(root, logging.getLogger('\0'))
4913 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4914
4915 def test_invalid_names(self):
4916 self.assertRaises(TypeError, logging.getLogger, any)
4917 self.assertRaises(TypeError, logging.getLogger, b'foo')
4918
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004919 def test_pickling(self):
4920 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4921 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4922 logger = logging.getLogger(name)
4923 s = pickle.dumps(logger, proto)
4924 unpickled = pickle.loads(s)
4925 self.assertIs(unpickled, logger)
4926
Avram Lubkin78c18a92017-07-30 05:36:33 -04004927 def test_caching(self):
4928 root = self.root_logger
4929 logger1 = logging.getLogger("abc")
4930 logger2 = logging.getLogger("abc.def")
4931
4932 # Set root logger level and ensure cache is empty
4933 root.setLevel(logging.ERROR)
4934 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4935 self.assertEqual(logger2._cache, {})
4936
4937 # Ensure cache is populated and calls are consistent
4938 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4939 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4940 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4941 self.assertEqual(root._cache, {})
4942 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4943
4944 # Ensure root cache gets populated
4945 self.assertEqual(root._cache, {})
4946 self.assertTrue(root.isEnabledFor(logging.ERROR))
4947 self.assertEqual(root._cache, {logging.ERROR: True})
4948
4949 # Set parent logger level and ensure caches are emptied
4950 logger1.setLevel(logging.CRITICAL)
4951 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4952 self.assertEqual(logger2._cache, {})
4953
4954 # Ensure logger2 uses parent logger's effective level
4955 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4956
4957 # Set level to NOTSET and ensure caches are empty
4958 logger2.setLevel(logging.NOTSET)
4959 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4960 self.assertEqual(logger2._cache, {})
4961 self.assertEqual(logger1._cache, {})
4962 self.assertEqual(root._cache, {})
4963
4964 # Verify logger2 follows parent and not root
4965 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4966 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4967 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4968 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4969 self.assertTrue(root.isEnabledFor(logging.ERROR))
4970
4971 # Disable logging in manager and ensure caches are clear
4972 logging.disable()
4973 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4974 self.assertEqual(logger2._cache, {})
4975 self.assertEqual(logger1._cache, {})
4976 self.assertEqual(root._cache, {})
4977
4978 # Ensure no loggers are enabled
4979 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4980 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4981 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4982
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004983
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004984class BaseFileTest(BaseTest):
4985 "Base class for handler tests that write log files"
4986
4987 def setUp(self):
4988 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004989 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4990 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004991 self.rmfiles = []
4992
4993 def tearDown(self):
4994 for fn in self.rmfiles:
4995 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004996 if os.path.exists(self.fn):
4997 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004998 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004999
5000 def assertLogFile(self, filename):
5001 "Assert a log file is there and register it for deletion"
5002 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01005003 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005004 self.rmfiles.append(filename)
5005
5006
Vinay Sajip26fe4b72011-04-26 18:43:05 +01005007class FileHandlerTest(BaseFileTest):
5008 def test_delay(self):
5009 os.unlink(self.fn)
5010 fh = logging.FileHandler(self.fn, delay=True)
5011 self.assertIsNone(fh.stream)
5012 self.assertFalse(os.path.exists(self.fn))
5013 fh.handle(logging.makeLogRecord({}))
5014 self.assertIsNotNone(fh.stream)
5015 self.assertTrue(os.path.exists(self.fn))
5016 fh.close()
5017
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005018class RotatingFileHandlerTest(BaseFileTest):
5019 def next_rec(self):
5020 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
5021 self.next_message(), None, None, None)
5022
5023 def test_should_not_rollover(self):
5024 # If maxbytes is zero rollover never occurs
5025 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
5026 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00005027 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005028
5029 def test_should_rollover(self):
5030 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
5031 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00005032 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005033
5034 def test_file_created(self):
5035 # checks that the file is created and assumes it was created
5036 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005037 rh = logging.handlers.RotatingFileHandler(self.fn)
5038 rh.emit(self.next_rec())
5039 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00005040 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005041
5042 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00005043 def namer(name):
5044 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005045 rh = logging.handlers.RotatingFileHandler(
5046 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005047 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005048 rh.emit(self.next_rec())
5049 self.assertLogFile(self.fn)
5050 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005051 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005052 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005053 self.assertLogFile(namer(self.fn + ".2"))
5054 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
5055 rh.close()
5056
l0rb519cb872019-11-06 22:21:40 +01005057 def test_namer_rotator_inheritance(self):
5058 class HandlerWithNamerAndRotator(logging.handlers.RotatingFileHandler):
5059 def namer(self, name):
5060 return name + ".test"
5061
5062 def rotator(self, source, dest):
5063 if os.path.exists(source):
5064 os.rename(source, dest + ".rotated")
5065
5066 rh = HandlerWithNamerAndRotator(
5067 self.fn, backupCount=2, maxBytes=1)
5068 self.assertEqual(rh.namer(self.fn), self.fn + ".test")
5069 rh.emit(self.next_rec())
5070 self.assertLogFile(self.fn)
5071 rh.emit(self.next_rec())
5072 self.assertLogFile(rh.namer(self.fn + ".1") + ".rotated")
5073 self.assertFalse(os.path.exists(rh.namer(self.fn + ".1")))
5074 rh.close()
5075
Vinay Sajip1feedb42014-05-31 08:19:12 +01005076 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00005077 def test_rotator(self):
5078 def namer(name):
5079 return name + ".gz"
5080
5081 def rotator(source, dest):
5082 with open(source, "rb") as sf:
5083 data = sf.read()
5084 compressed = zlib.compress(data, 9)
5085 with open(dest, "wb") as df:
5086 df.write(compressed)
5087 os.remove(source)
5088
5089 rh = logging.handlers.RotatingFileHandler(
5090 self.fn, backupCount=2, maxBytes=1)
5091 rh.rotator = rotator
5092 rh.namer = namer
5093 m1 = self.next_rec()
5094 rh.emit(m1)
5095 self.assertLogFile(self.fn)
5096 m2 = self.next_rec()
5097 rh.emit(m2)
5098 fn = namer(self.fn + ".1")
5099 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005100 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00005101 with open(fn, "rb") as f:
5102 compressed = f.read()
5103 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005104 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005105 rh.emit(self.next_rec())
5106 fn = namer(self.fn + ".2")
5107 self.assertLogFile(fn)
5108 with open(fn, "rb") as f:
5109 compressed = f.read()
5110 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005111 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005112 rh.emit(self.next_rec())
5113 fn = namer(self.fn + ".2")
5114 with open(fn, "rb") as f:
5115 compressed = f.read()
5116 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005117 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005118 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00005119 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005120
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005121class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01005122 # other test methods added below
5123 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01005124 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
5125 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00005126 fmt = logging.Formatter('%(asctime)s %(message)s')
5127 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005128 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005129 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01005130 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005131 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00005132 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005133 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01005134 fh.close()
5135 # At this point, we should have a recent rotated file which we
5136 # can test for the existence of. However, in practice, on some
5137 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01005138 # in time to go to look for the log file. So, we go back a fair
5139 # bit, and stop as soon as we see a rotated file. In theory this
5140 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01005141 found = False
5142 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01005143 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01005144 for secs in range(GO_BACK):
5145 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01005146 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
5147 found = os.path.exists(fn)
5148 if found:
5149 self.rmfiles.append(fn)
5150 break
Vinay Sajip672c5812011-05-13 07:09:40 +01005151 msg = 'No rotated files found, went back %d seconds' % GO_BACK
5152 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03005153 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01005154 dn, fn = os.path.split(self.fn)
5155 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02005156 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
5157 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00005158 for f in files:
5159 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00005160 path = os.path.join(dn, f)
5161 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00005162 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01005163 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005164
Vinay Sajip0372e102011-05-05 12:59:14 +01005165 def test_invalid(self):
5166 assertRaises = self.assertRaises
5167 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005168 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005169 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005170 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005171 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005172 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005173
Vinay Sajipa7130792013-04-12 17:04:23 +01005174 def test_compute_rollover_daily_attime(self):
5175 currentTime = 0
5176 atTime = datetime.time(12, 0, 0)
5177 rh = logging.handlers.TimedRotatingFileHandler(
5178 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
5179 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005180 try:
5181 actual = rh.computeRollover(currentTime)
5182 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01005183
Vinay Sajipd86ac962013-04-14 12:20:46 +01005184 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
5185 self.assertEqual(actual, currentTime + 36 * 60 * 60)
5186 finally:
5187 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005188
Vinay Sajip10e8c492013-05-18 10:19:54 -07005189 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01005190 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01005191 currentTime = int(time.time())
5192 today = currentTime - currentTime % 86400
5193
Vinay Sajipa7130792013-04-12 17:04:23 +01005194 atTime = datetime.time(12, 0, 0)
5195
Vinay Sajip10e8c492013-05-18 10:19:54 -07005196 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01005197 for day in range(7):
5198 rh = logging.handlers.TimedRotatingFileHandler(
5199 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
5200 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005201 try:
5202 if wday > day:
5203 # The rollover day has already passed this week, so we
5204 # go over into next week
5205 expected = (7 - wday + day)
5206 else:
5207 expected = (day - wday)
5208 # At this point expected is in days from now, convert to seconds
5209 expected *= 24 * 60 * 60
5210 # Add in the rollover time
5211 expected += 12 * 60 * 60
5212 # Add in adjustment for today
5213 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01005214 actual = rh.computeRollover(today)
5215 if actual != expected:
5216 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005217 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005218 self.assertEqual(actual, expected)
5219 if day == wday:
5220 # goes into following week
5221 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01005222 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01005223 if actual != expected:
5224 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005225 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005226 self.assertEqual(actual, expected)
5227 finally:
5228 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005229
5230
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005231def secs(**kw):
5232 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
5233
5234for when, exp in (('S', 1),
5235 ('M', 60),
5236 ('H', 60 * 60),
5237 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00005238 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005239 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00005240 ('W0', secs(days=4, hours=24)),
5241 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005242 def test_compute_rollover(self, when=when, exp=exp):
5243 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00005244 self.fn, when=when, interval=1, backupCount=0, utc=True)
5245 currentTime = 0.0
5246 actual = rh.computeRollover(currentTime)
5247 if exp != actual:
5248 # Failures occur on some systems for MIDNIGHT and W0.
5249 # Print detailed calculation for MIDNIGHT so we can try to see
5250 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00005251 if when == 'MIDNIGHT':
5252 try:
5253 if rh.utc:
5254 t = time.gmtime(currentTime)
5255 else:
5256 t = time.localtime(currentTime)
5257 currentHour = t[3]
5258 currentMinute = t[4]
5259 currentSecond = t[5]
5260 # r is the number of seconds left between now and midnight
5261 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
5262 currentMinute) * 60 +
5263 currentSecond)
5264 result = currentTime + r
5265 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
5266 print('currentHour: %s' % currentHour, file=sys.stderr)
5267 print('currentMinute: %s' % currentMinute, file=sys.stderr)
5268 print('currentSecond: %s' % currentSecond, file=sys.stderr)
5269 print('r: %s' % r, file=sys.stderr)
5270 print('result: %s' % result, file=sys.stderr)
5271 except Exception:
5272 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
5273 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00005274 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005275 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
5276
Vinay Sajip60ccd822011-05-09 17:32:09 +01005277
Vinay Sajip223349c2015-10-01 20:37:54 +01005278@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01005279class NTEventLogHandlerTest(BaseTest):
5280 def test_basic(self):
5281 logtype = 'Application'
5282 elh = win32evtlog.OpenEventLog(None, logtype)
5283 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01005284
5285 try:
5286 h = logging.handlers.NTEventLogHandler('test_logging')
5287 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05005288 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01005289 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05005290 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01005291
Vinay Sajip60ccd822011-05-09 17:32:09 +01005292 r = logging.makeLogRecord({'msg': 'Test Log Message'})
5293 h.handle(r)
5294 h.close()
5295 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02005296 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01005297 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
5298 win32evtlog.EVENTLOG_SEQUENTIAL_READ
5299 found = False
5300 GO_BACK = 100
5301 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
5302 for e in events:
5303 if e.SourceName != 'test_logging':
5304 continue
5305 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
5306 if msg != 'Test Log Message\r\n':
5307 continue
5308 found = True
5309 break
5310 msg = 'Record not found in event log, went back %d records' % GO_BACK
5311 self.assertTrue(found, msg=msg)
5312
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005313
5314class MiscTestCase(unittest.TestCase):
5315 def test__all__(self):
5316 blacklist = {'logThreads', 'logMultiprocessing',
5317 'logProcesses', 'currentframe',
5318 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
5319 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00005320 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005321 support.check__all__(self, logging, blacklist=blacklist)
5322
5323
Christian Heimes180510d2008-03-03 19:15:45 +00005324# Set the locale to the platform-dependent default. I have no idea
5325# why the test does this, but in any case we save the current locale
5326# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01005327@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00005328def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01005329 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01005330 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
5331 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
5332 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
5333 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
5334 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
5335 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
5336 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
5337 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08005338 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01005339 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01005340 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005341 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01005342 ]
5343 if hasattr(logging.handlers, 'QueueListener'):
5344 tests.append(QueueListenerTest)
5345 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00005346
Christian Heimes180510d2008-03-03 19:15:45 +00005347if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00005348 test_main()