blob: 3b135b8ddf966a8a40163a57fa7ce9c50fe15ec5 [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 Stinner31b50b82018-07-11 12:35:38 +02001062 # bpo-14314, bpo-19665, bpo-34092: don't wait forever, timeout of 1 minute
1063 TIMEOUT = 60.0
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
3382class ManagerTest(BaseTest):
3383 def test_manager_loggerclass(self):
3384 logged = []
3385
3386 class MyLogger(logging.Logger):
3387 def _log(self, level, msg, args, exc_info=None, extra=None):
3388 logged.append(msg)
3389
3390 man = logging.Manager(None)
3391 self.assertRaises(TypeError, man.setLoggerClass, int)
3392 man.setLoggerClass(MyLogger)
3393 logger = man.getLogger('test')
3394 logger.warning('should appear in logged')
3395 logging.warning('should not appear in logged')
3396
3397 self.assertEqual(logged, ['should appear in logged'])
3398
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003399 def test_set_log_record_factory(self):
3400 man = logging.Manager(None)
3401 expected = object()
3402 man.setLogRecordFactory(expected)
3403 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003404
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003405class ChildLoggerTest(BaseTest):
3406 def test_child_loggers(self):
3407 r = logging.getLogger()
3408 l1 = logging.getLogger('abc')
3409 l2 = logging.getLogger('def.ghi')
3410 c1 = r.getChild('xyz')
3411 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003412 self.assertIs(c1, logging.getLogger('xyz'))
3413 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003414 c1 = l1.getChild('def')
3415 c2 = c1.getChild('ghi')
3416 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003417 self.assertIs(c1, logging.getLogger('abc.def'))
3418 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3419 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003420
3421
Vinay Sajip6fac8172010-10-19 20:44:14 +00003422class DerivedLogRecord(logging.LogRecord):
3423 pass
3424
Vinay Sajip61561522010-12-03 11:50:38 +00003425class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003426
3427 def setUp(self):
3428 class CheckingFilter(logging.Filter):
3429 def __init__(self, cls):
3430 self.cls = cls
3431
3432 def filter(self, record):
3433 t = type(record)
3434 if t is not self.cls:
3435 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3436 self.cls)
3437 raise TypeError(msg)
3438 return True
3439
3440 BaseTest.setUp(self)
3441 self.filter = CheckingFilter(DerivedLogRecord)
3442 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003443 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003444
3445 def tearDown(self):
3446 self.root_logger.removeFilter(self.filter)
3447 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003448 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003449
3450 def test_logrecord_class(self):
3451 self.assertRaises(TypeError, self.root_logger.warning,
3452 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003453 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003454 self.root_logger.error(self.next_message())
3455 self.assert_log_lines([
3456 ('root', 'ERROR', '2'),
3457 ])
3458
3459
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003460class QueueHandlerTest(BaseTest):
3461 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003462 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003463
3464 def setUp(self):
3465 BaseTest.setUp(self)
3466 self.queue = queue.Queue(-1)
3467 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003468 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003469 self.que_logger = logging.getLogger('que')
3470 self.que_logger.propagate = False
3471 self.que_logger.setLevel(logging.WARNING)
3472 self.que_logger.addHandler(self.que_hdlr)
3473
3474 def tearDown(self):
3475 self.que_hdlr.close()
3476 BaseTest.tearDown(self)
3477
3478 def test_queue_handler(self):
3479 self.que_logger.debug(self.next_message())
3480 self.assertRaises(queue.Empty, self.queue.get_nowait)
3481 self.que_logger.info(self.next_message())
3482 self.assertRaises(queue.Empty, self.queue.get_nowait)
3483 msg = self.next_message()
3484 self.que_logger.warning(msg)
3485 data = self.queue.get_nowait()
3486 self.assertTrue(isinstance(data, logging.LogRecord))
3487 self.assertEqual(data.name, self.que_logger.name)
3488 self.assertEqual((data.msg, data.args), (msg, None))
3489
favlladfe3442017-08-01 20:12:26 +02003490 def test_formatting(self):
3491 msg = self.next_message()
3492 levelname = logging.getLevelName(logging.WARNING)
3493 log_format_str = '{name} -> {levelname}: {message}'
3494 formatted_msg = log_format_str.format(name=self.name,
3495 levelname=levelname, message=msg)
3496 formatter = logging.Formatter(self.log_format)
3497 self.que_hdlr.setFormatter(formatter)
3498 self.que_logger.warning(msg)
3499 log_record = self.queue.get_nowait()
3500 self.assertEqual(formatted_msg, log_record.msg)
3501 self.assertEqual(formatted_msg, log_record.message)
3502
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003503 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3504 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003505 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003506 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003507 listener = logging.handlers.QueueListener(self.queue, handler)
3508 listener.start()
3509 try:
3510 self.que_logger.warning(self.next_message())
3511 self.que_logger.error(self.next_message())
3512 self.que_logger.critical(self.next_message())
3513 finally:
3514 listener.stop()
3515 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3516 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3517 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003518 handler.close()
3519
3520 # Now test with respect_handler_level set
3521
3522 handler = support.TestHandler(support.Matcher())
3523 handler.setLevel(logging.CRITICAL)
3524 listener = logging.handlers.QueueListener(self.queue, handler,
3525 respect_handler_level=True)
3526 listener.start()
3527 try:
3528 self.que_logger.warning(self.next_message())
3529 self.que_logger.error(self.next_message())
3530 self.que_logger.critical(self.next_message())
3531 finally:
3532 listener.stop()
3533 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3534 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3535 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
Cheryl Sabellad345bb42018-09-25 19:00:08 -04003536 handler.close()
3537
3538 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3539 'logging.handlers.QueueListener required for this test')
3540 def test_queue_listener_with_StreamHandler(self):
3541 # Test that traceback only appends once (bpo-34334).
3542 listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
3543 listener.start()
3544 try:
3545 1 / 0
3546 except ZeroDivisionError as e:
3547 exc = e
3548 self.que_logger.exception(self.next_message(), exc_info=exc)
3549 listener.stop()
3550 self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
Vinay Sajip365701a2015-02-09 19:49:00 +00003551
Xtreak2dad9602019-04-07 13:21:27 +05303552 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3553 'logging.handlers.QueueListener required for this test')
3554 def test_queue_listener_with_multiple_handlers(self):
3555 # Test that queue handler format doesn't affect other handler formats (bpo-35726).
3556 self.que_hdlr.setFormatter(self.root_formatter)
3557 self.que_logger.addHandler(self.root_hdlr)
3558
3559 listener = logging.handlers.QueueListener(self.queue, self.que_hdlr)
3560 listener.start()
3561 self.que_logger.error("error")
3562 listener.stop()
3563 self.assertEqual(self.stream.getvalue().strip(), "que -> ERROR: error")
3564
Vinay Sajipd61910c2016-09-08 01:13:39 +01003565if hasattr(logging.handlers, 'QueueListener'):
3566 import multiprocessing
3567 from unittest.mock import patch
3568
3569 class QueueListenerTest(BaseTest):
3570 """
3571 Tests based on patch submitted for issue #27930. Ensure that
3572 QueueListener handles all log messages.
3573 """
3574
3575 repeat = 20
3576
3577 @staticmethod
3578 def setup_and_log(log_queue, ident):
3579 """
3580 Creates a logger with a QueueHandler that logs to a queue read by a
3581 QueueListener. Starts the listener, logs five messages, and stops
3582 the listener.
3583 """
3584 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3585 logger.setLevel(logging.DEBUG)
3586 handler = logging.handlers.QueueHandler(log_queue)
3587 logger.addHandler(handler)
3588 listener = logging.handlers.QueueListener(log_queue)
3589 listener.start()
3590
3591 logger.info('one')
3592 logger.info('two')
3593 logger.info('three')
3594 logger.info('four')
3595 logger.info('five')
3596
3597 listener.stop()
3598 logger.removeHandler(handler)
3599 handler.close()
3600
3601 @patch.object(logging.handlers.QueueListener, 'handle')
3602 def test_handle_called_with_queue_queue(self, mock_handle):
3603 for i in range(self.repeat):
3604 log_queue = queue.Queue()
3605 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3606 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3607 'correct number of handled log messages')
3608
3609 @patch.object(logging.handlers.QueueListener, 'handle')
3610 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003611 # Issue 28668: The multiprocessing (mp) module is not functional
3612 # when the mp.synchronize module cannot be imported.
3613 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003614 for i in range(self.repeat):
3615 log_queue = multiprocessing.Queue()
3616 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003617 log_queue.close()
3618 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003619 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3620 'correct number of handled log messages')
3621
3622 @staticmethod
3623 def get_all_from_queue(log_queue):
3624 try:
3625 while True:
3626 yield log_queue.get_nowait()
3627 except queue.Empty:
3628 return []
3629
3630 def test_no_messages_in_queue_after_stop(self):
3631 """
3632 Five messages are logged then the QueueListener is stopped. This
3633 test then gets everything off the queue. Failure of this test
3634 indicates that messages were not registered on the queue until
3635 _after_ the QueueListener stopped.
3636 """
xdegayebf2b65e2017-12-01 08:08:49 +01003637 # Issue 28668: The multiprocessing (mp) module is not functional
3638 # when the mp.synchronize module cannot be imported.
3639 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003640 for i in range(self.repeat):
3641 queue = multiprocessing.Queue()
3642 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3643 # time.sleep(1)
3644 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003645 queue.close()
3646 queue.join_thread()
3647
Vinay Sajipd61910c2016-09-08 01:13:39 +01003648 expected = [[], [logging.handlers.QueueListener._sentinel]]
3649 self.assertIn(items, expected,
3650 'Found unexpected messages in queue: %s' % (
3651 [m.msg if isinstance(m, logging.LogRecord)
3652 else m for m in items]))
3653
Bar Harel6b282e12019-06-01 12:19:09 +03003654 def test_calls_task_done_after_stop(self):
3655 # Issue 36813: Make sure queue.join does not deadlock.
3656 log_queue = queue.Queue()
3657 listener = logging.handlers.QueueListener(log_queue)
3658 listener.start()
3659 listener.stop()
3660 with self.assertRaises(ValueError):
3661 # Make sure all tasks are done and .join won't block.
3662 log_queue.task_done()
3663
Vinay Sajipe723e962011-04-15 22:27:17 +01003664
Vinay Sajip37eb3382011-04-26 20:26:41 +01003665ZERO = datetime.timedelta(0)
3666
3667class UTC(datetime.tzinfo):
3668 def utcoffset(self, dt):
3669 return ZERO
3670
3671 dst = utcoffset
3672
3673 def tzname(self, dt):
3674 return 'UTC'
3675
3676utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003677
Vinay Sajipa39c5712010-10-25 13:57:39 +00003678class FormatterTest(unittest.TestCase):
3679 def setUp(self):
3680 self.common = {
3681 'name': 'formatter.test',
3682 'level': logging.DEBUG,
3683 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3684 'lineno': 42,
3685 'exc_info': None,
3686 'func': None,
3687 'msg': 'Message with %d %s',
3688 'args': (2, 'placeholders'),
3689 }
3690 self.variants = {
3691 }
3692
3693 def get_record(self, name=None):
3694 result = dict(self.common)
3695 if name is not None:
3696 result.update(self.variants[name])
3697 return logging.makeLogRecord(result)
3698
BNMetrics18fb1fb2018-10-15 19:41:36 +01003699 def assert_error_message(self, exception, message, *args, **kwargs):
3700 try:
3701 self.assertRaises(exception, *args, **kwargs)
3702 except exception as e:
3703 self.assertEqual(message, e.message)
3704
Vinay Sajipa39c5712010-10-25 13:57:39 +00003705 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003706 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003707 r = self.get_record()
3708 f = logging.Formatter('${%(message)s}')
3709 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3710 f = logging.Formatter('%(random)s')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003711 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003712 self.assertFalse(f.usesTime())
3713 f = logging.Formatter('%(asctime)s')
3714 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003715 f = logging.Formatter('%(asctime)-15s')
3716 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003717 f = logging.Formatter('%(asctime)#15s')
3718 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003719
3720 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003721 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003722 r = self.get_record()
3723 f = logging.Formatter('$%{message}%$', style='{')
3724 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3725 f = logging.Formatter('{random}', style='{')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003726 self.assertRaises(ValueError, f.format, r)
3727 f = logging.Formatter("{message}", style='{')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003728 self.assertFalse(f.usesTime())
3729 f = logging.Formatter('{asctime}', style='{')
3730 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003731 f = logging.Formatter('{asctime!s:15}', style='{')
3732 self.assertTrue(f.usesTime())
3733 f = logging.Formatter('{asctime:15}', style='{')
3734 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003735
3736 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003737 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003738 r = self.get_record()
BNMetrics18fb1fb2018-10-15 19:41:36 +01003739 f = logging.Formatter('${message}', style='$')
3740 self.assertEqual(f.format(r), 'Message with 2 placeholders')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003741 f = logging.Formatter('$message', style='$')
3742 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3743 f = logging.Formatter('$$%${message}%$$', style='$')
3744 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3745 f = logging.Formatter('${random}', style='$')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003746 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003747 self.assertFalse(f.usesTime())
3748 f = logging.Formatter('${asctime}', style='$')
3749 self.assertTrue(f.usesTime())
3750 f = logging.Formatter('$asctime', style='$')
3751 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003752 f = logging.Formatter('${message}', style='$')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003753 self.assertFalse(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003754 f = logging.Formatter('${asctime}--', style='$')
3755 self.assertTrue(f.usesTime())
3756
3757 def test_format_validate(self):
3758 # Check correct formatting
3759 # Percentage style
3760 f = logging.Formatter("%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3761 self.assertEqual(f._fmt, "%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3762 f = logging.Formatter("%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3763 self.assertEqual(f._fmt, "%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3764 f = logging.Formatter("%(process)#+027.23X")
3765 self.assertEqual(f._fmt, "%(process)#+027.23X")
3766 f = logging.Formatter("%(foo)#.*g")
3767 self.assertEqual(f._fmt, "%(foo)#.*g")
3768
3769 # StrFormat Style
3770 f = logging.Formatter("$%{message}%$ - {asctime!a:15} - {customfield['key']}", style="{")
3771 self.assertEqual(f._fmt, "$%{message}%$ - {asctime!a:15} - {customfield['key']}")
3772 f = logging.Formatter("{process:.2f} - {custom.f:.4f}", style="{")
3773 self.assertEqual(f._fmt, "{process:.2f} - {custom.f:.4f}")
3774 f = logging.Formatter("{customfield!s:#<30}", style="{")
3775 self.assertEqual(f._fmt, "{customfield!s:#<30}")
3776 f = logging.Formatter("{message!r}", style="{")
3777 self.assertEqual(f._fmt, "{message!r}")
3778 f = logging.Formatter("{message!s}", style="{")
3779 self.assertEqual(f._fmt, "{message!s}")
3780 f = logging.Formatter("{message!a}", style="{")
3781 self.assertEqual(f._fmt, "{message!a}")
3782 f = logging.Formatter("{process!r:4.2}", style="{")
3783 self.assertEqual(f._fmt, "{process!r:4.2}")
3784 f = logging.Formatter("{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}", style="{")
3785 self.assertEqual(f._fmt, "{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}")
3786 f = logging.Formatter("{process!s:{w},.{p}}", style="{")
3787 self.assertEqual(f._fmt, "{process!s:{w},.{p}}")
3788 f = logging.Formatter("{foo:12.{p}}", style="{")
3789 self.assertEqual(f._fmt, "{foo:12.{p}}")
3790 f = logging.Formatter("{foo:{w}.6}", style="{")
3791 self.assertEqual(f._fmt, "{foo:{w}.6}")
3792 f = logging.Formatter("{foo[0].bar[1].baz}", style="{")
3793 self.assertEqual(f._fmt, "{foo[0].bar[1].baz}")
3794 f = logging.Formatter("{foo[k1].bar[k2].baz}", style="{")
3795 self.assertEqual(f._fmt, "{foo[k1].bar[k2].baz}")
3796 f = logging.Formatter("{12[k1].bar[k2].baz}", style="{")
3797 self.assertEqual(f._fmt, "{12[k1].bar[k2].baz}")
3798
3799 # Dollar style
3800 f = logging.Formatter("${asctime} - $message", style="$")
3801 self.assertEqual(f._fmt, "${asctime} - $message")
3802 f = logging.Formatter("$bar $$", style="$")
3803 self.assertEqual(f._fmt, "$bar $$")
3804 f = logging.Formatter("$bar $$$$", style="$")
3805 self.assertEqual(f._fmt, "$bar $$$$") # this would print two $($$)
3806
3807 # Testing when ValueError being raised from incorrect format
3808 # Percentage Style
3809 self.assertRaises(ValueError, logging.Formatter, "%(asctime)Z")
3810 self.assertRaises(ValueError, logging.Formatter, "%(asctime)b")
3811 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*")
3812 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*3s")
3813 self.assertRaises(ValueError, logging.Formatter, "%(asctime)_")
3814 self.assertRaises(ValueError, logging.Formatter, '{asctime}')
3815 self.assertRaises(ValueError, logging.Formatter, '${message}')
3816 self.assertRaises(ValueError, logging.Formatter, '%(foo)#12.3*f') # with both * and decimal number as precision
3817 self.assertRaises(ValueError, logging.Formatter, '%(foo)0*.8*f')
3818
3819 # StrFormat Style
3820 # Testing failure for '-' in field name
3821 self.assert_error_message(
3822 ValueError,
3823 "invalid field name/expression: 'name-thing'",
3824 logging.Formatter, "{name-thing}", style="{"
3825 )
3826 # Testing failure for style mismatch
3827 self.assert_error_message(
3828 ValueError,
3829 "invalid format: no fields",
3830 logging.Formatter, '%(asctime)s', style='{'
3831 )
3832 # Testing failure for invalid conversion
3833 self.assert_error_message(
3834 ValueError,
3835 "invalid conversion: 'Z'"
3836 )
3837 self.assertRaises(ValueError, logging.Formatter, '{asctime!s:#30,15f}', style='{')
3838 self.assert_error_message(
3839 ValueError,
3840 "invalid format: expected ':' after conversion specifier",
3841 logging.Formatter, '{asctime!aa:15}', style='{'
3842 )
3843 # Testing failure for invalid spec
3844 self.assert_error_message(
3845 ValueError,
3846 "bad specifier: '.2ff'",
3847 logging.Formatter, '{process:.2ff}', style='{'
3848 )
3849 self.assertRaises(ValueError, logging.Formatter, '{process:.2Z}', style='{')
3850 self.assertRaises(ValueError, logging.Formatter, '{process!s:<##30,12g}', style='{')
3851 self.assertRaises(ValueError, logging.Formatter, '{process!s:<#30#,12g}', style='{')
3852 self.assertRaises(ValueError, logging.Formatter, '{process!s:{{w}},{{p}}}', style='{')
3853 # Testing failure for mismatch braces
3854 self.assert_error_message(
3855 ValueError,
3856 "invalid format: unmatched '{' in format spec",
3857 logging.Formatter, '{process', style='{'
3858 )
3859 self.assert_error_message(
3860 ValueError,
3861 "invalid format: unmatched '{' in format spec",
3862 logging.Formatter, 'process}', style='{'
3863 )
3864 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}', style='{')
3865 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}}', style='{')
3866 self.assertRaises(ValueError, logging.Formatter, '{foo/bar}', style='{')
3867 self.assertRaises(ValueError, logging.Formatter, '{foo:{{w}}.{{p}}}}', style='{')
3868 self.assertRaises(ValueError, logging.Formatter, '{foo!X:{{w}}.{{p}}}', style='{')
3869 self.assertRaises(ValueError, logging.Formatter, '{foo!a:random}', style='{')
3870 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{dom}', style='{')
3871 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{d}om}', style='{')
3872 self.assertRaises(ValueError, logging.Formatter, '{foo.!a:d}', style='{')
3873
3874 # Dollar style
3875 # Testing failure for mismatch bare $
3876 self.assert_error_message(
3877 ValueError,
3878 "invalid format: bare \'$\' not allowed",
3879 logging.Formatter, '$bar $$$', style='$'
3880 )
3881 self.assert_error_message(
3882 ValueError,
3883 "invalid format: bare \'$\' not allowed",
3884 logging.Formatter, 'bar $', style='$'
3885 )
3886 self.assert_error_message(
3887 ValueError,
3888 "invalid format: bare \'$\' not allowed",
3889 logging.Formatter, 'foo $.', style='$'
3890 )
3891 # Testing failure for mismatch style
3892 self.assert_error_message(
3893 ValueError,
3894 "invalid format: no fields",
3895 logging.Formatter, '{asctime}', style='$'
3896 )
3897 self.assertRaises(ValueError, logging.Formatter, '%(asctime)s', style='$')
3898
3899 # Testing failure for incorrect fields
3900 self.assert_error_message(
3901 ValueError,
3902 "invalid format: no fields",
3903 logging.Formatter, 'foo', style='$'
3904 )
3905 self.assertRaises(ValueError, logging.Formatter, '${asctime', style='$')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003906
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003907 def test_invalid_style(self):
3908 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3909
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003910 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003911 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003912 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3913 # We use None to indicate we want the local timezone
3914 # We're essentially converting a UTC time to local time
3915 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003916 r.msecs = 123
3917 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003918 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003919 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3920 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003921 f.format(r)
3922 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3923
3924class TestBufferingFormatter(logging.BufferingFormatter):
3925 def formatHeader(self, records):
3926 return '[(%d)' % len(records)
3927
3928 def formatFooter(self, records):
3929 return '(%d)]' % len(records)
3930
3931class BufferingFormatterTest(unittest.TestCase):
3932 def setUp(self):
3933 self.records = [
3934 logging.makeLogRecord({'msg': 'one'}),
3935 logging.makeLogRecord({'msg': 'two'}),
3936 ]
3937
3938 def test_default(self):
3939 f = logging.BufferingFormatter()
3940 self.assertEqual('', f.format([]))
3941 self.assertEqual('onetwo', f.format(self.records))
3942
3943 def test_custom(self):
3944 f = TestBufferingFormatter()
3945 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3946 lf = logging.Formatter('<%(message)s>')
3947 f = TestBufferingFormatter(lf)
3948 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003949
3950class ExceptionTest(BaseTest):
3951 def test_formatting(self):
3952 r = self.root_logger
3953 h = RecordingHandler()
3954 r.addHandler(h)
3955 try:
3956 raise RuntimeError('deliberate mistake')
3957 except:
3958 logging.exception('failed', stack_info=True)
3959 r.removeHandler(h)
3960 h.close()
3961 r = h.records[0]
3962 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3963 'call last):\n'))
3964 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3965 'deliberate mistake'))
3966 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3967 'call last):\n'))
3968 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3969 'stack_info=True)'))
3970
3971
Vinay Sajip5a27d402010-12-10 11:42:57 +00003972class LastResortTest(BaseTest):
3973 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003974 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003975 root = self.root_logger
3976 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003977 old_lastresort = logging.lastResort
3978 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003979
Vinay Sajip5a27d402010-12-10 11:42:57 +00003980 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003981 with support.captured_stderr() as stderr:
3982 root.debug('This should not appear')
3983 self.assertEqual(stderr.getvalue(), '')
3984 root.warning('Final chance!')
3985 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3986
3987 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003988 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003989 with support.captured_stderr() as stderr:
3990 root.warning('Final chance!')
3991 msg = 'No handlers could be found for logger "root"\n'
3992 self.assertEqual(stderr.getvalue(), msg)
3993
Vinay Sajip5a27d402010-12-10 11:42:57 +00003994 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003995 with support.captured_stderr() as stderr:
3996 root.warning('Final chance!')
3997 self.assertEqual(stderr.getvalue(), '')
3998
3999 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00004000 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00004001 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01004002 with support.captured_stderr() as stderr:
4003 root.warning('Final chance!')
4004 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00004005 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00004006 root.addHandler(self.root_hdlr)
4007 logging.lastResort = old_lastresort
4008 logging.raiseExceptions = old_raise_exceptions
4009
4010
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004011class FakeHandler:
4012
4013 def __init__(self, identifier, called):
4014 for method in ('acquire', 'flush', 'close', 'release'):
4015 setattr(self, method, self.record_call(identifier, method, called))
4016
4017 def record_call(self, identifier, method_name, called):
4018 def inner():
4019 called.append('{} - {}'.format(identifier, method_name))
4020 return inner
4021
4022
4023class RecordingHandler(logging.NullHandler):
4024
4025 def __init__(self, *args, **kwargs):
4026 super(RecordingHandler, self).__init__(*args, **kwargs)
4027 self.records = []
4028
4029 def handle(self, record):
4030 """Keep track of all the emitted records."""
4031 self.records.append(record)
4032
4033
4034class ShutdownTest(BaseTest):
4035
Vinay Sajip5e66b162011-04-20 15:41:14 +01004036 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004037
4038 def setUp(self):
4039 super(ShutdownTest, self).setUp()
4040 self.called = []
4041
4042 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004043 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004044
4045 def raise_error(self, error):
4046 def inner():
4047 raise error()
4048 return inner
4049
4050 def test_no_failure(self):
4051 # create some fake handlers
4052 handler0 = FakeHandler(0, self.called)
4053 handler1 = FakeHandler(1, self.called)
4054 handler2 = FakeHandler(2, self.called)
4055
4056 # create live weakref to those handlers
4057 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
4058
4059 logging.shutdown(handlerList=list(handlers))
4060
4061 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
4062 '1 - acquire', '1 - flush', '1 - close', '1 - release',
4063 '0 - acquire', '0 - flush', '0 - close', '0 - release']
4064 self.assertEqual(expected, self.called)
4065
4066 def _test_with_failure_in_method(self, method, error):
4067 handler = FakeHandler(0, self.called)
4068 setattr(handler, method, self.raise_error(error))
4069 handlers = [logging.weakref.ref(handler)]
4070
4071 logging.shutdown(handlerList=list(handlers))
4072
4073 self.assertEqual('0 - release', self.called[-1])
4074
4075 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004076 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004077
4078 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004079 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004080
4081 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004082 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004083
4084 def test_with_valueerror_in_acquire(self):
4085 self._test_with_failure_in_method('acquire', ValueError)
4086
4087 def test_with_valueerror_in_flush(self):
4088 self._test_with_failure_in_method('flush', ValueError)
4089
4090 def test_with_valueerror_in_close(self):
4091 self._test_with_failure_in_method('close', ValueError)
4092
4093 def test_with_other_error_in_acquire_without_raise(self):
4094 logging.raiseExceptions = False
4095 self._test_with_failure_in_method('acquire', IndexError)
4096
4097 def test_with_other_error_in_flush_without_raise(self):
4098 logging.raiseExceptions = False
4099 self._test_with_failure_in_method('flush', IndexError)
4100
4101 def test_with_other_error_in_close_without_raise(self):
4102 logging.raiseExceptions = False
4103 self._test_with_failure_in_method('close', IndexError)
4104
4105 def test_with_other_error_in_acquire_with_raise(self):
4106 logging.raiseExceptions = True
4107 self.assertRaises(IndexError, self._test_with_failure_in_method,
4108 'acquire', IndexError)
4109
4110 def test_with_other_error_in_flush_with_raise(self):
4111 logging.raiseExceptions = True
4112 self.assertRaises(IndexError, self._test_with_failure_in_method,
4113 'flush', IndexError)
4114
4115 def test_with_other_error_in_close_with_raise(self):
4116 logging.raiseExceptions = True
4117 self.assertRaises(IndexError, self._test_with_failure_in_method,
4118 'close', IndexError)
4119
4120
4121class ModuleLevelMiscTest(BaseTest):
4122
Vinay Sajip5e66b162011-04-20 15:41:14 +01004123 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004124
4125 def test_disable(self):
4126 old_disable = logging.root.manager.disable
4127 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004128 self.assertEqual(old_disable, 0)
4129 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004130
4131 logging.disable(83)
4132 self.assertEqual(logging.root.manager.disable, 83)
4133
Vinay Sajipd489ac92016-12-31 11:40:11 +00004134 # test the default value introduced in 3.7
4135 # (Issue #28524)
4136 logging.disable()
4137 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
4138
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004139 def _test_log(self, method, level=None):
4140 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004141 support.patch(self, logging, 'basicConfig',
4142 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004143
4144 recording = RecordingHandler()
4145 logging.root.addHandler(recording)
4146
4147 log_method = getattr(logging, method)
4148 if level is not None:
4149 log_method(level, "test me: %r", recording)
4150 else:
4151 log_method("test me: %r", recording)
4152
4153 self.assertEqual(len(recording.records), 1)
4154 record = recording.records[0]
4155 self.assertEqual(record.getMessage(), "test me: %r" % recording)
4156
4157 expected_level = level if level is not None else getattr(logging, method.upper())
4158 self.assertEqual(record.levelno, expected_level)
4159
4160 # basicConfig was not called!
4161 self.assertEqual(called, [])
4162
4163 def test_log(self):
4164 self._test_log('log', logging.ERROR)
4165
4166 def test_debug(self):
4167 self._test_log('debug')
4168
4169 def test_info(self):
4170 self._test_log('info')
4171
4172 def test_warning(self):
4173 self._test_log('warning')
4174
4175 def test_error(self):
4176 self._test_log('error')
4177
4178 def test_critical(self):
4179 self._test_log('critical')
4180
4181 def test_set_logger_class(self):
4182 self.assertRaises(TypeError, logging.setLoggerClass, object)
4183
4184 class MyLogger(logging.Logger):
4185 pass
4186
4187 logging.setLoggerClass(MyLogger)
4188 self.assertEqual(logging.getLoggerClass(), MyLogger)
4189
4190 logging.setLoggerClass(logging.Logger)
4191 self.assertEqual(logging.getLoggerClass(), logging.Logger)
4192
Vinay Sajip01500012019-06-19 11:46:53 +01004193 def test_subclass_logger_cache(self):
4194 # bpo-37258
4195 message = []
4196
4197 class MyLogger(logging.getLoggerClass()):
4198 def __init__(self, name='MyLogger', level=logging.NOTSET):
4199 super().__init__(name, level)
4200 message.append('initialized')
4201
4202 logging.setLoggerClass(MyLogger)
4203 logger = logging.getLogger('just_some_logger')
4204 self.assertEqual(message, ['initialized'])
4205 stream = io.StringIO()
4206 h = logging.StreamHandler(stream)
4207 logger.addHandler(h)
4208 try:
4209 logger.setLevel(logging.DEBUG)
4210 logger.debug("hello")
4211 self.assertEqual(stream.getvalue().strip(), "hello")
4212
4213 stream.truncate(0)
4214 stream.seek(0)
4215
4216 logger.setLevel(logging.INFO)
4217 logger.debug("hello")
4218 self.assertEqual(stream.getvalue(), "")
4219 finally:
4220 logger.removeHandler(h)
4221 h.close()
4222 logging.setLoggerClass(logging.Logger)
4223
Serhiy Storchakaa7930372016-07-03 22:27:26 +03004224 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01004225 def test_logging_at_shutdown(self):
4226 # Issue #20037
4227 code = """if 1:
4228 import logging
4229
4230 class A:
4231 def __del__(self):
4232 try:
4233 raise ValueError("some error")
4234 except Exception:
4235 logging.exception("exception in __del__")
4236
4237 a = A()"""
4238 rc, out, err = assert_python_ok("-c", code)
4239 err = err.decode()
4240 self.assertIn("exception in __del__", err)
4241 self.assertIn("ValueError: some error", err)
4242
Rémi Lapeyre65f64b12019-03-15 07:53:34 +01004243 def test_recursion_error(self):
4244 # Issue 36272
4245 code = """if 1:
4246 import logging
4247
4248 def rec():
4249 logging.error("foo")
4250 rec()
4251
4252 rec()"""
4253 rc, out, err = assert_python_failure("-c", code)
4254 err = err.decode()
4255 self.assertNotIn("Cannot recover from stack overflow.", err)
4256 self.assertEqual(rc, 1)
4257
Antoine Pitrou712cb732013-12-21 15:51:54 +01004258
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004259class LogRecordTest(BaseTest):
4260 def test_str_rep(self):
4261 r = logging.makeLogRecord({})
4262 s = str(r)
4263 self.assertTrue(s.startswith('<LogRecord: '))
4264 self.assertTrue(s.endswith('>'))
4265
4266 def test_dict_arg(self):
4267 h = RecordingHandler()
4268 r = logging.getLogger()
4269 r.addHandler(h)
4270 d = {'less' : 'more' }
4271 logging.warning('less is %(less)s', d)
4272 self.assertIs(h.records[0].args, d)
4273 self.assertEqual(h.records[0].message, 'less is more')
4274 r.removeHandler(h)
4275 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004276
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004277 def test_multiprocessing(self):
4278 r = logging.makeLogRecord({})
4279 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01004280 try:
4281 import multiprocessing as mp
4282 r = logging.makeLogRecord({})
4283 self.assertEqual(r.processName, mp.current_process().name)
4284 except ImportError:
4285 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004286
4287 def test_optional(self):
4288 r = logging.makeLogRecord({})
4289 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004290 NOT_NONE(r.thread)
4291 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004292 NOT_NONE(r.process)
4293 NOT_NONE(r.processName)
4294 log_threads = logging.logThreads
4295 log_processes = logging.logProcesses
4296 log_multiprocessing = logging.logMultiprocessing
4297 try:
4298 logging.logThreads = False
4299 logging.logProcesses = False
4300 logging.logMultiprocessing = False
4301 r = logging.makeLogRecord({})
4302 NONE = self.assertIsNone
4303 NONE(r.thread)
4304 NONE(r.threadName)
4305 NONE(r.process)
4306 NONE(r.processName)
4307 finally:
4308 logging.logThreads = log_threads
4309 logging.logProcesses = log_processes
4310 logging.logMultiprocessing = log_multiprocessing
4311
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004312class BasicConfigTest(unittest.TestCase):
4313
Vinay Sajip95bf5042011-04-20 11:50:56 +01004314 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004315
4316 def setUp(self):
4317 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01004318 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01004319 self.saved_handlers = logging._handlers.copy()
4320 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01004321 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01004322 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004323 logging.root.handlers = []
4324
4325 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01004326 for h in logging.root.handlers[:]:
4327 logging.root.removeHandler(h)
4328 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004329 super(BasicConfigTest, self).tearDown()
4330
Vinay Sajip3def7e02011-04-20 10:58:06 +01004331 def cleanup(self):
4332 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01004333 logging._handlers.clear()
4334 logging._handlers.update(self.saved_handlers)
4335 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1d094af2019-09-22 03:51:51 +01004336 logging.root.setLevel(self.original_logging_level)
Vinay Sajip3def7e02011-04-20 10:58:06 +01004337
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004338 def test_no_kwargs(self):
4339 logging.basicConfig()
4340
4341 # handler defaults to a StreamHandler to sys.stderr
4342 self.assertEqual(len(logging.root.handlers), 1)
4343 handler = logging.root.handlers[0]
4344 self.assertIsInstance(handler, logging.StreamHandler)
4345 self.assertEqual(handler.stream, sys.stderr)
4346
4347 formatter = handler.formatter
4348 # format defaults to logging.BASIC_FORMAT
4349 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
4350 # datefmt defaults to None
4351 self.assertIsNone(formatter.datefmt)
4352 # style defaults to %
4353 self.assertIsInstance(formatter._style, logging.PercentStyle)
4354
Florent Xiclunae41f0de2011-11-11 19:39:25 +01004355 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01004356 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004357
Vinay Sajip1fd12022014-01-13 21:59:56 +00004358 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004359 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004360 logging.basicConfig(stream=sys.stdout, style="{")
4361 logging.error("Log an error")
4362 sys.stdout.seek(0)
4363 self.assertEqual(output.getvalue().strip(),
4364 "ERROR:root:Log an error")
4365
4366 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004367 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004368 logging.basicConfig(stream=sys.stdout, style="$")
4369 logging.error("Log an error")
4370 sys.stdout.seek(0)
4371 self.assertEqual(output.getvalue().strip(),
4372 "ERROR:root:Log an error")
4373
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004374 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004375
4376 def cleanup(h1, h2, fn):
4377 h1.close()
4378 h2.close()
4379 os.remove(fn)
4380
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004381 logging.basicConfig(filename='test.log')
4382
4383 self.assertEqual(len(logging.root.handlers), 1)
4384 handler = logging.root.handlers[0]
4385 self.assertIsInstance(handler, logging.FileHandler)
4386
4387 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004388 self.assertEqual(handler.stream.mode, expected.stream.mode)
4389 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004390 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004391
4392 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004393
4394 def cleanup(h1, h2, fn):
4395 h1.close()
4396 h2.close()
4397 os.remove(fn)
4398
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004399 logging.basicConfig(filename='test.log', filemode='wb')
4400
4401 handler = logging.root.handlers[0]
4402 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004403 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004404 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004405
4406 def test_stream(self):
4407 stream = io.StringIO()
4408 self.addCleanup(stream.close)
4409 logging.basicConfig(stream=stream)
4410
4411 self.assertEqual(len(logging.root.handlers), 1)
4412 handler = logging.root.handlers[0]
4413 self.assertIsInstance(handler, logging.StreamHandler)
4414 self.assertEqual(handler.stream, stream)
4415
4416 def test_format(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01004417 logging.basicConfig(format='%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004418
4419 formatter = logging.root.handlers[0].formatter
BNMetrics18fb1fb2018-10-15 19:41:36 +01004420 self.assertEqual(formatter._style._fmt, '%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004421
4422 def test_datefmt(self):
4423 logging.basicConfig(datefmt='bar')
4424
4425 formatter = logging.root.handlers[0].formatter
4426 self.assertEqual(formatter.datefmt, 'bar')
4427
4428 def test_style(self):
4429 logging.basicConfig(style='$')
4430
4431 formatter = logging.root.handlers[0].formatter
4432 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
4433
4434 def test_level(self):
4435 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004436 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004437
4438 logging.basicConfig(level=57)
4439 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004440 # Test that second call has no effect
4441 logging.basicConfig(level=58)
4442 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004443
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004444 def test_incompatible(self):
4445 assertRaises = self.assertRaises
4446 handlers = [logging.StreamHandler()]
4447 stream = sys.stderr
4448 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004449 stream=stream)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004450 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004451 handlers=handlers)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004452 assertRaises(ValueError, logging.basicConfig, stream=stream,
BNMetrics18fb1fb2018-10-15 19:41:36 +01004453 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00004454 # Issue 23207: test for invalid kwargs
4455 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
4456 # Should pop both filename and filemode even if filename is None
4457 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004458
4459 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004460 handlers = [
4461 logging.StreamHandler(),
4462 logging.StreamHandler(sys.stdout),
4463 logging.StreamHandler(),
4464 ]
4465 f = logging.Formatter()
4466 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004467 logging.basicConfig(handlers=handlers)
4468 self.assertIs(handlers[0], logging.root.handlers[0])
4469 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004470 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004471 self.assertIsNotNone(handlers[0].formatter)
4472 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004473 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004474 self.assertIs(handlers[0].formatter, handlers[1].formatter)
4475
Dong-hee Nacf67d6a2018-06-25 13:11:09 +09004476 def test_force(self):
4477 old_string_io = io.StringIO()
4478 new_string_io = io.StringIO()
4479 old_handlers = [logging.StreamHandler(old_string_io)]
4480 new_handlers = [logging.StreamHandler(new_string_io)]
4481 logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
4482 logging.warning('warn')
4483 logging.info('info')
4484 logging.debug('debug')
4485 self.assertEqual(len(logging.root.handlers), 1)
4486 logging.basicConfig(level=logging.INFO, handlers=new_handlers,
4487 force=True)
4488 logging.warning('warn')
4489 logging.info('info')
4490 logging.debug('debug')
4491 self.assertEqual(len(logging.root.handlers), 1)
4492 self.assertEqual(old_string_io.getvalue().strip(),
4493 'WARNING:root:warn')
4494 self.assertEqual(new_string_io.getvalue().strip(),
4495 'WARNING:root:warn\nINFO:root:info')
4496
Vinay Sajipca7b5042019-06-17 17:40:52 +01004497 def test_encoding(self):
4498 try:
4499 encoding = 'utf-8'
4500 logging.basicConfig(filename='test.log', encoding=encoding,
4501 errors='strict',
4502 format='%(message)s', level=logging.DEBUG)
4503
4504 self.assertEqual(len(logging.root.handlers), 1)
4505 handler = logging.root.handlers[0]
4506 self.assertIsInstance(handler, logging.FileHandler)
4507 self.assertEqual(handler.encoding, encoding)
4508 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4509 finally:
4510 handler.close()
4511 with open('test.log', encoding='utf-8') as f:
4512 data = f.read().strip()
4513 os.remove('test.log')
4514 self.assertEqual(data,
4515 'The Øresund Bridge joins Copenhagen to Malmö')
4516
4517 def test_encoding_errors(self):
4518 try:
4519 encoding = 'ascii'
4520 logging.basicConfig(filename='test.log', encoding=encoding,
4521 errors='ignore',
4522 format='%(message)s', level=logging.DEBUG)
4523
4524 self.assertEqual(len(logging.root.handlers), 1)
4525 handler = logging.root.handlers[0]
4526 self.assertIsInstance(handler, logging.FileHandler)
4527 self.assertEqual(handler.encoding, encoding)
4528 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4529 finally:
4530 handler.close()
4531 with open('test.log', encoding='utf-8') as f:
4532 data = f.read().strip()
4533 os.remove('test.log')
4534 self.assertEqual(data, 'The resund Bridge joins Copenhagen to Malm')
4535
4536 def test_encoding_errors_default(self):
4537 try:
4538 encoding = 'ascii'
4539 logging.basicConfig(filename='test.log', encoding=encoding,
4540 format='%(message)s', level=logging.DEBUG)
4541
4542 self.assertEqual(len(logging.root.handlers), 1)
4543 handler = logging.root.handlers[0]
4544 self.assertIsInstance(handler, logging.FileHandler)
4545 self.assertEqual(handler.encoding, encoding)
4546 self.assertEqual(handler.errors, 'backslashreplace')
4547 logging.debug('😂: ☃️: The Øresund Bridge joins Copenhagen to Malmö')
4548 finally:
4549 handler.close()
4550 with open('test.log', encoding='utf-8') as f:
4551 data = f.read().strip()
4552 os.remove('test.log')
4553 self.assertEqual(data, r'\U0001f602: \u2603\ufe0f: The \xd8resund '
4554 r'Bridge joins Copenhagen to Malm\xf6')
4555
4556 def test_encoding_errors_none(self):
4557 # Specifying None should behave as 'strict'
4558 try:
4559 encoding = 'ascii'
4560 logging.basicConfig(filename='test.log', encoding=encoding,
4561 errors=None,
4562 format='%(message)s', level=logging.DEBUG)
4563
4564 self.assertEqual(len(logging.root.handlers), 1)
4565 handler = logging.root.handlers[0]
4566 self.assertIsInstance(handler, logging.FileHandler)
4567 self.assertEqual(handler.encoding, encoding)
4568 self.assertIsNone(handler.errors)
4569
4570 message = []
4571
4572 def dummy_handle_error(record):
4573 _, v, _ = sys.exc_info()
4574 message.append(str(v))
4575
4576 handler.handleError = dummy_handle_error
4577 logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
4578 self.assertTrue(message)
4579 self.assertIn("'ascii' codec can't encode "
4580 "character '\\xd8' in position 4:", message[0])
4581 finally:
4582 handler.close()
4583 with open('test.log', encoding='utf-8') as f:
4584 data = f.read().strip()
4585 os.remove('test.log')
4586 # didn't write anything due to the encoding error
4587 self.assertEqual(data, r'')
4588
4589
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004590 def _test_log(self, method, level=None):
4591 # logging.root has no handlers so basicConfig should be called
4592 called = []
4593
4594 old_basic_config = logging.basicConfig
4595 def my_basic_config(*a, **kw):
4596 old_basic_config()
4597 old_level = logging.root.level
4598 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004599 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004600 called.append((a, kw))
4601
Vinay Sajip1feedb42014-05-31 08:19:12 +01004602 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004603
4604 log_method = getattr(logging, method)
4605 if level is not None:
4606 log_method(level, "test me")
4607 else:
4608 log_method("test me")
4609
4610 # basicConfig was called with no arguments
4611 self.assertEqual(called, [((), {})])
4612
4613 def test_log(self):
4614 self._test_log('log', logging.WARNING)
4615
4616 def test_debug(self):
4617 self._test_log('debug')
4618
4619 def test_info(self):
4620 self._test_log('info')
4621
4622 def test_warning(self):
4623 self._test_log('warning')
4624
4625 def test_error(self):
4626 self._test_log('error')
4627
4628 def test_critical(self):
4629 self._test_log('critical')
4630
4631
4632class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004633 def setUp(self):
4634 super(LoggerAdapterTest, self).setUp()
4635 old_handler_list = logging._handlerList[:]
4636
4637 self.recording = RecordingHandler()
4638 self.logger = logging.root
4639 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004640 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004641 self.addCleanup(self.recording.close)
4642
4643 def cleanup():
4644 logging._handlerList[:] = old_handler_list
4645
4646 self.addCleanup(cleanup)
4647 self.addCleanup(logging.shutdown)
4648 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4649
4650 def test_exception(self):
4651 msg = 'testing exception: %r'
4652 exc = None
4653 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004654 1 / 0
4655 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004656 exc = e
4657 self.adapter.exception(msg, self.recording)
4658
4659 self.assertEqual(len(self.recording.records), 1)
4660 record = self.recording.records[0]
4661 self.assertEqual(record.levelno, logging.ERROR)
4662 self.assertEqual(record.msg, msg)
4663 self.assertEqual(record.args, (self.recording,))
4664 self.assertEqual(record.exc_info,
4665 (exc.__class__, exc, exc.__traceback__))
4666
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004667 def test_exception_excinfo(self):
4668 try:
4669 1 / 0
4670 except ZeroDivisionError as e:
4671 exc = e
4672
4673 self.adapter.exception('exc_info test', exc_info=exc)
4674
4675 self.assertEqual(len(self.recording.records), 1)
4676 record = self.recording.records[0]
4677 self.assertEqual(record.exc_info,
4678 (exc.__class__, exc, exc.__traceback__))
4679
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004680 def test_critical(self):
4681 msg = 'critical test! %r'
4682 self.adapter.critical(msg, self.recording)
4683
4684 self.assertEqual(len(self.recording.records), 1)
4685 record = self.recording.records[0]
4686 self.assertEqual(record.levelno, logging.CRITICAL)
4687 self.assertEqual(record.msg, msg)
4688 self.assertEqual(record.args, (self.recording,))
4689
4690 def test_is_enabled_for(self):
4691 old_disable = self.adapter.logger.manager.disable
4692 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004693 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4694 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004695 self.assertFalse(self.adapter.isEnabledFor(32))
4696
4697 def test_has_handlers(self):
4698 self.assertTrue(self.adapter.hasHandlers())
4699
4700 for handler in self.logger.handlers:
4701 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004702
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004703 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004704 self.assertFalse(self.adapter.hasHandlers())
4705
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004706 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004707 class Adapter(logging.LoggerAdapter):
4708 prefix = 'Adapter'
4709
4710 def process(self, msg, kwargs):
4711 return f"{self.prefix} {msg}", kwargs
4712
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004713 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004714 adapter = Adapter(logger=self.logger, extra=None)
4715 adapter_adapter = Adapter(logger=adapter, extra=None)
4716 adapter_adapter.prefix = 'AdapterAdapter'
4717 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004718 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004719 self.assertEqual(len(self.recording.records), 1)
4720 record = self.recording.records[0]
4721 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004722 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004723 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004724 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004725 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004726 self.assertIs(self.logger.manager, orig_manager)
4727 temp_manager = object()
4728 try:
4729 adapter_adapter.manager = temp_manager
4730 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004731 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004732 self.assertIs(self.logger.manager, temp_manager)
4733 finally:
4734 adapter_adapter.manager = orig_manager
4735 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004736 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004737 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004738
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004739
4740class LoggerTest(BaseTest):
4741
4742 def setUp(self):
4743 super(LoggerTest, self).setUp()
4744 self.recording = RecordingHandler()
4745 self.logger = logging.Logger(name='blah')
4746 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004747 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004748 self.addCleanup(self.recording.close)
4749 self.addCleanup(logging.shutdown)
4750
4751 def test_set_invalid_level(self):
4752 self.assertRaises(TypeError, self.logger.setLevel, object())
4753
4754 def test_exception(self):
4755 msg = 'testing exception: %r'
4756 exc = None
4757 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004758 1 / 0
4759 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004760 exc = e
4761 self.logger.exception(msg, self.recording)
4762
4763 self.assertEqual(len(self.recording.records), 1)
4764 record = self.recording.records[0]
4765 self.assertEqual(record.levelno, logging.ERROR)
4766 self.assertEqual(record.msg, msg)
4767 self.assertEqual(record.args, (self.recording,))
4768 self.assertEqual(record.exc_info,
4769 (exc.__class__, exc, exc.__traceback__))
4770
4771 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004772 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004773 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004774
4775 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004776 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004777 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004778
4779 def test_find_caller_with_stack_info(self):
4780 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004781 support.patch(self, logging.traceback, 'print_stack',
4782 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004783
4784 self.logger.findCaller(stack_info=True)
4785
4786 self.assertEqual(len(called), 1)
4787 self.assertEqual('Stack (most recent call last):\n', called[0])
4788
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004789 def test_find_caller_with_stacklevel(self):
4790 the_level = 1
4791
4792 def innermost():
4793 self.logger.warning('test', stacklevel=the_level)
4794
4795 def inner():
4796 innermost()
4797
4798 def outer():
4799 inner()
4800
4801 records = self.recording.records
4802 outer()
4803 self.assertEqual(records[-1].funcName, 'innermost')
4804 lineno = records[-1].lineno
4805 the_level += 1
4806 outer()
4807 self.assertEqual(records[-1].funcName, 'inner')
4808 self.assertGreater(records[-1].lineno, lineno)
4809 lineno = records[-1].lineno
4810 the_level += 1
4811 outer()
4812 self.assertEqual(records[-1].funcName, 'outer')
4813 self.assertGreater(records[-1].lineno, lineno)
4814 lineno = records[-1].lineno
4815 the_level += 1
4816 outer()
4817 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4818 self.assertGreater(records[-1].lineno, lineno)
4819
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004820 def test_make_record_with_extra_overwrite(self):
4821 name = 'my record'
4822 level = 13
4823 fn = lno = msg = args = exc_info = func = sinfo = None
4824 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4825 exc_info, func, sinfo)
4826
4827 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4828 extra = {key: 'some value'}
4829 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4830 fn, lno, msg, args, exc_info,
4831 extra=extra, sinfo=sinfo)
4832
4833 def test_make_record_with_extra_no_overwrite(self):
4834 name = 'my record'
4835 level = 13
4836 fn = lno = msg = args = exc_info = func = sinfo = None
4837 extra = {'valid_key': 'some value'}
4838 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4839 exc_info, extra=extra, sinfo=sinfo)
4840 self.assertIn('valid_key', result.__dict__)
4841
4842 def test_has_handlers(self):
4843 self.assertTrue(self.logger.hasHandlers())
4844
4845 for handler in self.logger.handlers:
4846 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004847 self.assertFalse(self.logger.hasHandlers())
4848
4849 def test_has_handlers_no_propagate(self):
4850 child_logger = logging.getLogger('blah.child')
4851 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004852 self.assertFalse(child_logger.hasHandlers())
4853
4854 def test_is_enabled_for(self):
4855 old_disable = self.logger.manager.disable
4856 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004857 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004858 self.assertFalse(self.logger.isEnabledFor(22))
4859
Timo Furrer6e3ca642018-06-01 09:29:46 +02004860 def test_is_enabled_for_disabled_logger(self):
4861 old_disabled = self.logger.disabled
4862 old_disable = self.logger.manager.disable
4863
4864 self.logger.disabled = True
4865 self.logger.manager.disable = 21
4866
4867 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4868 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4869
4870 self.assertFalse(self.logger.isEnabledFor(22))
4871
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004872 def test_root_logger_aliases(self):
4873 root = logging.getLogger()
4874 self.assertIs(root, logging.root)
4875 self.assertIs(root, logging.getLogger(None))
4876 self.assertIs(root, logging.getLogger(''))
Vinay Sajipcb65b3a2019-08-02 16:53:00 +01004877 self.assertIs(root, logging.getLogger('root'))
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004878 self.assertIs(root, logging.getLogger('foo').root)
4879 self.assertIs(root, logging.getLogger('foo.bar').root)
4880 self.assertIs(root, logging.getLogger('foo').parent)
4881
4882 self.assertIsNot(root, logging.getLogger('\0'))
4883 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4884
4885 def test_invalid_names(self):
4886 self.assertRaises(TypeError, logging.getLogger, any)
4887 self.assertRaises(TypeError, logging.getLogger, b'foo')
4888
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004889 def test_pickling(self):
4890 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4891 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4892 logger = logging.getLogger(name)
4893 s = pickle.dumps(logger, proto)
4894 unpickled = pickle.loads(s)
4895 self.assertIs(unpickled, logger)
4896
Avram Lubkin78c18a92017-07-30 05:36:33 -04004897 def test_caching(self):
4898 root = self.root_logger
4899 logger1 = logging.getLogger("abc")
4900 logger2 = logging.getLogger("abc.def")
4901
4902 # Set root logger level and ensure cache is empty
4903 root.setLevel(logging.ERROR)
4904 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4905 self.assertEqual(logger2._cache, {})
4906
4907 # Ensure cache is populated and calls are consistent
4908 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4909 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4910 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4911 self.assertEqual(root._cache, {})
4912 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4913
4914 # Ensure root cache gets populated
4915 self.assertEqual(root._cache, {})
4916 self.assertTrue(root.isEnabledFor(logging.ERROR))
4917 self.assertEqual(root._cache, {logging.ERROR: True})
4918
4919 # Set parent logger level and ensure caches are emptied
4920 logger1.setLevel(logging.CRITICAL)
4921 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4922 self.assertEqual(logger2._cache, {})
4923
4924 # Ensure logger2 uses parent logger's effective level
4925 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4926
4927 # Set level to NOTSET and ensure caches are empty
4928 logger2.setLevel(logging.NOTSET)
4929 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4930 self.assertEqual(logger2._cache, {})
4931 self.assertEqual(logger1._cache, {})
4932 self.assertEqual(root._cache, {})
4933
4934 # Verify logger2 follows parent and not root
4935 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4936 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4937 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4938 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4939 self.assertTrue(root.isEnabledFor(logging.ERROR))
4940
4941 # Disable logging in manager and ensure caches are clear
4942 logging.disable()
4943 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4944 self.assertEqual(logger2._cache, {})
4945 self.assertEqual(logger1._cache, {})
4946 self.assertEqual(root._cache, {})
4947
4948 # Ensure no loggers are enabled
4949 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4950 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4951 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4952
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004953
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004954class BaseFileTest(BaseTest):
4955 "Base class for handler tests that write log files"
4956
4957 def setUp(self):
4958 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004959 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4960 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004961 self.rmfiles = []
4962
4963 def tearDown(self):
4964 for fn in self.rmfiles:
4965 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004966 if os.path.exists(self.fn):
4967 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004968 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004969
4970 def assertLogFile(self, filename):
4971 "Assert a log file is there and register it for deletion"
4972 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004973 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004974 self.rmfiles.append(filename)
4975
4976
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004977class FileHandlerTest(BaseFileTest):
4978 def test_delay(self):
4979 os.unlink(self.fn)
4980 fh = logging.FileHandler(self.fn, delay=True)
4981 self.assertIsNone(fh.stream)
4982 self.assertFalse(os.path.exists(self.fn))
4983 fh.handle(logging.makeLogRecord({}))
4984 self.assertIsNotNone(fh.stream)
4985 self.assertTrue(os.path.exists(self.fn))
4986 fh.close()
4987
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004988class RotatingFileHandlerTest(BaseFileTest):
4989 def next_rec(self):
4990 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4991 self.next_message(), None, None, None)
4992
4993 def test_should_not_rollover(self):
4994 # If maxbytes is zero rollover never occurs
4995 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4996 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004997 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004998
4999 def test_should_rollover(self):
5000 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
5001 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00005002 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005003
5004 def test_file_created(self):
5005 # checks that the file is created and assumes it was created
5006 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005007 rh = logging.handlers.RotatingFileHandler(self.fn)
5008 rh.emit(self.next_rec())
5009 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00005010 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005011
5012 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00005013 def namer(name):
5014 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005015 rh = logging.handlers.RotatingFileHandler(
5016 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005017 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005018 rh.emit(self.next_rec())
5019 self.assertLogFile(self.fn)
5020 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005021 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005022 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00005023 self.assertLogFile(namer(self.fn + ".2"))
5024 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
5025 rh.close()
5026
l0rb519cb872019-11-06 22:21:40 +01005027 def test_namer_rotator_inheritance(self):
5028 class HandlerWithNamerAndRotator(logging.handlers.RotatingFileHandler):
5029 def namer(self, name):
5030 return name + ".test"
5031
5032 def rotator(self, source, dest):
5033 if os.path.exists(source):
5034 os.rename(source, dest + ".rotated")
5035
5036 rh = HandlerWithNamerAndRotator(
5037 self.fn, backupCount=2, maxBytes=1)
5038 self.assertEqual(rh.namer(self.fn), self.fn + ".test")
5039 rh.emit(self.next_rec())
5040 self.assertLogFile(self.fn)
5041 rh.emit(self.next_rec())
5042 self.assertLogFile(rh.namer(self.fn + ".1") + ".rotated")
5043 self.assertFalse(os.path.exists(rh.namer(self.fn + ".1")))
5044 rh.close()
5045
Vinay Sajip1feedb42014-05-31 08:19:12 +01005046 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00005047 def test_rotator(self):
5048 def namer(name):
5049 return name + ".gz"
5050
5051 def rotator(source, dest):
5052 with open(source, "rb") as sf:
5053 data = sf.read()
5054 compressed = zlib.compress(data, 9)
5055 with open(dest, "wb") as df:
5056 df.write(compressed)
5057 os.remove(source)
5058
5059 rh = logging.handlers.RotatingFileHandler(
5060 self.fn, backupCount=2, maxBytes=1)
5061 rh.rotator = rotator
5062 rh.namer = namer
5063 m1 = self.next_rec()
5064 rh.emit(m1)
5065 self.assertLogFile(self.fn)
5066 m2 = self.next_rec()
5067 rh.emit(m2)
5068 fn = namer(self.fn + ".1")
5069 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005070 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00005071 with open(fn, "rb") as f:
5072 compressed = f.read()
5073 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005074 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005075 rh.emit(self.next_rec())
5076 fn = namer(self.fn + ".2")
5077 self.assertLogFile(fn)
5078 with open(fn, "rb") as f:
5079 compressed = f.read()
5080 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005081 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005082 rh.emit(self.next_rec())
5083 fn = namer(self.fn + ".2")
5084 with open(fn, "rb") as f:
5085 compressed = f.read()
5086 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00005087 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00005088 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00005089 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005090
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005091class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01005092 # other test methods added below
5093 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01005094 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
5095 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00005096 fmt = logging.Formatter('%(asctime)s %(message)s')
5097 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005098 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005099 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01005100 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00005101 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00005102 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00005103 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01005104 fh.close()
5105 # At this point, we should have a recent rotated file which we
5106 # can test for the existence of. However, in practice, on some
5107 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01005108 # in time to go to look for the log file. So, we go back a fair
5109 # bit, and stop as soon as we see a rotated file. In theory this
5110 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01005111 found = False
5112 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01005113 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01005114 for secs in range(GO_BACK):
5115 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01005116 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
5117 found = os.path.exists(fn)
5118 if found:
5119 self.rmfiles.append(fn)
5120 break
Vinay Sajip672c5812011-05-13 07:09:40 +01005121 msg = 'No rotated files found, went back %d seconds' % GO_BACK
5122 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03005123 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01005124 dn, fn = os.path.split(self.fn)
5125 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02005126 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
5127 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00005128 for f in files:
5129 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00005130 path = os.path.join(dn, f)
5131 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00005132 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01005133 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005134
Vinay Sajip0372e102011-05-05 12:59:14 +01005135 def test_invalid(self):
5136 assertRaises = self.assertRaises
5137 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005138 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005139 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005140 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005141 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01005142 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01005143
Vinay Sajipa7130792013-04-12 17:04:23 +01005144 def test_compute_rollover_daily_attime(self):
5145 currentTime = 0
5146 atTime = datetime.time(12, 0, 0)
5147 rh = logging.handlers.TimedRotatingFileHandler(
5148 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
5149 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005150 try:
5151 actual = rh.computeRollover(currentTime)
5152 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01005153
Vinay Sajipd86ac962013-04-14 12:20:46 +01005154 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
5155 self.assertEqual(actual, currentTime + 36 * 60 * 60)
5156 finally:
5157 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005158
Vinay Sajip10e8c492013-05-18 10:19:54 -07005159 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01005160 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01005161 currentTime = int(time.time())
5162 today = currentTime - currentTime % 86400
5163
Vinay Sajipa7130792013-04-12 17:04:23 +01005164 atTime = datetime.time(12, 0, 0)
5165
Vinay Sajip10e8c492013-05-18 10:19:54 -07005166 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01005167 for day in range(7):
5168 rh = logging.handlers.TimedRotatingFileHandler(
5169 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
5170 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01005171 try:
5172 if wday > day:
5173 # The rollover day has already passed this week, so we
5174 # go over into next week
5175 expected = (7 - wday + day)
5176 else:
5177 expected = (day - wday)
5178 # At this point expected is in days from now, convert to seconds
5179 expected *= 24 * 60 * 60
5180 # Add in the rollover time
5181 expected += 12 * 60 * 60
5182 # Add in adjustment for today
5183 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01005184 actual = rh.computeRollover(today)
5185 if actual != expected:
5186 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005187 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005188 self.assertEqual(actual, expected)
5189 if day == wday:
5190 # goes into following week
5191 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01005192 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01005193 if actual != expected:
5194 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01005195 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01005196 self.assertEqual(actual, expected)
5197 finally:
5198 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01005199
5200
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005201def secs(**kw):
5202 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
5203
5204for when, exp in (('S', 1),
5205 ('M', 60),
5206 ('H', 60 * 60),
5207 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00005208 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005209 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00005210 ('W0', secs(days=4, hours=24)),
5211 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005212 def test_compute_rollover(self, when=when, exp=exp):
5213 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00005214 self.fn, when=when, interval=1, backupCount=0, utc=True)
5215 currentTime = 0.0
5216 actual = rh.computeRollover(currentTime)
5217 if exp != actual:
5218 # Failures occur on some systems for MIDNIGHT and W0.
5219 # Print detailed calculation for MIDNIGHT so we can try to see
5220 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00005221 if when == 'MIDNIGHT':
5222 try:
5223 if rh.utc:
5224 t = time.gmtime(currentTime)
5225 else:
5226 t = time.localtime(currentTime)
5227 currentHour = t[3]
5228 currentMinute = t[4]
5229 currentSecond = t[5]
5230 # r is the number of seconds left between now and midnight
5231 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
5232 currentMinute) * 60 +
5233 currentSecond)
5234 result = currentTime + r
5235 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
5236 print('currentHour: %s' % currentHour, file=sys.stderr)
5237 print('currentMinute: %s' % currentMinute, file=sys.stderr)
5238 print('currentSecond: %s' % currentSecond, file=sys.stderr)
5239 print('r: %s' % r, file=sys.stderr)
5240 print('result: %s' % result, file=sys.stderr)
5241 except Exception:
5242 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
5243 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00005244 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005245 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
5246
Vinay Sajip60ccd822011-05-09 17:32:09 +01005247
Vinay Sajip223349c2015-10-01 20:37:54 +01005248@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01005249class NTEventLogHandlerTest(BaseTest):
5250 def test_basic(self):
5251 logtype = 'Application'
5252 elh = win32evtlog.OpenEventLog(None, logtype)
5253 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01005254
5255 try:
5256 h = logging.handlers.NTEventLogHandler('test_logging')
5257 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05005258 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01005259 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05005260 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01005261
Vinay Sajip60ccd822011-05-09 17:32:09 +01005262 r = logging.makeLogRecord({'msg': 'Test Log Message'})
5263 h.handle(r)
5264 h.close()
5265 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02005266 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01005267 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
5268 win32evtlog.EVENTLOG_SEQUENTIAL_READ
5269 found = False
5270 GO_BACK = 100
5271 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
5272 for e in events:
5273 if e.SourceName != 'test_logging':
5274 continue
5275 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
5276 if msg != 'Test Log Message\r\n':
5277 continue
5278 found = True
5279 break
5280 msg = 'Record not found in event log, went back %d records' % GO_BACK
5281 self.assertTrue(found, msg=msg)
5282
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005283
5284class MiscTestCase(unittest.TestCase):
5285 def test__all__(self):
5286 blacklist = {'logThreads', 'logMultiprocessing',
5287 'logProcesses', 'currentframe',
5288 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
5289 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00005290 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005291 support.check__all__(self, logging, blacklist=blacklist)
5292
5293
Christian Heimes180510d2008-03-03 19:15:45 +00005294# Set the locale to the platform-dependent default. I have no idea
5295# why the test does this, but in any case we save the current locale
5296# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01005297@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00005298def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01005299 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01005300 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
5301 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
5302 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
5303 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
5304 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
5305 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
5306 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
5307 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08005308 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01005309 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01005310 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005311 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01005312 ]
5313 if hasattr(logging.handlers, 'QueueListener'):
5314 tests.append(QueueListenerTest)
5315 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00005316
Christian Heimes180510d2008-03-03 19:15:45 +00005317if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00005318 test_main()