blob: c797d66aa6452c1d01e8682be7973c595452bf82 [file] [log] [blame]
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001# Copyright 2001-2017 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 Sajip1e6499c2017-01-09 16:54:12 +000019Copyright (C) 2001-2017 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
Berker Peksagce643912015-05-06 06:33:17 +030044from test.support.script_helper import assert_python_ok
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 Sajip8b866d52017-01-11 06:57:55 +0000318 def test_regression_29220(self):
319 """See issue #29220 for more information."""
320 logging.addLevelName(logging.INFO, '')
321 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
322 self.assertEqual(logging.getLevelName(logging.INFO), '')
323
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100324 def test_issue27935(self):
325 fatal = logging.getLevelName('FATAL')
326 self.assertEqual(fatal, logging.FATAL)
327
Vinay Sajip924aaae2017-01-11 17:35:36 +0000328 def test_regression_29220(self):
329 """See issue #29220 for more information."""
330 logging.addLevelName(logging.INFO, '')
331 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
332 self.assertEqual(logging.getLevelName(logging.INFO), '')
333 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
334 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
335
Christian Heimes180510d2008-03-03 19:15:45 +0000336class BasicFilterTest(BaseTest):
337
338 """Test the bundled Filter class."""
339
340 def test_filter(self):
341 # Only messages satisfying the specified criteria pass through the
342 # filter.
343 filter_ = logging.Filter("spam.eggs")
344 handler = self.root_logger.handlers[0]
345 try:
346 handler.addFilter(filter_)
347 spam = logging.getLogger("spam")
348 spam_eggs = logging.getLogger("spam.eggs")
349 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
350 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
351
352 spam.info(self.next_message())
353 spam_eggs.info(self.next_message()) # Good.
354 spam_eggs_fish.info(self.next_message()) # Good.
355 spam_bakedbeans.info(self.next_message())
356
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000357 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000358 ('spam.eggs', 'INFO', '2'),
359 ('spam.eggs.fish', 'INFO', '3'),
360 ])
361 finally:
362 handler.removeFilter(filter_)
363
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000364 def test_callable_filter(self):
365 # Only messages satisfying the specified criteria pass through the
366 # filter.
367
368 def filterfunc(record):
369 parts = record.name.split('.')
370 prefix = '.'.join(parts[:2])
371 return prefix == 'spam.eggs'
372
373 handler = self.root_logger.handlers[0]
374 try:
375 handler.addFilter(filterfunc)
376 spam = logging.getLogger("spam")
377 spam_eggs = logging.getLogger("spam.eggs")
378 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
379 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
380
381 spam.info(self.next_message())
382 spam_eggs.info(self.next_message()) # Good.
383 spam_eggs_fish.info(self.next_message()) # Good.
384 spam_bakedbeans.info(self.next_message())
385
386 self.assert_log_lines([
387 ('spam.eggs', 'INFO', '2'),
388 ('spam.eggs.fish', 'INFO', '3'),
389 ])
390 finally:
391 handler.removeFilter(filterfunc)
392
Vinay Sajip985ef872011-04-26 19:34:04 +0100393 def test_empty_filter(self):
394 f = logging.Filter()
395 r = logging.makeLogRecord({'name': 'spam.eggs'})
396 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000397
398#
399# First, we define our levels. There can be as many as you want - the only
400# limitations are that they should be integers, the lowest should be > 0 and
401# larger values mean less information being logged. If you need specific
402# level values which do not fit into these limitations, you can use a
403# mapping dictionary to convert between your application levels and the
404# logging system.
405#
406SILENT = 120
407TACITURN = 119
408TERSE = 118
409EFFUSIVE = 117
410SOCIABLE = 116
411VERBOSE = 115
412TALKATIVE = 114
413GARRULOUS = 113
414CHATTERBOX = 112
415BORING = 111
416
417LEVEL_RANGE = range(BORING, SILENT + 1)
418
419#
420# Next, we define names for our levels. You don't need to do this - in which
421# case the system will use "Level n" to denote the text for the level.
422#
423my_logging_levels = {
424 SILENT : 'Silent',
425 TACITURN : 'Taciturn',
426 TERSE : 'Terse',
427 EFFUSIVE : 'Effusive',
428 SOCIABLE : 'Sociable',
429 VERBOSE : 'Verbose',
430 TALKATIVE : 'Talkative',
431 GARRULOUS : 'Garrulous',
432 CHATTERBOX : 'Chatterbox',
433 BORING : 'Boring',
434}
435
436class GarrulousFilter(logging.Filter):
437
438 """A filter which blocks garrulous messages."""
439
440 def filter(self, record):
441 return record.levelno != GARRULOUS
442
443class VerySpecificFilter(logging.Filter):
444
445 """A filter which blocks sociable and taciturn messages."""
446
447 def filter(self, record):
448 return record.levelno not in [SOCIABLE, TACITURN]
449
450
451class CustomLevelsAndFiltersTest(BaseTest):
452
453 """Test various filtering possibilities with custom logging levels."""
454
455 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300456 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000457
458 def setUp(self):
459 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000460 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000461 logging.addLevelName(k, v)
462
463 def log_at_all_levels(self, logger):
464 for lvl in LEVEL_RANGE:
465 logger.log(lvl, self.next_message())
466
467 def test_logger_filter(self):
468 # Filter at logger level.
469 self.root_logger.setLevel(VERBOSE)
470 # Levels >= 'Verbose' are good.
471 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000472 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000473 ('Verbose', '5'),
474 ('Sociable', '6'),
475 ('Effusive', '7'),
476 ('Terse', '8'),
477 ('Taciturn', '9'),
478 ('Silent', '10'),
479 ])
480
481 def test_handler_filter(self):
482 # Filter at handler level.
483 self.root_logger.handlers[0].setLevel(SOCIABLE)
484 try:
485 # Levels >= 'Sociable' are good.
486 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000487 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000488 ('Sociable', '6'),
489 ('Effusive', '7'),
490 ('Terse', '8'),
491 ('Taciturn', '9'),
492 ('Silent', '10'),
493 ])
494 finally:
495 self.root_logger.handlers[0].setLevel(logging.NOTSET)
496
497 def test_specific_filters(self):
498 # Set a specific filter object on the handler, and then add another
499 # filter object on the logger itself.
500 handler = self.root_logger.handlers[0]
501 specific_filter = None
502 garr = GarrulousFilter()
503 handler.addFilter(garr)
504 try:
505 self.log_at_all_levels(self.root_logger)
506 first_lines = [
507 # Notice how 'Garrulous' is missing
508 ('Boring', '1'),
509 ('Chatterbox', '2'),
510 ('Talkative', '4'),
511 ('Verbose', '5'),
512 ('Sociable', '6'),
513 ('Effusive', '7'),
514 ('Terse', '8'),
515 ('Taciturn', '9'),
516 ('Silent', '10'),
517 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000518 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000519
520 specific_filter = VerySpecificFilter()
521 self.root_logger.addFilter(specific_filter)
522 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000523 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000524 # Not only 'Garrulous' is still missing, but also 'Sociable'
525 # and 'Taciturn'
526 ('Boring', '11'),
527 ('Chatterbox', '12'),
528 ('Talkative', '14'),
529 ('Verbose', '15'),
530 ('Effusive', '17'),
531 ('Terse', '18'),
532 ('Silent', '20'),
533 ])
534 finally:
535 if specific_filter:
536 self.root_logger.removeFilter(specific_filter)
537 handler.removeFilter(garr)
538
539
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100540class HandlerTest(BaseTest):
541 def test_name(self):
542 h = logging.Handler()
543 h.name = 'generic'
544 self.assertEqual(h.name, 'generic')
545 h.name = 'anothergeneric'
546 self.assertEqual(h.name, 'anothergeneric')
547 self.assertRaises(NotImplementedError, h.emit, None)
548
Vinay Sajip5a35b062011-04-27 11:31:14 +0100549 def test_builtin_handlers(self):
550 # We can't actually *use* too many handlers in the tests,
551 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200552 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100553 for existing in (True, False):
554 fd, fn = tempfile.mkstemp()
555 os.close(fd)
556 if not existing:
557 os.unlink(fn)
558 h = logging.handlers.WatchedFileHandler(fn, delay=True)
559 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100560 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100561 self.assertEqual(dev, -1)
562 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100563 r = logging.makeLogRecord({'msg': 'Test'})
564 h.handle(r)
565 # Now remove the file.
566 os.unlink(fn)
567 self.assertFalse(os.path.exists(fn))
568 # The next call should recreate the file.
569 h.handle(r)
570 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100571 else:
572 self.assertEqual(h.dev, -1)
573 self.assertEqual(h.ino, -1)
574 h.close()
575 if existing:
576 os.unlink(fn)
577 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100578 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100579 else:
580 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100581 try:
582 h = logging.handlers.SysLogHandler(sockname)
583 self.assertEqual(h.facility, h.LOG_USER)
584 self.assertTrue(h.unixsocket)
585 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200586 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100587 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100588 for method in ('GET', 'POST', 'PUT'):
589 if method == 'PUT':
590 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
591 'localhost', '/log', method)
592 else:
593 h = logging.handlers.HTTPHandler('localhost', '/log', method)
594 h.close()
595 h = logging.handlers.BufferingHandler(0)
596 r = logging.makeLogRecord({})
597 self.assertTrue(h.shouldFlush(r))
598 h.close()
599 h = logging.handlers.BufferingHandler(1)
600 self.assertFalse(h.shouldFlush(r))
601 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100602
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100603 def test_path_objects(self):
604 """
605 Test that Path objects are accepted as filename arguments to handlers.
606
607 See Issue #27493.
608 """
609 fd, fn = tempfile.mkstemp()
610 os.close(fd)
611 os.unlink(fn)
612 pfn = pathlib.Path(fn)
613 cases = (
614 (logging.FileHandler, (pfn, 'w')),
615 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
616 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
617 )
618 if sys.platform in ('linux', 'darwin'):
619 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
620 for cls, args in cases:
621 h = cls(*args)
622 self.assertTrue(os.path.exists(fn))
623 h.close()
624 os.unlink(fn)
625
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100626 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100627 def test_race(self):
628 # Issue #14632 refers.
629 def remove_loop(fname, tries):
630 for _ in range(tries):
631 try:
632 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000633 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100634 except OSError:
635 pass
636 time.sleep(0.004 * random.randint(0, 4))
637
Vinay Sajipc94871a2012-04-25 10:51:35 +0100638 del_count = 500
639 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100640
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000641 self.handle_time = None
642 self.deletion_time = None
643
Vinay Sajipa5798de2012-04-24 23:33:33 +0100644 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100645 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
646 os.close(fd)
647 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
648 remover.daemon = True
649 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100650 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100651 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
652 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100653 try:
654 for _ in range(log_count):
655 time.sleep(0.005)
656 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000657 try:
658 self.handle_time = time.time()
659 h.handle(r)
660 except Exception:
661 print('Deleted at %s, '
662 'opened at %s' % (self.deletion_time,
663 self.handle_time))
664 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100665 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100666 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100667 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100668 if os.path.exists(fn):
669 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100670
Gregory P. Smith19003842018-09-13 22:08:31 -0700671 # The implementation relies on os.register_at_fork existing, but we test
672 # based on os.fork existing because that is what users and this test use.
673 # This helps ensure that when fork exists (the important concept) that the
674 # register_at_fork mechanism is also present and used.
675 @unittest.skipIf(not hasattr(os, 'fork'), 'Test requires os.fork().')
676 def test_post_fork_child_no_deadlock(self):
677 """Ensure forked child logging locks are not held; bpo-6721."""
678 refed_h = logging.Handler()
679 refed_h.name = 'because we need at least one for this test'
680 self.assertGreater(len(logging._handlers), 0)
681
682 locks_held__ready_to_fork = threading.Event()
683 fork_happened__release_locks_and_end_thread = threading.Event()
684
685 def lock_holder_thread_fn():
686 logging._acquireLock()
687 try:
688 refed_h.acquire()
689 try:
690 # Tell the main thread to do the fork.
691 locks_held__ready_to_fork.set()
692
693 # If the deadlock bug exists, the fork will happen
694 # without dealing with the locks we hold, deadlocking
695 # the child.
696
697 # Wait for a successful fork or an unreasonable amount of
698 # time before releasing our locks. To avoid a timing based
699 # test we'd need communication from os.fork() as to when it
700 # has actually happened. Given this is a regression test
701 # for a fixed issue, potentially less reliably detecting
702 # regression via timing is acceptable for simplicity.
703 # The test will always take at least this long. :(
704 fork_happened__release_locks_and_end_thread.wait(0.5)
705 finally:
706 refed_h.release()
707 finally:
708 logging._releaseLock()
709
710 lock_holder_thread = threading.Thread(
711 target=lock_holder_thread_fn,
712 name='test_post_fork_child_no_deadlock lock holder')
713 lock_holder_thread.start()
714
715 locks_held__ready_to_fork.wait()
716 pid = os.fork()
717 if pid == 0: # Child.
718 logging.error(r'Child process did not deadlock. \o/')
719 os._exit(0)
720 else: # Parent.
721 fork_happened__release_locks_and_end_thread.set()
722 lock_holder_thread.join()
723 start_time = time.monotonic()
724 while True:
725 waited_pid, status = os.waitpid(pid, os.WNOHANG)
726 if waited_pid == pid:
727 break # child process exited.
728 if time.monotonic() - start_time > 7:
729 break # so long? implies child deadlock.
730 time.sleep(0.05)
731 if waited_pid != pid:
732 os.kill(pid, signal.SIGKILL)
733 waited_pid, status = os.waitpid(pid, 0)
734 self.fail("child process deadlocked.")
735 self.assertEqual(status, 0, msg="child process error")
736
Vinay Sajipa5798de2012-04-24 23:33:33 +0100737
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100738class BadStream(object):
739 def write(self, data):
740 raise RuntimeError('deliberate mistake')
741
742class TestStreamHandler(logging.StreamHandler):
743 def handleError(self, record):
744 self.error_record = record
745
746class StreamHandlerTest(BaseTest):
747 def test_error_handling(self):
748 h = TestStreamHandler(BadStream())
749 r = logging.makeLogRecord({})
750 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100751
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100752 try:
753 h.handle(r)
754 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100755
Vinay Sajip985ef872011-04-26 19:34:04 +0100756 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100757 with support.captured_stderr() as stderr:
758 h.handle(r)
759 msg = '\nRuntimeError: deliberate mistake\n'
760 self.assertIn(msg, stderr.getvalue())
761
Vinay Sajip985ef872011-04-26 19:34:04 +0100762 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100763 with support.captured_stderr() as stderr:
764 h.handle(r)
765 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100766 finally:
767 logging.raiseExceptions = old_raise
768
Vinay Sajip2543f502017-07-30 10:41:45 +0100769 def test_stream_setting(self):
770 """
771 Test setting the handler's stream
772 """
773 h = logging.StreamHandler()
774 stream = io.StringIO()
775 old = h.setStream(stream)
776 self.assertIs(old, sys.stderr)
777 actual = h.setStream(old)
778 self.assertIs(actual, stream)
779 # test that setting to existing value returns None
780 actual = h.setStream(old)
781 self.assertIsNone(actual)
782
Vinay Sajip7367d082011-05-02 13:17:27 +0100783# -- The following section could be moved into a server_helper.py module
784# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100785
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200786class TestSMTPServer(smtpd.SMTPServer):
787 """
788 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100789
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200790 :param addr: A (host, port) tuple which the server listens on.
791 You can specify a port value of zero: the server's
792 *port* attribute will hold the actual port number
793 used, which can be used in client connections.
794 :param handler: A callable which will be called to process
795 incoming messages. The handler will be passed
796 the client address tuple, who the message is from,
797 a list of recipients and the message data.
798 :param poll_interval: The interval, in seconds, used in the underlying
799 :func:`select` or :func:`poll` call by
800 :func:`asyncore.loop`.
801 :param sockmap: A dictionary which will be used to hold
802 :class:`asyncore.dispatcher` instances used by
803 :func:`asyncore.loop`. This avoids changing the
804 :mod:`asyncore` module's global state.
805 """
806
807 def __init__(self, addr, handler, poll_interval, sockmap):
808 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
809 decode_data=True)
810 self.port = self.socket.getsockname()[1]
811 self._handler = handler
812 self._thread = None
813 self.poll_interval = poll_interval
814
815 def process_message(self, peer, mailfrom, rcpttos, data):
816 """
817 Delegates to the handler passed in to the server's constructor.
818
819 Typically, this will be a test case method.
820 :param peer: The client (host, port) tuple.
821 :param mailfrom: The address of the sender.
822 :param rcpttos: The addresses of the recipients.
823 :param data: The message.
824 """
825 self._handler(peer, mailfrom, rcpttos, data)
826
827 def start(self):
828 """
829 Start the server running on a separate daemon thread.
830 """
831 self._thread = t = threading.Thread(target=self.serve_forever,
832 args=(self.poll_interval,))
833 t.setDaemon(True)
834 t.start()
835
836 def serve_forever(self, poll_interval):
837 """
838 Run the :mod:`asyncore` loop until normal termination
839 conditions arise.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100840 :param poll_interval: The interval, in seconds, used in the underlying
841 :func:`select` or :func:`poll` call by
842 :func:`asyncore.loop`.
843 """
Victor Stinner13ff2452018-01-22 18:32:50 +0100844 asyncore.loop(poll_interval, map=self._map)
Vinay Sajipce7c9782011-05-17 07:15:53 +0100845
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200846 def stop(self, timeout=None):
847 """
848 Stop the thread by closing the server instance.
849 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100850
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200851 :param timeout: How long to wait for the server thread
852 to terminate.
853 """
854 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700855 support.join_thread(self._thread, timeout)
856 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200857 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100858
Vinay Sajip7367d082011-05-02 13:17:27 +0100859
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200860class ControlMixin(object):
861 """
862 This mixin is used to start a server on a separate thread, and
863 shut it down programmatically. Request handling is simplified - instead
864 of needing to derive a suitable RequestHandler subclass, you just
865 provide a callable which will be passed each received request to be
866 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100867
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200868 :param handler: A handler callable which will be called with a
869 single parameter - the request - in order to
870 process the request. This handler is called on the
871 server thread, effectively meaning that requests are
872 processed serially. While not quite Web scale ;-),
873 this should be fine for testing applications.
874 :param poll_interval: The polling interval in seconds.
875 """
876 def __init__(self, handler, poll_interval):
877 self._thread = None
878 self.poll_interval = poll_interval
879 self._handler = handler
880 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100881
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200882 def start(self):
883 """
884 Create a daemon thread to run the server, and start it.
885 """
886 self._thread = t = threading.Thread(target=self.serve_forever,
887 args=(self.poll_interval,))
888 t.setDaemon(True)
889 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100890
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200891 def serve_forever(self, poll_interval):
892 """
893 Run the server. Set the ready flag before entering the
894 service loop.
895 """
896 self.ready.set()
897 super(ControlMixin, self).serve_forever(poll_interval)
898
899 def stop(self, timeout=None):
900 """
901 Tell the server thread to stop, and wait for it to do so.
902
903 :param timeout: How long to wait for the server thread
904 to terminate.
905 """
906 self.shutdown()
907 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700908 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100909 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200910 self.server_close()
911 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100912
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200913class TestHTTPServer(ControlMixin, HTTPServer):
914 """
915 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100916
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200917 :param addr: A tuple with the IP address and port to listen on.
918 :param handler: A handler callable which will be called with a
919 single parameter - the request - in order to
920 process the request.
921 :param poll_interval: The polling interval in seconds.
922 :param log: Pass ``True`` to enable log messages.
923 """
924 def __init__(self, addr, handler, poll_interval=0.5,
925 log=False, sslctx=None):
926 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
927 def __getattr__(self, name, default=None):
928 if name.startswith('do_'):
929 return self.process_request
930 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100931
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200932 def process_request(self):
933 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100934
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200935 def log_message(self, format, *args):
936 if log:
937 super(DelegatingHTTPRequestHandler,
938 self).log_message(format, *args)
939 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
940 ControlMixin.__init__(self, handler, poll_interval)
941 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100942
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200943 def get_request(self):
944 try:
945 sock, addr = self.socket.accept()
946 if self.sslctx:
947 sock = self.sslctx.wrap_socket(sock, server_side=True)
948 except OSError as e:
949 # socket errors are silenced by the caller, print them here
950 sys.stderr.write("Got an error:\n%s\n" % e)
951 raise
952 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100953
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200954class TestTCPServer(ControlMixin, ThreadingTCPServer):
955 """
956 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100957
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200958 :param addr: A tuple with the IP address and port to listen on.
959 :param handler: A handler callable which will be called with a single
960 parameter - the request - in order to process the request.
961 :param poll_interval: The polling interval in seconds.
962 :bind_and_activate: If True (the default), binds the server and starts it
963 listening. If False, you need to call
964 :meth:`server_bind` and :meth:`server_activate` at
965 some later time before calling :meth:`start`, so that
966 the server will set up the socket and listen on it.
967 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100968
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200969 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100970
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200971 def __init__(self, addr, handler, poll_interval=0.5,
972 bind_and_activate=True):
973 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100974
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200975 def handle(self):
976 self.server._handler(self)
977 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
978 bind_and_activate)
979 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100980
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200981 def server_bind(self):
982 super(TestTCPServer, self).server_bind()
983 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100984
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200985class TestUDPServer(ControlMixin, ThreadingUDPServer):
986 """
987 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100988
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200989 :param addr: A tuple with the IP address and port to listen on.
990 :param handler: A handler callable which will be called with a
991 single parameter - the request - in order to
992 process the request.
993 :param poll_interval: The polling interval for shutdown requests,
994 in seconds.
995 :bind_and_activate: If True (the default), binds the server and
996 starts it listening. If False, you need to
997 call :meth:`server_bind` and
998 :meth:`server_activate` at some later time
999 before calling :meth:`start`, so that the server will
1000 set up the socket and listen on it.
1001 """
1002 def __init__(self, addr, handler, poll_interval=0.5,
1003 bind_and_activate=True):
1004 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +01001005
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001006 def handle(self):
1007 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001008
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001009 def finish(self):
1010 data = self.wfile.getvalue()
1011 if data:
1012 try:
1013 super(DelegatingUDPRequestHandler, self).finish()
1014 except OSError:
1015 if not self.server._closed:
1016 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +01001017
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001018 ThreadingUDPServer.__init__(self, addr,
1019 DelegatingUDPRequestHandler,
1020 bind_and_activate)
1021 ControlMixin.__init__(self, handler, poll_interval)
1022 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +01001023
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001024 def server_bind(self):
1025 super(TestUDPServer, self).server_bind()
1026 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +01001027
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001028 def server_close(self):
1029 super(TestUDPServer, self).server_close()
1030 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +01001031
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001032if hasattr(socket, "AF_UNIX"):
1033 class TestUnixStreamServer(TestTCPServer):
1034 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +01001035
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001036 class TestUnixDatagramServer(TestUDPServer):
1037 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +01001038
Vinay Sajip7367d082011-05-02 13:17:27 +01001039# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +01001040
1041class SMTPHandlerTest(BaseTest):
Victor Stinner31b50b82018-07-11 12:35:38 +02001042 # bpo-14314, bpo-19665, bpo-34092: don't wait forever, timeout of 1 minute
1043 TIMEOUT = 60.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02001044
Vinay Sajipa463d252011-04-30 21:52:48 +01001045 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +01001046 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -08001047 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +01001048 sockmap)
1049 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -08001050 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001051 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
1052 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001053 self.assertEqual(h.toaddrs, ['you'])
1054 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001055 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001056 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001057 h.handle(r)
Victor Stinner31b50b82018-07-11 12:35:38 +02001058 self.handled.wait(self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001059 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001060 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001061 self.assertEqual(len(self.messages), 1)
1062 peer, mailfrom, rcpttos, data = self.messages[0]
1063 self.assertEqual(mailfrom, 'me')
1064 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001065 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001066 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001067 h.close()
1068
1069 def process_message(self, *args):
1070 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001071 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001072
Christian Heimes180510d2008-03-03 19:15:45 +00001073class MemoryHandlerTest(BaseTest):
1074
1075 """Tests for the MemoryHandler."""
1076
1077 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001078 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001079
1080 def setUp(self):
1081 BaseTest.setUp(self)
1082 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001083 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001084 self.mem_logger = logging.getLogger('mem')
1085 self.mem_logger.propagate = 0
1086 self.mem_logger.addHandler(self.mem_hdlr)
1087
1088 def tearDown(self):
1089 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001090 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001091
1092 def test_flush(self):
1093 # The memory handler flushes to its target handler based on specific
1094 # criteria (message count and message level).
1095 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001096 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001097 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001098 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001099 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001100 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001101 lines = [
1102 ('DEBUG', '1'),
1103 ('INFO', '2'),
1104 ('WARNING', '3'),
1105 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001106 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001107 for n in (4, 14):
1108 for i in range(9):
1109 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001110 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001111 # This will flush because it's the 10th message since the last
1112 # flush.
1113 self.mem_logger.debug(self.next_message())
1114 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001115 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001116
1117 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001118 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001119
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001120 def test_flush_on_close(self):
1121 """
1122 Test that the flush-on-close configuration works as expected.
1123 """
1124 self.mem_logger.debug(self.next_message())
1125 self.assert_log_lines([])
1126 self.mem_logger.info(self.next_message())
1127 self.assert_log_lines([])
1128 self.mem_logger.removeHandler(self.mem_hdlr)
1129 # Default behaviour is to flush on close. Check that it happens.
1130 self.mem_hdlr.close()
1131 lines = [
1132 ('DEBUG', '1'),
1133 ('INFO', '2'),
1134 ]
1135 self.assert_log_lines(lines)
1136 # Now configure for flushing not to be done on close.
1137 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1138 self.root_hdlr,
1139 False)
1140 self.mem_logger.addHandler(self.mem_hdlr)
1141 self.mem_logger.debug(self.next_message())
1142 self.assert_log_lines(lines) # no change
1143 self.mem_logger.info(self.next_message())
1144 self.assert_log_lines(lines) # no change
1145 self.mem_logger.removeHandler(self.mem_hdlr)
1146 self.mem_hdlr.close()
1147 # assert that no new lines have been added
1148 self.assert_log_lines(lines) # no change
1149
Christian Heimes180510d2008-03-03 19:15:45 +00001150
1151class ExceptionFormatter(logging.Formatter):
1152 """A special exception formatter."""
1153 def formatException(self, ei):
1154 return "Got a [%s]" % ei[0].__name__
1155
1156
1157class ConfigFileTest(BaseTest):
1158
1159 """Reading logging config from a .ini-style config file."""
1160
Xtreak087570a2018-07-02 14:27:46 +05301161 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001162 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001163
1164 # config0 is a standard configuration.
1165 config0 = """
1166 [loggers]
1167 keys=root
1168
1169 [handlers]
1170 keys=hand1
1171
1172 [formatters]
1173 keys=form1
1174
1175 [logger_root]
1176 level=WARNING
1177 handlers=hand1
1178
1179 [handler_hand1]
1180 class=StreamHandler
1181 level=NOTSET
1182 formatter=form1
1183 args=(sys.stdout,)
1184
1185 [formatter_form1]
1186 format=%(levelname)s ++ %(message)s
1187 datefmt=
1188 """
1189
1190 # config1 adds a little to the standard configuration.
1191 config1 = """
1192 [loggers]
1193 keys=root,parser
1194
1195 [handlers]
1196 keys=hand1
1197
1198 [formatters]
1199 keys=form1
1200
1201 [logger_root]
1202 level=WARNING
1203 handlers=
1204
1205 [logger_parser]
1206 level=DEBUG
1207 handlers=hand1
1208 propagate=1
1209 qualname=compiler.parser
1210
1211 [handler_hand1]
1212 class=StreamHandler
1213 level=NOTSET
1214 formatter=form1
1215 args=(sys.stdout,)
1216
1217 [formatter_form1]
1218 format=%(levelname)s ++ %(message)s
1219 datefmt=
1220 """
1221
Vinay Sajip3f84b072011-03-07 17:49:33 +00001222 # config1a moves the handler to the root.
1223 config1a = """
1224 [loggers]
1225 keys=root,parser
1226
1227 [handlers]
1228 keys=hand1
1229
1230 [formatters]
1231 keys=form1
1232
1233 [logger_root]
1234 level=WARNING
1235 handlers=hand1
1236
1237 [logger_parser]
1238 level=DEBUG
1239 handlers=
1240 propagate=1
1241 qualname=compiler.parser
1242
1243 [handler_hand1]
1244 class=StreamHandler
1245 level=NOTSET
1246 formatter=form1
1247 args=(sys.stdout,)
1248
1249 [formatter_form1]
1250 format=%(levelname)s ++ %(message)s
1251 datefmt=
1252 """
1253
Christian Heimes180510d2008-03-03 19:15:45 +00001254 # config2 has a subtle configuration error that should be reported
1255 config2 = config1.replace("sys.stdout", "sys.stbout")
1256
1257 # config3 has a less subtle configuration error
1258 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1259
1260 # config4 specifies a custom formatter class to be loaded
1261 config4 = """
1262 [loggers]
1263 keys=root
1264
1265 [handlers]
1266 keys=hand1
1267
1268 [formatters]
1269 keys=form1
1270
1271 [logger_root]
1272 level=NOTSET
1273 handlers=hand1
1274
1275 [handler_hand1]
1276 class=StreamHandler
1277 level=NOTSET
1278 formatter=form1
1279 args=(sys.stdout,)
1280
1281 [formatter_form1]
1282 class=""" + __name__ + """.ExceptionFormatter
1283 format=%(levelname)s:%(name)s:%(message)s
1284 datefmt=
1285 """
1286
Georg Brandl3dbca812008-07-23 16:10:53 +00001287 # config5 specifies a custom handler class to be loaded
1288 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1289
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001290 # config6 uses ', ' delimiters in the handlers and formatters sections
1291 config6 = """
1292 [loggers]
1293 keys=root,parser
1294
1295 [handlers]
1296 keys=hand1, hand2
1297
1298 [formatters]
1299 keys=form1, form2
1300
1301 [logger_root]
1302 level=WARNING
1303 handlers=
1304
1305 [logger_parser]
1306 level=DEBUG
1307 handlers=hand1
1308 propagate=1
1309 qualname=compiler.parser
1310
1311 [handler_hand1]
1312 class=StreamHandler
1313 level=NOTSET
1314 formatter=form1
1315 args=(sys.stdout,)
1316
1317 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001318 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001319 level=NOTSET
1320 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001321 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001322
1323 [formatter_form1]
1324 format=%(levelname)s ++ %(message)s
1325 datefmt=
1326
1327 [formatter_form2]
1328 format=%(message)s
1329 datefmt=
1330 """
1331
Preston Landers6ea56d22017-08-02 15:44:28 -05001332 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001333 config7 = """
1334 [loggers]
1335 keys=root,parser,compiler
1336
1337 [handlers]
1338 keys=hand1
1339
1340 [formatters]
1341 keys=form1
1342
1343 [logger_root]
1344 level=WARNING
1345 handlers=hand1
1346
1347 [logger_compiler]
1348 level=DEBUG
1349 handlers=
1350 propagate=1
1351 qualname=compiler
1352
1353 [logger_parser]
1354 level=DEBUG
1355 handlers=
1356 propagate=1
1357 qualname=compiler.parser
1358
1359 [handler_hand1]
1360 class=StreamHandler
1361 level=NOTSET
1362 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001363 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001364
1365 [formatter_form1]
1366 format=%(levelname)s ++ %(message)s
1367 datefmt=
1368 """
1369
Xtreak087570a2018-07-02 14:27:46 +05301370 # config 8, check for resource warning
1371 config8 = r"""
1372 [loggers]
1373 keys=root
1374
1375 [handlers]
1376 keys=file
1377
1378 [formatters]
1379 keys=
1380
1381 [logger_root]
1382 level=DEBUG
1383 handlers=file
1384
1385 [handler_file]
1386 class=FileHandler
1387 level=DEBUG
1388 args=("{tempfile}",)
1389 """
1390
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001391 disable_test = """
1392 [loggers]
1393 keys=root
1394
1395 [handlers]
1396 keys=screen
1397
1398 [formatters]
1399 keys=
1400
1401 [logger_root]
1402 level=DEBUG
1403 handlers=screen
1404
1405 [handler_screen]
1406 level=DEBUG
1407 class=StreamHandler
1408 args=(sys.stdout,)
1409 formatter=
1410 """
1411
1412 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001413 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001414 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001415
1416 def test_config0_ok(self):
1417 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001418 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001419 self.apply_config(self.config0)
1420 logger = logging.getLogger()
1421 # Won't output anything
1422 logger.info(self.next_message())
1423 # Outputs a message
1424 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001425 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001426 ('ERROR', '2'),
1427 ], stream=output)
1428 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001429 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001430
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001431 def test_config0_using_cp_ok(self):
1432 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001433 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001434 file = io.StringIO(textwrap.dedent(self.config0))
1435 cp = configparser.ConfigParser()
1436 cp.read_file(file)
1437 logging.config.fileConfig(cp)
1438 logger = logging.getLogger()
1439 # Won't output anything
1440 logger.info(self.next_message())
1441 # Outputs a message
1442 logger.error(self.next_message())
1443 self.assert_log_lines([
1444 ('ERROR', '2'),
1445 ], stream=output)
1446 # Original logger output is empty.
1447 self.assert_log_lines([])
1448
Georg Brandl3dbca812008-07-23 16:10:53 +00001449 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001450 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001451 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001452 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001453 logger = logging.getLogger("compiler.parser")
1454 # Both will output a message
1455 logger.info(self.next_message())
1456 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001457 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001458 ('INFO', '1'),
1459 ('ERROR', '2'),
1460 ], stream=output)
1461 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001462 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001463
1464 def test_config2_failure(self):
1465 # A simple config file which overrides the default settings.
1466 self.assertRaises(Exception, self.apply_config, self.config2)
1467
1468 def test_config3_failure(self):
1469 # A simple config file which overrides the default settings.
1470 self.assertRaises(Exception, self.apply_config, self.config3)
1471
1472 def test_config4_ok(self):
1473 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001474 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001475 self.apply_config(self.config4)
1476 logger = logging.getLogger()
1477 try:
1478 raise RuntimeError()
1479 except RuntimeError:
1480 logging.exception("just testing")
1481 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001482 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001483 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1484 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001485 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001486
Georg Brandl3dbca812008-07-23 16:10:53 +00001487 def test_config5_ok(self):
1488 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001489
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001490 def test_config6_ok(self):
1491 self.test_config1_ok(config=self.config6)
1492
Vinay Sajip3f84b072011-03-07 17:49:33 +00001493 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001494 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001495 self.apply_config(self.config1a)
1496 logger = logging.getLogger("compiler.parser")
1497 # See issue #11424. compiler-hyphenated sorts
1498 # between compiler and compiler.xyz and this
1499 # was preventing compiler.xyz from being included
1500 # in the child loggers of compiler because of an
1501 # overzealous loop termination condition.
1502 hyphenated = logging.getLogger('compiler-hyphenated')
1503 # All will output a message
1504 logger.info(self.next_message())
1505 logger.error(self.next_message())
1506 hyphenated.critical(self.next_message())
1507 self.assert_log_lines([
1508 ('INFO', '1'),
1509 ('ERROR', '2'),
1510 ('CRITICAL', '3'),
1511 ], stream=output)
1512 # Original logger output is empty.
1513 self.assert_log_lines([])
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.config7)
1516 logger = logging.getLogger("compiler.parser")
1517 self.assertFalse(logger.disabled)
1518 # Both will output a message
1519 logger.info(self.next_message())
1520 logger.error(self.next_message())
1521 logger = logging.getLogger("compiler.lexer")
1522 # Both will output a message
1523 logger.info(self.next_message())
1524 logger.error(self.next_message())
1525 # Will not appear
1526 hyphenated.critical(self.next_message())
1527 self.assert_log_lines([
1528 ('INFO', '4'),
1529 ('ERROR', '5'),
1530 ('INFO', '6'),
1531 ('ERROR', '7'),
1532 ], stream=output)
1533 # Original logger output is empty.
1534 self.assert_log_lines([])
1535
Xtreak087570a2018-07-02 14:27:46 +05301536 def test_config8_ok(self):
1537
1538 def cleanup(h1, fn):
1539 h1.close()
1540 os.remove(fn)
1541
1542 with self.check_no_resource_warning():
1543 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1544 os.close(fd)
1545
1546 # Replace single backslash with double backslash in windows
1547 # to avoid unicode error during string formatting
1548 if os.name == "nt":
1549 fn = fn.replace("\\", "\\\\")
1550
1551 config8 = self.config8.format(tempfile=fn)
1552
1553 self.apply_config(config8)
1554 self.apply_config(config8)
1555
1556 handler = logging.root.handlers[0]
1557 self.addCleanup(cleanup, handler, fn)
1558
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001559 def test_logger_disabling(self):
1560 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001561 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001562 self.assertFalse(logger.disabled)
1563 self.apply_config(self.disable_test)
1564 self.assertTrue(logger.disabled)
1565 self.apply_config(self.disable_test, disable_existing_loggers=False)
1566 self.assertFalse(logger.disabled)
1567
Łukasz Langa214f18e2018-06-08 04:02:48 -07001568 def test_defaults_do_no_interpolation(self):
1569 """bpo-33802 defaults should not get interpolated"""
1570 ini = textwrap.dedent("""
1571 [formatters]
1572 keys=default
1573
1574 [formatter_default]
1575
1576 [handlers]
1577 keys=console
1578
1579 [handler_console]
1580 class=logging.StreamHandler
1581 args=tuple()
1582
1583 [loggers]
1584 keys=root
1585
1586 [logger_root]
1587 formatter=default
1588 handlers=console
1589 """).strip()
1590 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1591 try:
1592 os.write(fd, ini.encode('ascii'))
1593 os.close(fd)
1594 logging.config.fileConfig(
1595 fn,
1596 defaults=dict(
1597 version=1,
1598 disable_existing_loggers=False,
1599 formatters={
1600 "generic": {
1601 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1602 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1603 "class": "logging.Formatter"
1604 },
1605 },
1606 )
1607 )
1608 finally:
1609 os.unlink(fn)
1610
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001611
Christian Heimes180510d2008-03-03 19:15:45 +00001612class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001613
Christian Heimes180510d2008-03-03 19:15:45 +00001614 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001615
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001616 server_class = TestTCPServer
1617 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001618
Christian Heimes180510d2008-03-03 19:15:45 +00001619 def setUp(self):
1620 """Set up a TCP server to receive log messages, and a SocketHandler
1621 pointing to that server's address and port."""
1622 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001623 # Issue #29177: deal with errors that happen during setup
1624 self.server = self.sock_hdlr = self.server_exception = None
1625 try:
1626 self.server = server = self.server_class(self.address,
1627 self.handle_socket, 0.01)
1628 server.start()
1629 # Uncomment next line to test error recovery in setUp()
1630 # raise OSError('dummy error raised')
1631 except OSError as e:
1632 self.server_exception = e
1633 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001634 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001635 hcls = logging.handlers.SocketHandler
1636 if isinstance(server.server_address, tuple):
1637 self.sock_hdlr = hcls('localhost', server.port)
1638 else:
1639 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001640 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001641 self.root_logger.removeHandler(self.root_logger.handlers[0])
1642 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001643 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001644
Christian Heimes180510d2008-03-03 19:15:45 +00001645 def tearDown(self):
1646 """Shutdown the TCP server."""
1647 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001648 if self.sock_hdlr:
1649 self.root_logger.removeHandler(self.sock_hdlr)
1650 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001651 if self.server:
1652 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001653 finally:
1654 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001655
Vinay Sajip7367d082011-05-02 13:17:27 +01001656 def handle_socket(self, request):
1657 conn = request.connection
1658 while True:
1659 chunk = conn.recv(4)
1660 if len(chunk) < 4:
1661 break
1662 slen = struct.unpack(">L", chunk)[0]
1663 chunk = conn.recv(slen)
1664 while len(chunk) < slen:
1665 chunk = chunk + conn.recv(slen - len(chunk))
1666 obj = pickle.loads(chunk)
1667 record = logging.makeLogRecord(obj)
1668 self.log_output += record.msg + '\n'
1669 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001670
Christian Heimes180510d2008-03-03 19:15:45 +00001671 def test_output(self):
1672 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001673 if self.server_exception:
1674 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001675 logger = logging.getLogger("tcp")
1676 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001677 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001678 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 self.handled.acquire()
1680 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001681
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001682 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001683 if self.server_exception:
1684 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001685 # Avoid timing-related failures due to SocketHandler's own hard-wired
1686 # one-second timeout on socket.create_connection() (issue #16264).
1687 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001688 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001689 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001690 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001691 try:
1692 raise RuntimeError('Deliberate mistake')
1693 except RuntimeError:
1694 self.root_logger.exception('Never sent')
1695 self.root_logger.error('Never sent, either')
1696 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001697 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001698 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1699 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001700
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001701def _get_temp_domain_socket():
1702 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1703 os.close(fd)
1704 # just need a name - file can't be present, or we'll get an
1705 # 'address already in use' error.
1706 os.remove(fn)
1707 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001708
Victor Stinnerec5a8602014-06-02 14:41:51 +02001709@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001710class UnixSocketHandlerTest(SocketHandlerTest):
1711
1712 """Test for SocketHandler with unix sockets."""
1713
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001714 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001715 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001716
1717 def setUp(self):
1718 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001719 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001720 SocketHandlerTest.setUp(self)
1721
1722 def tearDown(self):
1723 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001724 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001725
Vinay Sajip7367d082011-05-02 13:17:27 +01001726class DatagramHandlerTest(BaseTest):
1727
1728 """Test for DatagramHandler."""
1729
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001730 server_class = TestUDPServer
1731 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001732
Vinay Sajip7367d082011-05-02 13:17:27 +01001733 def setUp(self):
1734 """Set up a UDP server to receive log messages, and a DatagramHandler
1735 pointing to that server's address and port."""
1736 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001737 # Issue #29177: deal with errors that happen during setup
1738 self.server = self.sock_hdlr = self.server_exception = None
1739 try:
1740 self.server = server = self.server_class(self.address,
1741 self.handle_datagram, 0.01)
1742 server.start()
1743 # Uncomment next line to test error recovery in setUp()
1744 # raise OSError('dummy error raised')
1745 except OSError as e:
1746 self.server_exception = e
1747 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001748 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001749 hcls = logging.handlers.DatagramHandler
1750 if isinstance(server.server_address, tuple):
1751 self.sock_hdlr = hcls('localhost', server.port)
1752 else:
1753 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001754 self.log_output = ''
1755 self.root_logger.removeHandler(self.root_logger.handlers[0])
1756 self.root_logger.addHandler(self.sock_hdlr)
1757 self.handled = threading.Event()
1758
1759 def tearDown(self):
1760 """Shutdown the UDP server."""
1761 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001762 if self.server:
1763 self.server.stop(2.0)
1764 if self.sock_hdlr:
1765 self.root_logger.removeHandler(self.sock_hdlr)
1766 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001767 finally:
1768 BaseTest.tearDown(self)
1769
1770 def handle_datagram(self, request):
1771 slen = struct.pack('>L', 0) # length of prefix
1772 packet = request.packet[len(slen):]
1773 obj = pickle.loads(packet)
1774 record = logging.makeLogRecord(obj)
1775 self.log_output += record.msg + '\n'
1776 self.handled.set()
1777
1778 def test_output(self):
1779 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001780 if self.server_exception:
1781 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001782 logger = logging.getLogger("udp")
1783 logger.error("spam")
1784 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001785 self.handled.clear()
1786 logger.error("eggs")
1787 self.handled.wait()
1788 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001789
Victor Stinnerec5a8602014-06-02 14:41:51 +02001790@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001791class UnixDatagramHandlerTest(DatagramHandlerTest):
1792
1793 """Test for DatagramHandler using Unix sockets."""
1794
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001795 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001796 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001797
1798 def setUp(self):
1799 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001800 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001801 DatagramHandlerTest.setUp(self)
1802
1803 def tearDown(self):
1804 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001805 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001806
Vinay Sajip7367d082011-05-02 13:17:27 +01001807class SysLogHandlerTest(BaseTest):
1808
1809 """Test for SysLogHandler using UDP."""
1810
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001811 server_class = TestUDPServer
1812 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001813
Vinay Sajip7367d082011-05-02 13:17:27 +01001814 def setUp(self):
1815 """Set up a UDP server to receive log messages, and a SysLogHandler
1816 pointing to that server's address and port."""
1817 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001818 # Issue #29177: deal with errors that happen during setup
1819 self.server = self.sl_hdlr = self.server_exception = None
1820 try:
1821 self.server = server = self.server_class(self.address,
1822 self.handle_datagram, 0.01)
1823 server.start()
1824 # Uncomment next line to test error recovery in setUp()
1825 # raise OSError('dummy error raised')
1826 except OSError as e:
1827 self.server_exception = e
1828 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001829 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001830 hcls = logging.handlers.SysLogHandler
1831 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001832 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001833 else:
1834 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001835 self.log_output = ''
1836 self.root_logger.removeHandler(self.root_logger.handlers[0])
1837 self.root_logger.addHandler(self.sl_hdlr)
1838 self.handled = threading.Event()
1839
1840 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001841 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001842 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001843 if self.server:
1844 self.server.stop(2.0)
1845 if self.sl_hdlr:
1846 self.root_logger.removeHandler(self.sl_hdlr)
1847 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001848 finally:
1849 BaseTest.tearDown(self)
1850
1851 def handle_datagram(self, request):
1852 self.log_output = request.packet
1853 self.handled.set()
1854
1855 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001856 if self.server_exception:
1857 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001858 # The log message sent to the SysLogHandler is properly received.
1859 logger = logging.getLogger("slh")
1860 logger.error("sp\xe4m")
1861 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001862 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001863 self.handled.clear()
1864 self.sl_hdlr.append_nul = False
1865 logger.error("sp\xe4m")
1866 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001867 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001868 self.handled.clear()
1869 self.sl_hdlr.ident = "h\xe4m-"
1870 logger.error("sp\xe4m")
1871 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001872 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001873
Victor Stinnerec5a8602014-06-02 14:41:51 +02001874@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001875class UnixSysLogHandlerTest(SysLogHandlerTest):
1876
1877 """Test for SysLogHandler with Unix sockets."""
1878
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001879 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001880 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001881
1882 def setUp(self):
1883 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001884 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001885 SysLogHandlerTest.setUp(self)
1886
1887 def tearDown(self):
1888 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001889 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001890
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001891@unittest.skipUnless(support.IPV6_ENABLED,
1892 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001893class IPv6SysLogHandlerTest(SysLogHandlerTest):
1894
1895 """Test for SysLogHandler with IPv6 host."""
1896
1897 server_class = TestUDPServer
1898 address = ('::1', 0)
1899
1900 def setUp(self):
1901 self.server_class.address_family = socket.AF_INET6
1902 super(IPv6SysLogHandlerTest, self).setUp()
1903
1904 def tearDown(self):
1905 self.server_class.address_family = socket.AF_INET
1906 super(IPv6SysLogHandlerTest, self).tearDown()
1907
Vinay Sajip7367d082011-05-02 13:17:27 +01001908class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001909 """Test for HTTPHandler."""
1910
1911 def setUp(self):
1912 """Set up an HTTP server to receive log messages, and a HTTPHandler
1913 pointing to that server's address and port."""
1914 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001915 self.handled = threading.Event()
1916
Vinay Sajip7367d082011-05-02 13:17:27 +01001917 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001918 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001919 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001920 if self.command == 'POST':
1921 try:
1922 rlen = int(request.headers['Content-Length'])
1923 self.post_data = request.rfile.read(rlen)
1924 except:
1925 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001926 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001927 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001928 self.handled.set()
1929
1930 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001931 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001932 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001933 root_logger = self.root_logger
1934 root_logger.removeHandler(self.root_logger.handlers[0])
1935 for secure in (False, True):
1936 addr = ('localhost', 0)
1937 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001938 try:
1939 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001940 except ImportError:
1941 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001942 else:
1943 here = os.path.dirname(__file__)
1944 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001945 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001946 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001947
1948 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001949 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001950 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001951 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001952 self.server = server = TestHTTPServer(addr, self.handle_request,
1953 0.01, sslctx=sslctx)
1954 server.start()
1955 server.ready.wait()
1956 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001957 secure_client = secure and sslctx
1958 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001959 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001960 context=context,
1961 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001962 self.log_data = None
1963 root_logger.addHandler(self.h_hdlr)
1964
1965 for method in ('GET', 'POST'):
1966 self.h_hdlr.method = method
1967 self.handled.clear()
1968 msg = "sp\xe4m"
1969 logger.error(msg)
1970 self.handled.wait()
1971 self.assertEqual(self.log_data.path, '/frob')
1972 self.assertEqual(self.command, method)
1973 if method == 'GET':
1974 d = parse_qs(self.log_data.query)
1975 else:
1976 d = parse_qs(self.post_data.decode('utf-8'))
1977 self.assertEqual(d['name'], ['http'])
1978 self.assertEqual(d['funcName'], ['test_output'])
1979 self.assertEqual(d['msg'], [msg])
1980
1981 self.server.stop(2.0)
1982 self.root_logger.removeHandler(self.h_hdlr)
1983 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001984
Christian Heimes180510d2008-03-03 19:15:45 +00001985class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001986
Christian Heimes180510d2008-03-03 19:15:45 +00001987 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001988
Christian Heimes180510d2008-03-03 19:15:45 +00001989 def setUp(self):
1990 """Create a dict to remember potentially destroyed objects."""
1991 BaseTest.setUp(self)
1992 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001993
Christian Heimes180510d2008-03-03 19:15:45 +00001994 def _watch_for_survival(self, *args):
1995 """Watch the given objects for survival, by creating weakrefs to
1996 them."""
1997 for obj in args:
1998 key = id(obj), repr(obj)
1999 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002000
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002001 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00002002 """Assert that all objects watched for survival have survived."""
2003 # Trigger cycle breaking.
2004 gc.collect()
2005 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002006 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00002007 if ref() is None:
2008 dead.append(repr_)
2009 if dead:
2010 self.fail("%d objects should have survived "
2011 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002012
Christian Heimes180510d2008-03-03 19:15:45 +00002013 def test_persistent_loggers(self):
2014 # Logger objects are persistent and retain their configuration, even
2015 # if visible references are destroyed.
2016 self.root_logger.setLevel(logging.INFO)
2017 foo = logging.getLogger("foo")
2018 self._watch_for_survival(foo)
2019 foo.setLevel(logging.DEBUG)
2020 self.root_logger.debug(self.next_message())
2021 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002022 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002023 ('foo', 'DEBUG', '2'),
2024 ])
2025 del foo
2026 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002027 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00002028 # foo has retained its settings.
2029 bar = logging.getLogger("foo")
2030 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00002031 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00002032 ('foo', 'DEBUG', '2'),
2033 ('foo', 'DEBUG', '3'),
2034 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002035
Benjamin Petersonf91df042009-02-13 02:50:59 +00002036
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002037class EncodingTest(BaseTest):
2038 def test_encoding_plain_file(self):
2039 # In Python 2.x, a plain file object is treated as having no encoding.
2040 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00002041 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
2042 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002043 # the non-ascii data we write to the log.
2044 data = "foo\x80"
2045 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002046 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002047 log.addHandler(handler)
2048 try:
2049 # write non-ascii data to the log.
2050 log.warning(data)
2051 finally:
2052 log.removeHandler(handler)
2053 handler.close()
2054 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002055 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002056 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00002057 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00002058 finally:
2059 f.close()
2060 finally:
2061 if os.path.isfile(fn):
2062 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002063
Benjamin Petersonf91df042009-02-13 02:50:59 +00002064 def test_encoding_cyrillic_unicode(self):
2065 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03002066 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00002067 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03002068 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00002069 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00002070 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00002071 stream = io.BytesIO()
2072 writer = writer_class(stream, 'strict')
2073 handler = logging.StreamHandler(writer)
2074 log.addHandler(handler)
2075 try:
2076 log.warning(message)
2077 finally:
2078 log.removeHandler(handler)
2079 handler.close()
2080 # check we wrote exactly those bytes, ignoring trailing \n etc
2081 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03002082 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00002083 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
2084
2085
Georg Brandlf9734072008-12-07 15:30:06 +00002086class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00002087
Georg Brandlf9734072008-12-07 15:30:06 +00002088 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00002089 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00002090 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002091 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002092 warnings.filterwarnings("always", category=UserWarning)
2093 stream = io.StringIO()
2094 h = logging.StreamHandler(stream)
2095 logger = logging.getLogger("py.warnings")
2096 logger.addHandler(h)
2097 warnings.warn("I'm warning you...")
2098 logger.removeHandler(h)
2099 s = stream.getvalue()
2100 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002101 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00002102
Mike53f7a7c2017-12-14 14:04:53 +03002103 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002104 a_file = io.StringIO()
2105 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
2106 a_file, "Dummy line")
2107 s = a_file.getvalue()
2108 a_file.close()
2109 self.assertEqual(s,
2110 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
2111
2112 def test_warnings_no_handlers(self):
2113 with warnings.catch_warnings():
2114 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002115 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002116
2117 # confirm our assumption: no loggers are set
2118 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002119 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002120
2121 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002122 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002123 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002124
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125
2126def formatFunc(format, datefmt=None):
2127 return logging.Formatter(format, datefmt)
2128
BNMetrics18fb1fb2018-10-15 19:41:36 +01002129class myCustomFormatter:
2130 def __init__(self, fmt, datefmt=None):
2131 pass
2132
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002133def handlerFunc():
2134 return logging.StreamHandler()
2135
2136class CustomHandler(logging.StreamHandler):
2137 pass
2138
2139class ConfigDictTest(BaseTest):
2140
2141 """Reading logging config from a dictionary."""
2142
Xtreak087570a2018-07-02 14:27:46 +05302143 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002144 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002145
2146 # config0 is a standard configuration.
2147 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002148 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002149 'formatters': {
2150 'form1' : {
2151 'format' : '%(levelname)s ++ %(message)s',
2152 },
2153 },
2154 'handlers' : {
2155 'hand1' : {
2156 'class' : 'logging.StreamHandler',
2157 'formatter' : 'form1',
2158 'level' : 'NOTSET',
2159 'stream' : 'ext://sys.stdout',
2160 },
2161 },
2162 'root' : {
2163 'level' : 'WARNING',
2164 'handlers' : ['hand1'],
2165 },
2166 }
2167
2168 # config1 adds a little to the standard configuration.
2169 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002170 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002171 'formatters': {
2172 'form1' : {
2173 'format' : '%(levelname)s ++ %(message)s',
2174 },
2175 },
2176 'handlers' : {
2177 'hand1' : {
2178 'class' : 'logging.StreamHandler',
2179 'formatter' : 'form1',
2180 'level' : 'NOTSET',
2181 'stream' : 'ext://sys.stdout',
2182 },
2183 },
2184 'loggers' : {
2185 'compiler.parser' : {
2186 'level' : 'DEBUG',
2187 'handlers' : ['hand1'],
2188 },
2189 },
2190 'root' : {
2191 'level' : 'WARNING',
2192 },
2193 }
2194
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002195 # config1a moves the handler to the root. Used with config8a
2196 config1a = {
2197 'version': 1,
2198 'formatters': {
2199 'form1' : {
2200 'format' : '%(levelname)s ++ %(message)s',
2201 },
2202 },
2203 'handlers' : {
2204 'hand1' : {
2205 'class' : 'logging.StreamHandler',
2206 'formatter' : 'form1',
2207 'level' : 'NOTSET',
2208 'stream' : 'ext://sys.stdout',
2209 },
2210 },
2211 'loggers' : {
2212 'compiler.parser' : {
2213 'level' : 'DEBUG',
2214 },
2215 },
2216 'root' : {
2217 'level' : 'WARNING',
2218 'handlers' : ['hand1'],
2219 },
2220 }
2221
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002222 # config2 has a subtle configuration error that should be reported
2223 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002224 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002225 'formatters': {
2226 'form1' : {
2227 'format' : '%(levelname)s ++ %(message)s',
2228 },
2229 },
2230 'handlers' : {
2231 'hand1' : {
2232 'class' : 'logging.StreamHandler',
2233 'formatter' : 'form1',
2234 'level' : 'NOTSET',
2235 'stream' : 'ext://sys.stdbout',
2236 },
2237 },
2238 'loggers' : {
2239 'compiler.parser' : {
2240 'level' : 'DEBUG',
2241 'handlers' : ['hand1'],
2242 },
2243 },
2244 'root' : {
2245 'level' : 'WARNING',
2246 },
2247 }
2248
Mike53f7a7c2017-12-14 14:04:53 +03002249 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002250 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002251 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002252 'formatters': {
2253 'form1' : {
2254 'format' : '%(levelname)s ++ %(message)s',
2255 },
2256 },
2257 'handlers' : {
2258 'hand1' : {
2259 'class' : 'logging.StreamHandler',
2260 'formatter' : 'form1',
2261 'level' : 'NTOSET',
2262 'stream' : 'ext://sys.stdout',
2263 },
2264 },
2265 'loggers' : {
2266 'compiler.parser' : {
2267 'level' : 'DEBUG',
2268 'handlers' : ['hand1'],
2269 },
2270 },
2271 'root' : {
2272 'level' : 'WARNING',
2273 },
2274 }
2275
2276
Mike53f7a7c2017-12-14 14:04:53 +03002277 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002278 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002279 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002280 'formatters': {
2281 'form1' : {
2282 'format' : '%(levelname)s ++ %(message)s',
2283 },
2284 },
2285 'handlers' : {
2286 'hand1' : {
2287 'class' : 'logging.StreamHandler',
2288 'formatter' : 'form1',
2289 'level' : 'NOTSET',
2290 'stream' : 'ext://sys.stdout',
2291 },
2292 },
2293 'loggers' : {
2294 'compiler.parser' : {
2295 'level' : 'DEBUG',
2296 'handlers' : ['hand1'],
2297 },
2298 },
2299 'root' : {
2300 'level' : 'WRANING',
2301 },
2302 }
2303
2304 # config3 has a less subtle configuration error
2305 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002306 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002307 'formatters': {
2308 'form1' : {
2309 'format' : '%(levelname)s ++ %(message)s',
2310 },
2311 },
2312 'handlers' : {
2313 'hand1' : {
2314 'class' : 'logging.StreamHandler',
2315 'formatter' : 'misspelled_name',
2316 'level' : 'NOTSET',
2317 'stream' : 'ext://sys.stdout',
2318 },
2319 },
2320 'loggers' : {
2321 'compiler.parser' : {
2322 'level' : 'DEBUG',
2323 'handlers' : ['hand1'],
2324 },
2325 },
2326 'root' : {
2327 'level' : 'WARNING',
2328 },
2329 }
2330
2331 # config4 specifies a custom formatter class to be loaded
2332 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002333 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002334 'formatters': {
2335 'form1' : {
2336 '()' : __name__ + '.ExceptionFormatter',
2337 'format' : '%(levelname)s:%(name)s:%(message)s',
2338 },
2339 },
2340 'handlers' : {
2341 'hand1' : {
2342 'class' : 'logging.StreamHandler',
2343 'formatter' : 'form1',
2344 'level' : 'NOTSET',
2345 'stream' : 'ext://sys.stdout',
2346 },
2347 },
2348 'root' : {
2349 'level' : 'NOTSET',
2350 'handlers' : ['hand1'],
2351 },
2352 }
2353
2354 # As config4 but using an actual callable rather than a string
2355 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002356 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002357 'formatters': {
2358 'form1' : {
2359 '()' : ExceptionFormatter,
2360 'format' : '%(levelname)s:%(name)s:%(message)s',
2361 },
2362 'form2' : {
2363 '()' : __name__ + '.formatFunc',
2364 'format' : '%(levelname)s:%(name)s:%(message)s',
2365 },
2366 'form3' : {
2367 '()' : formatFunc,
2368 'format' : '%(levelname)s:%(name)s:%(message)s',
2369 },
2370 },
2371 'handlers' : {
2372 'hand1' : {
2373 'class' : 'logging.StreamHandler',
2374 'formatter' : 'form1',
2375 'level' : 'NOTSET',
2376 'stream' : 'ext://sys.stdout',
2377 },
2378 'hand2' : {
2379 '()' : handlerFunc,
2380 },
2381 },
2382 'root' : {
2383 'level' : 'NOTSET',
2384 'handlers' : ['hand1'],
2385 },
2386 }
2387
2388 # config5 specifies a custom handler class to be loaded
2389 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002390 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002391 'formatters': {
2392 'form1' : {
2393 'format' : '%(levelname)s ++ %(message)s',
2394 },
2395 },
2396 'handlers' : {
2397 'hand1' : {
2398 'class' : __name__ + '.CustomHandler',
2399 'formatter' : 'form1',
2400 'level' : 'NOTSET',
2401 'stream' : 'ext://sys.stdout',
2402 },
2403 },
2404 'loggers' : {
2405 'compiler.parser' : {
2406 'level' : 'DEBUG',
2407 'handlers' : ['hand1'],
2408 },
2409 },
2410 'root' : {
2411 'level' : 'WARNING',
2412 },
2413 }
2414
2415 # config6 specifies a custom handler class to be loaded
2416 # but has bad arguments
2417 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002418 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002419 'formatters': {
2420 'form1' : {
2421 'format' : '%(levelname)s ++ %(message)s',
2422 },
2423 },
2424 'handlers' : {
2425 'hand1' : {
2426 'class' : __name__ + '.CustomHandler',
2427 'formatter' : 'form1',
2428 'level' : 'NOTSET',
2429 'stream' : 'ext://sys.stdout',
2430 '9' : 'invalid parameter name',
2431 },
2432 },
2433 'loggers' : {
2434 'compiler.parser' : {
2435 'level' : 'DEBUG',
2436 'handlers' : ['hand1'],
2437 },
2438 },
2439 'root' : {
2440 'level' : 'WARNING',
2441 },
2442 }
2443
Mike53f7a7c2017-12-14 14:04:53 +03002444 # config 7 does not define compiler.parser but defines compiler.lexer
2445 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002446 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002447 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002448 'formatters': {
2449 'form1' : {
2450 'format' : '%(levelname)s ++ %(message)s',
2451 },
2452 },
2453 'handlers' : {
2454 'hand1' : {
2455 'class' : 'logging.StreamHandler',
2456 'formatter' : 'form1',
2457 'level' : 'NOTSET',
2458 'stream' : 'ext://sys.stdout',
2459 },
2460 },
2461 'loggers' : {
2462 'compiler.lexer' : {
2463 'level' : 'DEBUG',
2464 'handlers' : ['hand1'],
2465 },
2466 },
2467 'root' : {
2468 'level' : 'WARNING',
2469 },
2470 }
2471
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002472 # config8 defines both compiler and compiler.lexer
2473 # so compiler.parser should not be disabled (since
2474 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002475 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002476 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002477 'disable_existing_loggers' : False,
2478 'formatters': {
2479 'form1' : {
2480 'format' : '%(levelname)s ++ %(message)s',
2481 },
2482 },
2483 'handlers' : {
2484 'hand1' : {
2485 'class' : 'logging.StreamHandler',
2486 'formatter' : 'form1',
2487 'level' : 'NOTSET',
2488 'stream' : 'ext://sys.stdout',
2489 },
2490 },
2491 'loggers' : {
2492 'compiler' : {
2493 'level' : 'DEBUG',
2494 'handlers' : ['hand1'],
2495 },
2496 'compiler.lexer' : {
2497 },
2498 },
2499 'root' : {
2500 'level' : 'WARNING',
2501 },
2502 }
2503
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002504 # config8a disables existing loggers
2505 config8a = {
2506 'version': 1,
2507 'disable_existing_loggers' : True,
2508 'formatters': {
2509 'form1' : {
2510 'format' : '%(levelname)s ++ %(message)s',
2511 },
2512 },
2513 'handlers' : {
2514 'hand1' : {
2515 'class' : 'logging.StreamHandler',
2516 'formatter' : 'form1',
2517 'level' : 'NOTSET',
2518 'stream' : 'ext://sys.stdout',
2519 },
2520 },
2521 'loggers' : {
2522 'compiler' : {
2523 'level' : 'DEBUG',
2524 'handlers' : ['hand1'],
2525 },
2526 'compiler.lexer' : {
2527 },
2528 },
2529 'root' : {
2530 'level' : 'WARNING',
2531 },
2532 }
2533
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002534 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002535 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002536 'formatters': {
2537 'form1' : {
2538 'format' : '%(levelname)s ++ %(message)s',
2539 },
2540 },
2541 'handlers' : {
2542 'hand1' : {
2543 'class' : 'logging.StreamHandler',
2544 'formatter' : 'form1',
2545 'level' : 'WARNING',
2546 'stream' : 'ext://sys.stdout',
2547 },
2548 },
2549 'loggers' : {
2550 'compiler.parser' : {
2551 'level' : 'WARNING',
2552 'handlers' : ['hand1'],
2553 },
2554 },
2555 'root' : {
2556 'level' : 'NOTSET',
2557 },
2558 }
2559
2560 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002561 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002562 'incremental' : True,
2563 'handlers' : {
2564 'hand1' : {
2565 'level' : 'WARNING',
2566 },
2567 },
2568 'loggers' : {
2569 'compiler.parser' : {
2570 'level' : 'INFO',
2571 },
2572 },
2573 }
2574
2575 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002576 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002577 'incremental' : True,
2578 'handlers' : {
2579 'hand1' : {
2580 'level' : 'INFO',
2581 },
2582 },
2583 'loggers' : {
2584 'compiler.parser' : {
2585 'level' : 'INFO',
2586 },
2587 },
2588 }
2589
Mike53f7a7c2017-12-14 14:04:53 +03002590 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002591 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002592 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002593 'formatters': {
2594 'form1' : {
2595 'format' : '%(levelname)s ++ %(message)s',
2596 },
2597 },
2598 'filters' : {
2599 'filt1' : {
2600 'name' : 'compiler.parser',
2601 },
2602 },
2603 'handlers' : {
2604 'hand1' : {
2605 'class' : 'logging.StreamHandler',
2606 'formatter' : 'form1',
2607 'level' : 'NOTSET',
2608 'stream' : 'ext://sys.stdout',
2609 'filters' : ['filt1'],
2610 },
2611 },
2612 'loggers' : {
2613 'compiler.parser' : {
2614 'level' : 'DEBUG',
2615 'filters' : ['filt1'],
2616 },
2617 },
2618 'root' : {
2619 'level' : 'WARNING',
2620 'handlers' : ['hand1'],
2621 },
2622 }
2623
Mike53f7a7c2017-12-14 14:04:53 +03002624 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002625 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002626 'version': 1,
2627 'true_formatters': {
2628 'form1' : {
2629 'format' : '%(levelname)s ++ %(message)s',
2630 },
2631 },
2632 'handler_configs': {
2633 'hand1' : {
2634 'class' : 'logging.StreamHandler',
2635 'formatter' : 'form1',
2636 'level' : 'NOTSET',
2637 'stream' : 'ext://sys.stdout',
2638 },
2639 },
2640 'formatters' : 'cfg://true_formatters',
2641 'handlers' : {
2642 'hand1' : 'cfg://handler_configs[hand1]',
2643 },
2644 'loggers' : {
2645 'compiler.parser' : {
2646 'level' : 'DEBUG',
2647 'handlers' : ['hand1'],
2648 },
2649 },
2650 'root' : {
2651 'level' : 'WARNING',
2652 },
2653 }
2654
Mike53f7a7c2017-12-14 14:04:53 +03002655 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002656 config12 = {
2657 'true_formatters': {
2658 'form1' : {
2659 'format' : '%(levelname)s ++ %(message)s',
2660 },
2661 },
2662 'handler_configs': {
2663 'hand1' : {
2664 'class' : 'logging.StreamHandler',
2665 'formatter' : 'form1',
2666 'level' : 'NOTSET',
2667 'stream' : 'ext://sys.stdout',
2668 },
2669 },
2670 'formatters' : 'cfg://true_formatters',
2671 'handlers' : {
2672 'hand1' : 'cfg://handler_configs[hand1]',
2673 },
2674 'loggers' : {
2675 'compiler.parser' : {
2676 'level' : 'DEBUG',
2677 'handlers' : ['hand1'],
2678 },
2679 },
2680 'root' : {
2681 'level' : 'WARNING',
2682 },
2683 }
2684
Mike53f7a7c2017-12-14 14:04:53 +03002685 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002686 config13 = {
2687 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002688 'true_formatters': {
2689 'form1' : {
2690 'format' : '%(levelname)s ++ %(message)s',
2691 },
2692 },
2693 'handler_configs': {
2694 'hand1' : {
2695 'class' : 'logging.StreamHandler',
2696 'formatter' : 'form1',
2697 'level' : 'NOTSET',
2698 'stream' : 'ext://sys.stdout',
2699 },
2700 },
2701 'formatters' : 'cfg://true_formatters',
2702 'handlers' : {
2703 'hand1' : 'cfg://handler_configs[hand1]',
2704 },
2705 'loggers' : {
2706 'compiler.parser' : {
2707 'level' : 'DEBUG',
2708 'handlers' : ['hand1'],
2709 },
2710 },
2711 'root' : {
2712 'level' : 'WARNING',
2713 },
2714 }
2715
Vinay Sajip8d270232012-11-15 14:20:18 +00002716 # As config0, but with properties
2717 config14 = {
2718 'version': 1,
2719 'formatters': {
2720 'form1' : {
2721 'format' : '%(levelname)s ++ %(message)s',
2722 },
2723 },
2724 'handlers' : {
2725 'hand1' : {
2726 'class' : 'logging.StreamHandler',
2727 'formatter' : 'form1',
2728 'level' : 'NOTSET',
2729 'stream' : 'ext://sys.stdout',
2730 '.': {
2731 'foo': 'bar',
2732 'terminator': '!\n',
2733 }
2734 },
2735 },
2736 'root' : {
2737 'level' : 'WARNING',
2738 'handlers' : ['hand1'],
2739 },
2740 }
2741
Vinay Sajip3f885b52013-03-22 15:19:54 +00002742 out_of_order = {
2743 "version": 1,
2744 "formatters": {
2745 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002746 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2747 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002748 }
2749 },
2750 "handlers": {
2751 "fileGlobal": {
2752 "class": "logging.StreamHandler",
2753 "level": "DEBUG",
2754 "formatter": "mySimpleFormatter"
2755 },
2756 "bufferGlobal": {
2757 "class": "logging.handlers.MemoryHandler",
2758 "capacity": 5,
2759 "formatter": "mySimpleFormatter",
2760 "target": "fileGlobal",
2761 "level": "DEBUG"
2762 }
2763 },
2764 "loggers": {
2765 "mymodule": {
2766 "level": "DEBUG",
2767 "handlers": ["bufferGlobal"],
2768 "propagate": "true"
2769 }
2770 }
2771 }
2772
BNMetrics18fb1fb2018-10-15 19:41:36 +01002773 # Configuration with custom logging.Formatter subclass as '()' key and 'validate' set to False
2774 custom_formatter_class_validate = {
2775 'version': 1,
2776 'formatters': {
2777 'form1': {
2778 '()': __name__ + '.ExceptionFormatter',
2779 'format': '%(levelname)s:%(name)s:%(message)s',
2780 'validate': False,
2781 },
2782 },
2783 'handlers' : {
2784 'hand1' : {
2785 'class': 'logging.StreamHandler',
2786 'formatter': 'form1',
2787 'level': 'NOTSET',
2788 'stream': 'ext://sys.stdout',
2789 },
2790 },
2791 "loggers": {
2792 "my_test_logger_custom_formatter": {
2793 "level": "DEBUG",
2794 "handlers": ["hand1"],
2795 "propagate": "true"
2796 }
2797 }
2798 }
2799
2800 # Configuration with custom logging.Formatter subclass as 'class' key and 'validate' set to False
2801 custom_formatter_class_validate2 = {
2802 'version': 1,
2803 'formatters': {
2804 'form1': {
2805 'class': __name__ + '.ExceptionFormatter',
2806 'format': '%(levelname)s:%(name)s:%(message)s',
2807 'validate': False,
2808 },
2809 },
2810 'handlers' : {
2811 'hand1' : {
2812 'class': 'logging.StreamHandler',
2813 'formatter': 'form1',
2814 'level': 'NOTSET',
2815 'stream': 'ext://sys.stdout',
2816 },
2817 },
2818 "loggers": {
2819 "my_test_logger_custom_formatter": {
2820 "level": "DEBUG",
2821 "handlers": ["hand1"],
2822 "propagate": "true"
2823 }
2824 }
2825 }
2826
2827 # Configuration with custom class that is not inherited from logging.Formatter
2828 custom_formatter_class_validate3 = {
2829 'version': 1,
2830 'formatters': {
2831 'form1': {
2832 'class': __name__ + '.myCustomFormatter',
2833 'format': '%(levelname)s:%(name)s:%(message)s',
2834 'validate': False,
2835 },
2836 },
2837 'handlers' : {
2838 'hand1' : {
2839 'class': 'logging.StreamHandler',
2840 'formatter': 'form1',
2841 'level': 'NOTSET',
2842 'stream': 'ext://sys.stdout',
2843 },
2844 },
2845 "loggers": {
2846 "my_test_logger_custom_formatter": {
2847 "level": "DEBUG",
2848 "handlers": ["hand1"],
2849 "propagate": "true"
2850 }
2851 }
2852 }
2853
2854 # Configuration with custom function and 'validate' set to False
2855 custom_formatter_with_function = {
2856 'version': 1,
2857 'formatters': {
2858 'form1': {
2859 '()': formatFunc,
2860 'format': '%(levelname)s:%(name)s:%(message)s',
2861 'validate': False,
2862 },
2863 },
2864 'handlers' : {
2865 'hand1' : {
2866 'class': 'logging.StreamHandler',
2867 'formatter': 'form1',
2868 'level': 'NOTSET',
2869 'stream': 'ext://sys.stdout',
2870 },
2871 },
2872 "loggers": {
2873 "my_test_logger_custom_formatter": {
2874 "level": "DEBUG",
2875 "handlers": ["hand1"],
2876 "propagate": "true"
2877 }
2878 }
2879 }
2880
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002881 def apply_config(self, conf):
2882 logging.config.dictConfig(conf)
2883
2884 def test_config0_ok(self):
2885 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002886 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002887 self.apply_config(self.config0)
2888 logger = logging.getLogger()
2889 # Won't output anything
2890 logger.info(self.next_message())
2891 # Outputs a message
2892 logger.error(self.next_message())
2893 self.assert_log_lines([
2894 ('ERROR', '2'),
2895 ], stream=output)
2896 # Original logger output is empty.
2897 self.assert_log_lines([])
2898
2899 def test_config1_ok(self, config=config1):
2900 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002901 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002902 self.apply_config(config)
2903 logger = logging.getLogger("compiler.parser")
2904 # Both will output a message
2905 logger.info(self.next_message())
2906 logger.error(self.next_message())
2907 self.assert_log_lines([
2908 ('INFO', '1'),
2909 ('ERROR', '2'),
2910 ], stream=output)
2911 # Original logger output is empty.
2912 self.assert_log_lines([])
2913
2914 def test_config2_failure(self):
2915 # A simple config which overrides the default settings.
2916 self.assertRaises(Exception, self.apply_config, self.config2)
2917
2918 def test_config2a_failure(self):
2919 # A simple config which overrides the default settings.
2920 self.assertRaises(Exception, self.apply_config, self.config2a)
2921
2922 def test_config2b_failure(self):
2923 # A simple config which overrides the default settings.
2924 self.assertRaises(Exception, self.apply_config, self.config2b)
2925
2926 def test_config3_failure(self):
2927 # A simple config which overrides the default settings.
2928 self.assertRaises(Exception, self.apply_config, self.config3)
2929
2930 def test_config4_ok(self):
2931 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002932 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002933 self.apply_config(self.config4)
2934 #logger = logging.getLogger()
2935 try:
2936 raise RuntimeError()
2937 except RuntimeError:
2938 logging.exception("just testing")
2939 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002940 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002941 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2942 # Original logger output is empty
2943 self.assert_log_lines([])
2944
2945 def test_config4a_ok(self):
2946 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002947 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002948 self.apply_config(self.config4a)
2949 #logger = logging.getLogger()
2950 try:
2951 raise RuntimeError()
2952 except RuntimeError:
2953 logging.exception("just testing")
2954 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002955 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002956 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2957 # Original logger output is empty
2958 self.assert_log_lines([])
2959
2960 def test_config5_ok(self):
2961 self.test_config1_ok(config=self.config5)
2962
2963 def test_config6_failure(self):
2964 self.assertRaises(Exception, self.apply_config, self.config6)
2965
2966 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002967 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002968 self.apply_config(self.config1)
2969 logger = logging.getLogger("compiler.parser")
2970 # Both will output a message
2971 logger.info(self.next_message())
2972 logger.error(self.next_message())
2973 self.assert_log_lines([
2974 ('INFO', '1'),
2975 ('ERROR', '2'),
2976 ], stream=output)
2977 # Original logger output is empty.
2978 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002979 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002980 self.apply_config(self.config7)
2981 logger = logging.getLogger("compiler.parser")
2982 self.assertTrue(logger.disabled)
2983 logger = logging.getLogger("compiler.lexer")
2984 # Both will output a message
2985 logger.info(self.next_message())
2986 logger.error(self.next_message())
2987 self.assert_log_lines([
2988 ('INFO', '3'),
2989 ('ERROR', '4'),
2990 ], stream=output)
2991 # Original logger output is empty.
2992 self.assert_log_lines([])
2993
Mike53f7a7c2017-12-14 14:04:53 +03002994 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002995 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002996 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002997 self.apply_config(self.config1)
2998 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002999 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003000 logger.info(self.next_message())
3001 logger.error(self.next_message())
3002 self.assert_log_lines([
3003 ('INFO', '1'),
3004 ('ERROR', '2'),
3005 ], stream=output)
3006 # Original logger output is empty.
3007 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003008 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003009 self.apply_config(self.config8)
3010 logger = logging.getLogger("compiler.parser")
3011 self.assertFalse(logger.disabled)
3012 # Both will output a message
3013 logger.info(self.next_message())
3014 logger.error(self.next_message())
3015 logger = logging.getLogger("compiler.lexer")
3016 # Both will output a message
3017 logger.info(self.next_message())
3018 logger.error(self.next_message())
3019 self.assert_log_lines([
3020 ('INFO', '3'),
3021 ('ERROR', '4'),
3022 ('INFO', '5'),
3023 ('ERROR', '6'),
3024 ], stream=output)
3025 # Original logger output is empty.
3026 self.assert_log_lines([])
3027
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003028 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003029 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003030 self.apply_config(self.config1a)
3031 logger = logging.getLogger("compiler.parser")
3032 # See issue #11424. compiler-hyphenated sorts
3033 # between compiler and compiler.xyz and this
3034 # was preventing compiler.xyz from being included
3035 # in the child loggers of compiler because of an
3036 # overzealous loop termination condition.
3037 hyphenated = logging.getLogger('compiler-hyphenated')
3038 # All will output a message
3039 logger.info(self.next_message())
3040 logger.error(self.next_message())
3041 hyphenated.critical(self.next_message())
3042 self.assert_log_lines([
3043 ('INFO', '1'),
3044 ('ERROR', '2'),
3045 ('CRITICAL', '3'),
3046 ], stream=output)
3047 # Original logger output is empty.
3048 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01003049 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00003050 self.apply_config(self.config8a)
3051 logger = logging.getLogger("compiler.parser")
3052 self.assertFalse(logger.disabled)
3053 # Both will output a message
3054 logger.info(self.next_message())
3055 logger.error(self.next_message())
3056 logger = logging.getLogger("compiler.lexer")
3057 # Both will output a message
3058 logger.info(self.next_message())
3059 logger.error(self.next_message())
3060 # Will not appear
3061 hyphenated.critical(self.next_message())
3062 self.assert_log_lines([
3063 ('INFO', '4'),
3064 ('ERROR', '5'),
3065 ('INFO', '6'),
3066 ('ERROR', '7'),
3067 ], stream=output)
3068 # Original logger output is empty.
3069 self.assert_log_lines([])
3070
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003071 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003072 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003073 self.apply_config(self.config9)
3074 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03003075 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003076 logger.info(self.next_message())
3077 self.assert_log_lines([], stream=output)
3078 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03003079 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003080 logger.info(self.next_message())
3081 self.assert_log_lines([], stream=output)
3082 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03003083 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003084 logger.info(self.next_message())
3085 self.assert_log_lines([
3086 ('INFO', '3'),
3087 ], stream=output)
3088
3089 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003090 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003091 self.apply_config(self.config10)
3092 logger = logging.getLogger("compiler.parser")
3093 logger.warning(self.next_message())
3094 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003095 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003096 logger.warning(self.next_message())
3097 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003098 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003099 logger.warning(self.next_message())
3100 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003101 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003102 logger.error(self.next_message())
3103 self.assert_log_lines([
3104 ('WARNING', '1'),
3105 ('ERROR', '4'),
3106 ], stream=output)
3107
3108 def test_config11_ok(self):
3109 self.test_config1_ok(self.config11)
3110
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003111 def test_config12_failure(self):
3112 self.assertRaises(Exception, self.apply_config, self.config12)
3113
3114 def test_config13_failure(self):
3115 self.assertRaises(Exception, self.apply_config, self.config13)
3116
Vinay Sajip8d270232012-11-15 14:20:18 +00003117 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003118 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00003119 self.apply_config(self.config14)
3120 h = logging._handlers['hand1']
3121 self.assertEqual(h.foo, 'bar')
3122 self.assertEqual(h.terminator, '!\n')
3123 logging.warning('Exclamation')
3124 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
3125
Xtreak087570a2018-07-02 14:27:46 +05303126 def test_config15_ok(self):
3127
3128 def cleanup(h1, fn):
3129 h1.close()
3130 os.remove(fn)
3131
3132 with self.check_no_resource_warning():
3133 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
3134 os.close(fd)
3135
3136 config = {
3137 "version": 1,
3138 "handlers": {
3139 "file": {
3140 "class": "logging.FileHandler",
3141 "filename": fn
3142 }
3143 },
3144 "root": {
3145 "handlers": ["file"]
3146 }
3147 }
3148
3149 self.apply_config(config)
3150 self.apply_config(config)
3151
3152 handler = logging.root.handlers[0]
3153 self.addCleanup(cleanup, handler, fn)
3154
Vinay Sajip4ded5512012-10-02 15:56:16 +01003155 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00003156 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00003157 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01003158 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003159 t.start()
3160 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00003161 # Now get the port allocated
3162 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003163 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003164 try:
3165 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3166 sock.settimeout(2.0)
3167 sock.connect(('localhost', port))
3168
3169 slen = struct.pack('>L', len(text))
3170 s = slen + text
3171 sentsofar = 0
3172 left = len(s)
3173 while left > 0:
3174 sent = sock.send(s[sentsofar:])
3175 sentsofar += sent
3176 left -= sent
3177 sock.close()
3178 finally:
3179 t.ready.wait(2.0)
3180 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07003181 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003182
3183 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003184 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003185 self.setup_via_listener(json.dumps(self.config10))
3186 logger = logging.getLogger("compiler.parser")
3187 logger.warning(self.next_message())
3188 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003189 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003190 logger.warning(self.next_message())
3191 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003192 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003193 logger.warning(self.next_message())
3194 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003195 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003196 logger.error(self.next_message())
3197 self.assert_log_lines([
3198 ('WARNING', '1'),
3199 ('ERROR', '4'),
3200 ], stream=output)
3201
3202 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003203 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003204 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
3205 logger = logging.getLogger("compiler.parser")
3206 # Both will output a message
3207 logger.info(self.next_message())
3208 logger.error(self.next_message())
3209 self.assert_log_lines([
3210 ('INFO', '1'),
3211 ('ERROR', '2'),
3212 ], stream=output)
3213 # Original logger output is empty.
3214 self.assert_log_lines([])
3215
Vinay Sajip4ded5512012-10-02 15:56:16 +01003216 def test_listen_verify(self):
3217
3218 def verify_fail(stuff):
3219 return None
3220
3221 def verify_reverse(stuff):
3222 return stuff[::-1]
3223
3224 logger = logging.getLogger("compiler.parser")
3225 to_send = textwrap.dedent(ConfigFileTest.config1)
3226 # First, specify a verification function that will fail.
3227 # We expect to see no output, since our configuration
3228 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01003229 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003230 self.setup_via_listener(to_send, verify_fail)
3231 # Both will output a message
3232 logger.info(self.next_message())
3233 logger.error(self.next_message())
3234 self.assert_log_lines([], stream=output)
3235 # Original logger output has the stuff we logged.
3236 self.assert_log_lines([
3237 ('INFO', '1'),
3238 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003239 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003240
3241 # Now, perform no verification. Our configuration
3242 # should take effect.
3243
Vinay Sajip1feedb42014-05-31 08:19:12 +01003244 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003245 self.setup_via_listener(to_send) # no verify callable specified
3246 logger = logging.getLogger("compiler.parser")
3247 # Both will output a message
3248 logger.info(self.next_message())
3249 logger.error(self.next_message())
3250 self.assert_log_lines([
3251 ('INFO', '3'),
3252 ('ERROR', '4'),
3253 ], stream=output)
3254 # Original logger output still has the stuff we logged before.
3255 self.assert_log_lines([
3256 ('INFO', '1'),
3257 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003258 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003259
3260 # Now, perform verification which transforms the bytes.
3261
Vinay Sajip1feedb42014-05-31 08:19:12 +01003262 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003263 self.setup_via_listener(to_send[::-1], verify_reverse)
3264 logger = logging.getLogger("compiler.parser")
3265 # Both will output a message
3266 logger.info(self.next_message())
3267 logger.error(self.next_message())
3268 self.assert_log_lines([
3269 ('INFO', '5'),
3270 ('ERROR', '6'),
3271 ], stream=output)
3272 # Original logger output still has the stuff we logged before.
3273 self.assert_log_lines([
3274 ('INFO', '1'),
3275 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003276 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003277
Vinay Sajip3f885b52013-03-22 15:19:54 +00003278 def test_out_of_order(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01003279 self.assertRaises(ValueError, self.apply_config, self.out_of_order)
3280
3281 def test_out_of_order_with_dollar_style(self):
Pablo Galindo137b0632018-10-16 15:17:57 +01003282 config = copy.deepcopy(self.out_of_order)
BNMetrics18fb1fb2018-10-15 19:41:36 +01003283 config['formatters']['mySimpleFormatter']['format'] = "${asctime} (${name}) ${levelname}: ${message}"
3284
3285 self.apply_config(config)
Vinay Sajip3f885b52013-03-22 15:19:54 +00003286 handler = logging.getLogger('mymodule').handlers[0]
3287 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003288 self.assertIsInstance(handler.formatter._style,
3289 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003290
BNMetrics18fb1fb2018-10-15 19:41:36 +01003291 def test_custom_formatter_class_with_validate(self):
3292 self.apply_config(self.custom_formatter_class_validate)
3293 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3294 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3295
3296 def test_custom_formatter_class_with_validate2(self):
3297 self.apply_config(self.custom_formatter_class_validate2)
3298 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3299 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3300
3301 def test_custom_formatter_class_with_validate2_with_wrong_fmt(self):
3302 config = self.custom_formatter_class_validate.copy()
3303 config['formatters']['form1']['style'] = "$"
3304
3305 # Exception should not be raise as we have configured 'validate' to False
3306 self.apply_config(config)
3307 handler = logging.getLogger("my_test_logger_custom_formatter").handlers[0]
3308 self.assertIsInstance(handler.formatter, ExceptionFormatter)
3309
3310 def test_custom_formatter_class_with_validate3(self):
3311 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_class_validate3)
3312
3313 def test_custom_formatter_function_with_validate(self):
3314 self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_function)
3315
Vinay Sajip373baef2011-04-26 20:05:24 +01003316 def test_baseconfig(self):
3317 d = {
3318 'atuple': (1, 2, 3),
3319 'alist': ['a', 'b', 'c'],
3320 'adict': {'d': 'e', 'f': 3 },
3321 'nest1': ('g', ('h', 'i'), 'j'),
3322 'nest2': ['k', ['l', 'm'], 'n'],
3323 'nest3': ['o', 'cfg://alist', 'p'],
3324 }
3325 bc = logging.config.BaseConfigurator(d)
3326 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3327 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3328 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3329 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3330 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3331 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3332 v = bc.convert('cfg://nest3')
3333 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3334 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3335 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3336 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003337
3338class ManagerTest(BaseTest):
3339 def test_manager_loggerclass(self):
3340 logged = []
3341
3342 class MyLogger(logging.Logger):
3343 def _log(self, level, msg, args, exc_info=None, extra=None):
3344 logged.append(msg)
3345
3346 man = logging.Manager(None)
3347 self.assertRaises(TypeError, man.setLoggerClass, int)
3348 man.setLoggerClass(MyLogger)
3349 logger = man.getLogger('test')
3350 logger.warning('should appear in logged')
3351 logging.warning('should not appear in logged')
3352
3353 self.assertEqual(logged, ['should appear in logged'])
3354
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003355 def test_set_log_record_factory(self):
3356 man = logging.Manager(None)
3357 expected = object()
3358 man.setLogRecordFactory(expected)
3359 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003360
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003361class ChildLoggerTest(BaseTest):
3362 def test_child_loggers(self):
3363 r = logging.getLogger()
3364 l1 = logging.getLogger('abc')
3365 l2 = logging.getLogger('def.ghi')
3366 c1 = r.getChild('xyz')
3367 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003368 self.assertIs(c1, logging.getLogger('xyz'))
3369 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003370 c1 = l1.getChild('def')
3371 c2 = c1.getChild('ghi')
3372 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003373 self.assertIs(c1, logging.getLogger('abc.def'))
3374 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3375 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003376
3377
Vinay Sajip6fac8172010-10-19 20:44:14 +00003378class DerivedLogRecord(logging.LogRecord):
3379 pass
3380
Vinay Sajip61561522010-12-03 11:50:38 +00003381class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003382
3383 def setUp(self):
3384 class CheckingFilter(logging.Filter):
3385 def __init__(self, cls):
3386 self.cls = cls
3387
3388 def filter(self, record):
3389 t = type(record)
3390 if t is not self.cls:
3391 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3392 self.cls)
3393 raise TypeError(msg)
3394 return True
3395
3396 BaseTest.setUp(self)
3397 self.filter = CheckingFilter(DerivedLogRecord)
3398 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003399 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003400
3401 def tearDown(self):
3402 self.root_logger.removeFilter(self.filter)
3403 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003404 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003405
3406 def test_logrecord_class(self):
3407 self.assertRaises(TypeError, self.root_logger.warning,
3408 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003409 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003410 self.root_logger.error(self.next_message())
3411 self.assert_log_lines([
3412 ('root', 'ERROR', '2'),
3413 ])
3414
3415
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003416class QueueHandlerTest(BaseTest):
3417 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003418 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003419
3420 def setUp(self):
3421 BaseTest.setUp(self)
3422 self.queue = queue.Queue(-1)
3423 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003424 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003425 self.que_logger = logging.getLogger('que')
3426 self.que_logger.propagate = False
3427 self.que_logger.setLevel(logging.WARNING)
3428 self.que_logger.addHandler(self.que_hdlr)
3429
3430 def tearDown(self):
3431 self.que_hdlr.close()
3432 BaseTest.tearDown(self)
3433
3434 def test_queue_handler(self):
3435 self.que_logger.debug(self.next_message())
3436 self.assertRaises(queue.Empty, self.queue.get_nowait)
3437 self.que_logger.info(self.next_message())
3438 self.assertRaises(queue.Empty, self.queue.get_nowait)
3439 msg = self.next_message()
3440 self.que_logger.warning(msg)
3441 data = self.queue.get_nowait()
3442 self.assertTrue(isinstance(data, logging.LogRecord))
3443 self.assertEqual(data.name, self.que_logger.name)
3444 self.assertEqual((data.msg, data.args), (msg, None))
3445
favlladfe3442017-08-01 20:12:26 +02003446 def test_formatting(self):
3447 msg = self.next_message()
3448 levelname = logging.getLevelName(logging.WARNING)
3449 log_format_str = '{name} -> {levelname}: {message}'
3450 formatted_msg = log_format_str.format(name=self.name,
3451 levelname=levelname, message=msg)
3452 formatter = logging.Formatter(self.log_format)
3453 self.que_hdlr.setFormatter(formatter)
3454 self.que_logger.warning(msg)
3455 log_record = self.queue.get_nowait()
3456 self.assertEqual(formatted_msg, log_record.msg)
3457 self.assertEqual(formatted_msg, log_record.message)
3458
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003459 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3460 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003461 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003462 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003463 listener = logging.handlers.QueueListener(self.queue, handler)
3464 listener.start()
3465 try:
3466 self.que_logger.warning(self.next_message())
3467 self.que_logger.error(self.next_message())
3468 self.que_logger.critical(self.next_message())
3469 finally:
3470 listener.stop()
3471 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3472 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3473 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003474 handler.close()
3475
3476 # Now test with respect_handler_level set
3477
3478 handler = support.TestHandler(support.Matcher())
3479 handler.setLevel(logging.CRITICAL)
3480 listener = logging.handlers.QueueListener(self.queue, handler,
3481 respect_handler_level=True)
3482 listener.start()
3483 try:
3484 self.que_logger.warning(self.next_message())
3485 self.que_logger.error(self.next_message())
3486 self.que_logger.critical(self.next_message())
3487 finally:
3488 listener.stop()
3489 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3490 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3491 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
Cheryl Sabellad345bb42018-09-25 19:00:08 -04003492 handler.close()
3493
3494 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3495 'logging.handlers.QueueListener required for this test')
3496 def test_queue_listener_with_StreamHandler(self):
3497 # Test that traceback only appends once (bpo-34334).
3498 listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
3499 listener.start()
3500 try:
3501 1 / 0
3502 except ZeroDivisionError as e:
3503 exc = e
3504 self.que_logger.exception(self.next_message(), exc_info=exc)
3505 listener.stop()
3506 self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
Vinay Sajip365701a2015-02-09 19:49:00 +00003507
Vinay Sajipd61910c2016-09-08 01:13:39 +01003508if hasattr(logging.handlers, 'QueueListener'):
3509 import multiprocessing
3510 from unittest.mock import patch
3511
3512 class QueueListenerTest(BaseTest):
3513 """
3514 Tests based on patch submitted for issue #27930. Ensure that
3515 QueueListener handles all log messages.
3516 """
3517
3518 repeat = 20
3519
3520 @staticmethod
3521 def setup_and_log(log_queue, ident):
3522 """
3523 Creates a logger with a QueueHandler that logs to a queue read by a
3524 QueueListener. Starts the listener, logs five messages, and stops
3525 the listener.
3526 """
3527 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3528 logger.setLevel(logging.DEBUG)
3529 handler = logging.handlers.QueueHandler(log_queue)
3530 logger.addHandler(handler)
3531 listener = logging.handlers.QueueListener(log_queue)
3532 listener.start()
3533
3534 logger.info('one')
3535 logger.info('two')
3536 logger.info('three')
3537 logger.info('four')
3538 logger.info('five')
3539
3540 listener.stop()
3541 logger.removeHandler(handler)
3542 handler.close()
3543
3544 @patch.object(logging.handlers.QueueListener, 'handle')
3545 def test_handle_called_with_queue_queue(self, mock_handle):
3546 for i in range(self.repeat):
3547 log_queue = queue.Queue()
3548 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3549 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3550 'correct number of handled log messages')
3551
3552 @patch.object(logging.handlers.QueueListener, 'handle')
3553 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003554 # Issue 28668: The multiprocessing (mp) module is not functional
3555 # when the mp.synchronize module cannot be imported.
3556 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003557 for i in range(self.repeat):
3558 log_queue = multiprocessing.Queue()
3559 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003560 log_queue.close()
3561 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003562 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3563 'correct number of handled log messages')
3564
3565 @staticmethod
3566 def get_all_from_queue(log_queue):
3567 try:
3568 while True:
3569 yield log_queue.get_nowait()
3570 except queue.Empty:
3571 return []
3572
3573 def test_no_messages_in_queue_after_stop(self):
3574 """
3575 Five messages are logged then the QueueListener is stopped. This
3576 test then gets everything off the queue. Failure of this test
3577 indicates that messages were not registered on the queue until
3578 _after_ the QueueListener stopped.
3579 """
xdegayebf2b65e2017-12-01 08:08:49 +01003580 # Issue 28668: The multiprocessing (mp) module is not functional
3581 # when the mp.synchronize module cannot be imported.
3582 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003583 for i in range(self.repeat):
3584 queue = multiprocessing.Queue()
3585 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3586 # time.sleep(1)
3587 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003588 queue.close()
3589 queue.join_thread()
3590
Vinay Sajipd61910c2016-09-08 01:13:39 +01003591 expected = [[], [logging.handlers.QueueListener._sentinel]]
3592 self.assertIn(items, expected,
3593 'Found unexpected messages in queue: %s' % (
3594 [m.msg if isinstance(m, logging.LogRecord)
3595 else m for m in items]))
3596
Vinay Sajipe723e962011-04-15 22:27:17 +01003597
Vinay Sajip37eb3382011-04-26 20:26:41 +01003598ZERO = datetime.timedelta(0)
3599
3600class UTC(datetime.tzinfo):
3601 def utcoffset(self, dt):
3602 return ZERO
3603
3604 dst = utcoffset
3605
3606 def tzname(self, dt):
3607 return 'UTC'
3608
3609utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003610
Vinay Sajipa39c5712010-10-25 13:57:39 +00003611class FormatterTest(unittest.TestCase):
3612 def setUp(self):
3613 self.common = {
3614 'name': 'formatter.test',
3615 'level': logging.DEBUG,
3616 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3617 'lineno': 42,
3618 'exc_info': None,
3619 'func': None,
3620 'msg': 'Message with %d %s',
3621 'args': (2, 'placeholders'),
3622 }
3623 self.variants = {
3624 }
3625
3626 def get_record(self, name=None):
3627 result = dict(self.common)
3628 if name is not None:
3629 result.update(self.variants[name])
3630 return logging.makeLogRecord(result)
3631
BNMetrics18fb1fb2018-10-15 19:41:36 +01003632 def assert_error_message(self, exception, message, *args, **kwargs):
3633 try:
3634 self.assertRaises(exception, *args, **kwargs)
3635 except exception as e:
3636 self.assertEqual(message, e.message)
3637
Vinay Sajipa39c5712010-10-25 13:57:39 +00003638 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003639 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003640 r = self.get_record()
3641 f = logging.Formatter('${%(message)s}')
3642 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3643 f = logging.Formatter('%(random)s')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003644 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003645 self.assertFalse(f.usesTime())
3646 f = logging.Formatter('%(asctime)s')
3647 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003648 f = logging.Formatter('%(asctime)-15s')
3649 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003650 f = logging.Formatter('%(asctime)#15s')
3651 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003652
3653 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003654 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003655 r = self.get_record()
3656 f = logging.Formatter('$%{message}%$', style='{')
3657 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3658 f = logging.Formatter('{random}', style='{')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003659 self.assertRaises(ValueError, f.format, r)
3660 f = logging.Formatter("{message}", style='{')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003661 self.assertFalse(f.usesTime())
3662 f = logging.Formatter('{asctime}', style='{')
3663 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003664 f = logging.Formatter('{asctime!s:15}', style='{')
3665 self.assertTrue(f.usesTime())
3666 f = logging.Formatter('{asctime:15}', style='{')
3667 self.assertTrue(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003668
3669 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003670 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003671 r = self.get_record()
BNMetrics18fb1fb2018-10-15 19:41:36 +01003672 f = logging.Formatter('${message}', style='$')
3673 self.assertEqual(f.format(r), 'Message with 2 placeholders')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003674 f = logging.Formatter('$message', style='$')
3675 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3676 f = logging.Formatter('$$%${message}%$$', style='$')
3677 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3678 f = logging.Formatter('${random}', style='$')
BNMetrics18fb1fb2018-10-15 19:41:36 +01003679 self.assertRaises(ValueError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003680 self.assertFalse(f.usesTime())
3681 f = logging.Formatter('${asctime}', style='$')
3682 self.assertTrue(f.usesTime())
3683 f = logging.Formatter('$asctime', style='$')
3684 self.assertTrue(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003685 f = logging.Formatter('${message}', style='$')
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003686 self.assertFalse(f.usesTime())
BNMetrics18fb1fb2018-10-15 19:41:36 +01003687 f = logging.Formatter('${asctime}--', style='$')
3688 self.assertTrue(f.usesTime())
3689
3690 def test_format_validate(self):
3691 # Check correct formatting
3692 # Percentage style
3693 f = logging.Formatter("%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3694 self.assertEqual(f._fmt, "%(levelname)-15s - %(message) 5s - %(process)03d - %(module) - %(asctime)*.3s")
3695 f = logging.Formatter("%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3696 self.assertEqual(f._fmt, "%(asctime)*s - %(asctime)*.3s - %(process)-34.33o")
3697 f = logging.Formatter("%(process)#+027.23X")
3698 self.assertEqual(f._fmt, "%(process)#+027.23X")
3699 f = logging.Formatter("%(foo)#.*g")
3700 self.assertEqual(f._fmt, "%(foo)#.*g")
3701
3702 # StrFormat Style
3703 f = logging.Formatter("$%{message}%$ - {asctime!a:15} - {customfield['key']}", style="{")
3704 self.assertEqual(f._fmt, "$%{message}%$ - {asctime!a:15} - {customfield['key']}")
3705 f = logging.Formatter("{process:.2f} - {custom.f:.4f}", style="{")
3706 self.assertEqual(f._fmt, "{process:.2f} - {custom.f:.4f}")
3707 f = logging.Formatter("{customfield!s:#<30}", style="{")
3708 self.assertEqual(f._fmt, "{customfield!s:#<30}")
3709 f = logging.Formatter("{message!r}", style="{")
3710 self.assertEqual(f._fmt, "{message!r}")
3711 f = logging.Formatter("{message!s}", style="{")
3712 self.assertEqual(f._fmt, "{message!s}")
3713 f = logging.Formatter("{message!a}", style="{")
3714 self.assertEqual(f._fmt, "{message!a}")
3715 f = logging.Formatter("{process!r:4.2}", style="{")
3716 self.assertEqual(f._fmt, "{process!r:4.2}")
3717 f = logging.Formatter("{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}", style="{")
3718 self.assertEqual(f._fmt, "{process!s:<#30,.12f}- {custom:=+#30,.1d} - {module:^30}")
3719 f = logging.Formatter("{process!s:{w},.{p}}", style="{")
3720 self.assertEqual(f._fmt, "{process!s:{w},.{p}}")
3721 f = logging.Formatter("{foo:12.{p}}", style="{")
3722 self.assertEqual(f._fmt, "{foo:12.{p}}")
3723 f = logging.Formatter("{foo:{w}.6}", style="{")
3724 self.assertEqual(f._fmt, "{foo:{w}.6}")
3725 f = logging.Formatter("{foo[0].bar[1].baz}", style="{")
3726 self.assertEqual(f._fmt, "{foo[0].bar[1].baz}")
3727 f = logging.Formatter("{foo[k1].bar[k2].baz}", style="{")
3728 self.assertEqual(f._fmt, "{foo[k1].bar[k2].baz}")
3729 f = logging.Formatter("{12[k1].bar[k2].baz}", style="{")
3730 self.assertEqual(f._fmt, "{12[k1].bar[k2].baz}")
3731
3732 # Dollar style
3733 f = logging.Formatter("${asctime} - $message", style="$")
3734 self.assertEqual(f._fmt, "${asctime} - $message")
3735 f = logging.Formatter("$bar $$", style="$")
3736 self.assertEqual(f._fmt, "$bar $$")
3737 f = logging.Formatter("$bar $$$$", style="$")
3738 self.assertEqual(f._fmt, "$bar $$$$") # this would print two $($$)
3739
3740 # Testing when ValueError being raised from incorrect format
3741 # Percentage Style
3742 self.assertRaises(ValueError, logging.Formatter, "%(asctime)Z")
3743 self.assertRaises(ValueError, logging.Formatter, "%(asctime)b")
3744 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*")
3745 self.assertRaises(ValueError, logging.Formatter, "%(asctime)*3s")
3746 self.assertRaises(ValueError, logging.Formatter, "%(asctime)_")
3747 self.assertRaises(ValueError, logging.Formatter, '{asctime}')
3748 self.assertRaises(ValueError, logging.Formatter, '${message}')
3749 self.assertRaises(ValueError, logging.Formatter, '%(foo)#12.3*f') # with both * and decimal number as precision
3750 self.assertRaises(ValueError, logging.Formatter, '%(foo)0*.8*f')
3751
3752 # StrFormat Style
3753 # Testing failure for '-' in field name
3754 self.assert_error_message(
3755 ValueError,
3756 "invalid field name/expression: 'name-thing'",
3757 logging.Formatter, "{name-thing}", style="{"
3758 )
3759 # Testing failure for style mismatch
3760 self.assert_error_message(
3761 ValueError,
3762 "invalid format: no fields",
3763 logging.Formatter, '%(asctime)s', style='{'
3764 )
3765 # Testing failure for invalid conversion
3766 self.assert_error_message(
3767 ValueError,
3768 "invalid conversion: 'Z'"
3769 )
3770 self.assertRaises(ValueError, logging.Formatter, '{asctime!s:#30,15f}', style='{')
3771 self.assert_error_message(
3772 ValueError,
3773 "invalid format: expected ':' after conversion specifier",
3774 logging.Formatter, '{asctime!aa:15}', style='{'
3775 )
3776 # Testing failure for invalid spec
3777 self.assert_error_message(
3778 ValueError,
3779 "bad specifier: '.2ff'",
3780 logging.Formatter, '{process:.2ff}', style='{'
3781 )
3782 self.assertRaises(ValueError, logging.Formatter, '{process:.2Z}', style='{')
3783 self.assertRaises(ValueError, logging.Formatter, '{process!s:<##30,12g}', style='{')
3784 self.assertRaises(ValueError, logging.Formatter, '{process!s:<#30#,12g}', style='{')
3785 self.assertRaises(ValueError, logging.Formatter, '{process!s:{{w}},{{p}}}', style='{')
3786 # Testing failure for mismatch braces
3787 self.assert_error_message(
3788 ValueError,
3789 "invalid format: unmatched '{' in format spec",
3790 logging.Formatter, '{process', style='{'
3791 )
3792 self.assert_error_message(
3793 ValueError,
3794 "invalid format: unmatched '{' in format spec",
3795 logging.Formatter, 'process}', style='{'
3796 )
3797 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}', style='{')
3798 self.assertRaises(ValueError, logging.Formatter, '{{foo!r:4.2}}', style='{')
3799 self.assertRaises(ValueError, logging.Formatter, '{foo/bar}', style='{')
3800 self.assertRaises(ValueError, logging.Formatter, '{foo:{{w}}.{{p}}}}', style='{')
3801 self.assertRaises(ValueError, logging.Formatter, '{foo!X:{{w}}.{{p}}}', style='{')
3802 self.assertRaises(ValueError, logging.Formatter, '{foo!a:random}', style='{')
3803 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{dom}', style='{')
3804 self.assertRaises(ValueError, logging.Formatter, '{foo!a:ran{d}om}', style='{')
3805 self.assertRaises(ValueError, logging.Formatter, '{foo.!a:d}', style='{')
3806
3807 # Dollar style
3808 # Testing failure for mismatch bare $
3809 self.assert_error_message(
3810 ValueError,
3811 "invalid format: bare \'$\' not allowed",
3812 logging.Formatter, '$bar $$$', style='$'
3813 )
3814 self.assert_error_message(
3815 ValueError,
3816 "invalid format: bare \'$\' not allowed",
3817 logging.Formatter, 'bar $', style='$'
3818 )
3819 self.assert_error_message(
3820 ValueError,
3821 "invalid format: bare \'$\' not allowed",
3822 logging.Formatter, 'foo $.', style='$'
3823 )
3824 # Testing failure for mismatch style
3825 self.assert_error_message(
3826 ValueError,
3827 "invalid format: no fields",
3828 logging.Formatter, '{asctime}', style='$'
3829 )
3830 self.assertRaises(ValueError, logging.Formatter, '%(asctime)s', style='$')
3831
3832 # Testing failure for incorrect fields
3833 self.assert_error_message(
3834 ValueError,
3835 "invalid format: no fields",
3836 logging.Formatter, 'foo', style='$'
3837 )
3838 self.assertRaises(ValueError, logging.Formatter, '${asctime', style='$')
Vinay Sajipa39c5712010-10-25 13:57:39 +00003839
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003840 def test_invalid_style(self):
3841 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3842
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003843 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003844 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003845 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3846 # We use None to indicate we want the local timezone
3847 # We're essentially converting a UTC time to local time
3848 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003849 r.msecs = 123
3850 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003851 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003852 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3853 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003854 f.format(r)
3855 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3856
3857class TestBufferingFormatter(logging.BufferingFormatter):
3858 def formatHeader(self, records):
3859 return '[(%d)' % len(records)
3860
3861 def formatFooter(self, records):
3862 return '(%d)]' % len(records)
3863
3864class BufferingFormatterTest(unittest.TestCase):
3865 def setUp(self):
3866 self.records = [
3867 logging.makeLogRecord({'msg': 'one'}),
3868 logging.makeLogRecord({'msg': 'two'}),
3869 ]
3870
3871 def test_default(self):
3872 f = logging.BufferingFormatter()
3873 self.assertEqual('', f.format([]))
3874 self.assertEqual('onetwo', f.format(self.records))
3875
3876 def test_custom(self):
3877 f = TestBufferingFormatter()
3878 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3879 lf = logging.Formatter('<%(message)s>')
3880 f = TestBufferingFormatter(lf)
3881 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003882
3883class ExceptionTest(BaseTest):
3884 def test_formatting(self):
3885 r = self.root_logger
3886 h = RecordingHandler()
3887 r.addHandler(h)
3888 try:
3889 raise RuntimeError('deliberate mistake')
3890 except:
3891 logging.exception('failed', stack_info=True)
3892 r.removeHandler(h)
3893 h.close()
3894 r = h.records[0]
3895 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3896 'call last):\n'))
3897 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3898 'deliberate mistake'))
3899 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3900 'call last):\n'))
3901 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3902 'stack_info=True)'))
3903
3904
Vinay Sajip5a27d402010-12-10 11:42:57 +00003905class LastResortTest(BaseTest):
3906 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003907 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003908 root = self.root_logger
3909 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003910 old_lastresort = logging.lastResort
3911 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003912
Vinay Sajip5a27d402010-12-10 11:42:57 +00003913 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003914 with support.captured_stderr() as stderr:
3915 root.debug('This should not appear')
3916 self.assertEqual(stderr.getvalue(), '')
3917 root.warning('Final chance!')
3918 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3919
3920 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003921 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003922 with support.captured_stderr() as stderr:
3923 root.warning('Final chance!')
3924 msg = 'No handlers could be found for logger "root"\n'
3925 self.assertEqual(stderr.getvalue(), msg)
3926
Vinay Sajip5a27d402010-12-10 11:42:57 +00003927 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003928 with support.captured_stderr() as stderr:
3929 root.warning('Final chance!')
3930 self.assertEqual(stderr.getvalue(), '')
3931
3932 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003933 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003934 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003935 with support.captured_stderr() as stderr:
3936 root.warning('Final chance!')
3937 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003938 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003939 root.addHandler(self.root_hdlr)
3940 logging.lastResort = old_lastresort
3941 logging.raiseExceptions = old_raise_exceptions
3942
3943
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003944class FakeHandler:
3945
3946 def __init__(self, identifier, called):
3947 for method in ('acquire', 'flush', 'close', 'release'):
3948 setattr(self, method, self.record_call(identifier, method, called))
3949
3950 def record_call(self, identifier, method_name, called):
3951 def inner():
3952 called.append('{} - {}'.format(identifier, method_name))
3953 return inner
3954
3955
3956class RecordingHandler(logging.NullHandler):
3957
3958 def __init__(self, *args, **kwargs):
3959 super(RecordingHandler, self).__init__(*args, **kwargs)
3960 self.records = []
3961
3962 def handle(self, record):
3963 """Keep track of all the emitted records."""
3964 self.records.append(record)
3965
3966
3967class ShutdownTest(BaseTest):
3968
Vinay Sajip5e66b162011-04-20 15:41:14 +01003969 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003970
3971 def setUp(self):
3972 super(ShutdownTest, self).setUp()
3973 self.called = []
3974
3975 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003976 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003977
3978 def raise_error(self, error):
3979 def inner():
3980 raise error()
3981 return inner
3982
3983 def test_no_failure(self):
3984 # create some fake handlers
3985 handler0 = FakeHandler(0, self.called)
3986 handler1 = FakeHandler(1, self.called)
3987 handler2 = FakeHandler(2, self.called)
3988
3989 # create live weakref to those handlers
3990 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3991
3992 logging.shutdown(handlerList=list(handlers))
3993
3994 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3995 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3996 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3997 self.assertEqual(expected, self.called)
3998
3999 def _test_with_failure_in_method(self, method, error):
4000 handler = FakeHandler(0, self.called)
4001 setattr(handler, method, self.raise_error(error))
4002 handlers = [logging.weakref.ref(handler)]
4003
4004 logging.shutdown(handlerList=list(handlers))
4005
4006 self.assertEqual('0 - release', self.called[-1])
4007
4008 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004009 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004010
4011 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004012 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004013
4014 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02004015 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004016
4017 def test_with_valueerror_in_acquire(self):
4018 self._test_with_failure_in_method('acquire', ValueError)
4019
4020 def test_with_valueerror_in_flush(self):
4021 self._test_with_failure_in_method('flush', ValueError)
4022
4023 def test_with_valueerror_in_close(self):
4024 self._test_with_failure_in_method('close', ValueError)
4025
4026 def test_with_other_error_in_acquire_without_raise(self):
4027 logging.raiseExceptions = False
4028 self._test_with_failure_in_method('acquire', IndexError)
4029
4030 def test_with_other_error_in_flush_without_raise(self):
4031 logging.raiseExceptions = False
4032 self._test_with_failure_in_method('flush', IndexError)
4033
4034 def test_with_other_error_in_close_without_raise(self):
4035 logging.raiseExceptions = False
4036 self._test_with_failure_in_method('close', IndexError)
4037
4038 def test_with_other_error_in_acquire_with_raise(self):
4039 logging.raiseExceptions = True
4040 self.assertRaises(IndexError, self._test_with_failure_in_method,
4041 'acquire', IndexError)
4042
4043 def test_with_other_error_in_flush_with_raise(self):
4044 logging.raiseExceptions = True
4045 self.assertRaises(IndexError, self._test_with_failure_in_method,
4046 'flush', IndexError)
4047
4048 def test_with_other_error_in_close_with_raise(self):
4049 logging.raiseExceptions = True
4050 self.assertRaises(IndexError, self._test_with_failure_in_method,
4051 'close', IndexError)
4052
4053
4054class ModuleLevelMiscTest(BaseTest):
4055
Vinay Sajip5e66b162011-04-20 15:41:14 +01004056 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004057
4058 def test_disable(self):
4059 old_disable = logging.root.manager.disable
4060 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004061 self.assertEqual(old_disable, 0)
4062 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004063
4064 logging.disable(83)
4065 self.assertEqual(logging.root.manager.disable, 83)
4066
Vinay Sajipd489ac92016-12-31 11:40:11 +00004067 # test the default value introduced in 3.7
4068 # (Issue #28524)
4069 logging.disable()
4070 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
4071
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004072 def _test_log(self, method, level=None):
4073 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004074 support.patch(self, logging, 'basicConfig',
4075 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004076
4077 recording = RecordingHandler()
4078 logging.root.addHandler(recording)
4079
4080 log_method = getattr(logging, method)
4081 if level is not None:
4082 log_method(level, "test me: %r", recording)
4083 else:
4084 log_method("test me: %r", recording)
4085
4086 self.assertEqual(len(recording.records), 1)
4087 record = recording.records[0]
4088 self.assertEqual(record.getMessage(), "test me: %r" % recording)
4089
4090 expected_level = level if level is not None else getattr(logging, method.upper())
4091 self.assertEqual(record.levelno, expected_level)
4092
4093 # basicConfig was not called!
4094 self.assertEqual(called, [])
4095
4096 def test_log(self):
4097 self._test_log('log', logging.ERROR)
4098
4099 def test_debug(self):
4100 self._test_log('debug')
4101
4102 def test_info(self):
4103 self._test_log('info')
4104
4105 def test_warning(self):
4106 self._test_log('warning')
4107
4108 def test_error(self):
4109 self._test_log('error')
4110
4111 def test_critical(self):
4112 self._test_log('critical')
4113
4114 def test_set_logger_class(self):
4115 self.assertRaises(TypeError, logging.setLoggerClass, object)
4116
4117 class MyLogger(logging.Logger):
4118 pass
4119
4120 logging.setLoggerClass(MyLogger)
4121 self.assertEqual(logging.getLoggerClass(), MyLogger)
4122
4123 logging.setLoggerClass(logging.Logger)
4124 self.assertEqual(logging.getLoggerClass(), logging.Logger)
4125
Serhiy Storchakaa7930372016-07-03 22:27:26 +03004126 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01004127 def test_logging_at_shutdown(self):
4128 # Issue #20037
4129 code = """if 1:
4130 import logging
4131
4132 class A:
4133 def __del__(self):
4134 try:
4135 raise ValueError("some error")
4136 except Exception:
4137 logging.exception("exception in __del__")
4138
4139 a = A()"""
4140 rc, out, err = assert_python_ok("-c", code)
4141 err = err.decode()
4142 self.assertIn("exception in __del__", err)
4143 self.assertIn("ValueError: some error", err)
4144
4145
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004146class LogRecordTest(BaseTest):
4147 def test_str_rep(self):
4148 r = logging.makeLogRecord({})
4149 s = str(r)
4150 self.assertTrue(s.startswith('<LogRecord: '))
4151 self.assertTrue(s.endswith('>'))
4152
4153 def test_dict_arg(self):
4154 h = RecordingHandler()
4155 r = logging.getLogger()
4156 r.addHandler(h)
4157 d = {'less' : 'more' }
4158 logging.warning('less is %(less)s', d)
4159 self.assertIs(h.records[0].args, d)
4160 self.assertEqual(h.records[0].message, 'less is more')
4161 r.removeHandler(h)
4162 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004163
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004164 def test_multiprocessing(self):
4165 r = logging.makeLogRecord({})
4166 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01004167 try:
4168 import multiprocessing as mp
4169 r = logging.makeLogRecord({})
4170 self.assertEqual(r.processName, mp.current_process().name)
4171 except ImportError:
4172 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004173
4174 def test_optional(self):
4175 r = logging.makeLogRecord({})
4176 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02004177 NOT_NONE(r.thread)
4178 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01004179 NOT_NONE(r.process)
4180 NOT_NONE(r.processName)
4181 log_threads = logging.logThreads
4182 log_processes = logging.logProcesses
4183 log_multiprocessing = logging.logMultiprocessing
4184 try:
4185 logging.logThreads = False
4186 logging.logProcesses = False
4187 logging.logMultiprocessing = False
4188 r = logging.makeLogRecord({})
4189 NONE = self.assertIsNone
4190 NONE(r.thread)
4191 NONE(r.threadName)
4192 NONE(r.process)
4193 NONE(r.processName)
4194 finally:
4195 logging.logThreads = log_threads
4196 logging.logProcesses = log_processes
4197 logging.logMultiprocessing = log_multiprocessing
4198
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004199class BasicConfigTest(unittest.TestCase):
4200
Vinay Sajip95bf5042011-04-20 11:50:56 +01004201 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004202
4203 def setUp(self):
4204 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01004205 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01004206 self.saved_handlers = logging._handlers.copy()
4207 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01004208 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01004209 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004210 logging.root.handlers = []
4211
4212 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01004213 for h in logging.root.handlers[:]:
4214 logging.root.removeHandler(h)
4215 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004216 super(BasicConfigTest, self).tearDown()
4217
Vinay Sajip3def7e02011-04-20 10:58:06 +01004218 def cleanup(self):
4219 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01004220 logging._handlers.clear()
4221 logging._handlers.update(self.saved_handlers)
4222 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01004223 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01004224
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004225 def test_no_kwargs(self):
4226 logging.basicConfig()
4227
4228 # handler defaults to a StreamHandler to sys.stderr
4229 self.assertEqual(len(logging.root.handlers), 1)
4230 handler = logging.root.handlers[0]
4231 self.assertIsInstance(handler, logging.StreamHandler)
4232 self.assertEqual(handler.stream, sys.stderr)
4233
4234 formatter = handler.formatter
4235 # format defaults to logging.BASIC_FORMAT
4236 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
4237 # datefmt defaults to None
4238 self.assertIsNone(formatter.datefmt)
4239 # style defaults to %
4240 self.assertIsInstance(formatter._style, logging.PercentStyle)
4241
Florent Xiclunae41f0de2011-11-11 19:39:25 +01004242 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01004243 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004244
Vinay Sajip1fd12022014-01-13 21:59:56 +00004245 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004246 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004247 logging.basicConfig(stream=sys.stdout, style="{")
4248 logging.error("Log an error")
4249 sys.stdout.seek(0)
4250 self.assertEqual(output.getvalue().strip(),
4251 "ERROR:root:Log an error")
4252
4253 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01004254 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00004255 logging.basicConfig(stream=sys.stdout, style="$")
4256 logging.error("Log an error")
4257 sys.stdout.seek(0)
4258 self.assertEqual(output.getvalue().strip(),
4259 "ERROR:root:Log an error")
4260
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004261 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004262
4263 def cleanup(h1, h2, fn):
4264 h1.close()
4265 h2.close()
4266 os.remove(fn)
4267
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004268 logging.basicConfig(filename='test.log')
4269
4270 self.assertEqual(len(logging.root.handlers), 1)
4271 handler = logging.root.handlers[0]
4272 self.assertIsInstance(handler, logging.FileHandler)
4273
4274 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004275 self.assertEqual(handler.stream.mode, expected.stream.mode)
4276 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004277 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004278
4279 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004280
4281 def cleanup(h1, h2, fn):
4282 h1.close()
4283 h2.close()
4284 os.remove(fn)
4285
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004286 logging.basicConfig(filename='test.log', filemode='wb')
4287
4288 handler = logging.root.handlers[0]
4289 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004290 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00004291 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004292
4293 def test_stream(self):
4294 stream = io.StringIO()
4295 self.addCleanup(stream.close)
4296 logging.basicConfig(stream=stream)
4297
4298 self.assertEqual(len(logging.root.handlers), 1)
4299 handler = logging.root.handlers[0]
4300 self.assertIsInstance(handler, logging.StreamHandler)
4301 self.assertEqual(handler.stream, stream)
4302
4303 def test_format(self):
BNMetrics18fb1fb2018-10-15 19:41:36 +01004304 logging.basicConfig(format='%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004305
4306 formatter = logging.root.handlers[0].formatter
BNMetrics18fb1fb2018-10-15 19:41:36 +01004307 self.assertEqual(formatter._style._fmt, '%(asctime)s - %(message)s')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004308
4309 def test_datefmt(self):
4310 logging.basicConfig(datefmt='bar')
4311
4312 formatter = logging.root.handlers[0].formatter
4313 self.assertEqual(formatter.datefmt, 'bar')
4314
4315 def test_style(self):
4316 logging.basicConfig(style='$')
4317
4318 formatter = logging.root.handlers[0].formatter
4319 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
4320
4321 def test_level(self):
4322 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004323 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004324
4325 logging.basicConfig(level=57)
4326 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004327 # Test that second call has no effect
4328 logging.basicConfig(level=58)
4329 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004330
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004331 def test_incompatible(self):
4332 assertRaises = self.assertRaises
4333 handlers = [logging.StreamHandler()]
4334 stream = sys.stderr
4335 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004336 stream=stream)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004337 assertRaises(ValueError, logging.basicConfig, filename='test.log',
BNMetrics18fb1fb2018-10-15 19:41:36 +01004338 handlers=handlers)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004339 assertRaises(ValueError, logging.basicConfig, stream=stream,
BNMetrics18fb1fb2018-10-15 19:41:36 +01004340 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00004341 # Issue 23207: test for invalid kwargs
4342 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
4343 # Should pop both filename and filemode even if filename is None
4344 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004345
4346 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004347 handlers = [
4348 logging.StreamHandler(),
4349 logging.StreamHandler(sys.stdout),
4350 logging.StreamHandler(),
4351 ]
4352 f = logging.Formatter()
4353 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004354 logging.basicConfig(handlers=handlers)
4355 self.assertIs(handlers[0], logging.root.handlers[0])
4356 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004357 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004358 self.assertIsNotNone(handlers[0].formatter)
4359 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004360 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01004361 self.assertIs(handlers[0].formatter, handlers[1].formatter)
4362
Dong-hee Nacf67d6a2018-06-25 13:11:09 +09004363 def test_force(self):
4364 old_string_io = io.StringIO()
4365 new_string_io = io.StringIO()
4366 old_handlers = [logging.StreamHandler(old_string_io)]
4367 new_handlers = [logging.StreamHandler(new_string_io)]
4368 logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
4369 logging.warning('warn')
4370 logging.info('info')
4371 logging.debug('debug')
4372 self.assertEqual(len(logging.root.handlers), 1)
4373 logging.basicConfig(level=logging.INFO, handlers=new_handlers,
4374 force=True)
4375 logging.warning('warn')
4376 logging.info('info')
4377 logging.debug('debug')
4378 self.assertEqual(len(logging.root.handlers), 1)
4379 self.assertEqual(old_string_io.getvalue().strip(),
4380 'WARNING:root:warn')
4381 self.assertEqual(new_string_io.getvalue().strip(),
4382 'WARNING:root:warn\nINFO:root:info')
4383
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004384 def _test_log(self, method, level=None):
4385 # logging.root has no handlers so basicConfig should be called
4386 called = []
4387
4388 old_basic_config = logging.basicConfig
4389 def my_basic_config(*a, **kw):
4390 old_basic_config()
4391 old_level = logging.root.level
4392 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004393 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004394 called.append((a, kw))
4395
Vinay Sajip1feedb42014-05-31 08:19:12 +01004396 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004397
4398 log_method = getattr(logging, method)
4399 if level is not None:
4400 log_method(level, "test me")
4401 else:
4402 log_method("test me")
4403
4404 # basicConfig was called with no arguments
4405 self.assertEqual(called, [((), {})])
4406
4407 def test_log(self):
4408 self._test_log('log', logging.WARNING)
4409
4410 def test_debug(self):
4411 self._test_log('debug')
4412
4413 def test_info(self):
4414 self._test_log('info')
4415
4416 def test_warning(self):
4417 self._test_log('warning')
4418
4419 def test_error(self):
4420 self._test_log('error')
4421
4422 def test_critical(self):
4423 self._test_log('critical')
4424
4425
4426class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004427 def setUp(self):
4428 super(LoggerAdapterTest, self).setUp()
4429 old_handler_list = logging._handlerList[:]
4430
4431 self.recording = RecordingHandler()
4432 self.logger = logging.root
4433 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004434 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004435 self.addCleanup(self.recording.close)
4436
4437 def cleanup():
4438 logging._handlerList[:] = old_handler_list
4439
4440 self.addCleanup(cleanup)
4441 self.addCleanup(logging.shutdown)
4442 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4443
4444 def test_exception(self):
4445 msg = 'testing exception: %r'
4446 exc = None
4447 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004448 1 / 0
4449 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004450 exc = e
4451 self.adapter.exception(msg, self.recording)
4452
4453 self.assertEqual(len(self.recording.records), 1)
4454 record = self.recording.records[0]
4455 self.assertEqual(record.levelno, logging.ERROR)
4456 self.assertEqual(record.msg, msg)
4457 self.assertEqual(record.args, (self.recording,))
4458 self.assertEqual(record.exc_info,
4459 (exc.__class__, exc, exc.__traceback__))
4460
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004461 def test_exception_excinfo(self):
4462 try:
4463 1 / 0
4464 except ZeroDivisionError as e:
4465 exc = e
4466
4467 self.adapter.exception('exc_info test', exc_info=exc)
4468
4469 self.assertEqual(len(self.recording.records), 1)
4470 record = self.recording.records[0]
4471 self.assertEqual(record.exc_info,
4472 (exc.__class__, exc, exc.__traceback__))
4473
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004474 def test_critical(self):
4475 msg = 'critical test! %r'
4476 self.adapter.critical(msg, self.recording)
4477
4478 self.assertEqual(len(self.recording.records), 1)
4479 record = self.recording.records[0]
4480 self.assertEqual(record.levelno, logging.CRITICAL)
4481 self.assertEqual(record.msg, msg)
4482 self.assertEqual(record.args, (self.recording,))
4483
4484 def test_is_enabled_for(self):
4485 old_disable = self.adapter.logger.manager.disable
4486 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004487 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4488 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004489 self.assertFalse(self.adapter.isEnabledFor(32))
4490
4491 def test_has_handlers(self):
4492 self.assertTrue(self.adapter.hasHandlers())
4493
4494 for handler in self.logger.handlers:
4495 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004496
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004497 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004498 self.assertFalse(self.adapter.hasHandlers())
4499
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004500 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004501 class Adapter(logging.LoggerAdapter):
4502 prefix = 'Adapter'
4503
4504 def process(self, msg, kwargs):
4505 return f"{self.prefix} {msg}", kwargs
4506
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004507 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004508 adapter = Adapter(logger=self.logger, extra=None)
4509 adapter_adapter = Adapter(logger=adapter, extra=None)
4510 adapter_adapter.prefix = 'AdapterAdapter'
4511 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004512 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004513 self.assertEqual(len(self.recording.records), 1)
4514 record = self.recording.records[0]
4515 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004516 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004517 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004518 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004519 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004520 self.assertIs(self.logger.manager, orig_manager)
4521 temp_manager = object()
4522 try:
4523 adapter_adapter.manager = temp_manager
4524 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004525 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004526 self.assertIs(self.logger.manager, temp_manager)
4527 finally:
4528 adapter_adapter.manager = orig_manager
4529 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004530 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004531 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004532
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004533
4534class LoggerTest(BaseTest):
4535
4536 def setUp(self):
4537 super(LoggerTest, self).setUp()
4538 self.recording = RecordingHandler()
4539 self.logger = logging.Logger(name='blah')
4540 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004541 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004542 self.addCleanup(self.recording.close)
4543 self.addCleanup(logging.shutdown)
4544
4545 def test_set_invalid_level(self):
4546 self.assertRaises(TypeError, self.logger.setLevel, object())
4547
4548 def test_exception(self):
4549 msg = 'testing exception: %r'
4550 exc = None
4551 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004552 1 / 0
4553 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004554 exc = e
4555 self.logger.exception(msg, self.recording)
4556
4557 self.assertEqual(len(self.recording.records), 1)
4558 record = self.recording.records[0]
4559 self.assertEqual(record.levelno, logging.ERROR)
4560 self.assertEqual(record.msg, msg)
4561 self.assertEqual(record.args, (self.recording,))
4562 self.assertEqual(record.exc_info,
4563 (exc.__class__, exc, exc.__traceback__))
4564
4565 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004566 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004567 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004568
4569 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004570 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004571 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004572
4573 def test_find_caller_with_stack_info(self):
4574 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004575 support.patch(self, logging.traceback, 'print_stack',
4576 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004577
4578 self.logger.findCaller(stack_info=True)
4579
4580 self.assertEqual(len(called), 1)
4581 self.assertEqual('Stack (most recent call last):\n', called[0])
4582
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004583 def test_find_caller_with_stacklevel(self):
4584 the_level = 1
4585
4586 def innermost():
4587 self.logger.warning('test', stacklevel=the_level)
4588
4589 def inner():
4590 innermost()
4591
4592 def outer():
4593 inner()
4594
4595 records = self.recording.records
4596 outer()
4597 self.assertEqual(records[-1].funcName, 'innermost')
4598 lineno = records[-1].lineno
4599 the_level += 1
4600 outer()
4601 self.assertEqual(records[-1].funcName, 'inner')
4602 self.assertGreater(records[-1].lineno, lineno)
4603 lineno = records[-1].lineno
4604 the_level += 1
4605 outer()
4606 self.assertEqual(records[-1].funcName, 'outer')
4607 self.assertGreater(records[-1].lineno, lineno)
4608 lineno = records[-1].lineno
4609 the_level += 1
4610 outer()
4611 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4612 self.assertGreater(records[-1].lineno, lineno)
4613
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004614 def test_make_record_with_extra_overwrite(self):
4615 name = 'my record'
4616 level = 13
4617 fn = lno = msg = args = exc_info = func = sinfo = None
4618 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4619 exc_info, func, sinfo)
4620
4621 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4622 extra = {key: 'some value'}
4623 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4624 fn, lno, msg, args, exc_info,
4625 extra=extra, sinfo=sinfo)
4626
4627 def test_make_record_with_extra_no_overwrite(self):
4628 name = 'my record'
4629 level = 13
4630 fn = lno = msg = args = exc_info = func = sinfo = None
4631 extra = {'valid_key': 'some value'}
4632 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4633 exc_info, extra=extra, sinfo=sinfo)
4634 self.assertIn('valid_key', result.__dict__)
4635
4636 def test_has_handlers(self):
4637 self.assertTrue(self.logger.hasHandlers())
4638
4639 for handler in self.logger.handlers:
4640 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004641 self.assertFalse(self.logger.hasHandlers())
4642
4643 def test_has_handlers_no_propagate(self):
4644 child_logger = logging.getLogger('blah.child')
4645 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004646 self.assertFalse(child_logger.hasHandlers())
4647
4648 def test_is_enabled_for(self):
4649 old_disable = self.logger.manager.disable
4650 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004651 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004652 self.assertFalse(self.logger.isEnabledFor(22))
4653
Timo Furrer6e3ca642018-06-01 09:29:46 +02004654 def test_is_enabled_for_disabled_logger(self):
4655 old_disabled = self.logger.disabled
4656 old_disable = self.logger.manager.disable
4657
4658 self.logger.disabled = True
4659 self.logger.manager.disable = 21
4660
4661 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4662 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4663
4664 self.assertFalse(self.logger.isEnabledFor(22))
4665
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004666 def test_root_logger_aliases(self):
4667 root = logging.getLogger()
4668 self.assertIs(root, logging.root)
4669 self.assertIs(root, logging.getLogger(None))
4670 self.assertIs(root, logging.getLogger(''))
4671 self.assertIs(root, logging.getLogger('foo').root)
4672 self.assertIs(root, logging.getLogger('foo.bar').root)
4673 self.assertIs(root, logging.getLogger('foo').parent)
4674
4675 self.assertIsNot(root, logging.getLogger('\0'))
4676 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4677
4678 def test_invalid_names(self):
4679 self.assertRaises(TypeError, logging.getLogger, any)
4680 self.assertRaises(TypeError, logging.getLogger, b'foo')
4681
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004682 def test_pickling(self):
4683 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4684 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4685 logger = logging.getLogger(name)
4686 s = pickle.dumps(logger, proto)
4687 unpickled = pickle.loads(s)
4688 self.assertIs(unpickled, logger)
4689
Avram Lubkin78c18a92017-07-30 05:36:33 -04004690 def test_caching(self):
4691 root = self.root_logger
4692 logger1 = logging.getLogger("abc")
4693 logger2 = logging.getLogger("abc.def")
4694
4695 # Set root logger level and ensure cache is empty
4696 root.setLevel(logging.ERROR)
4697 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4698 self.assertEqual(logger2._cache, {})
4699
4700 # Ensure cache is populated and calls are consistent
4701 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4702 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4703 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4704 self.assertEqual(root._cache, {})
4705 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4706
4707 # Ensure root cache gets populated
4708 self.assertEqual(root._cache, {})
4709 self.assertTrue(root.isEnabledFor(logging.ERROR))
4710 self.assertEqual(root._cache, {logging.ERROR: True})
4711
4712 # Set parent logger level and ensure caches are emptied
4713 logger1.setLevel(logging.CRITICAL)
4714 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4715 self.assertEqual(logger2._cache, {})
4716
4717 # Ensure logger2 uses parent logger's effective level
4718 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4719
4720 # Set level to NOTSET and ensure caches are empty
4721 logger2.setLevel(logging.NOTSET)
4722 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4723 self.assertEqual(logger2._cache, {})
4724 self.assertEqual(logger1._cache, {})
4725 self.assertEqual(root._cache, {})
4726
4727 # Verify logger2 follows parent and not root
4728 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4729 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4730 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4731 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4732 self.assertTrue(root.isEnabledFor(logging.ERROR))
4733
4734 # Disable logging in manager and ensure caches are clear
4735 logging.disable()
4736 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4737 self.assertEqual(logger2._cache, {})
4738 self.assertEqual(logger1._cache, {})
4739 self.assertEqual(root._cache, {})
4740
4741 # Ensure no loggers are enabled
4742 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4743 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4744 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4745
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004746
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004747class BaseFileTest(BaseTest):
4748 "Base class for handler tests that write log files"
4749
4750 def setUp(self):
4751 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004752 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4753 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004754 self.rmfiles = []
4755
4756 def tearDown(self):
4757 for fn in self.rmfiles:
4758 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004759 if os.path.exists(self.fn):
4760 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004761 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004762
4763 def assertLogFile(self, filename):
4764 "Assert a log file is there and register it for deletion"
4765 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004766 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004767 self.rmfiles.append(filename)
4768
4769
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004770class FileHandlerTest(BaseFileTest):
4771 def test_delay(self):
4772 os.unlink(self.fn)
4773 fh = logging.FileHandler(self.fn, delay=True)
4774 self.assertIsNone(fh.stream)
4775 self.assertFalse(os.path.exists(self.fn))
4776 fh.handle(logging.makeLogRecord({}))
4777 self.assertIsNotNone(fh.stream)
4778 self.assertTrue(os.path.exists(self.fn))
4779 fh.close()
4780
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004781class RotatingFileHandlerTest(BaseFileTest):
4782 def next_rec(self):
4783 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4784 self.next_message(), None, None, None)
4785
4786 def test_should_not_rollover(self):
4787 # If maxbytes is zero rollover never occurs
4788 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4789 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004790 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004791
4792 def test_should_rollover(self):
4793 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4794 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004795 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004796
4797 def test_file_created(self):
4798 # checks that the file is created and assumes it was created
4799 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004800 rh = logging.handlers.RotatingFileHandler(self.fn)
4801 rh.emit(self.next_rec())
4802 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004803 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004804
4805 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004806 def namer(name):
4807 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004808 rh = logging.handlers.RotatingFileHandler(
4809 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004810 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004811 rh.emit(self.next_rec())
4812 self.assertLogFile(self.fn)
4813 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004814 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004815 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004816 self.assertLogFile(namer(self.fn + ".2"))
4817 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4818 rh.close()
4819
Vinay Sajip1feedb42014-05-31 08:19:12 +01004820 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004821 def test_rotator(self):
4822 def namer(name):
4823 return name + ".gz"
4824
4825 def rotator(source, dest):
4826 with open(source, "rb") as sf:
4827 data = sf.read()
4828 compressed = zlib.compress(data, 9)
4829 with open(dest, "wb") as df:
4830 df.write(compressed)
4831 os.remove(source)
4832
4833 rh = logging.handlers.RotatingFileHandler(
4834 self.fn, backupCount=2, maxBytes=1)
4835 rh.rotator = rotator
4836 rh.namer = namer
4837 m1 = self.next_rec()
4838 rh.emit(m1)
4839 self.assertLogFile(self.fn)
4840 m2 = self.next_rec()
4841 rh.emit(m2)
4842 fn = namer(self.fn + ".1")
4843 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004844 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004845 with open(fn, "rb") as f:
4846 compressed = f.read()
4847 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004848 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004849 rh.emit(self.next_rec())
4850 fn = namer(self.fn + ".2")
4851 self.assertLogFile(fn)
4852 with open(fn, "rb") as f:
4853 compressed = f.read()
4854 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004855 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004856 rh.emit(self.next_rec())
4857 fn = namer(self.fn + ".2")
4858 with open(fn, "rb") as f:
4859 compressed = f.read()
4860 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004861 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004862 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004863 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004864
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004865class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004866 # other test methods added below
4867 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004868 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4869 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004870 fmt = logging.Formatter('%(asctime)s %(message)s')
4871 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004872 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004873 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004874 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004875 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004876 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004877 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004878 fh.close()
4879 # At this point, we should have a recent rotated file which we
4880 # can test for the existence of. However, in practice, on some
4881 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004882 # in time to go to look for the log file. So, we go back a fair
4883 # bit, and stop as soon as we see a rotated file. In theory this
4884 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004885 found = False
4886 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004887 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004888 for secs in range(GO_BACK):
4889 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004890 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4891 found = os.path.exists(fn)
4892 if found:
4893 self.rmfiles.append(fn)
4894 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004895 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4896 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004897 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004898 dn, fn = os.path.split(self.fn)
4899 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004900 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4901 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004902 for f in files:
4903 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004904 path = os.path.join(dn, f)
4905 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004906 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004907 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004908
Vinay Sajip0372e102011-05-05 12:59:14 +01004909 def test_invalid(self):
4910 assertRaises = self.assertRaises
4911 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004912 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004913 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004914 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004915 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004916 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004917
Vinay Sajipa7130792013-04-12 17:04:23 +01004918 def test_compute_rollover_daily_attime(self):
4919 currentTime = 0
4920 atTime = datetime.time(12, 0, 0)
4921 rh = logging.handlers.TimedRotatingFileHandler(
4922 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4923 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004924 try:
4925 actual = rh.computeRollover(currentTime)
4926 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004927
Vinay Sajipd86ac962013-04-14 12:20:46 +01004928 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4929 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4930 finally:
4931 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004932
Vinay Sajip10e8c492013-05-18 10:19:54 -07004933 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004934 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004935 currentTime = int(time.time())
4936 today = currentTime - currentTime % 86400
4937
Vinay Sajipa7130792013-04-12 17:04:23 +01004938 atTime = datetime.time(12, 0, 0)
4939
Vinay Sajip10e8c492013-05-18 10:19:54 -07004940 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004941 for day in range(7):
4942 rh = logging.handlers.TimedRotatingFileHandler(
4943 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4944 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004945 try:
4946 if wday > day:
4947 # The rollover day has already passed this week, so we
4948 # go over into next week
4949 expected = (7 - wday + day)
4950 else:
4951 expected = (day - wday)
4952 # At this point expected is in days from now, convert to seconds
4953 expected *= 24 * 60 * 60
4954 # Add in the rollover time
4955 expected += 12 * 60 * 60
4956 # Add in adjustment for today
4957 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004958 actual = rh.computeRollover(today)
4959 if actual != expected:
4960 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004961 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004962 self.assertEqual(actual, expected)
4963 if day == wday:
4964 # goes into following week
4965 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004966 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004967 if actual != expected:
4968 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004969 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004970 self.assertEqual(actual, expected)
4971 finally:
4972 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004973
4974
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004975def secs(**kw):
4976 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4977
4978for when, exp in (('S', 1),
4979 ('M', 60),
4980 ('H', 60 * 60),
4981 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004982 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004983 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004984 ('W0', secs(days=4, hours=24)),
4985 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004986 def test_compute_rollover(self, when=when, exp=exp):
4987 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004988 self.fn, when=when, interval=1, backupCount=0, utc=True)
4989 currentTime = 0.0
4990 actual = rh.computeRollover(currentTime)
4991 if exp != actual:
4992 # Failures occur on some systems for MIDNIGHT and W0.
4993 # Print detailed calculation for MIDNIGHT so we can try to see
4994 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004995 if when == 'MIDNIGHT':
4996 try:
4997 if rh.utc:
4998 t = time.gmtime(currentTime)
4999 else:
5000 t = time.localtime(currentTime)
5001 currentHour = t[3]
5002 currentMinute = t[4]
5003 currentSecond = t[5]
5004 # r is the number of seconds left between now and midnight
5005 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
5006 currentMinute) * 60 +
5007 currentSecond)
5008 result = currentTime + r
5009 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
5010 print('currentHour: %s' % currentHour, file=sys.stderr)
5011 print('currentMinute: %s' % currentMinute, file=sys.stderr)
5012 print('currentSecond: %s' % currentSecond, file=sys.stderr)
5013 print('r: %s' % r, file=sys.stderr)
5014 print('result: %s' % result, file=sys.stderr)
5015 except Exception:
5016 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
5017 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00005018 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00005019 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
5020
Vinay Sajip60ccd822011-05-09 17:32:09 +01005021
Vinay Sajip223349c2015-10-01 20:37:54 +01005022@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01005023class NTEventLogHandlerTest(BaseTest):
5024 def test_basic(self):
5025 logtype = 'Application'
5026 elh = win32evtlog.OpenEventLog(None, logtype)
5027 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01005028
5029 try:
5030 h = logging.handlers.NTEventLogHandler('test_logging')
5031 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05005032 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01005033 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05005034 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01005035
Vinay Sajip60ccd822011-05-09 17:32:09 +01005036 r = logging.makeLogRecord({'msg': 'Test Log Message'})
5037 h.handle(r)
5038 h.close()
5039 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02005040 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01005041 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
5042 win32evtlog.EVENTLOG_SEQUENTIAL_READ
5043 found = False
5044 GO_BACK = 100
5045 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
5046 for e in events:
5047 if e.SourceName != 'test_logging':
5048 continue
5049 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
5050 if msg != 'Test Log Message\r\n':
5051 continue
5052 found = True
5053 break
5054 msg = 'Record not found in event log, went back %d records' % GO_BACK
5055 self.assertTrue(found, msg=msg)
5056
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005057
5058class MiscTestCase(unittest.TestCase):
5059 def test__all__(self):
5060 blacklist = {'logThreads', 'logMultiprocessing',
5061 'logProcesses', 'currentframe',
5062 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
5063 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00005064 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005065 support.check__all__(self, logging, blacklist=blacklist)
5066
5067
Christian Heimes180510d2008-03-03 19:15:45 +00005068# Set the locale to the platform-dependent default. I have no idea
5069# why the test does this, but in any case we save the current locale
5070# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01005071@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00005072def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01005073 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01005074 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
5075 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
5076 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
5077 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
5078 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
5079 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
5080 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
5081 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08005082 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01005083 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01005084 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01005085 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01005086 ]
5087 if hasattr(logging.handlers, 'QueueListener'):
5088 tests.append(QueueListenerTest)
5089 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00005090
Christian Heimes180510d2008-03-03 19:15:45 +00005091if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00005092 test_main()