blob: 5d5eba735745f0d3831228098aad2882c0cf9633 [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'))
Miss Islington (bot)1a218932018-10-06 21:33:37 -07003281 handler.close()
3282
3283 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3284 'logging.handlers.QueueListener required for this test')
3285 def test_queue_listener_with_StreamHandler(self):
3286 # Test that traceback only appends once (bpo-34334).
3287 listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
3288 listener.start()
3289 try:
3290 1 / 0
3291 except ZeroDivisionError as e:
3292 exc = e
3293 self.que_logger.exception(self.next_message(), exc_info=exc)
3294 listener.stop()
3295 self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
Vinay Sajip365701a2015-02-09 19:49:00 +00003296
Vinay Sajipd61910c2016-09-08 01:13:39 +01003297if hasattr(logging.handlers, 'QueueListener'):
3298 import multiprocessing
3299 from unittest.mock import patch
3300
3301 class QueueListenerTest(BaseTest):
3302 """
3303 Tests based on patch submitted for issue #27930. Ensure that
3304 QueueListener handles all log messages.
3305 """
3306
3307 repeat = 20
3308
3309 @staticmethod
3310 def setup_and_log(log_queue, ident):
3311 """
3312 Creates a logger with a QueueHandler that logs to a queue read by a
3313 QueueListener. Starts the listener, logs five messages, and stops
3314 the listener.
3315 """
3316 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3317 logger.setLevel(logging.DEBUG)
3318 handler = logging.handlers.QueueHandler(log_queue)
3319 logger.addHandler(handler)
3320 listener = logging.handlers.QueueListener(log_queue)
3321 listener.start()
3322
3323 logger.info('one')
3324 logger.info('two')
3325 logger.info('three')
3326 logger.info('four')
3327 logger.info('five')
3328
3329 listener.stop()
3330 logger.removeHandler(handler)
3331 handler.close()
3332
3333 @patch.object(logging.handlers.QueueListener, 'handle')
3334 def test_handle_called_with_queue_queue(self, mock_handle):
3335 for i in range(self.repeat):
3336 log_queue = queue.Queue()
3337 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3338 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3339 'correct number of handled log messages')
3340
3341 @patch.object(logging.handlers.QueueListener, 'handle')
3342 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003343 # Issue 28668: The multiprocessing (mp) module is not functional
3344 # when the mp.synchronize module cannot be imported.
3345 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003346 for i in range(self.repeat):
3347 log_queue = multiprocessing.Queue()
3348 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003349 log_queue.close()
3350 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003351 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3352 'correct number of handled log messages')
3353
3354 @staticmethod
3355 def get_all_from_queue(log_queue):
3356 try:
3357 while True:
3358 yield log_queue.get_nowait()
3359 except queue.Empty:
3360 return []
3361
3362 def test_no_messages_in_queue_after_stop(self):
3363 """
3364 Five messages are logged then the QueueListener is stopped. This
3365 test then gets everything off the queue. Failure of this test
3366 indicates that messages were not registered on the queue until
3367 _after_ the QueueListener stopped.
3368 """
xdegayebf2b65e2017-12-01 08:08:49 +01003369 # Issue 28668: The multiprocessing (mp) module is not functional
3370 # when the mp.synchronize module cannot be imported.
3371 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003372 for i in range(self.repeat):
3373 queue = multiprocessing.Queue()
3374 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3375 # time.sleep(1)
3376 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003377 queue.close()
3378 queue.join_thread()
3379
Vinay Sajipd61910c2016-09-08 01:13:39 +01003380 expected = [[], [logging.handlers.QueueListener._sentinel]]
3381 self.assertIn(items, expected,
3382 'Found unexpected messages in queue: %s' % (
3383 [m.msg if isinstance(m, logging.LogRecord)
3384 else m for m in items]))
3385
Vinay Sajipe723e962011-04-15 22:27:17 +01003386
Vinay Sajip37eb3382011-04-26 20:26:41 +01003387ZERO = datetime.timedelta(0)
3388
3389class UTC(datetime.tzinfo):
3390 def utcoffset(self, dt):
3391 return ZERO
3392
3393 dst = utcoffset
3394
3395 def tzname(self, dt):
3396 return 'UTC'
3397
3398utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003399
Vinay Sajipa39c5712010-10-25 13:57:39 +00003400class FormatterTest(unittest.TestCase):
3401 def setUp(self):
3402 self.common = {
3403 'name': 'formatter.test',
3404 'level': logging.DEBUG,
3405 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3406 'lineno': 42,
3407 'exc_info': None,
3408 'func': None,
3409 'msg': 'Message with %d %s',
3410 'args': (2, 'placeholders'),
3411 }
3412 self.variants = {
3413 }
3414
3415 def get_record(self, name=None):
3416 result = dict(self.common)
3417 if name is not None:
3418 result.update(self.variants[name])
3419 return logging.makeLogRecord(result)
3420
3421 def test_percent(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)s}')
3425 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3426 f = logging.Formatter('%(random)s')
3427 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003428 self.assertFalse(f.usesTime())
3429 f = logging.Formatter('%(asctime)s')
3430 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003431 f = logging.Formatter('%(asctime)-15s')
3432 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003433 f = logging.Formatter('asctime')
3434 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003435
3436 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003437 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003438 r = self.get_record()
3439 f = logging.Formatter('$%{message}%$', style='{')
3440 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3441 f = logging.Formatter('{random}', style='{')
3442 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003443 self.assertFalse(f.usesTime())
3444 f = logging.Formatter('{asctime}', style='{')
3445 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003446 f = logging.Formatter('{asctime!s:15}', style='{')
3447 self.assertTrue(f.usesTime())
3448 f = logging.Formatter('{asctime:15}', style='{')
3449 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003450 f = logging.Formatter('asctime', style='{')
3451 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003452
3453 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003454 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003455 r = self.get_record()
3456 f = logging.Formatter('$message', style='$')
3457 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3458 f = logging.Formatter('$$%${message}%$$', style='$')
3459 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3460 f = logging.Formatter('${random}', style='$')
3461 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003462 self.assertFalse(f.usesTime())
3463 f = logging.Formatter('${asctime}', style='$')
3464 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003465 f = logging.Formatter('${asctime', style='$')
3466 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003467 f = logging.Formatter('$asctime', style='$')
3468 self.assertTrue(f.usesTime())
3469 f = logging.Formatter('asctime', style='$')
3470 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003471
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003472 def test_invalid_style(self):
3473 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3474
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003475 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003476 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003477 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3478 # We use None to indicate we want the local timezone
3479 # We're essentially converting a UTC time to local time
3480 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003481 r.msecs = 123
3482 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003483 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003484 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3485 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003486 f.format(r)
3487 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3488
3489class TestBufferingFormatter(logging.BufferingFormatter):
3490 def formatHeader(self, records):
3491 return '[(%d)' % len(records)
3492
3493 def formatFooter(self, records):
3494 return '(%d)]' % len(records)
3495
3496class BufferingFormatterTest(unittest.TestCase):
3497 def setUp(self):
3498 self.records = [
3499 logging.makeLogRecord({'msg': 'one'}),
3500 logging.makeLogRecord({'msg': 'two'}),
3501 ]
3502
3503 def test_default(self):
3504 f = logging.BufferingFormatter()
3505 self.assertEqual('', f.format([]))
3506 self.assertEqual('onetwo', f.format(self.records))
3507
3508 def test_custom(self):
3509 f = TestBufferingFormatter()
3510 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3511 lf = logging.Formatter('<%(message)s>')
3512 f = TestBufferingFormatter(lf)
3513 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003514
3515class ExceptionTest(BaseTest):
3516 def test_formatting(self):
3517 r = self.root_logger
3518 h = RecordingHandler()
3519 r.addHandler(h)
3520 try:
3521 raise RuntimeError('deliberate mistake')
3522 except:
3523 logging.exception('failed', stack_info=True)
3524 r.removeHandler(h)
3525 h.close()
3526 r = h.records[0]
3527 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3528 'call last):\n'))
3529 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3530 'deliberate mistake'))
3531 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3532 'call last):\n'))
3533 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3534 'stack_info=True)'))
3535
3536
Vinay Sajip5a27d402010-12-10 11:42:57 +00003537class LastResortTest(BaseTest):
3538 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003539 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003540 root = self.root_logger
3541 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003542 old_lastresort = logging.lastResort
3543 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003544
Vinay Sajip5a27d402010-12-10 11:42:57 +00003545 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003546 with support.captured_stderr() as stderr:
3547 root.debug('This should not appear')
3548 self.assertEqual(stderr.getvalue(), '')
3549 root.warning('Final chance!')
3550 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3551
3552 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003553 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003554 with support.captured_stderr() as stderr:
3555 root.warning('Final chance!')
3556 msg = 'No handlers could be found for logger "root"\n'
3557 self.assertEqual(stderr.getvalue(), msg)
3558
Vinay Sajip5a27d402010-12-10 11:42:57 +00003559 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003560 with support.captured_stderr() as stderr:
3561 root.warning('Final chance!')
3562 self.assertEqual(stderr.getvalue(), '')
3563
3564 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003565 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003566 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003567 with support.captured_stderr() as stderr:
3568 root.warning('Final chance!')
3569 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003570 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003571 root.addHandler(self.root_hdlr)
3572 logging.lastResort = old_lastresort
3573 logging.raiseExceptions = old_raise_exceptions
3574
3575
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003576class FakeHandler:
3577
3578 def __init__(self, identifier, called):
3579 for method in ('acquire', 'flush', 'close', 'release'):
3580 setattr(self, method, self.record_call(identifier, method, called))
3581
3582 def record_call(self, identifier, method_name, called):
3583 def inner():
3584 called.append('{} - {}'.format(identifier, method_name))
3585 return inner
3586
3587
3588class RecordingHandler(logging.NullHandler):
3589
3590 def __init__(self, *args, **kwargs):
3591 super(RecordingHandler, self).__init__(*args, **kwargs)
3592 self.records = []
3593
3594 def handle(self, record):
3595 """Keep track of all the emitted records."""
3596 self.records.append(record)
3597
3598
3599class ShutdownTest(BaseTest):
3600
Vinay Sajip5e66b162011-04-20 15:41:14 +01003601 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003602
3603 def setUp(self):
3604 super(ShutdownTest, self).setUp()
3605 self.called = []
3606
3607 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003608 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003609
3610 def raise_error(self, error):
3611 def inner():
3612 raise error()
3613 return inner
3614
3615 def test_no_failure(self):
3616 # create some fake handlers
3617 handler0 = FakeHandler(0, self.called)
3618 handler1 = FakeHandler(1, self.called)
3619 handler2 = FakeHandler(2, self.called)
3620
3621 # create live weakref to those handlers
3622 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3623
3624 logging.shutdown(handlerList=list(handlers))
3625
3626 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3627 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3628 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3629 self.assertEqual(expected, self.called)
3630
3631 def _test_with_failure_in_method(self, method, error):
3632 handler = FakeHandler(0, self.called)
3633 setattr(handler, method, self.raise_error(error))
3634 handlers = [logging.weakref.ref(handler)]
3635
3636 logging.shutdown(handlerList=list(handlers))
3637
3638 self.assertEqual('0 - release', self.called[-1])
3639
3640 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003641 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003642
3643 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003644 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003645
3646 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003647 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003648
3649 def test_with_valueerror_in_acquire(self):
3650 self._test_with_failure_in_method('acquire', ValueError)
3651
3652 def test_with_valueerror_in_flush(self):
3653 self._test_with_failure_in_method('flush', ValueError)
3654
3655 def test_with_valueerror_in_close(self):
3656 self._test_with_failure_in_method('close', ValueError)
3657
3658 def test_with_other_error_in_acquire_without_raise(self):
3659 logging.raiseExceptions = False
3660 self._test_with_failure_in_method('acquire', IndexError)
3661
3662 def test_with_other_error_in_flush_without_raise(self):
3663 logging.raiseExceptions = False
3664 self._test_with_failure_in_method('flush', IndexError)
3665
3666 def test_with_other_error_in_close_without_raise(self):
3667 logging.raiseExceptions = False
3668 self._test_with_failure_in_method('close', IndexError)
3669
3670 def test_with_other_error_in_acquire_with_raise(self):
3671 logging.raiseExceptions = True
3672 self.assertRaises(IndexError, self._test_with_failure_in_method,
3673 'acquire', IndexError)
3674
3675 def test_with_other_error_in_flush_with_raise(self):
3676 logging.raiseExceptions = True
3677 self.assertRaises(IndexError, self._test_with_failure_in_method,
3678 'flush', IndexError)
3679
3680 def test_with_other_error_in_close_with_raise(self):
3681 logging.raiseExceptions = True
3682 self.assertRaises(IndexError, self._test_with_failure_in_method,
3683 'close', IndexError)
3684
3685
3686class ModuleLevelMiscTest(BaseTest):
3687
Vinay Sajip5e66b162011-04-20 15:41:14 +01003688 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003689
3690 def test_disable(self):
3691 old_disable = logging.root.manager.disable
3692 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003693 self.assertEqual(old_disable, 0)
3694 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003695
3696 logging.disable(83)
3697 self.assertEqual(logging.root.manager.disable, 83)
3698
Vinay Sajipd489ac92016-12-31 11:40:11 +00003699 # test the default value introduced in 3.7
3700 # (Issue #28524)
3701 logging.disable()
3702 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3703
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003704 def _test_log(self, method, level=None):
3705 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003706 support.patch(self, logging, 'basicConfig',
3707 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003708
3709 recording = RecordingHandler()
3710 logging.root.addHandler(recording)
3711
3712 log_method = getattr(logging, method)
3713 if level is not None:
3714 log_method(level, "test me: %r", recording)
3715 else:
3716 log_method("test me: %r", recording)
3717
3718 self.assertEqual(len(recording.records), 1)
3719 record = recording.records[0]
3720 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3721
3722 expected_level = level if level is not None else getattr(logging, method.upper())
3723 self.assertEqual(record.levelno, expected_level)
3724
3725 # basicConfig was not called!
3726 self.assertEqual(called, [])
3727
3728 def test_log(self):
3729 self._test_log('log', logging.ERROR)
3730
3731 def test_debug(self):
3732 self._test_log('debug')
3733
3734 def test_info(self):
3735 self._test_log('info')
3736
3737 def test_warning(self):
3738 self._test_log('warning')
3739
3740 def test_error(self):
3741 self._test_log('error')
3742
3743 def test_critical(self):
3744 self._test_log('critical')
3745
3746 def test_set_logger_class(self):
3747 self.assertRaises(TypeError, logging.setLoggerClass, object)
3748
3749 class MyLogger(logging.Logger):
3750 pass
3751
3752 logging.setLoggerClass(MyLogger)
3753 self.assertEqual(logging.getLoggerClass(), MyLogger)
3754
3755 logging.setLoggerClass(logging.Logger)
3756 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3757
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003758 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003759 def test_logging_at_shutdown(self):
3760 # Issue #20037
3761 code = """if 1:
3762 import logging
3763
3764 class A:
3765 def __del__(self):
3766 try:
3767 raise ValueError("some error")
3768 except Exception:
3769 logging.exception("exception in __del__")
3770
3771 a = A()"""
3772 rc, out, err = assert_python_ok("-c", code)
3773 err = err.decode()
3774 self.assertIn("exception in __del__", err)
3775 self.assertIn("ValueError: some error", err)
3776
3777
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003778class LogRecordTest(BaseTest):
3779 def test_str_rep(self):
3780 r = logging.makeLogRecord({})
3781 s = str(r)
3782 self.assertTrue(s.startswith('<LogRecord: '))
3783 self.assertTrue(s.endswith('>'))
3784
3785 def test_dict_arg(self):
3786 h = RecordingHandler()
3787 r = logging.getLogger()
3788 r.addHandler(h)
3789 d = {'less' : 'more' }
3790 logging.warning('less is %(less)s', d)
3791 self.assertIs(h.records[0].args, d)
3792 self.assertEqual(h.records[0].message, 'less is more')
3793 r.removeHandler(h)
3794 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003795
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003796 def test_multiprocessing(self):
3797 r = logging.makeLogRecord({})
3798 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003799 try:
3800 import multiprocessing as mp
3801 r = logging.makeLogRecord({})
3802 self.assertEqual(r.processName, mp.current_process().name)
3803 except ImportError:
3804 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003805
3806 def test_optional(self):
3807 r = logging.makeLogRecord({})
3808 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003809 NOT_NONE(r.thread)
3810 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003811 NOT_NONE(r.process)
3812 NOT_NONE(r.processName)
3813 log_threads = logging.logThreads
3814 log_processes = logging.logProcesses
3815 log_multiprocessing = logging.logMultiprocessing
3816 try:
3817 logging.logThreads = False
3818 logging.logProcesses = False
3819 logging.logMultiprocessing = False
3820 r = logging.makeLogRecord({})
3821 NONE = self.assertIsNone
3822 NONE(r.thread)
3823 NONE(r.threadName)
3824 NONE(r.process)
3825 NONE(r.processName)
3826 finally:
3827 logging.logThreads = log_threads
3828 logging.logProcesses = log_processes
3829 logging.logMultiprocessing = log_multiprocessing
3830
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003831class BasicConfigTest(unittest.TestCase):
3832
Vinay Sajip95bf5042011-04-20 11:50:56 +01003833 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003834
3835 def setUp(self):
3836 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003837 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003838 self.saved_handlers = logging._handlers.copy()
3839 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003840 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003841 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003842 logging.root.handlers = []
3843
3844 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003845 for h in logging.root.handlers[:]:
3846 logging.root.removeHandler(h)
3847 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003848 super(BasicConfigTest, self).tearDown()
3849
Vinay Sajip3def7e02011-04-20 10:58:06 +01003850 def cleanup(self):
3851 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003852 logging._handlers.clear()
3853 logging._handlers.update(self.saved_handlers)
3854 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003855 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003856
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003857 def test_no_kwargs(self):
3858 logging.basicConfig()
3859
3860 # handler defaults to a StreamHandler to sys.stderr
3861 self.assertEqual(len(logging.root.handlers), 1)
3862 handler = logging.root.handlers[0]
3863 self.assertIsInstance(handler, logging.StreamHandler)
3864 self.assertEqual(handler.stream, sys.stderr)
3865
3866 formatter = handler.formatter
3867 # format defaults to logging.BASIC_FORMAT
3868 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3869 # datefmt defaults to None
3870 self.assertIsNone(formatter.datefmt)
3871 # style defaults to %
3872 self.assertIsInstance(formatter._style, logging.PercentStyle)
3873
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003874 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003875 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003876
Vinay Sajip1fd12022014-01-13 21:59:56 +00003877 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003878 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003879 logging.basicConfig(stream=sys.stdout, style="{")
3880 logging.error("Log an error")
3881 sys.stdout.seek(0)
3882 self.assertEqual(output.getvalue().strip(),
3883 "ERROR:root:Log an error")
3884
3885 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003886 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003887 logging.basicConfig(stream=sys.stdout, style="$")
3888 logging.error("Log an error")
3889 sys.stdout.seek(0)
3890 self.assertEqual(output.getvalue().strip(),
3891 "ERROR:root:Log an error")
3892
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003893 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003894
3895 def cleanup(h1, h2, fn):
3896 h1.close()
3897 h2.close()
3898 os.remove(fn)
3899
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003900 logging.basicConfig(filename='test.log')
3901
3902 self.assertEqual(len(logging.root.handlers), 1)
3903 handler = logging.root.handlers[0]
3904 self.assertIsInstance(handler, logging.FileHandler)
3905
3906 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003907 self.assertEqual(handler.stream.mode, expected.stream.mode)
3908 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003909 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003910
3911 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003912
3913 def cleanup(h1, h2, fn):
3914 h1.close()
3915 h2.close()
3916 os.remove(fn)
3917
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003918 logging.basicConfig(filename='test.log', filemode='wb')
3919
3920 handler = logging.root.handlers[0]
3921 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003922 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003923 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003924
3925 def test_stream(self):
3926 stream = io.StringIO()
3927 self.addCleanup(stream.close)
3928 logging.basicConfig(stream=stream)
3929
3930 self.assertEqual(len(logging.root.handlers), 1)
3931 handler = logging.root.handlers[0]
3932 self.assertIsInstance(handler, logging.StreamHandler)
3933 self.assertEqual(handler.stream, stream)
3934
3935 def test_format(self):
3936 logging.basicConfig(format='foo')
3937
3938 formatter = logging.root.handlers[0].formatter
3939 self.assertEqual(formatter._style._fmt, 'foo')
3940
3941 def test_datefmt(self):
3942 logging.basicConfig(datefmt='bar')
3943
3944 formatter = logging.root.handlers[0].formatter
3945 self.assertEqual(formatter.datefmt, 'bar')
3946
3947 def test_style(self):
3948 logging.basicConfig(style='$')
3949
3950 formatter = logging.root.handlers[0].formatter
3951 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3952
3953 def test_level(self):
3954 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003955 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003956
3957 logging.basicConfig(level=57)
3958 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003959 # Test that second call has no effect
3960 logging.basicConfig(level=58)
3961 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003962
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003963 def test_incompatible(self):
3964 assertRaises = self.assertRaises
3965 handlers = [logging.StreamHandler()]
3966 stream = sys.stderr
3967 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3968 stream=stream)
3969 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3970 handlers=handlers)
3971 assertRaises(ValueError, logging.basicConfig, stream=stream,
3972 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003973 # Issue 23207: test for invalid kwargs
3974 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3975 # Should pop both filename and filemode even if filename is None
3976 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003977
3978 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003979 handlers = [
3980 logging.StreamHandler(),
3981 logging.StreamHandler(sys.stdout),
3982 logging.StreamHandler(),
3983 ]
3984 f = logging.Formatter()
3985 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003986 logging.basicConfig(handlers=handlers)
3987 self.assertIs(handlers[0], logging.root.handlers[0])
3988 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003989 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003990 self.assertIsNotNone(handlers[0].formatter)
3991 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003992 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003993 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3994
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003995 def _test_log(self, method, level=None):
3996 # logging.root has no handlers so basicConfig should be called
3997 called = []
3998
3999 old_basic_config = logging.basicConfig
4000 def my_basic_config(*a, **kw):
4001 old_basic_config()
4002 old_level = logging.root.level
4003 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004004 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004005 called.append((a, kw))
4006
Vinay Sajip1feedb42014-05-31 08:19:12 +01004007 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004008
4009 log_method = getattr(logging, method)
4010 if level is not None:
4011 log_method(level, "test me")
4012 else:
4013 log_method("test me")
4014
4015 # basicConfig was called with no arguments
4016 self.assertEqual(called, [((), {})])
4017
4018 def test_log(self):
4019 self._test_log('log', logging.WARNING)
4020
4021 def test_debug(self):
4022 self._test_log('debug')
4023
4024 def test_info(self):
4025 self._test_log('info')
4026
4027 def test_warning(self):
4028 self._test_log('warning')
4029
4030 def test_error(self):
4031 self._test_log('error')
4032
4033 def test_critical(self):
4034 self._test_log('critical')
4035
4036
4037class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004038 def setUp(self):
4039 super(LoggerAdapterTest, self).setUp()
4040 old_handler_list = logging._handlerList[:]
4041
4042 self.recording = RecordingHandler()
4043 self.logger = logging.root
4044 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004045 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004046 self.addCleanup(self.recording.close)
4047
4048 def cleanup():
4049 logging._handlerList[:] = old_handler_list
4050
4051 self.addCleanup(cleanup)
4052 self.addCleanup(logging.shutdown)
4053 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4054
4055 def test_exception(self):
4056 msg = 'testing exception: %r'
4057 exc = None
4058 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004059 1 / 0
4060 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004061 exc = e
4062 self.adapter.exception(msg, self.recording)
4063
4064 self.assertEqual(len(self.recording.records), 1)
4065 record = self.recording.records[0]
4066 self.assertEqual(record.levelno, logging.ERROR)
4067 self.assertEqual(record.msg, msg)
4068 self.assertEqual(record.args, (self.recording,))
4069 self.assertEqual(record.exc_info,
4070 (exc.__class__, exc, exc.__traceback__))
4071
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004072 def test_exception_excinfo(self):
4073 try:
4074 1 / 0
4075 except ZeroDivisionError as e:
4076 exc = e
4077
4078 self.adapter.exception('exc_info test', exc_info=exc)
4079
4080 self.assertEqual(len(self.recording.records), 1)
4081 record = self.recording.records[0]
4082 self.assertEqual(record.exc_info,
4083 (exc.__class__, exc, exc.__traceback__))
4084
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004085 def test_critical(self):
4086 msg = 'critical test! %r'
4087 self.adapter.critical(msg, self.recording)
4088
4089 self.assertEqual(len(self.recording.records), 1)
4090 record = self.recording.records[0]
4091 self.assertEqual(record.levelno, logging.CRITICAL)
4092 self.assertEqual(record.msg, msg)
4093 self.assertEqual(record.args, (self.recording,))
4094
4095 def test_is_enabled_for(self):
4096 old_disable = self.adapter.logger.manager.disable
4097 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004098 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4099 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004100 self.assertFalse(self.adapter.isEnabledFor(32))
4101
4102 def test_has_handlers(self):
4103 self.assertTrue(self.adapter.hasHandlers())
4104
4105 for handler in self.logger.handlers:
4106 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004107
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004108 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004109 self.assertFalse(self.adapter.hasHandlers())
4110
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004111 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004112 class Adapter(logging.LoggerAdapter):
4113 prefix = 'Adapter'
4114
4115 def process(self, msg, kwargs):
4116 return f"{self.prefix} {msg}", kwargs
4117
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004118 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004119 adapter = Adapter(logger=self.logger, extra=None)
4120 adapter_adapter = Adapter(logger=adapter, extra=None)
4121 adapter_adapter.prefix = 'AdapterAdapter'
4122 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004123 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004124 self.assertEqual(len(self.recording.records), 1)
4125 record = self.recording.records[0]
4126 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004127 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004128 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004129 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004130 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004131 self.assertIs(self.logger.manager, orig_manager)
4132 temp_manager = object()
4133 try:
4134 adapter_adapter.manager = temp_manager
4135 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004136 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004137 self.assertIs(self.logger.manager, temp_manager)
4138 finally:
4139 adapter_adapter.manager = orig_manager
4140 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004141 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004142 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004143
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004144
4145class LoggerTest(BaseTest):
4146
4147 def setUp(self):
4148 super(LoggerTest, self).setUp()
4149 self.recording = RecordingHandler()
4150 self.logger = logging.Logger(name='blah')
4151 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004152 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004153 self.addCleanup(self.recording.close)
4154 self.addCleanup(logging.shutdown)
4155
4156 def test_set_invalid_level(self):
4157 self.assertRaises(TypeError, self.logger.setLevel, object())
4158
4159 def test_exception(self):
4160 msg = 'testing exception: %r'
4161 exc = None
4162 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004163 1 / 0
4164 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004165 exc = e
4166 self.logger.exception(msg, self.recording)
4167
4168 self.assertEqual(len(self.recording.records), 1)
4169 record = self.recording.records[0]
4170 self.assertEqual(record.levelno, logging.ERROR)
4171 self.assertEqual(record.msg, msg)
4172 self.assertEqual(record.args, (self.recording,))
4173 self.assertEqual(record.exc_info,
4174 (exc.__class__, exc, exc.__traceback__))
4175
4176 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004177 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004178 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004179
4180 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004181 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004182 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004183
4184 def test_find_caller_with_stack_info(self):
4185 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004186 support.patch(self, logging.traceback, 'print_stack',
4187 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004188
4189 self.logger.findCaller(stack_info=True)
4190
4191 self.assertEqual(len(called), 1)
4192 self.assertEqual('Stack (most recent call last):\n', called[0])
4193
4194 def test_make_record_with_extra_overwrite(self):
4195 name = 'my record'
4196 level = 13
4197 fn = lno = msg = args = exc_info = func = sinfo = None
4198 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4199 exc_info, func, sinfo)
4200
4201 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4202 extra = {key: 'some value'}
4203 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4204 fn, lno, msg, args, exc_info,
4205 extra=extra, sinfo=sinfo)
4206
4207 def test_make_record_with_extra_no_overwrite(self):
4208 name = 'my record'
4209 level = 13
4210 fn = lno = msg = args = exc_info = func = sinfo = None
4211 extra = {'valid_key': 'some value'}
4212 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4213 exc_info, extra=extra, sinfo=sinfo)
4214 self.assertIn('valid_key', result.__dict__)
4215
4216 def test_has_handlers(self):
4217 self.assertTrue(self.logger.hasHandlers())
4218
4219 for handler in self.logger.handlers:
4220 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004221 self.assertFalse(self.logger.hasHandlers())
4222
4223 def test_has_handlers_no_propagate(self):
4224 child_logger = logging.getLogger('blah.child')
4225 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004226 self.assertFalse(child_logger.hasHandlers())
4227
4228 def test_is_enabled_for(self):
4229 old_disable = self.logger.manager.disable
4230 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004231 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004232 self.assertFalse(self.logger.isEnabledFor(22))
4233
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004234 def test_root_logger_aliases(self):
4235 root = logging.getLogger()
4236 self.assertIs(root, logging.root)
4237 self.assertIs(root, logging.getLogger(None))
4238 self.assertIs(root, logging.getLogger(''))
4239 self.assertIs(root, logging.getLogger('foo').root)
4240 self.assertIs(root, logging.getLogger('foo.bar').root)
4241 self.assertIs(root, logging.getLogger('foo').parent)
4242
4243 self.assertIsNot(root, logging.getLogger('\0'))
4244 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4245
4246 def test_invalid_names(self):
4247 self.assertRaises(TypeError, logging.getLogger, any)
4248 self.assertRaises(TypeError, logging.getLogger, b'foo')
4249
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004250 def test_pickling(self):
4251 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4252 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4253 logger = logging.getLogger(name)
4254 s = pickle.dumps(logger, proto)
4255 unpickled = pickle.loads(s)
4256 self.assertIs(unpickled, logger)
4257
Avram Lubkin78c18a92017-07-30 05:36:33 -04004258 def test_caching(self):
4259 root = self.root_logger
4260 logger1 = logging.getLogger("abc")
4261 logger2 = logging.getLogger("abc.def")
4262
4263 # Set root logger level and ensure cache is empty
4264 root.setLevel(logging.ERROR)
4265 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4266 self.assertEqual(logger2._cache, {})
4267
4268 # Ensure cache is populated and calls are consistent
4269 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4270 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4271 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4272 self.assertEqual(root._cache, {})
4273 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4274
4275 # Ensure root cache gets populated
4276 self.assertEqual(root._cache, {})
4277 self.assertTrue(root.isEnabledFor(logging.ERROR))
4278 self.assertEqual(root._cache, {logging.ERROR: True})
4279
4280 # Set parent logger level and ensure caches are emptied
4281 logger1.setLevel(logging.CRITICAL)
4282 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4283 self.assertEqual(logger2._cache, {})
4284
4285 # Ensure logger2 uses parent logger's effective level
4286 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4287
4288 # Set level to NOTSET and ensure caches are empty
4289 logger2.setLevel(logging.NOTSET)
4290 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4291 self.assertEqual(logger2._cache, {})
4292 self.assertEqual(logger1._cache, {})
4293 self.assertEqual(root._cache, {})
4294
4295 # Verify logger2 follows parent and not root
4296 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4297 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4298 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4299 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4300 self.assertTrue(root.isEnabledFor(logging.ERROR))
4301
4302 # Disable logging in manager and ensure caches are clear
4303 logging.disable()
4304 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4305 self.assertEqual(logger2._cache, {})
4306 self.assertEqual(logger1._cache, {})
4307 self.assertEqual(root._cache, {})
4308
4309 # Ensure no loggers are enabled
4310 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4311 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4312 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4313
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004314
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004315class BaseFileTest(BaseTest):
4316 "Base class for handler tests that write log files"
4317
4318 def setUp(self):
4319 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004320 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4321 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004322 self.rmfiles = []
4323
4324 def tearDown(self):
4325 for fn in self.rmfiles:
4326 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004327 if os.path.exists(self.fn):
4328 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004329 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004330
4331 def assertLogFile(self, filename):
4332 "Assert a log file is there and register it for deletion"
4333 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004334 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004335 self.rmfiles.append(filename)
4336
4337
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004338class FileHandlerTest(BaseFileTest):
4339 def test_delay(self):
4340 os.unlink(self.fn)
4341 fh = logging.FileHandler(self.fn, delay=True)
4342 self.assertIsNone(fh.stream)
4343 self.assertFalse(os.path.exists(self.fn))
4344 fh.handle(logging.makeLogRecord({}))
4345 self.assertIsNotNone(fh.stream)
4346 self.assertTrue(os.path.exists(self.fn))
4347 fh.close()
4348
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004349class RotatingFileHandlerTest(BaseFileTest):
4350 def next_rec(self):
4351 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4352 self.next_message(), None, None, None)
4353
4354 def test_should_not_rollover(self):
4355 # If maxbytes is zero rollover never occurs
4356 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4357 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004358 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004359
4360 def test_should_rollover(self):
4361 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4362 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004363 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004364
4365 def test_file_created(self):
4366 # checks that the file is created and assumes it was created
4367 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004368 rh = logging.handlers.RotatingFileHandler(self.fn)
4369 rh.emit(self.next_rec())
4370 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004371 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004372
4373 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004374 def namer(name):
4375 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004376 rh = logging.handlers.RotatingFileHandler(
4377 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004378 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004379 rh.emit(self.next_rec())
4380 self.assertLogFile(self.fn)
4381 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004382 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004383 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004384 self.assertLogFile(namer(self.fn + ".2"))
4385 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4386 rh.close()
4387
Vinay Sajip1feedb42014-05-31 08:19:12 +01004388 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004389 def test_rotator(self):
4390 def namer(name):
4391 return name + ".gz"
4392
4393 def rotator(source, dest):
4394 with open(source, "rb") as sf:
4395 data = sf.read()
4396 compressed = zlib.compress(data, 9)
4397 with open(dest, "wb") as df:
4398 df.write(compressed)
4399 os.remove(source)
4400
4401 rh = logging.handlers.RotatingFileHandler(
4402 self.fn, backupCount=2, maxBytes=1)
4403 rh.rotator = rotator
4404 rh.namer = namer
4405 m1 = self.next_rec()
4406 rh.emit(m1)
4407 self.assertLogFile(self.fn)
4408 m2 = self.next_rec()
4409 rh.emit(m2)
4410 fn = namer(self.fn + ".1")
4411 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004412 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004413 with open(fn, "rb") as f:
4414 compressed = f.read()
4415 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004416 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004417 rh.emit(self.next_rec())
4418 fn = namer(self.fn + ".2")
4419 self.assertLogFile(fn)
4420 with open(fn, "rb") as f:
4421 compressed = f.read()
4422 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004423 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004424 rh.emit(self.next_rec())
4425 fn = namer(self.fn + ".2")
4426 with open(fn, "rb") as f:
4427 compressed = f.read()
4428 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004429 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004430 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004431 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004432
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004433class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004434 # other test methods added below
4435 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004436 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4437 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004438 fmt = logging.Formatter('%(asctime)s %(message)s')
4439 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004440 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004441 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004442 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004443 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004444 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004445 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004446 fh.close()
4447 # At this point, we should have a recent rotated file which we
4448 # can test for the existence of. However, in practice, on some
4449 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004450 # in time to go to look for the log file. So, we go back a fair
4451 # bit, and stop as soon as we see a rotated file. In theory this
4452 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004453 found = False
4454 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004455 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004456 for secs in range(GO_BACK):
4457 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004458 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4459 found = os.path.exists(fn)
4460 if found:
4461 self.rmfiles.append(fn)
4462 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004463 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4464 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004465 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004466 dn, fn = os.path.split(self.fn)
4467 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004468 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4469 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004470 for f in files:
4471 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004472 path = os.path.join(dn, f)
4473 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004474 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004475 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004476
Vinay Sajip0372e102011-05-05 12:59:14 +01004477 def test_invalid(self):
4478 assertRaises = self.assertRaises
4479 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004480 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004481 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004482 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004483 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004484 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004485
Vinay Sajipa7130792013-04-12 17:04:23 +01004486 def test_compute_rollover_daily_attime(self):
4487 currentTime = 0
4488 atTime = datetime.time(12, 0, 0)
4489 rh = logging.handlers.TimedRotatingFileHandler(
4490 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4491 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004492 try:
4493 actual = rh.computeRollover(currentTime)
4494 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004495
Vinay Sajipd86ac962013-04-14 12:20:46 +01004496 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4497 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4498 finally:
4499 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004500
Vinay Sajip10e8c492013-05-18 10:19:54 -07004501 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004502 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004503 currentTime = int(time.time())
4504 today = currentTime - currentTime % 86400
4505
Vinay Sajipa7130792013-04-12 17:04:23 +01004506 atTime = datetime.time(12, 0, 0)
4507
Vinay Sajip10e8c492013-05-18 10:19:54 -07004508 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004509 for day in range(7):
4510 rh = logging.handlers.TimedRotatingFileHandler(
4511 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4512 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004513 try:
4514 if wday > day:
4515 # The rollover day has already passed this week, so we
4516 # go over into next week
4517 expected = (7 - wday + day)
4518 else:
4519 expected = (day - wday)
4520 # At this point expected is in days from now, convert to seconds
4521 expected *= 24 * 60 * 60
4522 # Add in the rollover time
4523 expected += 12 * 60 * 60
4524 # Add in adjustment for today
4525 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004526 actual = rh.computeRollover(today)
4527 if actual != expected:
4528 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004529 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004530 self.assertEqual(actual, expected)
4531 if day == wday:
4532 # goes into following week
4533 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004534 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004535 if actual != expected:
4536 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004537 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004538 self.assertEqual(actual, expected)
4539 finally:
4540 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004541
4542
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004543def secs(**kw):
4544 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4545
4546for when, exp in (('S', 1),
4547 ('M', 60),
4548 ('H', 60 * 60),
4549 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004550 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004551 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004552 ('W0', secs(days=4, hours=24)),
4553 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004554 def test_compute_rollover(self, when=when, exp=exp):
4555 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004556 self.fn, when=when, interval=1, backupCount=0, utc=True)
4557 currentTime = 0.0
4558 actual = rh.computeRollover(currentTime)
4559 if exp != actual:
4560 # Failures occur on some systems for MIDNIGHT and W0.
4561 # Print detailed calculation for MIDNIGHT so we can try to see
4562 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004563 if when == 'MIDNIGHT':
4564 try:
4565 if rh.utc:
4566 t = time.gmtime(currentTime)
4567 else:
4568 t = time.localtime(currentTime)
4569 currentHour = t[3]
4570 currentMinute = t[4]
4571 currentSecond = t[5]
4572 # r is the number of seconds left between now and midnight
4573 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4574 currentMinute) * 60 +
4575 currentSecond)
4576 result = currentTime + r
4577 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4578 print('currentHour: %s' % currentHour, file=sys.stderr)
4579 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4580 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4581 print('r: %s' % r, file=sys.stderr)
4582 print('result: %s' % result, file=sys.stderr)
4583 except Exception:
4584 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4585 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004586 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004587 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4588
Vinay Sajip60ccd822011-05-09 17:32:09 +01004589
Vinay Sajip223349c2015-10-01 20:37:54 +01004590@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004591class NTEventLogHandlerTest(BaseTest):
4592 def test_basic(self):
4593 logtype = 'Application'
4594 elh = win32evtlog.OpenEventLog(None, logtype)
4595 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004596
4597 try:
4598 h = logging.handlers.NTEventLogHandler('test_logging')
4599 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004600 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004601 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004602 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004603
Vinay Sajip60ccd822011-05-09 17:32:09 +01004604 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4605 h.handle(r)
4606 h.close()
4607 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004608 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004609 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4610 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4611 found = False
4612 GO_BACK = 100
4613 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4614 for e in events:
4615 if e.SourceName != 'test_logging':
4616 continue
4617 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4618 if msg != 'Test Log Message\r\n':
4619 continue
4620 found = True
4621 break
4622 msg = 'Record not found in event log, went back %d records' % GO_BACK
4623 self.assertTrue(found, msg=msg)
4624
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004625
4626class MiscTestCase(unittest.TestCase):
4627 def test__all__(self):
4628 blacklist = {'logThreads', 'logMultiprocessing',
4629 'logProcesses', 'currentframe',
4630 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4631 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004632 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004633 support.check__all__(self, logging, blacklist=blacklist)
4634
4635
Christian Heimes180510d2008-03-03 19:15:45 +00004636# Set the locale to the platform-dependent default. I have no idea
4637# why the test does this, but in any case we save the current locale
4638# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004639@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004640def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004641 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004642 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4643 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4644 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4645 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4646 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4647 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4648 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4649 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004650 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004651 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004652 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004653 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004654 ]
4655 if hasattr(logging.handlers, 'QueueListener'):
4656 tests.append(QueueListenerTest)
4657 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004658
Christian Heimes180510d2008-03-03 19:15:45 +00004659if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004660 test_main()