blob: 13f49f6cc305e309665783a9344ef6aedc16b582 [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
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020045import threading
Vinay Sajip37eb3382011-04-26 20:26:41 +010046import time
Christian Heimes180510d2008-03-03 19:15:45 +000047import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000048import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000049import weakref
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020050
51import asyncore
52from http.server import HTTPServer, BaseHTTPRequestHandler
53import smtpd
54from urllib.parse import urlparse, parse_qs
55from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
56 ThreadingTCPServer, StreamRequestHandler)
57
Vinay Sajip60ccd822011-05-09 17:32:09 +010058try:
Vinay Sajip223349c2015-10-01 20:37:54 +010059 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010060except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010061 win32evtlog = win32evtlogutil = pywintypes = None
62
Eric V. Smith851cad72012-03-11 22:46:04 -070063try:
64 import zlib
65except ImportError:
66 pass
Christian Heimes18c66892008-02-17 13:31:39 +000067
Christian Heimes180510d2008-03-03 19:15:45 +000068class BaseTest(unittest.TestCase):
69
70 """Base class for logging tests."""
71
72 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030073 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000074 message_num = 0
75
76 def setUp(self):
77 """Setup the default logging stream to an internal StringIO instance,
78 so that we can examine log output as we want."""
Victor Stinner69669602017-08-18 23:47:54 +020079 self._threading_key = support.threading_setup()
80
Christian Heimes180510d2008-03-03 19:15:45 +000081 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000082 logging._acquireLock()
83 try:
Christian Heimes180510d2008-03-03 19:15:45 +000084 self.saved_handlers = logging._handlers.copy()
85 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000086 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070087 self.saved_name_to_level = logging._nameToLevel.copy()
88 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.logger_states = logger_states = {}
90 for name in saved_loggers:
91 logger_states[name] = getattr(saved_loggers[name],
92 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000093 finally:
94 logging._releaseLock()
95
Florent Xicluna5252f9f2011-11-07 19:43:05 +010096 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000097 self.logger1 = logging.getLogger("\xab\xd7\xbb")
98 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +000099
Christian Heimes180510d2008-03-03 19:15:45 +0000100 self.root_logger = logging.getLogger("")
101 self.original_logging_level = self.root_logger.getEffectiveLevel()
102
103 self.stream = io.StringIO()
104 self.root_logger.setLevel(logging.DEBUG)
105 self.root_hdlr = logging.StreamHandler(self.stream)
106 self.root_formatter = logging.Formatter(self.log_format)
107 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000108 if self.logger1.hasHandlers():
109 hlist = self.logger1.handlers + self.root_logger.handlers
110 raise AssertionError('Unexpected handlers: %s' % hlist)
111 if self.logger2.hasHandlers():
112 hlist = self.logger2.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000114 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000115 self.assertTrue(self.logger1.hasHandlers())
116 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000117
118 def tearDown(self):
119 """Remove our logging stream, and restore the original logging
120 level."""
121 self.stream.close()
122 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000123 while self.root_logger.handlers:
124 h = self.root_logger.handlers[0]
125 self.root_logger.removeHandler(h)
126 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000127 self.root_logger.setLevel(self.original_logging_level)
128 logging._acquireLock()
129 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700130 logging._levelToName.clear()
131 logging._levelToName.update(self.saved_level_to_name)
132 logging._nameToLevel.clear()
133 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000134 logging._handlers.clear()
135 logging._handlers.update(self.saved_handlers)
136 logging._handlerList[:] = self.saved_handler_list
Avram Lubkin78c18a92017-07-30 05:36:33 -0400137 manager = logging.getLogger().manager
138 manager.disable = 0
139 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000140 loggerDict.clear()
141 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000142 logger_states = self.logger_states
143 for name in self.logger_states:
144 if logger_states[name] is not None:
145 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000146 finally:
147 logging._releaseLock()
148
Victor Stinner69669602017-08-18 23:47:54 +0200149 self.doCleanups()
150 support.threading_cleanup(*self._threading_key)
151
Vinay Sajip4ded5512012-10-02 15:56:16 +0100152 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000153 """Match the collected log lines against the regular expression
154 self.expected_log_pat, and compare the extracted group values to
155 the expected_values list of tuples."""
156 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100157 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300158 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100159 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000160 for actual, expected in zip(actual_lines, expected_values):
161 match = pat.search(actual)
162 if not match:
163 self.fail("Log line does not match expected pattern:\n" +
164 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000165 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000166 s = stream.read()
167 if s:
168 self.fail("Remaining output at end of log stream:\n" + s)
169
170 def next_message(self):
171 """Generate a message consisting solely of an auto-incrementing
172 integer."""
173 self.message_num += 1
174 return "%d" % self.message_num
175
176
177class BuiltinLevelsTest(BaseTest):
178 """Test builtin levels and their inheritance."""
179
180 def test_flat(self):
Mike53f7a7c2017-12-14 14:04:53 +0300181 # Logging levels in a flat logger namespace.
Christian Heimes180510d2008-03-03 19:15:45 +0000182 m = self.next_message
183
184 ERR = logging.getLogger("ERR")
185 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000186 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000187 INF.setLevel(logging.INFO)
188 DEB = logging.getLogger("DEB")
189 DEB.setLevel(logging.DEBUG)
190
191 # These should log.
192 ERR.log(logging.CRITICAL, m())
193 ERR.error(m())
194
195 INF.log(logging.CRITICAL, m())
196 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100197 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000198 INF.info(m())
199
200 DEB.log(logging.CRITICAL, m())
201 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 DEB.warning(m())
203 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 DEB.debug(m())
205
206 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000208 ERR.info(m())
209 ERR.debug(m())
210
211 INF.debug(m())
212
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000213 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000214 ('ERR', 'CRITICAL', '1'),
215 ('ERR', 'ERROR', '2'),
216 ('INF', 'CRITICAL', '3'),
217 ('INF', 'ERROR', '4'),
218 ('INF', 'WARNING', '5'),
219 ('INF', 'INFO', '6'),
220 ('DEB', 'CRITICAL', '7'),
221 ('DEB', 'ERROR', '8'),
222 ('DEB', 'WARNING', '9'),
223 ('DEB', 'INFO', '10'),
224 ('DEB', 'DEBUG', '11'),
225 ])
226
227 def test_nested_explicit(self):
228 # Logging levels in a nested namespace, all explicitly set.
229 m = self.next_message
230
231 INF = logging.getLogger("INF")
232 INF.setLevel(logging.INFO)
233 INF_ERR = logging.getLogger("INF.ERR")
234 INF_ERR.setLevel(logging.ERROR)
235
236 # These should log.
237 INF_ERR.log(logging.CRITICAL, m())
238 INF_ERR.error(m())
239
240 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100241 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000242 INF_ERR.info(m())
243 INF_ERR.debug(m())
244
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000245 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000246 ('INF.ERR', 'CRITICAL', '1'),
247 ('INF.ERR', 'ERROR', '2'),
248 ])
249
250 def test_nested_inherited(self):
Mike53f7a7c2017-12-14 14:04:53 +0300251 # Logging levels in a nested namespace, inherited from parent loggers.
Christian Heimes180510d2008-03-03 19:15:45 +0000252 m = self.next_message
253
254 INF = logging.getLogger("INF")
255 INF.setLevel(logging.INFO)
256 INF_ERR = logging.getLogger("INF.ERR")
257 INF_ERR.setLevel(logging.ERROR)
258 INF_UNDEF = logging.getLogger("INF.UNDEF")
259 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
260 UNDEF = logging.getLogger("UNDEF")
261
262 # These should log.
263 INF_UNDEF.log(logging.CRITICAL, m())
264 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100265 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000266 INF_UNDEF.info(m())
267 INF_ERR_UNDEF.log(logging.CRITICAL, m())
268 INF_ERR_UNDEF.error(m())
269
270 # These should not log.
271 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100272 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000273 INF_ERR_UNDEF.info(m())
274 INF_ERR_UNDEF.debug(m())
275
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000276 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000277 ('INF.UNDEF', 'CRITICAL', '1'),
278 ('INF.UNDEF', 'ERROR', '2'),
279 ('INF.UNDEF', 'WARNING', '3'),
280 ('INF.UNDEF', 'INFO', '4'),
281 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
282 ('INF.ERR.UNDEF', 'ERROR', '6'),
283 ])
284
285 def test_nested_with_virtual_parent(self):
286 # Logging levels when some parent does not exist yet.
287 m = self.next_message
288
289 INF = logging.getLogger("INF")
290 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
291 CHILD = logging.getLogger("INF.BADPARENT")
292 INF.setLevel(logging.INFO)
293
294 # These should log.
295 GRANDCHILD.log(logging.FATAL, m())
296 GRANDCHILD.info(m())
297 CHILD.log(logging.FATAL, m())
298 CHILD.info(m())
299
300 # These should not log.
301 GRANDCHILD.debug(m())
302 CHILD.debug(m())
303
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000304 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000305 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
306 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
307 ('INF.BADPARENT', 'CRITICAL', '3'),
308 ('INF.BADPARENT', 'INFO', '4'),
309 ])
310
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100311 def test_regression_22386(self):
312 """See issue #22386 for more information."""
313 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
314 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000315
Vinay Sajip8b866d52017-01-11 06:57:55 +0000316 def test_regression_29220(self):
317 """See issue #29220 for more information."""
318 logging.addLevelName(logging.INFO, '')
319 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
320 self.assertEqual(logging.getLevelName(logging.INFO), '')
321
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100322 def test_issue27935(self):
323 fatal = logging.getLevelName('FATAL')
324 self.assertEqual(fatal, logging.FATAL)
325
Vinay Sajip924aaae2017-01-11 17:35:36 +0000326 def test_regression_29220(self):
327 """See issue #29220 for more information."""
328 logging.addLevelName(logging.INFO, '')
329 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
330 self.assertEqual(logging.getLevelName(logging.INFO), '')
331 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
332 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
333
Christian Heimes180510d2008-03-03 19:15:45 +0000334class BasicFilterTest(BaseTest):
335
336 """Test the bundled Filter class."""
337
338 def test_filter(self):
339 # Only messages satisfying the specified criteria pass through the
340 # filter.
341 filter_ = logging.Filter("spam.eggs")
342 handler = self.root_logger.handlers[0]
343 try:
344 handler.addFilter(filter_)
345 spam = logging.getLogger("spam")
346 spam_eggs = logging.getLogger("spam.eggs")
347 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
348 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
349
350 spam.info(self.next_message())
351 spam_eggs.info(self.next_message()) # Good.
352 spam_eggs_fish.info(self.next_message()) # Good.
353 spam_bakedbeans.info(self.next_message())
354
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000355 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000356 ('spam.eggs', 'INFO', '2'),
357 ('spam.eggs.fish', 'INFO', '3'),
358 ])
359 finally:
360 handler.removeFilter(filter_)
361
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000362 def test_callable_filter(self):
363 # Only messages satisfying the specified criteria pass through the
364 # filter.
365
366 def filterfunc(record):
367 parts = record.name.split('.')
368 prefix = '.'.join(parts[:2])
369 return prefix == 'spam.eggs'
370
371 handler = self.root_logger.handlers[0]
372 try:
373 handler.addFilter(filterfunc)
374 spam = logging.getLogger("spam")
375 spam_eggs = logging.getLogger("spam.eggs")
376 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
377 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
378
379 spam.info(self.next_message())
380 spam_eggs.info(self.next_message()) # Good.
381 spam_eggs_fish.info(self.next_message()) # Good.
382 spam_bakedbeans.info(self.next_message())
383
384 self.assert_log_lines([
385 ('spam.eggs', 'INFO', '2'),
386 ('spam.eggs.fish', 'INFO', '3'),
387 ])
388 finally:
389 handler.removeFilter(filterfunc)
390
Vinay Sajip985ef872011-04-26 19:34:04 +0100391 def test_empty_filter(self):
392 f = logging.Filter()
393 r = logging.makeLogRecord({'name': 'spam.eggs'})
394 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000395
396#
397# First, we define our levels. There can be as many as you want - the only
398# limitations are that they should be integers, the lowest should be > 0 and
399# larger values mean less information being logged. If you need specific
400# level values which do not fit into these limitations, you can use a
401# mapping dictionary to convert between your application levels and the
402# logging system.
403#
404SILENT = 120
405TACITURN = 119
406TERSE = 118
407EFFUSIVE = 117
408SOCIABLE = 116
409VERBOSE = 115
410TALKATIVE = 114
411GARRULOUS = 113
412CHATTERBOX = 112
413BORING = 111
414
415LEVEL_RANGE = range(BORING, SILENT + 1)
416
417#
418# Next, we define names for our levels. You don't need to do this - in which
419# case the system will use "Level n" to denote the text for the level.
420#
421my_logging_levels = {
422 SILENT : 'Silent',
423 TACITURN : 'Taciturn',
424 TERSE : 'Terse',
425 EFFUSIVE : 'Effusive',
426 SOCIABLE : 'Sociable',
427 VERBOSE : 'Verbose',
428 TALKATIVE : 'Talkative',
429 GARRULOUS : 'Garrulous',
430 CHATTERBOX : 'Chatterbox',
431 BORING : 'Boring',
432}
433
434class GarrulousFilter(logging.Filter):
435
436 """A filter which blocks garrulous messages."""
437
438 def filter(self, record):
439 return record.levelno != GARRULOUS
440
441class VerySpecificFilter(logging.Filter):
442
443 """A filter which blocks sociable and taciturn messages."""
444
445 def filter(self, record):
446 return record.levelno not in [SOCIABLE, TACITURN]
447
448
449class CustomLevelsAndFiltersTest(BaseTest):
450
451 """Test various filtering possibilities with custom logging levels."""
452
453 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300454 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000455
456 def setUp(self):
457 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000458 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000459 logging.addLevelName(k, v)
460
461 def log_at_all_levels(self, logger):
462 for lvl in LEVEL_RANGE:
463 logger.log(lvl, self.next_message())
464
465 def test_logger_filter(self):
466 # Filter at logger level.
467 self.root_logger.setLevel(VERBOSE)
468 # Levels >= 'Verbose' are good.
469 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000470 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000471 ('Verbose', '5'),
472 ('Sociable', '6'),
473 ('Effusive', '7'),
474 ('Terse', '8'),
475 ('Taciturn', '9'),
476 ('Silent', '10'),
477 ])
478
479 def test_handler_filter(self):
480 # Filter at handler level.
481 self.root_logger.handlers[0].setLevel(SOCIABLE)
482 try:
483 # Levels >= 'Sociable' are good.
484 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000485 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000486 ('Sociable', '6'),
487 ('Effusive', '7'),
488 ('Terse', '8'),
489 ('Taciturn', '9'),
490 ('Silent', '10'),
491 ])
492 finally:
493 self.root_logger.handlers[0].setLevel(logging.NOTSET)
494
495 def test_specific_filters(self):
496 # Set a specific filter object on the handler, and then add another
497 # filter object on the logger itself.
498 handler = self.root_logger.handlers[0]
499 specific_filter = None
500 garr = GarrulousFilter()
501 handler.addFilter(garr)
502 try:
503 self.log_at_all_levels(self.root_logger)
504 first_lines = [
505 # Notice how 'Garrulous' is missing
506 ('Boring', '1'),
507 ('Chatterbox', '2'),
508 ('Talkative', '4'),
509 ('Verbose', '5'),
510 ('Sociable', '6'),
511 ('Effusive', '7'),
512 ('Terse', '8'),
513 ('Taciturn', '9'),
514 ('Silent', '10'),
515 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000516 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000517
518 specific_filter = VerySpecificFilter()
519 self.root_logger.addFilter(specific_filter)
520 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000521 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000522 # Not only 'Garrulous' is still missing, but also 'Sociable'
523 # and 'Taciturn'
524 ('Boring', '11'),
525 ('Chatterbox', '12'),
526 ('Talkative', '14'),
527 ('Verbose', '15'),
528 ('Effusive', '17'),
529 ('Terse', '18'),
530 ('Silent', '20'),
531 ])
532 finally:
533 if specific_filter:
534 self.root_logger.removeFilter(specific_filter)
535 handler.removeFilter(garr)
536
537
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100538class HandlerTest(BaseTest):
539 def test_name(self):
540 h = logging.Handler()
541 h.name = 'generic'
542 self.assertEqual(h.name, 'generic')
543 h.name = 'anothergeneric'
544 self.assertEqual(h.name, 'anothergeneric')
545 self.assertRaises(NotImplementedError, h.emit, None)
546
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 def test_builtin_handlers(self):
548 # We can't actually *use* too many handlers in the tests,
549 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200550 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100551 for existing in (True, False):
552 fd, fn = tempfile.mkstemp()
553 os.close(fd)
554 if not existing:
555 os.unlink(fn)
556 h = logging.handlers.WatchedFileHandler(fn, delay=True)
557 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100558 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100559 self.assertEqual(dev, -1)
560 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100561 r = logging.makeLogRecord({'msg': 'Test'})
562 h.handle(r)
563 # Now remove the file.
564 os.unlink(fn)
565 self.assertFalse(os.path.exists(fn))
566 # The next call should recreate the file.
567 h.handle(r)
568 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100569 else:
570 self.assertEqual(h.dev, -1)
571 self.assertEqual(h.ino, -1)
572 h.close()
573 if existing:
574 os.unlink(fn)
575 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100576 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100577 else:
578 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100579 try:
580 h = logging.handlers.SysLogHandler(sockname)
581 self.assertEqual(h.facility, h.LOG_USER)
582 self.assertTrue(h.unixsocket)
583 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200584 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100585 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100586 for method in ('GET', 'POST', 'PUT'):
587 if method == 'PUT':
588 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
589 'localhost', '/log', method)
590 else:
591 h = logging.handlers.HTTPHandler('localhost', '/log', method)
592 h.close()
593 h = logging.handlers.BufferingHandler(0)
594 r = logging.makeLogRecord({})
595 self.assertTrue(h.shouldFlush(r))
596 h.close()
597 h = logging.handlers.BufferingHandler(1)
598 self.assertFalse(h.shouldFlush(r))
599 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100600
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100601 def test_path_objects(self):
602 """
603 Test that Path objects are accepted as filename arguments to handlers.
604
605 See Issue #27493.
606 """
607 fd, fn = tempfile.mkstemp()
608 os.close(fd)
609 os.unlink(fn)
610 pfn = pathlib.Path(fn)
611 cases = (
612 (logging.FileHandler, (pfn, 'w')),
613 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
614 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
615 )
616 if sys.platform in ('linux', 'darwin'):
617 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
618 for cls, args in cases:
619 h = cls(*args)
620 self.assertTrue(os.path.exists(fn))
621 h.close()
622 os.unlink(fn)
623
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100624 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100625 def test_race(self):
626 # Issue #14632 refers.
627 def remove_loop(fname, tries):
628 for _ in range(tries):
629 try:
630 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000631 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100632 except OSError:
633 pass
634 time.sleep(0.004 * random.randint(0, 4))
635
Vinay Sajipc94871a2012-04-25 10:51:35 +0100636 del_count = 500
637 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100638
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000639 self.handle_time = None
640 self.deletion_time = None
641
Vinay Sajipa5798de2012-04-24 23:33:33 +0100642 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100643 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
644 os.close(fd)
645 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
646 remover.daemon = True
647 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100648 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100649 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
650 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100651 try:
652 for _ in range(log_count):
653 time.sleep(0.005)
654 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000655 try:
656 self.handle_time = time.time()
657 h.handle(r)
658 except Exception:
659 print('Deleted at %s, '
660 'opened at %s' % (self.deletion_time,
661 self.handle_time))
662 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100663 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100664 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100665 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100666 if os.path.exists(fn):
667 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100668
669
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100670class BadStream(object):
671 def write(self, data):
672 raise RuntimeError('deliberate mistake')
673
674class TestStreamHandler(logging.StreamHandler):
675 def handleError(self, record):
676 self.error_record = record
677
678class StreamHandlerTest(BaseTest):
679 def test_error_handling(self):
680 h = TestStreamHandler(BadStream())
681 r = logging.makeLogRecord({})
682 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100683
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100684 try:
685 h.handle(r)
686 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687
Vinay Sajip985ef872011-04-26 19:34:04 +0100688 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100689 with support.captured_stderr() as stderr:
690 h.handle(r)
691 msg = '\nRuntimeError: deliberate mistake\n'
692 self.assertIn(msg, stderr.getvalue())
693
Vinay Sajip985ef872011-04-26 19:34:04 +0100694 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100695 with support.captured_stderr() as stderr:
696 h.handle(r)
697 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100698 finally:
699 logging.raiseExceptions = old_raise
700
Vinay Sajip2543f502017-07-30 10:41:45 +0100701 def test_stream_setting(self):
702 """
703 Test setting the handler's stream
704 """
705 h = logging.StreamHandler()
706 stream = io.StringIO()
707 old = h.setStream(stream)
708 self.assertIs(old, sys.stderr)
709 actual = h.setStream(old)
710 self.assertIs(actual, stream)
711 # test that setting to existing value returns None
712 actual = h.setStream(old)
713 self.assertIsNone(actual)
714
Vinay Sajip7367d082011-05-02 13:17:27 +0100715# -- The following section could be moved into a server_helper.py module
716# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100717
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200718class TestSMTPServer(smtpd.SMTPServer):
719 """
720 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100721
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200722 :param addr: A (host, port) tuple which the server listens on.
723 You can specify a port value of zero: the server's
724 *port* attribute will hold the actual port number
725 used, which can be used in client connections.
726 :param handler: A callable which will be called to process
727 incoming messages. The handler will be passed
728 the client address tuple, who the message is from,
729 a list of recipients and the message data.
730 :param poll_interval: The interval, in seconds, used in the underlying
731 :func:`select` or :func:`poll` call by
732 :func:`asyncore.loop`.
733 :param sockmap: A dictionary which will be used to hold
734 :class:`asyncore.dispatcher` instances used by
735 :func:`asyncore.loop`. This avoids changing the
736 :mod:`asyncore` module's global state.
737 """
738
739 def __init__(self, addr, handler, poll_interval, sockmap):
740 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
741 decode_data=True)
742 self.port = self.socket.getsockname()[1]
743 self._handler = handler
744 self._thread = None
745 self.poll_interval = poll_interval
746
747 def process_message(self, peer, mailfrom, rcpttos, data):
748 """
749 Delegates to the handler passed in to the server's constructor.
750
751 Typically, this will be a test case method.
752 :param peer: The client (host, port) tuple.
753 :param mailfrom: The address of the sender.
754 :param rcpttos: The addresses of the recipients.
755 :param data: The message.
756 """
757 self._handler(peer, mailfrom, rcpttos, data)
758
759 def start(self):
760 """
761 Start the server running on a separate daemon thread.
762 """
763 self._thread = t = threading.Thread(target=self.serve_forever,
764 args=(self.poll_interval,))
765 t.setDaemon(True)
766 t.start()
767
768 def serve_forever(self, poll_interval):
769 """
770 Run the :mod:`asyncore` loop until normal termination
771 conditions arise.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100772 :param poll_interval: The interval, in seconds, used in the underlying
773 :func:`select` or :func:`poll` call by
774 :func:`asyncore.loop`.
775 """
Victor Stinner13ff2452018-01-22 18:32:50 +0100776 asyncore.loop(poll_interval, map=self._map)
Vinay Sajipce7c9782011-05-17 07:15:53 +0100777
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200778 def stop(self, timeout=None):
779 """
780 Stop the thread by closing the server instance.
781 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100782
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200783 :param timeout: How long to wait for the server thread
784 to terminate.
785 """
786 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700787 support.join_thread(self._thread, timeout)
788 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200789 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100790
Vinay Sajip7367d082011-05-02 13:17:27 +0100791
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200792class ControlMixin(object):
793 """
794 This mixin is used to start a server on a separate thread, and
795 shut it down programmatically. Request handling is simplified - instead
796 of needing to derive a suitable RequestHandler subclass, you just
797 provide a callable which will be passed each received request to be
798 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200800 :param handler: A handler callable which will be called with a
801 single parameter - the request - in order to
802 process the request. This handler is called on the
803 server thread, effectively meaning that requests are
804 processed serially. While not quite Web scale ;-),
805 this should be fine for testing applications.
806 :param poll_interval: The polling interval in seconds.
807 """
808 def __init__(self, handler, poll_interval):
809 self._thread = None
810 self.poll_interval = poll_interval
811 self._handler = handler
812 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200814 def start(self):
815 """
816 Create a daemon thread to run the server, and start it.
817 """
818 self._thread = t = threading.Thread(target=self.serve_forever,
819 args=(self.poll_interval,))
820 t.setDaemon(True)
821 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100822
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200823 def serve_forever(self, poll_interval):
824 """
825 Run the server. Set the ready flag before entering the
826 service loop.
827 """
828 self.ready.set()
829 super(ControlMixin, self).serve_forever(poll_interval)
830
831 def stop(self, timeout=None):
832 """
833 Tell the server thread to stop, and wait for it to do so.
834
835 :param timeout: How long to wait for the server thread
836 to terminate.
837 """
838 self.shutdown()
839 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700840 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100841 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200842 self.server_close()
843 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100844
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200845class TestHTTPServer(ControlMixin, HTTPServer):
846 """
847 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100848
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200849 :param addr: A tuple with the IP address and port to listen on.
850 :param handler: A handler callable which will be called with a
851 single parameter - the request - in order to
852 process the request.
853 :param poll_interval: The polling interval in seconds.
854 :param log: Pass ``True`` to enable log messages.
855 """
856 def __init__(self, addr, handler, poll_interval=0.5,
857 log=False, sslctx=None):
858 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
859 def __getattr__(self, name, default=None):
860 if name.startswith('do_'):
861 return self.process_request
862 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100863
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200864 def process_request(self):
865 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100866
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200867 def log_message(self, format, *args):
868 if log:
869 super(DelegatingHTTPRequestHandler,
870 self).log_message(format, *args)
871 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
872 ControlMixin.__init__(self, handler, poll_interval)
873 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100874
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200875 def get_request(self):
876 try:
877 sock, addr = self.socket.accept()
878 if self.sslctx:
879 sock = self.sslctx.wrap_socket(sock, server_side=True)
880 except OSError as e:
881 # socket errors are silenced by the caller, print them here
882 sys.stderr.write("Got an error:\n%s\n" % e)
883 raise
884 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100885
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200886class TestTCPServer(ControlMixin, ThreadingTCPServer):
887 """
888 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100889
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200890 :param addr: A tuple with the IP address and port to listen on.
891 :param handler: A handler callable which will be called with a single
892 parameter - the request - in order to process the request.
893 :param poll_interval: The polling interval in seconds.
894 :bind_and_activate: If True (the default), binds the server and starts it
895 listening. If False, you need to call
896 :meth:`server_bind` and :meth:`server_activate` at
897 some later time before calling :meth:`start`, so that
898 the server will set up the socket and listen on it.
899 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100900
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200901 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100902
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200903 def __init__(self, addr, handler, poll_interval=0.5,
904 bind_and_activate=True):
905 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100906
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200907 def handle(self):
908 self.server._handler(self)
909 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
910 bind_and_activate)
911 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100912
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200913 def server_bind(self):
914 super(TestTCPServer, self).server_bind()
915 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100916
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200917class TestUDPServer(ControlMixin, ThreadingUDPServer):
918 """
919 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100920
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200921 :param addr: A tuple with the IP address and port to listen on.
922 :param handler: A handler callable which will be called with a
923 single parameter - the request - in order to
924 process the request.
925 :param poll_interval: The polling interval for shutdown requests,
926 in seconds.
927 :bind_and_activate: If True (the default), binds the server and
928 starts it listening. If False, you need to
929 call :meth:`server_bind` and
930 :meth:`server_activate` at some later time
931 before calling :meth:`start`, so that the server will
932 set up the socket and listen on it.
933 """
934 def __init__(self, addr, handler, poll_interval=0.5,
935 bind_and_activate=True):
936 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100937
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200938 def handle(self):
939 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100940
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200941 def finish(self):
942 data = self.wfile.getvalue()
943 if data:
944 try:
945 super(DelegatingUDPRequestHandler, self).finish()
946 except OSError:
947 if not self.server._closed:
948 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100949
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200950 ThreadingUDPServer.__init__(self, addr,
951 DelegatingUDPRequestHandler,
952 bind_and_activate)
953 ControlMixin.__init__(self, handler, poll_interval)
954 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100955
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200956 def server_bind(self):
957 super(TestUDPServer, self).server_bind()
958 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100959
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200960 def server_close(self):
961 super(TestUDPServer, self).server_close()
962 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +0100963
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200964if hasattr(socket, "AF_UNIX"):
965 class TestUnixStreamServer(TestTCPServer):
966 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +0100967
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200968 class TestUnixDatagramServer(TestUDPServer):
969 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100970
Vinay Sajip7367d082011-05-02 13:17:27 +0100971# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100972
973class SMTPHandlerTest(BaseTest):
Miss Islington (bot)0a1db322018-07-11 06:56:45 -0700974 # bpo-14314, bpo-19665, bpo-34092: don't wait forever, timeout of 1 minute
975 TIMEOUT = 60.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200976
Vinay Sajipa463d252011-04-30 21:52:48 +0100977 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100978 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800979 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100980 sockmap)
981 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800982 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000983 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
984 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100985 self.assertEqual(h.toaddrs, ['you'])
986 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100987 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100988 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100989 h.handle(r)
Miss Islington (bot)0a1db322018-07-11 06:56:45 -0700990 self.handled.wait(self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100991 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000992 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100993 self.assertEqual(len(self.messages), 1)
994 peer, mailfrom, rcpttos, data = self.messages[0]
995 self.assertEqual(mailfrom, 'me')
996 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100997 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100998 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100999 h.close()
1000
1001 def process_message(self, *args):
1002 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001003 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001004
Christian Heimes180510d2008-03-03 19:15:45 +00001005class MemoryHandlerTest(BaseTest):
1006
1007 """Tests for the MemoryHandler."""
1008
1009 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001010 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001011
1012 def setUp(self):
1013 BaseTest.setUp(self)
1014 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001015 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001016 self.mem_logger = logging.getLogger('mem')
1017 self.mem_logger.propagate = 0
1018 self.mem_logger.addHandler(self.mem_hdlr)
1019
1020 def tearDown(self):
1021 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001022 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001023
1024 def test_flush(self):
1025 # The memory handler flushes to its target handler based on specific
1026 # criteria (message count and message level).
1027 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001028 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001029 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001030 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001031 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001032 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001033 lines = [
1034 ('DEBUG', '1'),
1035 ('INFO', '2'),
1036 ('WARNING', '3'),
1037 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001038 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001039 for n in (4, 14):
1040 for i in range(9):
1041 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001042 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001043 # This will flush because it's the 10th message since the last
1044 # flush.
1045 self.mem_logger.debug(self.next_message())
1046 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001047 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001048
1049 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001050 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001051
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001052 def test_flush_on_close(self):
1053 """
1054 Test that the flush-on-close configuration works as expected.
1055 """
1056 self.mem_logger.debug(self.next_message())
1057 self.assert_log_lines([])
1058 self.mem_logger.info(self.next_message())
1059 self.assert_log_lines([])
1060 self.mem_logger.removeHandler(self.mem_hdlr)
1061 # Default behaviour is to flush on close. Check that it happens.
1062 self.mem_hdlr.close()
1063 lines = [
1064 ('DEBUG', '1'),
1065 ('INFO', '2'),
1066 ]
1067 self.assert_log_lines(lines)
1068 # Now configure for flushing not to be done on close.
1069 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1070 self.root_hdlr,
1071 False)
1072 self.mem_logger.addHandler(self.mem_hdlr)
1073 self.mem_logger.debug(self.next_message())
1074 self.assert_log_lines(lines) # no change
1075 self.mem_logger.info(self.next_message())
1076 self.assert_log_lines(lines) # no change
1077 self.mem_logger.removeHandler(self.mem_hdlr)
1078 self.mem_hdlr.close()
1079 # assert that no new lines have been added
1080 self.assert_log_lines(lines) # no change
1081
Christian Heimes180510d2008-03-03 19:15:45 +00001082
1083class ExceptionFormatter(logging.Formatter):
1084 """A special exception formatter."""
1085 def formatException(self, ei):
1086 return "Got a [%s]" % ei[0].__name__
1087
1088
1089class ConfigFileTest(BaseTest):
1090
1091 """Reading logging config from a .ini-style config file."""
1092
Miss Islington (bot)6f49afc2018-07-02 02:35:09 -07001093 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001094 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001095
1096 # config0 is a standard configuration.
1097 config0 = """
1098 [loggers]
1099 keys=root
1100
1101 [handlers]
1102 keys=hand1
1103
1104 [formatters]
1105 keys=form1
1106
1107 [logger_root]
1108 level=WARNING
1109 handlers=hand1
1110
1111 [handler_hand1]
1112 class=StreamHandler
1113 level=NOTSET
1114 formatter=form1
1115 args=(sys.stdout,)
1116
1117 [formatter_form1]
1118 format=%(levelname)s ++ %(message)s
1119 datefmt=
1120 """
1121
1122 # config1 adds a little to the standard configuration.
1123 config1 = """
1124 [loggers]
1125 keys=root,parser
1126
1127 [handlers]
1128 keys=hand1
1129
1130 [formatters]
1131 keys=form1
1132
1133 [logger_root]
1134 level=WARNING
1135 handlers=
1136
1137 [logger_parser]
1138 level=DEBUG
1139 handlers=hand1
1140 propagate=1
1141 qualname=compiler.parser
1142
1143 [handler_hand1]
1144 class=StreamHandler
1145 level=NOTSET
1146 formatter=form1
1147 args=(sys.stdout,)
1148
1149 [formatter_form1]
1150 format=%(levelname)s ++ %(message)s
1151 datefmt=
1152 """
1153
Vinay Sajip3f84b072011-03-07 17:49:33 +00001154 # config1a moves the handler to the root.
1155 config1a = """
1156 [loggers]
1157 keys=root,parser
1158
1159 [handlers]
1160 keys=hand1
1161
1162 [formatters]
1163 keys=form1
1164
1165 [logger_root]
1166 level=WARNING
1167 handlers=hand1
1168
1169 [logger_parser]
1170 level=DEBUG
1171 handlers=
1172 propagate=1
1173 qualname=compiler.parser
1174
1175 [handler_hand1]
1176 class=StreamHandler
1177 level=NOTSET
1178 formatter=form1
1179 args=(sys.stdout,)
1180
1181 [formatter_form1]
1182 format=%(levelname)s ++ %(message)s
1183 datefmt=
1184 """
1185
Christian Heimes180510d2008-03-03 19:15:45 +00001186 # config2 has a subtle configuration error that should be reported
1187 config2 = config1.replace("sys.stdout", "sys.stbout")
1188
1189 # config3 has a less subtle configuration error
1190 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1191
1192 # config4 specifies a custom formatter class to be loaded
1193 config4 = """
1194 [loggers]
1195 keys=root
1196
1197 [handlers]
1198 keys=hand1
1199
1200 [formatters]
1201 keys=form1
1202
1203 [logger_root]
1204 level=NOTSET
1205 handlers=hand1
1206
1207 [handler_hand1]
1208 class=StreamHandler
1209 level=NOTSET
1210 formatter=form1
1211 args=(sys.stdout,)
1212
1213 [formatter_form1]
1214 class=""" + __name__ + """.ExceptionFormatter
1215 format=%(levelname)s:%(name)s:%(message)s
1216 datefmt=
1217 """
1218
Georg Brandl3dbca812008-07-23 16:10:53 +00001219 # config5 specifies a custom handler class to be loaded
1220 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1221
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001222 # config6 uses ', ' delimiters in the handlers and formatters sections
1223 config6 = """
1224 [loggers]
1225 keys=root,parser
1226
1227 [handlers]
1228 keys=hand1, hand2
1229
1230 [formatters]
1231 keys=form1, form2
1232
1233 [logger_root]
1234 level=WARNING
1235 handlers=
1236
1237 [logger_parser]
1238 level=DEBUG
1239 handlers=hand1
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 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001250 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001251 level=NOTSET
1252 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001253 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001254
1255 [formatter_form1]
1256 format=%(levelname)s ++ %(message)s
1257 datefmt=
1258
1259 [formatter_form2]
1260 format=%(message)s
1261 datefmt=
1262 """
1263
Preston Landers6ea56d22017-08-02 15:44:28 -05001264 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001265 config7 = """
1266 [loggers]
1267 keys=root,parser,compiler
1268
1269 [handlers]
1270 keys=hand1
1271
1272 [formatters]
1273 keys=form1
1274
1275 [logger_root]
1276 level=WARNING
1277 handlers=hand1
1278
1279 [logger_compiler]
1280 level=DEBUG
1281 handlers=
1282 propagate=1
1283 qualname=compiler
1284
1285 [logger_parser]
1286 level=DEBUG
1287 handlers=
1288 propagate=1
1289 qualname=compiler.parser
1290
1291 [handler_hand1]
1292 class=StreamHandler
1293 level=NOTSET
1294 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001295 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001296
1297 [formatter_form1]
1298 format=%(levelname)s ++ %(message)s
1299 datefmt=
1300 """
1301
Miss Islington (bot)6f49afc2018-07-02 02:35:09 -07001302 # config 8, check for resource warning
1303 config8 = r"""
1304 [loggers]
1305 keys=root
1306
1307 [handlers]
1308 keys=file
1309
1310 [formatters]
1311 keys=
1312
1313 [logger_root]
1314 level=DEBUG
1315 handlers=file
1316
1317 [handler_file]
1318 class=FileHandler
1319 level=DEBUG
1320 args=("{tempfile}",)
1321 """
1322
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001323 disable_test = """
1324 [loggers]
1325 keys=root
1326
1327 [handlers]
1328 keys=screen
1329
1330 [formatters]
1331 keys=
1332
1333 [logger_root]
1334 level=DEBUG
1335 handlers=screen
1336
1337 [handler_screen]
1338 level=DEBUG
1339 class=StreamHandler
1340 args=(sys.stdout,)
1341 formatter=
1342 """
1343
1344 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001345 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001346 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001347
1348 def test_config0_ok(self):
1349 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001350 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001351 self.apply_config(self.config0)
1352 logger = logging.getLogger()
1353 # Won't output anything
1354 logger.info(self.next_message())
1355 # Outputs a message
1356 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001357 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001358 ('ERROR', '2'),
1359 ], stream=output)
1360 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001361 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001362
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001363 def test_config0_using_cp_ok(self):
1364 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001365 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001366 file = io.StringIO(textwrap.dedent(self.config0))
1367 cp = configparser.ConfigParser()
1368 cp.read_file(file)
1369 logging.config.fileConfig(cp)
1370 logger = logging.getLogger()
1371 # Won't output anything
1372 logger.info(self.next_message())
1373 # Outputs a message
1374 logger.error(self.next_message())
1375 self.assert_log_lines([
1376 ('ERROR', '2'),
1377 ], stream=output)
1378 # Original logger output is empty.
1379 self.assert_log_lines([])
1380
Georg Brandl3dbca812008-07-23 16:10:53 +00001381 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001382 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001383 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001384 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001385 logger = logging.getLogger("compiler.parser")
1386 # Both will output a message
1387 logger.info(self.next_message())
1388 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001389 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001390 ('INFO', '1'),
1391 ('ERROR', '2'),
1392 ], stream=output)
1393 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001394 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001395
1396 def test_config2_failure(self):
1397 # A simple config file which overrides the default settings.
1398 self.assertRaises(Exception, self.apply_config, self.config2)
1399
1400 def test_config3_failure(self):
1401 # A simple config file which overrides the default settings.
1402 self.assertRaises(Exception, self.apply_config, self.config3)
1403
1404 def test_config4_ok(self):
1405 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001406 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001407 self.apply_config(self.config4)
1408 logger = logging.getLogger()
1409 try:
1410 raise RuntimeError()
1411 except RuntimeError:
1412 logging.exception("just testing")
1413 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001414 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001415 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1416 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001417 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001418
Georg Brandl3dbca812008-07-23 16:10:53 +00001419 def test_config5_ok(self):
1420 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001421
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001422 def test_config6_ok(self):
1423 self.test_config1_ok(config=self.config6)
1424
Vinay Sajip3f84b072011-03-07 17:49:33 +00001425 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001426 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001427 self.apply_config(self.config1a)
1428 logger = logging.getLogger("compiler.parser")
1429 # See issue #11424. compiler-hyphenated sorts
1430 # between compiler and compiler.xyz and this
1431 # was preventing compiler.xyz from being included
1432 # in the child loggers of compiler because of an
1433 # overzealous loop termination condition.
1434 hyphenated = logging.getLogger('compiler-hyphenated')
1435 # All will output a message
1436 logger.info(self.next_message())
1437 logger.error(self.next_message())
1438 hyphenated.critical(self.next_message())
1439 self.assert_log_lines([
1440 ('INFO', '1'),
1441 ('ERROR', '2'),
1442 ('CRITICAL', '3'),
1443 ], stream=output)
1444 # Original logger output is empty.
1445 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001446 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001447 self.apply_config(self.config7)
1448 logger = logging.getLogger("compiler.parser")
1449 self.assertFalse(logger.disabled)
1450 # Both will output a message
1451 logger.info(self.next_message())
1452 logger.error(self.next_message())
1453 logger = logging.getLogger("compiler.lexer")
1454 # Both will output a message
1455 logger.info(self.next_message())
1456 logger.error(self.next_message())
1457 # Will not appear
1458 hyphenated.critical(self.next_message())
1459 self.assert_log_lines([
1460 ('INFO', '4'),
1461 ('ERROR', '5'),
1462 ('INFO', '6'),
1463 ('ERROR', '7'),
1464 ], stream=output)
1465 # Original logger output is empty.
1466 self.assert_log_lines([])
1467
Miss Islington (bot)6f49afc2018-07-02 02:35:09 -07001468 def test_config8_ok(self):
1469
1470 def cleanup(h1, fn):
1471 h1.close()
1472 os.remove(fn)
1473
1474 with self.check_no_resource_warning():
1475 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1476 os.close(fd)
1477
1478 # Replace single backslash with double backslash in windows
1479 # to avoid unicode error during string formatting
1480 if os.name == "nt":
1481 fn = fn.replace("\\", "\\\\")
1482
1483 config8 = self.config8.format(tempfile=fn)
1484
1485 self.apply_config(config8)
1486 self.apply_config(config8)
1487
1488 handler = logging.root.handlers[0]
1489 self.addCleanup(cleanup, handler, fn)
1490
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001491 def test_logger_disabling(self):
1492 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001493 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001494 self.assertFalse(logger.disabled)
1495 self.apply_config(self.disable_test)
1496 self.assertTrue(logger.disabled)
1497 self.apply_config(self.disable_test, disable_existing_loggers=False)
1498 self.assertFalse(logger.disabled)
1499
Miss Islington (bot)f44203d2018-06-08 07:01:56 -07001500 def test_defaults_do_no_interpolation(self):
1501 """bpo-33802 defaults should not get interpolated"""
1502 ini = textwrap.dedent("""
1503 [formatters]
1504 keys=default
1505
1506 [formatter_default]
1507
1508 [handlers]
1509 keys=console
1510
1511 [handler_console]
1512 class=logging.StreamHandler
1513 args=tuple()
1514
1515 [loggers]
1516 keys=root
1517
1518 [logger_root]
1519 formatter=default
1520 handlers=console
1521 """).strip()
1522 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1523 try:
1524 os.write(fd, ini.encode('ascii'))
1525 os.close(fd)
1526 logging.config.fileConfig(
1527 fn,
1528 defaults=dict(
1529 version=1,
1530 disable_existing_loggers=False,
1531 formatters={
1532 "generic": {
1533 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1534 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1535 "class": "logging.Formatter"
1536 },
1537 },
1538 )
1539 )
1540 finally:
1541 os.unlink(fn)
1542
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001543
Christian Heimes180510d2008-03-03 19:15:45 +00001544class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001545
Christian Heimes180510d2008-03-03 19:15:45 +00001546 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001547
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001548 server_class = TestTCPServer
1549 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001550
Christian Heimes180510d2008-03-03 19:15:45 +00001551 def setUp(self):
1552 """Set up a TCP server to receive log messages, and a SocketHandler
1553 pointing to that server's address and port."""
1554 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001555 # Issue #29177: deal with errors that happen during setup
1556 self.server = self.sock_hdlr = self.server_exception = None
1557 try:
1558 self.server = server = self.server_class(self.address,
1559 self.handle_socket, 0.01)
1560 server.start()
1561 # Uncomment next line to test error recovery in setUp()
1562 # raise OSError('dummy error raised')
1563 except OSError as e:
1564 self.server_exception = e
1565 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001567 hcls = logging.handlers.SocketHandler
1568 if isinstance(server.server_address, tuple):
1569 self.sock_hdlr = hcls('localhost', server.port)
1570 else:
1571 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001572 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001573 self.root_logger.removeHandler(self.root_logger.handlers[0])
1574 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001575 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001576
Christian Heimes180510d2008-03-03 19:15:45 +00001577 def tearDown(self):
1578 """Shutdown the TCP server."""
1579 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001580 if self.sock_hdlr:
1581 self.root_logger.removeHandler(self.sock_hdlr)
1582 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001583 if self.server:
1584 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001585 finally:
1586 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001587
Vinay Sajip7367d082011-05-02 13:17:27 +01001588 def handle_socket(self, request):
1589 conn = request.connection
1590 while True:
1591 chunk = conn.recv(4)
1592 if len(chunk) < 4:
1593 break
1594 slen = struct.unpack(">L", chunk)[0]
1595 chunk = conn.recv(slen)
1596 while len(chunk) < slen:
1597 chunk = chunk + conn.recv(slen - len(chunk))
1598 obj = pickle.loads(chunk)
1599 record = logging.makeLogRecord(obj)
1600 self.log_output += record.msg + '\n'
1601 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001602
Christian Heimes180510d2008-03-03 19:15:45 +00001603 def test_output(self):
1604 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001605 if self.server_exception:
1606 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001607 logger = logging.getLogger("tcp")
1608 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001609 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001610 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001611 self.handled.acquire()
1612 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001613
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001614 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001615 if self.server_exception:
1616 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001617 # Avoid timing-related failures due to SocketHandler's own hard-wired
1618 # one-second timeout on socket.create_connection() (issue #16264).
1619 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001620 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001621 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001622 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001623 try:
1624 raise RuntimeError('Deliberate mistake')
1625 except RuntimeError:
1626 self.root_logger.exception('Never sent')
1627 self.root_logger.error('Never sent, either')
1628 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001629 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001630 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1631 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001632
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001633def _get_temp_domain_socket():
1634 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1635 os.close(fd)
1636 # just need a name - file can't be present, or we'll get an
1637 # 'address already in use' error.
1638 os.remove(fn)
1639 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001640
Victor Stinnerec5a8602014-06-02 14:41:51 +02001641@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001642class UnixSocketHandlerTest(SocketHandlerTest):
1643
1644 """Test for SocketHandler with unix sockets."""
1645
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001646 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001647 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001648
1649 def setUp(self):
1650 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001651 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001652 SocketHandlerTest.setUp(self)
1653
1654 def tearDown(self):
1655 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001656 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001657
Vinay Sajip7367d082011-05-02 13:17:27 +01001658class DatagramHandlerTest(BaseTest):
1659
1660 """Test for DatagramHandler."""
1661
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001662 server_class = TestUDPServer
1663 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001664
Vinay Sajip7367d082011-05-02 13:17:27 +01001665 def setUp(self):
1666 """Set up a UDP server to receive log messages, and a DatagramHandler
1667 pointing to that server's address and port."""
1668 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001669 # Issue #29177: deal with errors that happen during setup
1670 self.server = self.sock_hdlr = self.server_exception = None
1671 try:
1672 self.server = server = self.server_class(self.address,
1673 self.handle_datagram, 0.01)
1674 server.start()
1675 # Uncomment next line to test error recovery in setUp()
1676 # raise OSError('dummy error raised')
1677 except OSError as e:
1678 self.server_exception = e
1679 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001680 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001681 hcls = logging.handlers.DatagramHandler
1682 if isinstance(server.server_address, tuple):
1683 self.sock_hdlr = hcls('localhost', server.port)
1684 else:
1685 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001686 self.log_output = ''
1687 self.root_logger.removeHandler(self.root_logger.handlers[0])
1688 self.root_logger.addHandler(self.sock_hdlr)
1689 self.handled = threading.Event()
1690
1691 def tearDown(self):
1692 """Shutdown the UDP server."""
1693 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001694 if self.server:
1695 self.server.stop(2.0)
1696 if self.sock_hdlr:
1697 self.root_logger.removeHandler(self.sock_hdlr)
1698 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001699 finally:
1700 BaseTest.tearDown(self)
1701
1702 def handle_datagram(self, request):
1703 slen = struct.pack('>L', 0) # length of prefix
1704 packet = request.packet[len(slen):]
1705 obj = pickle.loads(packet)
1706 record = logging.makeLogRecord(obj)
1707 self.log_output += record.msg + '\n'
1708 self.handled.set()
1709
1710 def test_output(self):
1711 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001712 if self.server_exception:
1713 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001714 logger = logging.getLogger("udp")
1715 logger.error("spam")
1716 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001717 self.handled.clear()
1718 logger.error("eggs")
1719 self.handled.wait()
1720 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001721
Victor Stinnerec5a8602014-06-02 14:41:51 +02001722@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001723class UnixDatagramHandlerTest(DatagramHandlerTest):
1724
1725 """Test for DatagramHandler using Unix sockets."""
1726
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001727 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001728 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001729
1730 def setUp(self):
1731 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001732 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001733 DatagramHandlerTest.setUp(self)
1734
1735 def tearDown(self):
1736 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001737 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001738
Vinay Sajip7367d082011-05-02 13:17:27 +01001739class SysLogHandlerTest(BaseTest):
1740
1741 """Test for SysLogHandler using UDP."""
1742
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001743 server_class = TestUDPServer
1744 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001745
Vinay Sajip7367d082011-05-02 13:17:27 +01001746 def setUp(self):
1747 """Set up a UDP server to receive log messages, and a SysLogHandler
1748 pointing to that server's address and port."""
1749 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001750 # Issue #29177: deal with errors that happen during setup
1751 self.server = self.sl_hdlr = self.server_exception = None
1752 try:
1753 self.server = server = self.server_class(self.address,
1754 self.handle_datagram, 0.01)
1755 server.start()
1756 # Uncomment next line to test error recovery in setUp()
1757 # raise OSError('dummy error raised')
1758 except OSError as e:
1759 self.server_exception = e
1760 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001761 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001762 hcls = logging.handlers.SysLogHandler
1763 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001764 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001765 else:
1766 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001767 self.log_output = ''
1768 self.root_logger.removeHandler(self.root_logger.handlers[0])
1769 self.root_logger.addHandler(self.sl_hdlr)
1770 self.handled = threading.Event()
1771
1772 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001773 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001774 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001775 if self.server:
1776 self.server.stop(2.0)
1777 if self.sl_hdlr:
1778 self.root_logger.removeHandler(self.sl_hdlr)
1779 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001780 finally:
1781 BaseTest.tearDown(self)
1782
1783 def handle_datagram(self, request):
1784 self.log_output = request.packet
1785 self.handled.set()
1786
1787 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001788 if self.server_exception:
1789 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001790 # The log message sent to the SysLogHandler is properly received.
1791 logger = logging.getLogger("slh")
1792 logger.error("sp\xe4m")
1793 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001794 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001795 self.handled.clear()
1796 self.sl_hdlr.append_nul = False
1797 logger.error("sp\xe4m")
1798 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001799 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001800 self.handled.clear()
1801 self.sl_hdlr.ident = "h\xe4m-"
1802 logger.error("sp\xe4m")
1803 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001804 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001805
Victor Stinnerec5a8602014-06-02 14:41:51 +02001806@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001807class UnixSysLogHandlerTest(SysLogHandlerTest):
1808
1809 """Test for SysLogHandler with Unix sockets."""
1810
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001811 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001812 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001813
1814 def setUp(self):
1815 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001816 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001817 SysLogHandlerTest.setUp(self)
1818
1819 def tearDown(self):
1820 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001821 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001822
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001823@unittest.skipUnless(support.IPV6_ENABLED,
1824 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001825class IPv6SysLogHandlerTest(SysLogHandlerTest):
1826
1827 """Test for SysLogHandler with IPv6 host."""
1828
1829 server_class = TestUDPServer
1830 address = ('::1', 0)
1831
1832 def setUp(self):
1833 self.server_class.address_family = socket.AF_INET6
1834 super(IPv6SysLogHandlerTest, self).setUp()
1835
1836 def tearDown(self):
1837 self.server_class.address_family = socket.AF_INET
1838 super(IPv6SysLogHandlerTest, self).tearDown()
1839
Vinay Sajip7367d082011-05-02 13:17:27 +01001840class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001841 """Test for HTTPHandler."""
1842
1843 def setUp(self):
1844 """Set up an HTTP server to receive log messages, and a HTTPHandler
1845 pointing to that server's address and port."""
1846 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001847 self.handled = threading.Event()
1848
Vinay Sajip7367d082011-05-02 13:17:27 +01001849 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001850 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001851 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001852 if self.command == 'POST':
1853 try:
1854 rlen = int(request.headers['Content-Length'])
1855 self.post_data = request.rfile.read(rlen)
1856 except:
1857 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001858 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001859 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001860 self.handled.set()
1861
1862 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001863 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001864 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001865 root_logger = self.root_logger
1866 root_logger.removeHandler(self.root_logger.handlers[0])
1867 for secure in (False, True):
1868 addr = ('localhost', 0)
1869 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001870 try:
1871 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001872 except ImportError:
1873 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001874 else:
1875 here = os.path.dirname(__file__)
1876 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001877 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001878 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001879
1880 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001881 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001882 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001883 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001884 self.server = server = TestHTTPServer(addr, self.handle_request,
1885 0.01, sslctx=sslctx)
1886 server.start()
1887 server.ready.wait()
1888 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001889 secure_client = secure and sslctx
1890 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001891 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001892 context=context,
1893 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001894 self.log_data = None
1895 root_logger.addHandler(self.h_hdlr)
1896
1897 for method in ('GET', 'POST'):
1898 self.h_hdlr.method = method
1899 self.handled.clear()
1900 msg = "sp\xe4m"
1901 logger.error(msg)
1902 self.handled.wait()
1903 self.assertEqual(self.log_data.path, '/frob')
1904 self.assertEqual(self.command, method)
1905 if method == 'GET':
1906 d = parse_qs(self.log_data.query)
1907 else:
1908 d = parse_qs(self.post_data.decode('utf-8'))
1909 self.assertEqual(d['name'], ['http'])
1910 self.assertEqual(d['funcName'], ['test_output'])
1911 self.assertEqual(d['msg'], [msg])
1912
1913 self.server.stop(2.0)
1914 self.root_logger.removeHandler(self.h_hdlr)
1915 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001916
Christian Heimes180510d2008-03-03 19:15:45 +00001917class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001918
Christian Heimes180510d2008-03-03 19:15:45 +00001919 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001920
Christian Heimes180510d2008-03-03 19:15:45 +00001921 def setUp(self):
1922 """Create a dict to remember potentially destroyed objects."""
1923 BaseTest.setUp(self)
1924 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001925
Christian Heimes180510d2008-03-03 19:15:45 +00001926 def _watch_for_survival(self, *args):
1927 """Watch the given objects for survival, by creating weakrefs to
1928 them."""
1929 for obj in args:
1930 key = id(obj), repr(obj)
1931 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001932
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001933 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001934 """Assert that all objects watched for survival have survived."""
1935 # Trigger cycle breaking.
1936 gc.collect()
1937 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001938 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001939 if ref() is None:
1940 dead.append(repr_)
1941 if dead:
1942 self.fail("%d objects should have survived "
1943 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001944
Christian Heimes180510d2008-03-03 19:15:45 +00001945 def test_persistent_loggers(self):
1946 # Logger objects are persistent and retain their configuration, even
1947 # if visible references are destroyed.
1948 self.root_logger.setLevel(logging.INFO)
1949 foo = logging.getLogger("foo")
1950 self._watch_for_survival(foo)
1951 foo.setLevel(logging.DEBUG)
1952 self.root_logger.debug(self.next_message())
1953 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001954 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001955 ('foo', 'DEBUG', '2'),
1956 ])
1957 del foo
1958 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001959 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001960 # foo has retained its settings.
1961 bar = logging.getLogger("foo")
1962 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001963 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001964 ('foo', 'DEBUG', '2'),
1965 ('foo', 'DEBUG', '3'),
1966 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001967
Benjamin Petersonf91df042009-02-13 02:50:59 +00001968
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001969class EncodingTest(BaseTest):
1970 def test_encoding_plain_file(self):
1971 # In Python 2.x, a plain file object is treated as having no encoding.
1972 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001973 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1974 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001975 # the non-ascii data we write to the log.
1976 data = "foo\x80"
1977 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001978 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001979 log.addHandler(handler)
1980 try:
1981 # write non-ascii data to the log.
1982 log.warning(data)
1983 finally:
1984 log.removeHandler(handler)
1985 handler.close()
1986 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001987 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001988 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001989 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001990 finally:
1991 f.close()
1992 finally:
1993 if os.path.isfile(fn):
1994 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001995
Benjamin Petersonf91df042009-02-13 02:50:59 +00001996 def test_encoding_cyrillic_unicode(self):
1997 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03001998 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00001999 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03002000 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00002001 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00002002 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00002003 stream = io.BytesIO()
2004 writer = writer_class(stream, 'strict')
2005 handler = logging.StreamHandler(writer)
2006 log.addHandler(handler)
2007 try:
2008 log.warning(message)
2009 finally:
2010 log.removeHandler(handler)
2011 handler.close()
2012 # check we wrote exactly those bytes, ignoring trailing \n etc
2013 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03002014 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00002015 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
2016
2017
Georg Brandlf9734072008-12-07 15:30:06 +00002018class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00002019
Georg Brandlf9734072008-12-07 15:30:06 +00002020 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00002021 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00002022 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002023 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002024 warnings.filterwarnings("always", category=UserWarning)
2025 stream = io.StringIO()
2026 h = logging.StreamHandler(stream)
2027 logger = logging.getLogger("py.warnings")
2028 logger.addHandler(h)
2029 warnings.warn("I'm warning you...")
2030 logger.removeHandler(h)
2031 s = stream.getvalue()
2032 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002033 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00002034
Mike53f7a7c2017-12-14 14:04:53 +03002035 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002036 a_file = io.StringIO()
2037 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
2038 a_file, "Dummy line")
2039 s = a_file.getvalue()
2040 a_file.close()
2041 self.assertEqual(s,
2042 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
2043
2044 def test_warnings_no_handlers(self):
2045 with warnings.catch_warnings():
2046 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002047 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002048
2049 # confirm our assumption: no loggers are set
2050 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002051 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002052
2053 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002054 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002055 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002056
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002057
2058def formatFunc(format, datefmt=None):
2059 return logging.Formatter(format, datefmt)
2060
2061def handlerFunc():
2062 return logging.StreamHandler()
2063
2064class CustomHandler(logging.StreamHandler):
2065 pass
2066
2067class ConfigDictTest(BaseTest):
2068
2069 """Reading logging config from a dictionary."""
2070
Miss Islington (bot)6f49afc2018-07-02 02:35:09 -07002071 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002072 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002073
2074 # config0 is a standard configuration.
2075 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002076 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002077 'formatters': {
2078 'form1' : {
2079 'format' : '%(levelname)s ++ %(message)s',
2080 },
2081 },
2082 'handlers' : {
2083 'hand1' : {
2084 'class' : 'logging.StreamHandler',
2085 'formatter' : 'form1',
2086 'level' : 'NOTSET',
2087 'stream' : 'ext://sys.stdout',
2088 },
2089 },
2090 'root' : {
2091 'level' : 'WARNING',
2092 'handlers' : ['hand1'],
2093 },
2094 }
2095
2096 # config1 adds a little to the standard configuration.
2097 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002098 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002099 'formatters': {
2100 'form1' : {
2101 'format' : '%(levelname)s ++ %(message)s',
2102 },
2103 },
2104 'handlers' : {
2105 'hand1' : {
2106 'class' : 'logging.StreamHandler',
2107 'formatter' : 'form1',
2108 'level' : 'NOTSET',
2109 'stream' : 'ext://sys.stdout',
2110 },
2111 },
2112 'loggers' : {
2113 'compiler.parser' : {
2114 'level' : 'DEBUG',
2115 'handlers' : ['hand1'],
2116 },
2117 },
2118 'root' : {
2119 'level' : 'WARNING',
2120 },
2121 }
2122
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002123 # config1a moves the handler to the root. Used with config8a
2124 config1a = {
2125 'version': 1,
2126 'formatters': {
2127 'form1' : {
2128 'format' : '%(levelname)s ++ %(message)s',
2129 },
2130 },
2131 'handlers' : {
2132 'hand1' : {
2133 'class' : 'logging.StreamHandler',
2134 'formatter' : 'form1',
2135 'level' : 'NOTSET',
2136 'stream' : 'ext://sys.stdout',
2137 },
2138 },
2139 'loggers' : {
2140 'compiler.parser' : {
2141 'level' : 'DEBUG',
2142 },
2143 },
2144 'root' : {
2145 'level' : 'WARNING',
2146 'handlers' : ['hand1'],
2147 },
2148 }
2149
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002150 # config2 has a subtle configuration error that should be reported
2151 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002152 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002153 'formatters': {
2154 'form1' : {
2155 'format' : '%(levelname)s ++ %(message)s',
2156 },
2157 },
2158 'handlers' : {
2159 'hand1' : {
2160 'class' : 'logging.StreamHandler',
2161 'formatter' : 'form1',
2162 'level' : 'NOTSET',
2163 'stream' : 'ext://sys.stdbout',
2164 },
2165 },
2166 'loggers' : {
2167 'compiler.parser' : {
2168 'level' : 'DEBUG',
2169 'handlers' : ['hand1'],
2170 },
2171 },
2172 'root' : {
2173 'level' : 'WARNING',
2174 },
2175 }
2176
Mike53f7a7c2017-12-14 14:04:53 +03002177 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002178 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002179 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002180 'formatters': {
2181 'form1' : {
2182 'format' : '%(levelname)s ++ %(message)s',
2183 },
2184 },
2185 'handlers' : {
2186 'hand1' : {
2187 'class' : 'logging.StreamHandler',
2188 'formatter' : 'form1',
2189 'level' : 'NTOSET',
2190 'stream' : 'ext://sys.stdout',
2191 },
2192 },
2193 'loggers' : {
2194 'compiler.parser' : {
2195 'level' : 'DEBUG',
2196 'handlers' : ['hand1'],
2197 },
2198 },
2199 'root' : {
2200 'level' : 'WARNING',
2201 },
2202 }
2203
2204
Mike53f7a7c2017-12-14 14:04:53 +03002205 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002206 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002207 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002208 'formatters': {
2209 'form1' : {
2210 'format' : '%(levelname)s ++ %(message)s',
2211 },
2212 },
2213 'handlers' : {
2214 'hand1' : {
2215 'class' : 'logging.StreamHandler',
2216 'formatter' : 'form1',
2217 'level' : 'NOTSET',
2218 'stream' : 'ext://sys.stdout',
2219 },
2220 },
2221 'loggers' : {
2222 'compiler.parser' : {
2223 'level' : 'DEBUG',
2224 'handlers' : ['hand1'],
2225 },
2226 },
2227 'root' : {
2228 'level' : 'WRANING',
2229 },
2230 }
2231
2232 # config3 has a less subtle configuration error
2233 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002234 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002235 'formatters': {
2236 'form1' : {
2237 'format' : '%(levelname)s ++ %(message)s',
2238 },
2239 },
2240 'handlers' : {
2241 'hand1' : {
2242 'class' : 'logging.StreamHandler',
2243 'formatter' : 'misspelled_name',
2244 'level' : 'NOTSET',
2245 'stream' : 'ext://sys.stdout',
2246 },
2247 },
2248 'loggers' : {
2249 'compiler.parser' : {
2250 'level' : 'DEBUG',
2251 'handlers' : ['hand1'],
2252 },
2253 },
2254 'root' : {
2255 'level' : 'WARNING',
2256 },
2257 }
2258
2259 # config4 specifies a custom formatter class to be loaded
2260 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002261 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002262 'formatters': {
2263 'form1' : {
2264 '()' : __name__ + '.ExceptionFormatter',
2265 'format' : '%(levelname)s:%(name)s:%(message)s',
2266 },
2267 },
2268 'handlers' : {
2269 'hand1' : {
2270 'class' : 'logging.StreamHandler',
2271 'formatter' : 'form1',
2272 'level' : 'NOTSET',
2273 'stream' : 'ext://sys.stdout',
2274 },
2275 },
2276 'root' : {
2277 'level' : 'NOTSET',
2278 'handlers' : ['hand1'],
2279 },
2280 }
2281
2282 # As config4 but using an actual callable rather than a string
2283 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002284 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002285 'formatters': {
2286 'form1' : {
2287 '()' : ExceptionFormatter,
2288 'format' : '%(levelname)s:%(name)s:%(message)s',
2289 },
2290 'form2' : {
2291 '()' : __name__ + '.formatFunc',
2292 'format' : '%(levelname)s:%(name)s:%(message)s',
2293 },
2294 'form3' : {
2295 '()' : formatFunc,
2296 'format' : '%(levelname)s:%(name)s:%(message)s',
2297 },
2298 },
2299 'handlers' : {
2300 'hand1' : {
2301 'class' : 'logging.StreamHandler',
2302 'formatter' : 'form1',
2303 'level' : 'NOTSET',
2304 'stream' : 'ext://sys.stdout',
2305 },
2306 'hand2' : {
2307 '()' : handlerFunc,
2308 },
2309 },
2310 'root' : {
2311 'level' : 'NOTSET',
2312 'handlers' : ['hand1'],
2313 },
2314 }
2315
2316 # config5 specifies a custom handler class to be loaded
2317 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002318 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002319 'formatters': {
2320 'form1' : {
2321 'format' : '%(levelname)s ++ %(message)s',
2322 },
2323 },
2324 'handlers' : {
2325 'hand1' : {
2326 'class' : __name__ + '.CustomHandler',
2327 'formatter' : 'form1',
2328 'level' : 'NOTSET',
2329 'stream' : 'ext://sys.stdout',
2330 },
2331 },
2332 'loggers' : {
2333 'compiler.parser' : {
2334 'level' : 'DEBUG',
2335 'handlers' : ['hand1'],
2336 },
2337 },
2338 'root' : {
2339 'level' : 'WARNING',
2340 },
2341 }
2342
2343 # config6 specifies a custom handler class to be loaded
2344 # but has bad arguments
2345 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002346 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002347 'formatters': {
2348 'form1' : {
2349 'format' : '%(levelname)s ++ %(message)s',
2350 },
2351 },
2352 'handlers' : {
2353 'hand1' : {
2354 'class' : __name__ + '.CustomHandler',
2355 'formatter' : 'form1',
2356 'level' : 'NOTSET',
2357 'stream' : 'ext://sys.stdout',
2358 '9' : 'invalid parameter name',
2359 },
2360 },
2361 'loggers' : {
2362 'compiler.parser' : {
2363 'level' : 'DEBUG',
2364 'handlers' : ['hand1'],
2365 },
2366 },
2367 'root' : {
2368 'level' : 'WARNING',
2369 },
2370 }
2371
Mike53f7a7c2017-12-14 14:04:53 +03002372 # config 7 does not define compiler.parser but defines compiler.lexer
2373 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002374 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002375 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002376 'formatters': {
2377 'form1' : {
2378 'format' : '%(levelname)s ++ %(message)s',
2379 },
2380 },
2381 'handlers' : {
2382 'hand1' : {
2383 'class' : 'logging.StreamHandler',
2384 'formatter' : 'form1',
2385 'level' : 'NOTSET',
2386 'stream' : 'ext://sys.stdout',
2387 },
2388 },
2389 'loggers' : {
2390 'compiler.lexer' : {
2391 'level' : 'DEBUG',
2392 'handlers' : ['hand1'],
2393 },
2394 },
2395 'root' : {
2396 'level' : 'WARNING',
2397 },
2398 }
2399
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002400 # config8 defines both compiler and compiler.lexer
2401 # so compiler.parser should not be disabled (since
2402 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002403 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002404 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002405 'disable_existing_loggers' : False,
2406 'formatters': {
2407 'form1' : {
2408 'format' : '%(levelname)s ++ %(message)s',
2409 },
2410 },
2411 'handlers' : {
2412 'hand1' : {
2413 'class' : 'logging.StreamHandler',
2414 'formatter' : 'form1',
2415 'level' : 'NOTSET',
2416 'stream' : 'ext://sys.stdout',
2417 },
2418 },
2419 'loggers' : {
2420 'compiler' : {
2421 'level' : 'DEBUG',
2422 'handlers' : ['hand1'],
2423 },
2424 'compiler.lexer' : {
2425 },
2426 },
2427 'root' : {
2428 'level' : 'WARNING',
2429 },
2430 }
2431
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002432 # config8a disables existing loggers
2433 config8a = {
2434 'version': 1,
2435 'disable_existing_loggers' : True,
2436 'formatters': {
2437 'form1' : {
2438 'format' : '%(levelname)s ++ %(message)s',
2439 },
2440 },
2441 'handlers' : {
2442 'hand1' : {
2443 'class' : 'logging.StreamHandler',
2444 'formatter' : 'form1',
2445 'level' : 'NOTSET',
2446 'stream' : 'ext://sys.stdout',
2447 },
2448 },
2449 'loggers' : {
2450 'compiler' : {
2451 'level' : 'DEBUG',
2452 'handlers' : ['hand1'],
2453 },
2454 'compiler.lexer' : {
2455 },
2456 },
2457 'root' : {
2458 'level' : 'WARNING',
2459 },
2460 }
2461
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002462 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002463 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002464 'formatters': {
2465 'form1' : {
2466 'format' : '%(levelname)s ++ %(message)s',
2467 },
2468 },
2469 'handlers' : {
2470 'hand1' : {
2471 'class' : 'logging.StreamHandler',
2472 'formatter' : 'form1',
2473 'level' : 'WARNING',
2474 'stream' : 'ext://sys.stdout',
2475 },
2476 },
2477 'loggers' : {
2478 'compiler.parser' : {
2479 'level' : 'WARNING',
2480 'handlers' : ['hand1'],
2481 },
2482 },
2483 'root' : {
2484 'level' : 'NOTSET',
2485 },
2486 }
2487
2488 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002489 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002490 'incremental' : True,
2491 'handlers' : {
2492 'hand1' : {
2493 'level' : 'WARNING',
2494 },
2495 },
2496 'loggers' : {
2497 'compiler.parser' : {
2498 'level' : 'INFO',
2499 },
2500 },
2501 }
2502
2503 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002504 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002505 'incremental' : True,
2506 'handlers' : {
2507 'hand1' : {
2508 'level' : 'INFO',
2509 },
2510 },
2511 'loggers' : {
2512 'compiler.parser' : {
2513 'level' : 'INFO',
2514 },
2515 },
2516 }
2517
Mike53f7a7c2017-12-14 14:04:53 +03002518 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002519 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002520 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002521 'formatters': {
2522 'form1' : {
2523 'format' : '%(levelname)s ++ %(message)s',
2524 },
2525 },
2526 'filters' : {
2527 'filt1' : {
2528 'name' : 'compiler.parser',
2529 },
2530 },
2531 'handlers' : {
2532 'hand1' : {
2533 'class' : 'logging.StreamHandler',
2534 'formatter' : 'form1',
2535 'level' : 'NOTSET',
2536 'stream' : 'ext://sys.stdout',
2537 'filters' : ['filt1'],
2538 },
2539 },
2540 'loggers' : {
2541 'compiler.parser' : {
2542 'level' : 'DEBUG',
2543 'filters' : ['filt1'],
2544 },
2545 },
2546 'root' : {
2547 'level' : 'WARNING',
2548 'handlers' : ['hand1'],
2549 },
2550 }
2551
Mike53f7a7c2017-12-14 14:04:53 +03002552 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002553 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002554 'version': 1,
2555 'true_formatters': {
2556 'form1' : {
2557 'format' : '%(levelname)s ++ %(message)s',
2558 },
2559 },
2560 'handler_configs': {
2561 'hand1' : {
2562 'class' : 'logging.StreamHandler',
2563 'formatter' : 'form1',
2564 'level' : 'NOTSET',
2565 'stream' : 'ext://sys.stdout',
2566 },
2567 },
2568 'formatters' : 'cfg://true_formatters',
2569 'handlers' : {
2570 'hand1' : 'cfg://handler_configs[hand1]',
2571 },
2572 'loggers' : {
2573 'compiler.parser' : {
2574 'level' : 'DEBUG',
2575 'handlers' : ['hand1'],
2576 },
2577 },
2578 'root' : {
2579 'level' : 'WARNING',
2580 },
2581 }
2582
Mike53f7a7c2017-12-14 14:04:53 +03002583 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002584 config12 = {
2585 'true_formatters': {
2586 'form1' : {
2587 'format' : '%(levelname)s ++ %(message)s',
2588 },
2589 },
2590 'handler_configs': {
2591 'hand1' : {
2592 'class' : 'logging.StreamHandler',
2593 'formatter' : 'form1',
2594 'level' : 'NOTSET',
2595 'stream' : 'ext://sys.stdout',
2596 },
2597 },
2598 'formatters' : 'cfg://true_formatters',
2599 'handlers' : {
2600 'hand1' : 'cfg://handler_configs[hand1]',
2601 },
2602 'loggers' : {
2603 'compiler.parser' : {
2604 'level' : 'DEBUG',
2605 'handlers' : ['hand1'],
2606 },
2607 },
2608 'root' : {
2609 'level' : 'WARNING',
2610 },
2611 }
2612
Mike53f7a7c2017-12-14 14:04:53 +03002613 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002614 config13 = {
2615 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002616 'true_formatters': {
2617 'form1' : {
2618 'format' : '%(levelname)s ++ %(message)s',
2619 },
2620 },
2621 'handler_configs': {
2622 'hand1' : {
2623 'class' : 'logging.StreamHandler',
2624 'formatter' : 'form1',
2625 'level' : 'NOTSET',
2626 'stream' : 'ext://sys.stdout',
2627 },
2628 },
2629 'formatters' : 'cfg://true_formatters',
2630 'handlers' : {
2631 'hand1' : 'cfg://handler_configs[hand1]',
2632 },
2633 'loggers' : {
2634 'compiler.parser' : {
2635 'level' : 'DEBUG',
2636 'handlers' : ['hand1'],
2637 },
2638 },
2639 'root' : {
2640 'level' : 'WARNING',
2641 },
2642 }
2643
Vinay Sajip8d270232012-11-15 14:20:18 +00002644 # As config0, but with properties
2645 config14 = {
2646 'version': 1,
2647 'formatters': {
2648 'form1' : {
2649 'format' : '%(levelname)s ++ %(message)s',
2650 },
2651 },
2652 'handlers' : {
2653 'hand1' : {
2654 'class' : 'logging.StreamHandler',
2655 'formatter' : 'form1',
2656 'level' : 'NOTSET',
2657 'stream' : 'ext://sys.stdout',
2658 '.': {
2659 'foo': 'bar',
2660 'terminator': '!\n',
2661 }
2662 },
2663 },
2664 'root' : {
2665 'level' : 'WARNING',
2666 'handlers' : ['hand1'],
2667 },
2668 }
2669
Vinay Sajip3f885b52013-03-22 15:19:54 +00002670 out_of_order = {
2671 "version": 1,
2672 "formatters": {
2673 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002674 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2675 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002676 }
2677 },
2678 "handlers": {
2679 "fileGlobal": {
2680 "class": "logging.StreamHandler",
2681 "level": "DEBUG",
2682 "formatter": "mySimpleFormatter"
2683 },
2684 "bufferGlobal": {
2685 "class": "logging.handlers.MemoryHandler",
2686 "capacity": 5,
2687 "formatter": "mySimpleFormatter",
2688 "target": "fileGlobal",
2689 "level": "DEBUG"
2690 }
2691 },
2692 "loggers": {
2693 "mymodule": {
2694 "level": "DEBUG",
2695 "handlers": ["bufferGlobal"],
2696 "propagate": "true"
2697 }
2698 }
2699 }
2700
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002701 def apply_config(self, conf):
2702 logging.config.dictConfig(conf)
2703
2704 def test_config0_ok(self):
2705 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002706 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002707 self.apply_config(self.config0)
2708 logger = logging.getLogger()
2709 # Won't output anything
2710 logger.info(self.next_message())
2711 # Outputs a message
2712 logger.error(self.next_message())
2713 self.assert_log_lines([
2714 ('ERROR', '2'),
2715 ], stream=output)
2716 # Original logger output is empty.
2717 self.assert_log_lines([])
2718
2719 def test_config1_ok(self, config=config1):
2720 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002721 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002722 self.apply_config(config)
2723 logger = logging.getLogger("compiler.parser")
2724 # Both will output a message
2725 logger.info(self.next_message())
2726 logger.error(self.next_message())
2727 self.assert_log_lines([
2728 ('INFO', '1'),
2729 ('ERROR', '2'),
2730 ], stream=output)
2731 # Original logger output is empty.
2732 self.assert_log_lines([])
2733
2734 def test_config2_failure(self):
2735 # A simple config which overrides the default settings.
2736 self.assertRaises(Exception, self.apply_config, self.config2)
2737
2738 def test_config2a_failure(self):
2739 # A simple config which overrides the default settings.
2740 self.assertRaises(Exception, self.apply_config, self.config2a)
2741
2742 def test_config2b_failure(self):
2743 # A simple config which overrides the default settings.
2744 self.assertRaises(Exception, self.apply_config, self.config2b)
2745
2746 def test_config3_failure(self):
2747 # A simple config which overrides the default settings.
2748 self.assertRaises(Exception, self.apply_config, self.config3)
2749
2750 def test_config4_ok(self):
2751 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002752 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002753 self.apply_config(self.config4)
2754 #logger = logging.getLogger()
2755 try:
2756 raise RuntimeError()
2757 except RuntimeError:
2758 logging.exception("just testing")
2759 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002760 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002761 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2762 # Original logger output is empty
2763 self.assert_log_lines([])
2764
2765 def test_config4a_ok(self):
2766 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002767 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 self.apply_config(self.config4a)
2769 #logger = logging.getLogger()
2770 try:
2771 raise RuntimeError()
2772 except RuntimeError:
2773 logging.exception("just testing")
2774 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002775 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002776 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2777 # Original logger output is empty
2778 self.assert_log_lines([])
2779
2780 def test_config5_ok(self):
2781 self.test_config1_ok(config=self.config5)
2782
2783 def test_config6_failure(self):
2784 self.assertRaises(Exception, self.apply_config, self.config6)
2785
2786 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002787 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002788 self.apply_config(self.config1)
2789 logger = logging.getLogger("compiler.parser")
2790 # Both will output a message
2791 logger.info(self.next_message())
2792 logger.error(self.next_message())
2793 self.assert_log_lines([
2794 ('INFO', '1'),
2795 ('ERROR', '2'),
2796 ], stream=output)
2797 # Original logger output is empty.
2798 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002799 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002800 self.apply_config(self.config7)
2801 logger = logging.getLogger("compiler.parser")
2802 self.assertTrue(logger.disabled)
2803 logger = logging.getLogger("compiler.lexer")
2804 # Both will output a message
2805 logger.info(self.next_message())
2806 logger.error(self.next_message())
2807 self.assert_log_lines([
2808 ('INFO', '3'),
2809 ('ERROR', '4'),
2810 ], stream=output)
2811 # Original logger output is empty.
2812 self.assert_log_lines([])
2813
Mike53f7a7c2017-12-14 14:04:53 +03002814 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002815 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002816 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002817 self.apply_config(self.config1)
2818 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002819 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002820 logger.info(self.next_message())
2821 logger.error(self.next_message())
2822 self.assert_log_lines([
2823 ('INFO', '1'),
2824 ('ERROR', '2'),
2825 ], stream=output)
2826 # Original logger output is empty.
2827 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002828 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002829 self.apply_config(self.config8)
2830 logger = logging.getLogger("compiler.parser")
2831 self.assertFalse(logger.disabled)
2832 # Both will output a message
2833 logger.info(self.next_message())
2834 logger.error(self.next_message())
2835 logger = logging.getLogger("compiler.lexer")
2836 # Both will output a message
2837 logger.info(self.next_message())
2838 logger.error(self.next_message())
2839 self.assert_log_lines([
2840 ('INFO', '3'),
2841 ('ERROR', '4'),
2842 ('INFO', '5'),
2843 ('ERROR', '6'),
2844 ], stream=output)
2845 # Original logger output is empty.
2846 self.assert_log_lines([])
2847
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002848 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002849 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002850 self.apply_config(self.config1a)
2851 logger = logging.getLogger("compiler.parser")
2852 # See issue #11424. compiler-hyphenated sorts
2853 # between compiler and compiler.xyz and this
2854 # was preventing compiler.xyz from being included
2855 # in the child loggers of compiler because of an
2856 # overzealous loop termination condition.
2857 hyphenated = logging.getLogger('compiler-hyphenated')
2858 # All will output a message
2859 logger.info(self.next_message())
2860 logger.error(self.next_message())
2861 hyphenated.critical(self.next_message())
2862 self.assert_log_lines([
2863 ('INFO', '1'),
2864 ('ERROR', '2'),
2865 ('CRITICAL', '3'),
2866 ], stream=output)
2867 # Original logger output is empty.
2868 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002869 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002870 self.apply_config(self.config8a)
2871 logger = logging.getLogger("compiler.parser")
2872 self.assertFalse(logger.disabled)
2873 # Both will output a message
2874 logger.info(self.next_message())
2875 logger.error(self.next_message())
2876 logger = logging.getLogger("compiler.lexer")
2877 # Both will output a message
2878 logger.info(self.next_message())
2879 logger.error(self.next_message())
2880 # Will not appear
2881 hyphenated.critical(self.next_message())
2882 self.assert_log_lines([
2883 ('INFO', '4'),
2884 ('ERROR', '5'),
2885 ('INFO', '6'),
2886 ('ERROR', '7'),
2887 ], stream=output)
2888 # Original logger output is empty.
2889 self.assert_log_lines([])
2890
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002891 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002892 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002893 self.apply_config(self.config9)
2894 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03002895 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002896 logger.info(self.next_message())
2897 self.assert_log_lines([], stream=output)
2898 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03002899 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002900 logger.info(self.next_message())
2901 self.assert_log_lines([], stream=output)
2902 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03002903 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002904 logger.info(self.next_message())
2905 self.assert_log_lines([
2906 ('INFO', '3'),
2907 ], stream=output)
2908
2909 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002910 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002911 self.apply_config(self.config10)
2912 logger = logging.getLogger("compiler.parser")
2913 logger.warning(self.next_message())
2914 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002915 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002916 logger.warning(self.next_message())
2917 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002918 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002919 logger.warning(self.next_message())
2920 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002921 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002922 logger.error(self.next_message())
2923 self.assert_log_lines([
2924 ('WARNING', '1'),
2925 ('ERROR', '4'),
2926 ], stream=output)
2927
2928 def test_config11_ok(self):
2929 self.test_config1_ok(self.config11)
2930
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002931 def test_config12_failure(self):
2932 self.assertRaises(Exception, self.apply_config, self.config12)
2933
2934 def test_config13_failure(self):
2935 self.assertRaises(Exception, self.apply_config, self.config13)
2936
Vinay Sajip8d270232012-11-15 14:20:18 +00002937 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002938 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002939 self.apply_config(self.config14)
2940 h = logging._handlers['hand1']
2941 self.assertEqual(h.foo, 'bar')
2942 self.assertEqual(h.terminator, '!\n')
2943 logging.warning('Exclamation')
2944 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2945
Miss Islington (bot)6f49afc2018-07-02 02:35:09 -07002946 def test_config15_ok(self):
2947
2948 def cleanup(h1, fn):
2949 h1.close()
2950 os.remove(fn)
2951
2952 with self.check_no_resource_warning():
2953 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
2954 os.close(fd)
2955
2956 config = {
2957 "version": 1,
2958 "handlers": {
2959 "file": {
2960 "class": "logging.FileHandler",
2961 "filename": fn
2962 }
2963 },
2964 "root": {
2965 "handlers": ["file"]
2966 }
2967 }
2968
2969 self.apply_config(config)
2970 self.apply_config(config)
2971
2972 handler = logging.root.handlers[0]
2973 self.addCleanup(cleanup, handler, fn)
2974
Vinay Sajip4ded5512012-10-02 15:56:16 +01002975 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002976 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002977 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002978 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002979 t.start()
2980 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002981 # Now get the port allocated
2982 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002983 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002984 try:
2985 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2986 sock.settimeout(2.0)
2987 sock.connect(('localhost', port))
2988
2989 slen = struct.pack('>L', len(text))
2990 s = slen + text
2991 sentsofar = 0
2992 left = len(s)
2993 while left > 0:
2994 sent = sock.send(s[sentsofar:])
2995 sentsofar += sent
2996 left -= sent
2997 sock.close()
2998 finally:
2999 t.ready.wait(2.0)
3000 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07003001 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003002
3003 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003004 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003005 self.setup_via_listener(json.dumps(self.config10))
3006 logger = logging.getLogger("compiler.parser")
3007 logger.warning(self.next_message())
3008 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003009 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003010 logger.warning(self.next_message())
3011 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003012 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003013 logger.warning(self.next_message())
3014 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003015 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003016 logger.error(self.next_message())
3017 self.assert_log_lines([
3018 ('WARNING', '1'),
3019 ('ERROR', '4'),
3020 ], stream=output)
3021
3022 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003023 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003024 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
3025 logger = logging.getLogger("compiler.parser")
3026 # Both will output a message
3027 logger.info(self.next_message())
3028 logger.error(self.next_message())
3029 self.assert_log_lines([
3030 ('INFO', '1'),
3031 ('ERROR', '2'),
3032 ], stream=output)
3033 # Original logger output is empty.
3034 self.assert_log_lines([])
3035
Vinay Sajip4ded5512012-10-02 15:56:16 +01003036 def test_listen_verify(self):
3037
3038 def verify_fail(stuff):
3039 return None
3040
3041 def verify_reverse(stuff):
3042 return stuff[::-1]
3043
3044 logger = logging.getLogger("compiler.parser")
3045 to_send = textwrap.dedent(ConfigFileTest.config1)
3046 # First, specify a verification function that will fail.
3047 # We expect to see no output, since our configuration
3048 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01003049 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003050 self.setup_via_listener(to_send, verify_fail)
3051 # Both will output a message
3052 logger.info(self.next_message())
3053 logger.error(self.next_message())
3054 self.assert_log_lines([], stream=output)
3055 # Original logger output has the stuff we logged.
3056 self.assert_log_lines([
3057 ('INFO', '1'),
3058 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003059 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003060
3061 # Now, perform no verification. Our configuration
3062 # should take effect.
3063
Vinay Sajip1feedb42014-05-31 08:19:12 +01003064 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003065 self.setup_via_listener(to_send) # no verify callable specified
3066 logger = logging.getLogger("compiler.parser")
3067 # Both will output a message
3068 logger.info(self.next_message())
3069 logger.error(self.next_message())
3070 self.assert_log_lines([
3071 ('INFO', '3'),
3072 ('ERROR', '4'),
3073 ], stream=output)
3074 # Original logger output still has the stuff we logged before.
3075 self.assert_log_lines([
3076 ('INFO', '1'),
3077 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003078 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003079
3080 # Now, perform verification which transforms the bytes.
3081
Vinay Sajip1feedb42014-05-31 08:19:12 +01003082 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003083 self.setup_via_listener(to_send[::-1], verify_reverse)
3084 logger = logging.getLogger("compiler.parser")
3085 # Both will output a message
3086 logger.info(self.next_message())
3087 logger.error(self.next_message())
3088 self.assert_log_lines([
3089 ('INFO', '5'),
3090 ('ERROR', '6'),
3091 ], stream=output)
3092 # Original logger output still has the stuff we logged before.
3093 self.assert_log_lines([
3094 ('INFO', '1'),
3095 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003096 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003097
Vinay Sajip3f885b52013-03-22 15:19:54 +00003098 def test_out_of_order(self):
3099 self.apply_config(self.out_of_order)
3100 handler = logging.getLogger('mymodule').handlers[0]
3101 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003102 self.assertIsInstance(handler.formatter._style,
3103 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003104
Vinay Sajip373baef2011-04-26 20:05:24 +01003105 def test_baseconfig(self):
3106 d = {
3107 'atuple': (1, 2, 3),
3108 'alist': ['a', 'b', 'c'],
3109 'adict': {'d': 'e', 'f': 3 },
3110 'nest1': ('g', ('h', 'i'), 'j'),
3111 'nest2': ['k', ['l', 'm'], 'n'],
3112 'nest3': ['o', 'cfg://alist', 'p'],
3113 }
3114 bc = logging.config.BaseConfigurator(d)
3115 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3116 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3117 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3118 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3119 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3120 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3121 v = bc.convert('cfg://nest3')
3122 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3123 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3124 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3125 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003126
3127class ManagerTest(BaseTest):
3128 def test_manager_loggerclass(self):
3129 logged = []
3130
3131 class MyLogger(logging.Logger):
3132 def _log(self, level, msg, args, exc_info=None, extra=None):
3133 logged.append(msg)
3134
3135 man = logging.Manager(None)
3136 self.assertRaises(TypeError, man.setLoggerClass, int)
3137 man.setLoggerClass(MyLogger)
3138 logger = man.getLogger('test')
3139 logger.warning('should appear in logged')
3140 logging.warning('should not appear in logged')
3141
3142 self.assertEqual(logged, ['should appear in logged'])
3143
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003144 def test_set_log_record_factory(self):
3145 man = logging.Manager(None)
3146 expected = object()
3147 man.setLogRecordFactory(expected)
3148 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003149
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003150class ChildLoggerTest(BaseTest):
3151 def test_child_loggers(self):
3152 r = logging.getLogger()
3153 l1 = logging.getLogger('abc')
3154 l2 = logging.getLogger('def.ghi')
3155 c1 = r.getChild('xyz')
3156 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003157 self.assertIs(c1, logging.getLogger('xyz'))
3158 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003159 c1 = l1.getChild('def')
3160 c2 = c1.getChild('ghi')
3161 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003162 self.assertIs(c1, logging.getLogger('abc.def'))
3163 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3164 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003165
3166
Vinay Sajip6fac8172010-10-19 20:44:14 +00003167class DerivedLogRecord(logging.LogRecord):
3168 pass
3169
Vinay Sajip61561522010-12-03 11:50:38 +00003170class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003171
3172 def setUp(self):
3173 class CheckingFilter(logging.Filter):
3174 def __init__(self, cls):
3175 self.cls = cls
3176
3177 def filter(self, record):
3178 t = type(record)
3179 if t is not self.cls:
3180 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3181 self.cls)
3182 raise TypeError(msg)
3183 return True
3184
3185 BaseTest.setUp(self)
3186 self.filter = CheckingFilter(DerivedLogRecord)
3187 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003188 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003189
3190 def tearDown(self):
3191 self.root_logger.removeFilter(self.filter)
3192 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003193 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003194
3195 def test_logrecord_class(self):
3196 self.assertRaises(TypeError, self.root_logger.warning,
3197 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003198 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003199 self.root_logger.error(self.next_message())
3200 self.assert_log_lines([
3201 ('root', 'ERROR', '2'),
3202 ])
3203
3204
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003205class QueueHandlerTest(BaseTest):
3206 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003207 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003208
3209 def setUp(self):
3210 BaseTest.setUp(self)
3211 self.queue = queue.Queue(-1)
3212 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003213 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003214 self.que_logger = logging.getLogger('que')
3215 self.que_logger.propagate = False
3216 self.que_logger.setLevel(logging.WARNING)
3217 self.que_logger.addHandler(self.que_hdlr)
3218
3219 def tearDown(self):
3220 self.que_hdlr.close()
3221 BaseTest.tearDown(self)
3222
3223 def test_queue_handler(self):
3224 self.que_logger.debug(self.next_message())
3225 self.assertRaises(queue.Empty, self.queue.get_nowait)
3226 self.que_logger.info(self.next_message())
3227 self.assertRaises(queue.Empty, self.queue.get_nowait)
3228 msg = self.next_message()
3229 self.que_logger.warning(msg)
3230 data = self.queue.get_nowait()
3231 self.assertTrue(isinstance(data, logging.LogRecord))
3232 self.assertEqual(data.name, self.que_logger.name)
3233 self.assertEqual((data.msg, data.args), (msg, None))
3234
favlladfe3442017-08-01 20:12:26 +02003235 def test_formatting(self):
3236 msg = self.next_message()
3237 levelname = logging.getLevelName(logging.WARNING)
3238 log_format_str = '{name} -> {levelname}: {message}'
3239 formatted_msg = log_format_str.format(name=self.name,
3240 levelname=levelname, message=msg)
3241 formatter = logging.Formatter(self.log_format)
3242 self.que_hdlr.setFormatter(formatter)
3243 self.que_logger.warning(msg)
3244 log_record = self.queue.get_nowait()
3245 self.assertEqual(formatted_msg, log_record.msg)
3246 self.assertEqual(formatted_msg, log_record.message)
3247
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003248 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3249 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003250 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003251 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003252 listener = logging.handlers.QueueListener(self.queue, handler)
3253 listener.start()
3254 try:
3255 self.que_logger.warning(self.next_message())
3256 self.que_logger.error(self.next_message())
3257 self.que_logger.critical(self.next_message())
3258 finally:
3259 listener.stop()
3260 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3261 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3262 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003263 handler.close()
3264
3265 # Now test with respect_handler_level set
3266
3267 handler = support.TestHandler(support.Matcher())
3268 handler.setLevel(logging.CRITICAL)
3269 listener = logging.handlers.QueueListener(self.queue, handler,
3270 respect_handler_level=True)
3271 listener.start()
3272 try:
3273 self.que_logger.warning(self.next_message())
3274 self.que_logger.error(self.next_message())
3275 self.que_logger.critical(self.next_message())
3276 finally:
3277 listener.stop()
3278 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3279 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3280 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3281
Vinay Sajipd61910c2016-09-08 01:13:39 +01003282if hasattr(logging.handlers, 'QueueListener'):
3283 import multiprocessing
3284 from unittest.mock import patch
3285
3286 class QueueListenerTest(BaseTest):
3287 """
3288 Tests based on patch submitted for issue #27930. Ensure that
3289 QueueListener handles all log messages.
3290 """
3291
3292 repeat = 20
3293
3294 @staticmethod
3295 def setup_and_log(log_queue, ident):
3296 """
3297 Creates a logger with a QueueHandler that logs to a queue read by a
3298 QueueListener. Starts the listener, logs five messages, and stops
3299 the listener.
3300 """
3301 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3302 logger.setLevel(logging.DEBUG)
3303 handler = logging.handlers.QueueHandler(log_queue)
3304 logger.addHandler(handler)
3305 listener = logging.handlers.QueueListener(log_queue)
3306 listener.start()
3307
3308 logger.info('one')
3309 logger.info('two')
3310 logger.info('three')
3311 logger.info('four')
3312 logger.info('five')
3313
3314 listener.stop()
3315 logger.removeHandler(handler)
3316 handler.close()
3317
3318 @patch.object(logging.handlers.QueueListener, 'handle')
3319 def test_handle_called_with_queue_queue(self, mock_handle):
3320 for i in range(self.repeat):
3321 log_queue = queue.Queue()
3322 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3323 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3324 'correct number of handled log messages')
3325
3326 @patch.object(logging.handlers.QueueListener, 'handle')
3327 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003328 # Issue 28668: The multiprocessing (mp) module is not functional
3329 # when the mp.synchronize module cannot be imported.
3330 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003331 for i in range(self.repeat):
3332 log_queue = multiprocessing.Queue()
3333 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003334 log_queue.close()
3335 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003336 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3337 'correct number of handled log messages')
3338
3339 @staticmethod
3340 def get_all_from_queue(log_queue):
3341 try:
3342 while True:
3343 yield log_queue.get_nowait()
3344 except queue.Empty:
3345 return []
3346
3347 def test_no_messages_in_queue_after_stop(self):
3348 """
3349 Five messages are logged then the QueueListener is stopped. This
3350 test then gets everything off the queue. Failure of this test
3351 indicates that messages were not registered on the queue until
3352 _after_ the QueueListener stopped.
3353 """
xdegayebf2b65e2017-12-01 08:08:49 +01003354 # Issue 28668: The multiprocessing (mp) module is not functional
3355 # when the mp.synchronize module cannot be imported.
3356 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003357 for i in range(self.repeat):
3358 queue = multiprocessing.Queue()
3359 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3360 # time.sleep(1)
3361 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003362 queue.close()
3363 queue.join_thread()
3364
Vinay Sajipd61910c2016-09-08 01:13:39 +01003365 expected = [[], [logging.handlers.QueueListener._sentinel]]
3366 self.assertIn(items, expected,
3367 'Found unexpected messages in queue: %s' % (
3368 [m.msg if isinstance(m, logging.LogRecord)
3369 else m for m in items]))
3370
Vinay Sajipe723e962011-04-15 22:27:17 +01003371
Vinay Sajip37eb3382011-04-26 20:26:41 +01003372ZERO = datetime.timedelta(0)
3373
3374class UTC(datetime.tzinfo):
3375 def utcoffset(self, dt):
3376 return ZERO
3377
3378 dst = utcoffset
3379
3380 def tzname(self, dt):
3381 return 'UTC'
3382
3383utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003384
Vinay Sajipa39c5712010-10-25 13:57:39 +00003385class FormatterTest(unittest.TestCase):
3386 def setUp(self):
3387 self.common = {
3388 'name': 'formatter.test',
3389 'level': logging.DEBUG,
3390 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3391 'lineno': 42,
3392 'exc_info': None,
3393 'func': None,
3394 'msg': 'Message with %d %s',
3395 'args': (2, 'placeholders'),
3396 }
3397 self.variants = {
3398 }
3399
3400 def get_record(self, name=None):
3401 result = dict(self.common)
3402 if name is not None:
3403 result.update(self.variants[name])
3404 return logging.makeLogRecord(result)
3405
3406 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003407 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003408 r = self.get_record()
3409 f = logging.Formatter('${%(message)s}')
3410 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3411 f = logging.Formatter('%(random)s')
3412 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003413 self.assertFalse(f.usesTime())
3414 f = logging.Formatter('%(asctime)s')
3415 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003416 f = logging.Formatter('%(asctime)-15s')
3417 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003418 f = logging.Formatter('asctime')
3419 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003420
3421 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003422 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003423 r = self.get_record()
3424 f = logging.Formatter('$%{message}%$', style='{')
3425 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3426 f = logging.Formatter('{random}', style='{')
3427 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003428 self.assertFalse(f.usesTime())
3429 f = logging.Formatter('{asctime}', style='{')
3430 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003431 f = logging.Formatter('{asctime!s:15}', style='{')
3432 self.assertTrue(f.usesTime())
3433 f = logging.Formatter('{asctime:15}', style='{')
3434 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003435 f = logging.Formatter('asctime', style='{')
3436 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003437
3438 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003439 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003440 r = self.get_record()
3441 f = logging.Formatter('$message', style='$')
3442 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3443 f = logging.Formatter('$$%${message}%$$', style='$')
3444 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3445 f = logging.Formatter('${random}', style='$')
3446 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003447 self.assertFalse(f.usesTime())
3448 f = logging.Formatter('${asctime}', style='$')
3449 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003450 f = logging.Formatter('${asctime', style='$')
3451 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003452 f = logging.Formatter('$asctime', style='$')
3453 self.assertTrue(f.usesTime())
3454 f = logging.Formatter('asctime', style='$')
3455 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003456
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003457 def test_invalid_style(self):
3458 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3459
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003460 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003461 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003462 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3463 # We use None to indicate we want the local timezone
3464 # We're essentially converting a UTC time to local time
3465 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003466 r.msecs = 123
3467 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003468 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003469 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3470 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003471 f.format(r)
3472 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3473
3474class TestBufferingFormatter(logging.BufferingFormatter):
3475 def formatHeader(self, records):
3476 return '[(%d)' % len(records)
3477
3478 def formatFooter(self, records):
3479 return '(%d)]' % len(records)
3480
3481class BufferingFormatterTest(unittest.TestCase):
3482 def setUp(self):
3483 self.records = [
3484 logging.makeLogRecord({'msg': 'one'}),
3485 logging.makeLogRecord({'msg': 'two'}),
3486 ]
3487
3488 def test_default(self):
3489 f = logging.BufferingFormatter()
3490 self.assertEqual('', f.format([]))
3491 self.assertEqual('onetwo', f.format(self.records))
3492
3493 def test_custom(self):
3494 f = TestBufferingFormatter()
3495 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3496 lf = logging.Formatter('<%(message)s>')
3497 f = TestBufferingFormatter(lf)
3498 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003499
3500class ExceptionTest(BaseTest):
3501 def test_formatting(self):
3502 r = self.root_logger
3503 h = RecordingHandler()
3504 r.addHandler(h)
3505 try:
3506 raise RuntimeError('deliberate mistake')
3507 except:
3508 logging.exception('failed', stack_info=True)
3509 r.removeHandler(h)
3510 h.close()
3511 r = h.records[0]
3512 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3513 'call last):\n'))
3514 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3515 'deliberate mistake'))
3516 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3517 'call last):\n'))
3518 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3519 'stack_info=True)'))
3520
3521
Vinay Sajip5a27d402010-12-10 11:42:57 +00003522class LastResortTest(BaseTest):
3523 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003524 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003525 root = self.root_logger
3526 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003527 old_lastresort = logging.lastResort
3528 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003529
Vinay Sajip5a27d402010-12-10 11:42:57 +00003530 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003531 with support.captured_stderr() as stderr:
3532 root.debug('This should not appear')
3533 self.assertEqual(stderr.getvalue(), '')
3534 root.warning('Final chance!')
3535 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3536
3537 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003538 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003539 with support.captured_stderr() as stderr:
3540 root.warning('Final chance!')
3541 msg = 'No handlers could be found for logger "root"\n'
3542 self.assertEqual(stderr.getvalue(), msg)
3543
Vinay Sajip5a27d402010-12-10 11:42:57 +00003544 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003545 with support.captured_stderr() as stderr:
3546 root.warning('Final chance!')
3547 self.assertEqual(stderr.getvalue(), '')
3548
3549 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003550 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003551 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003552 with support.captured_stderr() as stderr:
3553 root.warning('Final chance!')
3554 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003555 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003556 root.addHandler(self.root_hdlr)
3557 logging.lastResort = old_lastresort
3558 logging.raiseExceptions = old_raise_exceptions
3559
3560
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561class FakeHandler:
3562
3563 def __init__(self, identifier, called):
3564 for method in ('acquire', 'flush', 'close', 'release'):
3565 setattr(self, method, self.record_call(identifier, method, called))
3566
3567 def record_call(self, identifier, method_name, called):
3568 def inner():
3569 called.append('{} - {}'.format(identifier, method_name))
3570 return inner
3571
3572
3573class RecordingHandler(logging.NullHandler):
3574
3575 def __init__(self, *args, **kwargs):
3576 super(RecordingHandler, self).__init__(*args, **kwargs)
3577 self.records = []
3578
3579 def handle(self, record):
3580 """Keep track of all the emitted records."""
3581 self.records.append(record)
3582
3583
3584class ShutdownTest(BaseTest):
3585
Vinay Sajip5e66b162011-04-20 15:41:14 +01003586 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003587
3588 def setUp(self):
3589 super(ShutdownTest, self).setUp()
3590 self.called = []
3591
3592 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003593 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003594
3595 def raise_error(self, error):
3596 def inner():
3597 raise error()
3598 return inner
3599
3600 def test_no_failure(self):
3601 # create some fake handlers
3602 handler0 = FakeHandler(0, self.called)
3603 handler1 = FakeHandler(1, self.called)
3604 handler2 = FakeHandler(2, self.called)
3605
3606 # create live weakref to those handlers
3607 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3608
3609 logging.shutdown(handlerList=list(handlers))
3610
3611 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3612 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3613 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3614 self.assertEqual(expected, self.called)
3615
3616 def _test_with_failure_in_method(self, method, error):
3617 handler = FakeHandler(0, self.called)
3618 setattr(handler, method, self.raise_error(error))
3619 handlers = [logging.weakref.ref(handler)]
3620
3621 logging.shutdown(handlerList=list(handlers))
3622
3623 self.assertEqual('0 - release', self.called[-1])
3624
3625 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003626 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003627
3628 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003629 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003630
3631 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003632 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003633
3634 def test_with_valueerror_in_acquire(self):
3635 self._test_with_failure_in_method('acquire', ValueError)
3636
3637 def test_with_valueerror_in_flush(self):
3638 self._test_with_failure_in_method('flush', ValueError)
3639
3640 def test_with_valueerror_in_close(self):
3641 self._test_with_failure_in_method('close', ValueError)
3642
3643 def test_with_other_error_in_acquire_without_raise(self):
3644 logging.raiseExceptions = False
3645 self._test_with_failure_in_method('acquire', IndexError)
3646
3647 def test_with_other_error_in_flush_without_raise(self):
3648 logging.raiseExceptions = False
3649 self._test_with_failure_in_method('flush', IndexError)
3650
3651 def test_with_other_error_in_close_without_raise(self):
3652 logging.raiseExceptions = False
3653 self._test_with_failure_in_method('close', IndexError)
3654
3655 def test_with_other_error_in_acquire_with_raise(self):
3656 logging.raiseExceptions = True
3657 self.assertRaises(IndexError, self._test_with_failure_in_method,
3658 'acquire', IndexError)
3659
3660 def test_with_other_error_in_flush_with_raise(self):
3661 logging.raiseExceptions = True
3662 self.assertRaises(IndexError, self._test_with_failure_in_method,
3663 'flush', IndexError)
3664
3665 def test_with_other_error_in_close_with_raise(self):
3666 logging.raiseExceptions = True
3667 self.assertRaises(IndexError, self._test_with_failure_in_method,
3668 'close', IndexError)
3669
3670
3671class ModuleLevelMiscTest(BaseTest):
3672
Vinay Sajip5e66b162011-04-20 15:41:14 +01003673 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003674
3675 def test_disable(self):
3676 old_disable = logging.root.manager.disable
3677 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003678 self.assertEqual(old_disable, 0)
3679 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003680
3681 logging.disable(83)
3682 self.assertEqual(logging.root.manager.disable, 83)
3683
Vinay Sajipd489ac92016-12-31 11:40:11 +00003684 # test the default value introduced in 3.7
3685 # (Issue #28524)
3686 logging.disable()
3687 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3688
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003689 def _test_log(self, method, level=None):
3690 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003691 support.patch(self, logging, 'basicConfig',
3692 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003693
3694 recording = RecordingHandler()
3695 logging.root.addHandler(recording)
3696
3697 log_method = getattr(logging, method)
3698 if level is not None:
3699 log_method(level, "test me: %r", recording)
3700 else:
3701 log_method("test me: %r", recording)
3702
3703 self.assertEqual(len(recording.records), 1)
3704 record = recording.records[0]
3705 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3706
3707 expected_level = level if level is not None else getattr(logging, method.upper())
3708 self.assertEqual(record.levelno, expected_level)
3709
3710 # basicConfig was not called!
3711 self.assertEqual(called, [])
3712
3713 def test_log(self):
3714 self._test_log('log', logging.ERROR)
3715
3716 def test_debug(self):
3717 self._test_log('debug')
3718
3719 def test_info(self):
3720 self._test_log('info')
3721
3722 def test_warning(self):
3723 self._test_log('warning')
3724
3725 def test_error(self):
3726 self._test_log('error')
3727
3728 def test_critical(self):
3729 self._test_log('critical')
3730
3731 def test_set_logger_class(self):
3732 self.assertRaises(TypeError, logging.setLoggerClass, object)
3733
3734 class MyLogger(logging.Logger):
3735 pass
3736
3737 logging.setLoggerClass(MyLogger)
3738 self.assertEqual(logging.getLoggerClass(), MyLogger)
3739
3740 logging.setLoggerClass(logging.Logger)
3741 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3742
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003743 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003744 def test_logging_at_shutdown(self):
3745 # Issue #20037
3746 code = """if 1:
3747 import logging
3748
3749 class A:
3750 def __del__(self):
3751 try:
3752 raise ValueError("some error")
3753 except Exception:
3754 logging.exception("exception in __del__")
3755
3756 a = A()"""
3757 rc, out, err = assert_python_ok("-c", code)
3758 err = err.decode()
3759 self.assertIn("exception in __del__", err)
3760 self.assertIn("ValueError: some error", err)
3761
3762
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003763class LogRecordTest(BaseTest):
3764 def test_str_rep(self):
3765 r = logging.makeLogRecord({})
3766 s = str(r)
3767 self.assertTrue(s.startswith('<LogRecord: '))
3768 self.assertTrue(s.endswith('>'))
3769
3770 def test_dict_arg(self):
3771 h = RecordingHandler()
3772 r = logging.getLogger()
3773 r.addHandler(h)
3774 d = {'less' : 'more' }
3775 logging.warning('less is %(less)s', d)
3776 self.assertIs(h.records[0].args, d)
3777 self.assertEqual(h.records[0].message, 'less is more')
3778 r.removeHandler(h)
3779 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003780
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003781 def test_multiprocessing(self):
3782 r = logging.makeLogRecord({})
3783 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003784 try:
3785 import multiprocessing as mp
3786 r = logging.makeLogRecord({})
3787 self.assertEqual(r.processName, mp.current_process().name)
3788 except ImportError:
3789 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003790
3791 def test_optional(self):
3792 r = logging.makeLogRecord({})
3793 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003794 NOT_NONE(r.thread)
3795 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003796 NOT_NONE(r.process)
3797 NOT_NONE(r.processName)
3798 log_threads = logging.logThreads
3799 log_processes = logging.logProcesses
3800 log_multiprocessing = logging.logMultiprocessing
3801 try:
3802 logging.logThreads = False
3803 logging.logProcesses = False
3804 logging.logMultiprocessing = False
3805 r = logging.makeLogRecord({})
3806 NONE = self.assertIsNone
3807 NONE(r.thread)
3808 NONE(r.threadName)
3809 NONE(r.process)
3810 NONE(r.processName)
3811 finally:
3812 logging.logThreads = log_threads
3813 logging.logProcesses = log_processes
3814 logging.logMultiprocessing = log_multiprocessing
3815
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003816class BasicConfigTest(unittest.TestCase):
3817
Vinay Sajip95bf5042011-04-20 11:50:56 +01003818 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003819
3820 def setUp(self):
3821 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003822 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003823 self.saved_handlers = logging._handlers.copy()
3824 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003825 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003826 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003827 logging.root.handlers = []
3828
3829 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003830 for h in logging.root.handlers[:]:
3831 logging.root.removeHandler(h)
3832 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003833 super(BasicConfigTest, self).tearDown()
3834
Vinay Sajip3def7e02011-04-20 10:58:06 +01003835 def cleanup(self):
3836 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003837 logging._handlers.clear()
3838 logging._handlers.update(self.saved_handlers)
3839 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003840 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003841
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003842 def test_no_kwargs(self):
3843 logging.basicConfig()
3844
3845 # handler defaults to a StreamHandler to sys.stderr
3846 self.assertEqual(len(logging.root.handlers), 1)
3847 handler = logging.root.handlers[0]
3848 self.assertIsInstance(handler, logging.StreamHandler)
3849 self.assertEqual(handler.stream, sys.stderr)
3850
3851 formatter = handler.formatter
3852 # format defaults to logging.BASIC_FORMAT
3853 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3854 # datefmt defaults to None
3855 self.assertIsNone(formatter.datefmt)
3856 # style defaults to %
3857 self.assertIsInstance(formatter._style, logging.PercentStyle)
3858
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003859 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003860 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003861
Vinay Sajip1fd12022014-01-13 21:59:56 +00003862 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003863 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003864 logging.basicConfig(stream=sys.stdout, style="{")
3865 logging.error("Log an error")
3866 sys.stdout.seek(0)
3867 self.assertEqual(output.getvalue().strip(),
3868 "ERROR:root:Log an error")
3869
3870 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003871 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003872 logging.basicConfig(stream=sys.stdout, style="$")
3873 logging.error("Log an error")
3874 sys.stdout.seek(0)
3875 self.assertEqual(output.getvalue().strip(),
3876 "ERROR:root:Log an error")
3877
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003878 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003879
3880 def cleanup(h1, h2, fn):
3881 h1.close()
3882 h2.close()
3883 os.remove(fn)
3884
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003885 logging.basicConfig(filename='test.log')
3886
3887 self.assertEqual(len(logging.root.handlers), 1)
3888 handler = logging.root.handlers[0]
3889 self.assertIsInstance(handler, logging.FileHandler)
3890
3891 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003892 self.assertEqual(handler.stream.mode, expected.stream.mode)
3893 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003894 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003895
3896 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003897
3898 def cleanup(h1, h2, fn):
3899 h1.close()
3900 h2.close()
3901 os.remove(fn)
3902
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003903 logging.basicConfig(filename='test.log', filemode='wb')
3904
3905 handler = logging.root.handlers[0]
3906 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003907 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003908 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003909
3910 def test_stream(self):
3911 stream = io.StringIO()
3912 self.addCleanup(stream.close)
3913 logging.basicConfig(stream=stream)
3914
3915 self.assertEqual(len(logging.root.handlers), 1)
3916 handler = logging.root.handlers[0]
3917 self.assertIsInstance(handler, logging.StreamHandler)
3918 self.assertEqual(handler.stream, stream)
3919
3920 def test_format(self):
3921 logging.basicConfig(format='foo')
3922
3923 formatter = logging.root.handlers[0].formatter
3924 self.assertEqual(formatter._style._fmt, 'foo')
3925
3926 def test_datefmt(self):
3927 logging.basicConfig(datefmt='bar')
3928
3929 formatter = logging.root.handlers[0].formatter
3930 self.assertEqual(formatter.datefmt, 'bar')
3931
3932 def test_style(self):
3933 logging.basicConfig(style='$')
3934
3935 formatter = logging.root.handlers[0].formatter
3936 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3937
3938 def test_level(self):
3939 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003940 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003941
3942 logging.basicConfig(level=57)
3943 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003944 # Test that second call has no effect
3945 logging.basicConfig(level=58)
3946 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003947
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003948 def test_incompatible(self):
3949 assertRaises = self.assertRaises
3950 handlers = [logging.StreamHandler()]
3951 stream = sys.stderr
3952 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3953 stream=stream)
3954 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3955 handlers=handlers)
3956 assertRaises(ValueError, logging.basicConfig, stream=stream,
3957 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003958 # Issue 23207: test for invalid kwargs
3959 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3960 # Should pop both filename and filemode even if filename is None
3961 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003962
3963 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003964 handlers = [
3965 logging.StreamHandler(),
3966 logging.StreamHandler(sys.stdout),
3967 logging.StreamHandler(),
3968 ]
3969 f = logging.Formatter()
3970 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003971 logging.basicConfig(handlers=handlers)
3972 self.assertIs(handlers[0], logging.root.handlers[0])
3973 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003974 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003975 self.assertIsNotNone(handlers[0].formatter)
3976 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003977 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003978 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3979
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003980 def _test_log(self, method, level=None):
3981 # logging.root has no handlers so basicConfig should be called
3982 called = []
3983
3984 old_basic_config = logging.basicConfig
3985 def my_basic_config(*a, **kw):
3986 old_basic_config()
3987 old_level = logging.root.level
3988 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003989 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003990 called.append((a, kw))
3991
Vinay Sajip1feedb42014-05-31 08:19:12 +01003992 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003993
3994 log_method = getattr(logging, method)
3995 if level is not None:
3996 log_method(level, "test me")
3997 else:
3998 log_method("test me")
3999
4000 # basicConfig was called with no arguments
4001 self.assertEqual(called, [((), {})])
4002
4003 def test_log(self):
4004 self._test_log('log', logging.WARNING)
4005
4006 def test_debug(self):
4007 self._test_log('debug')
4008
4009 def test_info(self):
4010 self._test_log('info')
4011
4012 def test_warning(self):
4013 self._test_log('warning')
4014
4015 def test_error(self):
4016 self._test_log('error')
4017
4018 def test_critical(self):
4019 self._test_log('critical')
4020
4021
4022class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004023 def setUp(self):
4024 super(LoggerAdapterTest, self).setUp()
4025 old_handler_list = logging._handlerList[:]
4026
4027 self.recording = RecordingHandler()
4028 self.logger = logging.root
4029 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004030 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004031 self.addCleanup(self.recording.close)
4032
4033 def cleanup():
4034 logging._handlerList[:] = old_handler_list
4035
4036 self.addCleanup(cleanup)
4037 self.addCleanup(logging.shutdown)
4038 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4039
4040 def test_exception(self):
4041 msg = 'testing exception: %r'
4042 exc = None
4043 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004044 1 / 0
4045 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004046 exc = e
4047 self.adapter.exception(msg, self.recording)
4048
4049 self.assertEqual(len(self.recording.records), 1)
4050 record = self.recording.records[0]
4051 self.assertEqual(record.levelno, logging.ERROR)
4052 self.assertEqual(record.msg, msg)
4053 self.assertEqual(record.args, (self.recording,))
4054 self.assertEqual(record.exc_info,
4055 (exc.__class__, exc, exc.__traceback__))
4056
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004057 def test_exception_excinfo(self):
4058 try:
4059 1 / 0
4060 except ZeroDivisionError as e:
4061 exc = e
4062
4063 self.adapter.exception('exc_info test', exc_info=exc)
4064
4065 self.assertEqual(len(self.recording.records), 1)
4066 record = self.recording.records[0]
4067 self.assertEqual(record.exc_info,
4068 (exc.__class__, exc, exc.__traceback__))
4069
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004070 def test_critical(self):
4071 msg = 'critical test! %r'
4072 self.adapter.critical(msg, self.recording)
4073
4074 self.assertEqual(len(self.recording.records), 1)
4075 record = self.recording.records[0]
4076 self.assertEqual(record.levelno, logging.CRITICAL)
4077 self.assertEqual(record.msg, msg)
4078 self.assertEqual(record.args, (self.recording,))
4079
4080 def test_is_enabled_for(self):
4081 old_disable = self.adapter.logger.manager.disable
4082 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004083 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4084 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004085 self.assertFalse(self.adapter.isEnabledFor(32))
4086
4087 def test_has_handlers(self):
4088 self.assertTrue(self.adapter.hasHandlers())
4089
4090 for handler in self.logger.handlers:
4091 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004092
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004093 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004094 self.assertFalse(self.adapter.hasHandlers())
4095
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004096 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004097 class Adapter(logging.LoggerAdapter):
4098 prefix = 'Adapter'
4099
4100 def process(self, msg, kwargs):
4101 return f"{self.prefix} {msg}", kwargs
4102
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004103 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004104 adapter = Adapter(logger=self.logger, extra=None)
4105 adapter_adapter = Adapter(logger=adapter, extra=None)
4106 adapter_adapter.prefix = 'AdapterAdapter'
4107 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004108 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004109 self.assertEqual(len(self.recording.records), 1)
4110 record = self.recording.records[0]
4111 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004112 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004113 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004114 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004115 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004116 self.assertIs(self.logger.manager, orig_manager)
4117 temp_manager = object()
4118 try:
4119 adapter_adapter.manager = temp_manager
4120 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004121 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004122 self.assertIs(self.logger.manager, temp_manager)
4123 finally:
4124 adapter_adapter.manager = orig_manager
4125 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004126 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004127 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004128
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004129
4130class LoggerTest(BaseTest):
4131
4132 def setUp(self):
4133 super(LoggerTest, self).setUp()
4134 self.recording = RecordingHandler()
4135 self.logger = logging.Logger(name='blah')
4136 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004137 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004138 self.addCleanup(self.recording.close)
4139 self.addCleanup(logging.shutdown)
4140
4141 def test_set_invalid_level(self):
4142 self.assertRaises(TypeError, self.logger.setLevel, object())
4143
4144 def test_exception(self):
4145 msg = 'testing exception: %r'
4146 exc = None
4147 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004148 1 / 0
4149 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004150 exc = e
4151 self.logger.exception(msg, self.recording)
4152
4153 self.assertEqual(len(self.recording.records), 1)
4154 record = self.recording.records[0]
4155 self.assertEqual(record.levelno, logging.ERROR)
4156 self.assertEqual(record.msg, msg)
4157 self.assertEqual(record.args, (self.recording,))
4158 self.assertEqual(record.exc_info,
4159 (exc.__class__, exc, exc.__traceback__))
4160
4161 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004162 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004163 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004164
4165 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004166 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004167 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004168
4169 def test_find_caller_with_stack_info(self):
4170 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004171 support.patch(self, logging.traceback, 'print_stack',
4172 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004173
4174 self.logger.findCaller(stack_info=True)
4175
4176 self.assertEqual(len(called), 1)
4177 self.assertEqual('Stack (most recent call last):\n', called[0])
4178
4179 def test_make_record_with_extra_overwrite(self):
4180 name = 'my record'
4181 level = 13
4182 fn = lno = msg = args = exc_info = func = sinfo = None
4183 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4184 exc_info, func, sinfo)
4185
4186 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4187 extra = {key: 'some value'}
4188 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4189 fn, lno, msg, args, exc_info,
4190 extra=extra, sinfo=sinfo)
4191
4192 def test_make_record_with_extra_no_overwrite(self):
4193 name = 'my record'
4194 level = 13
4195 fn = lno = msg = args = exc_info = func = sinfo = None
4196 extra = {'valid_key': 'some value'}
4197 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4198 exc_info, extra=extra, sinfo=sinfo)
4199 self.assertIn('valid_key', result.__dict__)
4200
4201 def test_has_handlers(self):
4202 self.assertTrue(self.logger.hasHandlers())
4203
4204 for handler in self.logger.handlers:
4205 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004206 self.assertFalse(self.logger.hasHandlers())
4207
4208 def test_has_handlers_no_propagate(self):
4209 child_logger = logging.getLogger('blah.child')
4210 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004211 self.assertFalse(child_logger.hasHandlers())
4212
4213 def test_is_enabled_for(self):
4214 old_disable = self.logger.manager.disable
4215 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004216 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004217 self.assertFalse(self.logger.isEnabledFor(22))
4218
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004219 def test_root_logger_aliases(self):
4220 root = logging.getLogger()
4221 self.assertIs(root, logging.root)
4222 self.assertIs(root, logging.getLogger(None))
4223 self.assertIs(root, logging.getLogger(''))
4224 self.assertIs(root, logging.getLogger('foo').root)
4225 self.assertIs(root, logging.getLogger('foo.bar').root)
4226 self.assertIs(root, logging.getLogger('foo').parent)
4227
4228 self.assertIsNot(root, logging.getLogger('\0'))
4229 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4230
4231 def test_invalid_names(self):
4232 self.assertRaises(TypeError, logging.getLogger, any)
4233 self.assertRaises(TypeError, logging.getLogger, b'foo')
4234
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004235 def test_pickling(self):
4236 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4237 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4238 logger = logging.getLogger(name)
4239 s = pickle.dumps(logger, proto)
4240 unpickled = pickle.loads(s)
4241 self.assertIs(unpickled, logger)
4242
Avram Lubkin78c18a92017-07-30 05:36:33 -04004243 def test_caching(self):
4244 root = self.root_logger
4245 logger1 = logging.getLogger("abc")
4246 logger2 = logging.getLogger("abc.def")
4247
4248 # Set root logger level and ensure cache is empty
4249 root.setLevel(logging.ERROR)
4250 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4251 self.assertEqual(logger2._cache, {})
4252
4253 # Ensure cache is populated and calls are consistent
4254 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4255 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4256 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4257 self.assertEqual(root._cache, {})
4258 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4259
4260 # Ensure root cache gets populated
4261 self.assertEqual(root._cache, {})
4262 self.assertTrue(root.isEnabledFor(logging.ERROR))
4263 self.assertEqual(root._cache, {logging.ERROR: True})
4264
4265 # Set parent logger level and ensure caches are emptied
4266 logger1.setLevel(logging.CRITICAL)
4267 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4268 self.assertEqual(logger2._cache, {})
4269
4270 # Ensure logger2 uses parent logger's effective level
4271 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4272
4273 # Set level to NOTSET and ensure caches are empty
4274 logger2.setLevel(logging.NOTSET)
4275 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4276 self.assertEqual(logger2._cache, {})
4277 self.assertEqual(logger1._cache, {})
4278 self.assertEqual(root._cache, {})
4279
4280 # Verify logger2 follows parent and not root
4281 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4282 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4283 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4284 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4285 self.assertTrue(root.isEnabledFor(logging.ERROR))
4286
4287 # Disable logging in manager and ensure caches are clear
4288 logging.disable()
4289 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4290 self.assertEqual(logger2._cache, {})
4291 self.assertEqual(logger1._cache, {})
4292 self.assertEqual(root._cache, {})
4293
4294 # Ensure no loggers are enabled
4295 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4296 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4297 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4298
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004299
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004300class BaseFileTest(BaseTest):
4301 "Base class for handler tests that write log files"
4302
4303 def setUp(self):
4304 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004305 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4306 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004307 self.rmfiles = []
4308
4309 def tearDown(self):
4310 for fn in self.rmfiles:
4311 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004312 if os.path.exists(self.fn):
4313 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004314 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004315
4316 def assertLogFile(self, filename):
4317 "Assert a log file is there and register it for deletion"
4318 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004319 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004320 self.rmfiles.append(filename)
4321
4322
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004323class FileHandlerTest(BaseFileTest):
4324 def test_delay(self):
4325 os.unlink(self.fn)
4326 fh = logging.FileHandler(self.fn, delay=True)
4327 self.assertIsNone(fh.stream)
4328 self.assertFalse(os.path.exists(self.fn))
4329 fh.handle(logging.makeLogRecord({}))
4330 self.assertIsNotNone(fh.stream)
4331 self.assertTrue(os.path.exists(self.fn))
4332 fh.close()
4333
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004334class RotatingFileHandlerTest(BaseFileTest):
4335 def next_rec(self):
4336 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4337 self.next_message(), None, None, None)
4338
4339 def test_should_not_rollover(self):
4340 # If maxbytes is zero rollover never occurs
4341 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4342 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004343 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004344
4345 def test_should_rollover(self):
4346 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4347 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004348 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004349
4350 def test_file_created(self):
4351 # checks that the file is created and assumes it was created
4352 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004353 rh = logging.handlers.RotatingFileHandler(self.fn)
4354 rh.emit(self.next_rec())
4355 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004356 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004357
4358 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004359 def namer(name):
4360 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004361 rh = logging.handlers.RotatingFileHandler(
4362 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004363 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004364 rh.emit(self.next_rec())
4365 self.assertLogFile(self.fn)
4366 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004367 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004368 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004369 self.assertLogFile(namer(self.fn + ".2"))
4370 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4371 rh.close()
4372
Vinay Sajip1feedb42014-05-31 08:19:12 +01004373 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004374 def test_rotator(self):
4375 def namer(name):
4376 return name + ".gz"
4377
4378 def rotator(source, dest):
4379 with open(source, "rb") as sf:
4380 data = sf.read()
4381 compressed = zlib.compress(data, 9)
4382 with open(dest, "wb") as df:
4383 df.write(compressed)
4384 os.remove(source)
4385
4386 rh = logging.handlers.RotatingFileHandler(
4387 self.fn, backupCount=2, maxBytes=1)
4388 rh.rotator = rotator
4389 rh.namer = namer
4390 m1 = self.next_rec()
4391 rh.emit(m1)
4392 self.assertLogFile(self.fn)
4393 m2 = self.next_rec()
4394 rh.emit(m2)
4395 fn = namer(self.fn + ".1")
4396 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004397 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004398 with open(fn, "rb") as f:
4399 compressed = f.read()
4400 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004401 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004402 rh.emit(self.next_rec())
4403 fn = namer(self.fn + ".2")
4404 self.assertLogFile(fn)
4405 with open(fn, "rb") as f:
4406 compressed = f.read()
4407 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004408 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004409 rh.emit(self.next_rec())
4410 fn = namer(self.fn + ".2")
4411 with open(fn, "rb") as f:
4412 compressed = f.read()
4413 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004414 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004415 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004416 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004417
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004418class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004419 # other test methods added below
4420 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004421 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4422 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004423 fmt = logging.Formatter('%(asctime)s %(message)s')
4424 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004425 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004426 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004427 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004428 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004429 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004430 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004431 fh.close()
4432 # At this point, we should have a recent rotated file which we
4433 # can test for the existence of. However, in practice, on some
4434 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004435 # in time to go to look for the log file. So, we go back a fair
4436 # bit, and stop as soon as we see a rotated file. In theory this
4437 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004438 found = False
4439 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004440 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004441 for secs in range(GO_BACK):
4442 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004443 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4444 found = os.path.exists(fn)
4445 if found:
4446 self.rmfiles.append(fn)
4447 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004448 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4449 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004450 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004451 dn, fn = os.path.split(self.fn)
4452 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004453 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4454 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004455 for f in files:
4456 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004457 path = os.path.join(dn, f)
4458 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004459 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004460 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004461
Vinay Sajip0372e102011-05-05 12:59:14 +01004462 def test_invalid(self):
4463 assertRaises = self.assertRaises
4464 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004465 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004466 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004467 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004468 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004469 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004470
Vinay Sajipa7130792013-04-12 17:04:23 +01004471 def test_compute_rollover_daily_attime(self):
4472 currentTime = 0
4473 atTime = datetime.time(12, 0, 0)
4474 rh = logging.handlers.TimedRotatingFileHandler(
4475 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4476 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004477 try:
4478 actual = rh.computeRollover(currentTime)
4479 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004480
Vinay Sajipd86ac962013-04-14 12:20:46 +01004481 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4482 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4483 finally:
4484 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004485
Vinay Sajip10e8c492013-05-18 10:19:54 -07004486 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004487 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004488 currentTime = int(time.time())
4489 today = currentTime - currentTime % 86400
4490
Vinay Sajipa7130792013-04-12 17:04:23 +01004491 atTime = datetime.time(12, 0, 0)
4492
Vinay Sajip10e8c492013-05-18 10:19:54 -07004493 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004494 for day in range(7):
4495 rh = logging.handlers.TimedRotatingFileHandler(
4496 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4497 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004498 try:
4499 if wday > day:
4500 # The rollover day has already passed this week, so we
4501 # go over into next week
4502 expected = (7 - wday + day)
4503 else:
4504 expected = (day - wday)
4505 # At this point expected is in days from now, convert to seconds
4506 expected *= 24 * 60 * 60
4507 # Add in the rollover time
4508 expected += 12 * 60 * 60
4509 # Add in adjustment for today
4510 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004511 actual = rh.computeRollover(today)
4512 if actual != expected:
4513 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004514 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004515 self.assertEqual(actual, expected)
4516 if day == wday:
4517 # goes into following week
4518 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004519 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004520 if actual != expected:
4521 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004522 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004523 self.assertEqual(actual, expected)
4524 finally:
4525 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004526
4527
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004528def secs(**kw):
4529 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4530
4531for when, exp in (('S', 1),
4532 ('M', 60),
4533 ('H', 60 * 60),
4534 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004535 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004536 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004537 ('W0', secs(days=4, hours=24)),
4538 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004539 def test_compute_rollover(self, when=when, exp=exp):
4540 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004541 self.fn, when=when, interval=1, backupCount=0, utc=True)
4542 currentTime = 0.0
4543 actual = rh.computeRollover(currentTime)
4544 if exp != actual:
4545 # Failures occur on some systems for MIDNIGHT and W0.
4546 # Print detailed calculation for MIDNIGHT so we can try to see
4547 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004548 if when == 'MIDNIGHT':
4549 try:
4550 if rh.utc:
4551 t = time.gmtime(currentTime)
4552 else:
4553 t = time.localtime(currentTime)
4554 currentHour = t[3]
4555 currentMinute = t[4]
4556 currentSecond = t[5]
4557 # r is the number of seconds left between now and midnight
4558 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4559 currentMinute) * 60 +
4560 currentSecond)
4561 result = currentTime + r
4562 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4563 print('currentHour: %s' % currentHour, file=sys.stderr)
4564 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4565 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4566 print('r: %s' % r, file=sys.stderr)
4567 print('result: %s' % result, file=sys.stderr)
4568 except Exception:
4569 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4570 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004571 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004572 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4573
Vinay Sajip60ccd822011-05-09 17:32:09 +01004574
Vinay Sajip223349c2015-10-01 20:37:54 +01004575@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004576class NTEventLogHandlerTest(BaseTest):
4577 def test_basic(self):
4578 logtype = 'Application'
4579 elh = win32evtlog.OpenEventLog(None, logtype)
4580 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004581
4582 try:
4583 h = logging.handlers.NTEventLogHandler('test_logging')
4584 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004585 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004586 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004587 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004588
Vinay Sajip60ccd822011-05-09 17:32:09 +01004589 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4590 h.handle(r)
4591 h.close()
4592 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004593 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004594 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4595 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4596 found = False
4597 GO_BACK = 100
4598 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4599 for e in events:
4600 if e.SourceName != 'test_logging':
4601 continue
4602 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4603 if msg != 'Test Log Message\r\n':
4604 continue
4605 found = True
4606 break
4607 msg = 'Record not found in event log, went back %d records' % GO_BACK
4608 self.assertTrue(found, msg=msg)
4609
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004610
4611class MiscTestCase(unittest.TestCase):
4612 def test__all__(self):
4613 blacklist = {'logThreads', 'logMultiprocessing',
4614 'logProcesses', 'currentframe',
4615 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4616 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004617 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004618 support.check__all__(self, logging, blacklist=blacklist)
4619
4620
Christian Heimes180510d2008-03-03 19:15:45 +00004621# Set the locale to the platform-dependent default. I have no idea
4622# why the test does this, but in any case we save the current locale
4623# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004624@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004625def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004626 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004627 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4628 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4629 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4630 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4631 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4632 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4633 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4634 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004635 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004636 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004637 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004638 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004639 ]
4640 if hasattr(logging.handlers, 'QueueListener'):
4641 tests.append(QueueListenerTest)
4642 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004643
Christian Heimes180510d2008-03-03 19:15:45 +00004644if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004645 test_main()