blob: a3731fa47939177ca18d9091e99457b4d41d1754 [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):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000974 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200975
Vinay Sajipa463d252011-04-30 21:52:48 +0100976 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100977 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800978 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100979 sockmap)
980 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800981 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000982 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
983 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100984 self.assertEqual(h.toaddrs, ['you'])
985 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100986 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100987 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100988 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000989 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100990 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000991 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100992 self.assertEqual(len(self.messages), 1)
993 peer, mailfrom, rcpttos, data = self.messages[0]
994 self.assertEqual(mailfrom, 'me')
995 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100996 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100997 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100998 h.close()
999
1000 def process_message(self, *args):
1001 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001002 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001003
Christian Heimes180510d2008-03-03 19:15:45 +00001004class MemoryHandlerTest(BaseTest):
1005
1006 """Tests for the MemoryHandler."""
1007
1008 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001009 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001010
1011 def setUp(self):
1012 BaseTest.setUp(self)
1013 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001014 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001015 self.mem_logger = logging.getLogger('mem')
1016 self.mem_logger.propagate = 0
1017 self.mem_logger.addHandler(self.mem_hdlr)
1018
1019 def tearDown(self):
1020 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001021 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001022
1023 def test_flush(self):
1024 # The memory handler flushes to its target handler based on specific
1025 # criteria (message count and message level).
1026 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001027 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001028 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001029 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001030 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001031 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001032 lines = [
1033 ('DEBUG', '1'),
1034 ('INFO', '2'),
1035 ('WARNING', '3'),
1036 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001037 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001038 for n in (4, 14):
1039 for i in range(9):
1040 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001041 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001042 # This will flush because it's the 10th message since the last
1043 # flush.
1044 self.mem_logger.debug(self.next_message())
1045 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001046 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001047
1048 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001049 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001050
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001051 def test_flush_on_close(self):
1052 """
1053 Test that the flush-on-close configuration works as expected.
1054 """
1055 self.mem_logger.debug(self.next_message())
1056 self.assert_log_lines([])
1057 self.mem_logger.info(self.next_message())
1058 self.assert_log_lines([])
1059 self.mem_logger.removeHandler(self.mem_hdlr)
1060 # Default behaviour is to flush on close. Check that it happens.
1061 self.mem_hdlr.close()
1062 lines = [
1063 ('DEBUG', '1'),
1064 ('INFO', '2'),
1065 ]
1066 self.assert_log_lines(lines)
1067 # Now configure for flushing not to be done on close.
1068 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1069 self.root_hdlr,
1070 False)
1071 self.mem_logger.addHandler(self.mem_hdlr)
1072 self.mem_logger.debug(self.next_message())
1073 self.assert_log_lines(lines) # no change
1074 self.mem_logger.info(self.next_message())
1075 self.assert_log_lines(lines) # no change
1076 self.mem_logger.removeHandler(self.mem_hdlr)
1077 self.mem_hdlr.close()
1078 # assert that no new lines have been added
1079 self.assert_log_lines(lines) # no change
1080
Christian Heimes180510d2008-03-03 19:15:45 +00001081
1082class ExceptionFormatter(logging.Formatter):
1083 """A special exception formatter."""
1084 def formatException(self, ei):
1085 return "Got a [%s]" % ei[0].__name__
1086
1087
1088class ConfigFileTest(BaseTest):
1089
1090 """Reading logging config from a .ini-style config file."""
1091
Xtreak087570a2018-07-02 14:27:46 +05301092 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001093 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001094
1095 # config0 is a standard configuration.
1096 config0 = """
1097 [loggers]
1098 keys=root
1099
1100 [handlers]
1101 keys=hand1
1102
1103 [formatters]
1104 keys=form1
1105
1106 [logger_root]
1107 level=WARNING
1108 handlers=hand1
1109
1110 [handler_hand1]
1111 class=StreamHandler
1112 level=NOTSET
1113 formatter=form1
1114 args=(sys.stdout,)
1115
1116 [formatter_form1]
1117 format=%(levelname)s ++ %(message)s
1118 datefmt=
1119 """
1120
1121 # config1 adds a little to the standard configuration.
1122 config1 = """
1123 [loggers]
1124 keys=root,parser
1125
1126 [handlers]
1127 keys=hand1
1128
1129 [formatters]
1130 keys=form1
1131
1132 [logger_root]
1133 level=WARNING
1134 handlers=
1135
1136 [logger_parser]
1137 level=DEBUG
1138 handlers=hand1
1139 propagate=1
1140 qualname=compiler.parser
1141
1142 [handler_hand1]
1143 class=StreamHandler
1144 level=NOTSET
1145 formatter=form1
1146 args=(sys.stdout,)
1147
1148 [formatter_form1]
1149 format=%(levelname)s ++ %(message)s
1150 datefmt=
1151 """
1152
Vinay Sajip3f84b072011-03-07 17:49:33 +00001153 # config1a moves the handler to the root.
1154 config1a = """
1155 [loggers]
1156 keys=root,parser
1157
1158 [handlers]
1159 keys=hand1
1160
1161 [formatters]
1162 keys=form1
1163
1164 [logger_root]
1165 level=WARNING
1166 handlers=hand1
1167
1168 [logger_parser]
1169 level=DEBUG
1170 handlers=
1171 propagate=1
1172 qualname=compiler.parser
1173
1174 [handler_hand1]
1175 class=StreamHandler
1176 level=NOTSET
1177 formatter=form1
1178 args=(sys.stdout,)
1179
1180 [formatter_form1]
1181 format=%(levelname)s ++ %(message)s
1182 datefmt=
1183 """
1184
Christian Heimes180510d2008-03-03 19:15:45 +00001185 # config2 has a subtle configuration error that should be reported
1186 config2 = config1.replace("sys.stdout", "sys.stbout")
1187
1188 # config3 has a less subtle configuration error
1189 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1190
1191 # config4 specifies a custom formatter class to be loaded
1192 config4 = """
1193 [loggers]
1194 keys=root
1195
1196 [handlers]
1197 keys=hand1
1198
1199 [formatters]
1200 keys=form1
1201
1202 [logger_root]
1203 level=NOTSET
1204 handlers=hand1
1205
1206 [handler_hand1]
1207 class=StreamHandler
1208 level=NOTSET
1209 formatter=form1
1210 args=(sys.stdout,)
1211
1212 [formatter_form1]
1213 class=""" + __name__ + """.ExceptionFormatter
1214 format=%(levelname)s:%(name)s:%(message)s
1215 datefmt=
1216 """
1217
Georg Brandl3dbca812008-07-23 16:10:53 +00001218 # config5 specifies a custom handler class to be loaded
1219 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1220
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001221 # config6 uses ', ' delimiters in the handlers and formatters sections
1222 config6 = """
1223 [loggers]
1224 keys=root,parser
1225
1226 [handlers]
1227 keys=hand1, hand2
1228
1229 [formatters]
1230 keys=form1, form2
1231
1232 [logger_root]
1233 level=WARNING
1234 handlers=
1235
1236 [logger_parser]
1237 level=DEBUG
1238 handlers=hand1
1239 propagate=1
1240 qualname=compiler.parser
1241
1242 [handler_hand1]
1243 class=StreamHandler
1244 level=NOTSET
1245 formatter=form1
1246 args=(sys.stdout,)
1247
1248 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001249 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001250 level=NOTSET
1251 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001252 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001253
1254 [formatter_form1]
1255 format=%(levelname)s ++ %(message)s
1256 datefmt=
1257
1258 [formatter_form2]
1259 format=%(message)s
1260 datefmt=
1261 """
1262
Preston Landers6ea56d22017-08-02 15:44:28 -05001263 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001264 config7 = """
1265 [loggers]
1266 keys=root,parser,compiler
1267
1268 [handlers]
1269 keys=hand1
1270
1271 [formatters]
1272 keys=form1
1273
1274 [logger_root]
1275 level=WARNING
1276 handlers=hand1
1277
1278 [logger_compiler]
1279 level=DEBUG
1280 handlers=
1281 propagate=1
1282 qualname=compiler
1283
1284 [logger_parser]
1285 level=DEBUG
1286 handlers=
1287 propagate=1
1288 qualname=compiler.parser
1289
1290 [handler_hand1]
1291 class=StreamHandler
1292 level=NOTSET
1293 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001294 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001295
1296 [formatter_form1]
1297 format=%(levelname)s ++ %(message)s
1298 datefmt=
1299 """
1300
Xtreak087570a2018-07-02 14:27:46 +05301301 # config 8, check for resource warning
1302 config8 = r"""
1303 [loggers]
1304 keys=root
1305
1306 [handlers]
1307 keys=file
1308
1309 [formatters]
1310 keys=
1311
1312 [logger_root]
1313 level=DEBUG
1314 handlers=file
1315
1316 [handler_file]
1317 class=FileHandler
1318 level=DEBUG
1319 args=("{tempfile}",)
1320 """
1321
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001322 disable_test = """
1323 [loggers]
1324 keys=root
1325
1326 [handlers]
1327 keys=screen
1328
1329 [formatters]
1330 keys=
1331
1332 [logger_root]
1333 level=DEBUG
1334 handlers=screen
1335
1336 [handler_screen]
1337 level=DEBUG
1338 class=StreamHandler
1339 args=(sys.stdout,)
1340 formatter=
1341 """
1342
1343 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001344 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001345 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001346
1347 def test_config0_ok(self):
1348 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001349 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001350 self.apply_config(self.config0)
1351 logger = logging.getLogger()
1352 # Won't output anything
1353 logger.info(self.next_message())
1354 # Outputs a message
1355 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001356 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001357 ('ERROR', '2'),
1358 ], stream=output)
1359 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001360 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001361
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001362 def test_config0_using_cp_ok(self):
1363 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001364 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001365 file = io.StringIO(textwrap.dedent(self.config0))
1366 cp = configparser.ConfigParser()
1367 cp.read_file(file)
1368 logging.config.fileConfig(cp)
1369 logger = logging.getLogger()
1370 # Won't output anything
1371 logger.info(self.next_message())
1372 # Outputs a message
1373 logger.error(self.next_message())
1374 self.assert_log_lines([
1375 ('ERROR', '2'),
1376 ], stream=output)
1377 # Original logger output is empty.
1378 self.assert_log_lines([])
1379
Georg Brandl3dbca812008-07-23 16:10:53 +00001380 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001381 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001382 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001383 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001384 logger = logging.getLogger("compiler.parser")
1385 # Both will output a message
1386 logger.info(self.next_message())
1387 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001388 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001389 ('INFO', '1'),
1390 ('ERROR', '2'),
1391 ], stream=output)
1392 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001393 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001394
1395 def test_config2_failure(self):
1396 # A simple config file which overrides the default settings.
1397 self.assertRaises(Exception, self.apply_config, self.config2)
1398
1399 def test_config3_failure(self):
1400 # A simple config file which overrides the default settings.
1401 self.assertRaises(Exception, self.apply_config, self.config3)
1402
1403 def test_config4_ok(self):
1404 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001405 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001406 self.apply_config(self.config4)
1407 logger = logging.getLogger()
1408 try:
1409 raise RuntimeError()
1410 except RuntimeError:
1411 logging.exception("just testing")
1412 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001413 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001414 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1415 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001416 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001417
Georg Brandl3dbca812008-07-23 16:10:53 +00001418 def test_config5_ok(self):
1419 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001420
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001421 def test_config6_ok(self):
1422 self.test_config1_ok(config=self.config6)
1423
Vinay Sajip3f84b072011-03-07 17:49:33 +00001424 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001425 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001426 self.apply_config(self.config1a)
1427 logger = logging.getLogger("compiler.parser")
1428 # See issue #11424. compiler-hyphenated sorts
1429 # between compiler and compiler.xyz and this
1430 # was preventing compiler.xyz from being included
1431 # in the child loggers of compiler because of an
1432 # overzealous loop termination condition.
1433 hyphenated = logging.getLogger('compiler-hyphenated')
1434 # All will output a message
1435 logger.info(self.next_message())
1436 logger.error(self.next_message())
1437 hyphenated.critical(self.next_message())
1438 self.assert_log_lines([
1439 ('INFO', '1'),
1440 ('ERROR', '2'),
1441 ('CRITICAL', '3'),
1442 ], stream=output)
1443 # Original logger output is empty.
1444 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001445 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001446 self.apply_config(self.config7)
1447 logger = logging.getLogger("compiler.parser")
1448 self.assertFalse(logger.disabled)
1449 # Both will output a message
1450 logger.info(self.next_message())
1451 logger.error(self.next_message())
1452 logger = logging.getLogger("compiler.lexer")
1453 # Both will output a message
1454 logger.info(self.next_message())
1455 logger.error(self.next_message())
1456 # Will not appear
1457 hyphenated.critical(self.next_message())
1458 self.assert_log_lines([
1459 ('INFO', '4'),
1460 ('ERROR', '5'),
1461 ('INFO', '6'),
1462 ('ERROR', '7'),
1463 ], stream=output)
1464 # Original logger output is empty.
1465 self.assert_log_lines([])
1466
Xtreak087570a2018-07-02 14:27:46 +05301467 def test_config8_ok(self):
1468
1469 def cleanup(h1, fn):
1470 h1.close()
1471 os.remove(fn)
1472
1473 with self.check_no_resource_warning():
1474 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1475 os.close(fd)
1476
1477 # Replace single backslash with double backslash in windows
1478 # to avoid unicode error during string formatting
1479 if os.name == "nt":
1480 fn = fn.replace("\\", "\\\\")
1481
1482 config8 = self.config8.format(tempfile=fn)
1483
1484 self.apply_config(config8)
1485 self.apply_config(config8)
1486
1487 handler = logging.root.handlers[0]
1488 self.addCleanup(cleanup, handler, fn)
1489
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001490 def test_logger_disabling(self):
1491 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001492 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001493 self.assertFalse(logger.disabled)
1494 self.apply_config(self.disable_test)
1495 self.assertTrue(logger.disabled)
1496 self.apply_config(self.disable_test, disable_existing_loggers=False)
1497 self.assertFalse(logger.disabled)
1498
Łukasz Langa214f18e2018-06-08 04:02:48 -07001499 def test_defaults_do_no_interpolation(self):
1500 """bpo-33802 defaults should not get interpolated"""
1501 ini = textwrap.dedent("""
1502 [formatters]
1503 keys=default
1504
1505 [formatter_default]
1506
1507 [handlers]
1508 keys=console
1509
1510 [handler_console]
1511 class=logging.StreamHandler
1512 args=tuple()
1513
1514 [loggers]
1515 keys=root
1516
1517 [logger_root]
1518 formatter=default
1519 handlers=console
1520 """).strip()
1521 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1522 try:
1523 os.write(fd, ini.encode('ascii'))
1524 os.close(fd)
1525 logging.config.fileConfig(
1526 fn,
1527 defaults=dict(
1528 version=1,
1529 disable_existing_loggers=False,
1530 formatters={
1531 "generic": {
1532 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1533 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1534 "class": "logging.Formatter"
1535 },
1536 },
1537 )
1538 )
1539 finally:
1540 os.unlink(fn)
1541
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001542
Christian Heimes180510d2008-03-03 19:15:45 +00001543class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001544
Christian Heimes180510d2008-03-03 19:15:45 +00001545 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001546
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001547 server_class = TestTCPServer
1548 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001549
Christian Heimes180510d2008-03-03 19:15:45 +00001550 def setUp(self):
1551 """Set up a TCP server to receive log messages, and a SocketHandler
1552 pointing to that server's address and port."""
1553 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001554 # Issue #29177: deal with errors that happen during setup
1555 self.server = self.sock_hdlr = self.server_exception = None
1556 try:
1557 self.server = server = self.server_class(self.address,
1558 self.handle_socket, 0.01)
1559 server.start()
1560 # Uncomment next line to test error recovery in setUp()
1561 # raise OSError('dummy error raised')
1562 except OSError as e:
1563 self.server_exception = e
1564 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001565 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001566 hcls = logging.handlers.SocketHandler
1567 if isinstance(server.server_address, tuple):
1568 self.sock_hdlr = hcls('localhost', server.port)
1569 else:
1570 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001571 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001572 self.root_logger.removeHandler(self.root_logger.handlers[0])
1573 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001574 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001575
Christian Heimes180510d2008-03-03 19:15:45 +00001576 def tearDown(self):
1577 """Shutdown the TCP server."""
1578 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001579 if self.sock_hdlr:
1580 self.root_logger.removeHandler(self.sock_hdlr)
1581 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001582 if self.server:
1583 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001584 finally:
1585 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001586
Vinay Sajip7367d082011-05-02 13:17:27 +01001587 def handle_socket(self, request):
1588 conn = request.connection
1589 while True:
1590 chunk = conn.recv(4)
1591 if len(chunk) < 4:
1592 break
1593 slen = struct.unpack(">L", chunk)[0]
1594 chunk = conn.recv(slen)
1595 while len(chunk) < slen:
1596 chunk = chunk + conn.recv(slen - len(chunk))
1597 obj = pickle.loads(chunk)
1598 record = logging.makeLogRecord(obj)
1599 self.log_output += record.msg + '\n'
1600 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001601
Christian Heimes180510d2008-03-03 19:15:45 +00001602 def test_output(self):
1603 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001604 if self.server_exception:
1605 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001606 logger = logging.getLogger("tcp")
1607 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001608 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001609 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001610 self.handled.acquire()
1611 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001612
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001613 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001614 if self.server_exception:
1615 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001616 # Avoid timing-related failures due to SocketHandler's own hard-wired
1617 # one-second timeout on socket.create_connection() (issue #16264).
1618 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001619 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001620 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001621 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001622 try:
1623 raise RuntimeError('Deliberate mistake')
1624 except RuntimeError:
1625 self.root_logger.exception('Never sent')
1626 self.root_logger.error('Never sent, either')
1627 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001628 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001629 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1630 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001631
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001632def _get_temp_domain_socket():
1633 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1634 os.close(fd)
1635 # just need a name - file can't be present, or we'll get an
1636 # 'address already in use' error.
1637 os.remove(fn)
1638 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001639
Victor Stinnerec5a8602014-06-02 14:41:51 +02001640@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001641class UnixSocketHandlerTest(SocketHandlerTest):
1642
1643 """Test for SocketHandler with unix sockets."""
1644
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001645 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001646 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001647
1648 def setUp(self):
1649 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001650 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001651 SocketHandlerTest.setUp(self)
1652
1653 def tearDown(self):
1654 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001655 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001656
Vinay Sajip7367d082011-05-02 13:17:27 +01001657class DatagramHandlerTest(BaseTest):
1658
1659 """Test for DatagramHandler."""
1660
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001661 server_class = TestUDPServer
1662 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001663
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 def setUp(self):
1665 """Set up a UDP server to receive log messages, and a DatagramHandler
1666 pointing to that server's address and port."""
1667 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001668 # Issue #29177: deal with errors that happen during setup
1669 self.server = self.sock_hdlr = self.server_exception = None
1670 try:
1671 self.server = server = self.server_class(self.address,
1672 self.handle_datagram, 0.01)
1673 server.start()
1674 # Uncomment next line to test error recovery in setUp()
1675 # raise OSError('dummy error raised')
1676 except OSError as e:
1677 self.server_exception = e
1678 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001680 hcls = logging.handlers.DatagramHandler
1681 if isinstance(server.server_address, tuple):
1682 self.sock_hdlr = hcls('localhost', server.port)
1683 else:
1684 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001685 self.log_output = ''
1686 self.root_logger.removeHandler(self.root_logger.handlers[0])
1687 self.root_logger.addHandler(self.sock_hdlr)
1688 self.handled = threading.Event()
1689
1690 def tearDown(self):
1691 """Shutdown the UDP server."""
1692 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001693 if self.server:
1694 self.server.stop(2.0)
1695 if self.sock_hdlr:
1696 self.root_logger.removeHandler(self.sock_hdlr)
1697 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001698 finally:
1699 BaseTest.tearDown(self)
1700
1701 def handle_datagram(self, request):
1702 slen = struct.pack('>L', 0) # length of prefix
1703 packet = request.packet[len(slen):]
1704 obj = pickle.loads(packet)
1705 record = logging.makeLogRecord(obj)
1706 self.log_output += record.msg + '\n'
1707 self.handled.set()
1708
1709 def test_output(self):
1710 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001711 if self.server_exception:
1712 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001713 logger = logging.getLogger("udp")
1714 logger.error("spam")
1715 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001716 self.handled.clear()
1717 logger.error("eggs")
1718 self.handled.wait()
1719 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001720
Victor Stinnerec5a8602014-06-02 14:41:51 +02001721@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001722class UnixDatagramHandlerTest(DatagramHandlerTest):
1723
1724 """Test for DatagramHandler using Unix sockets."""
1725
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001726 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001727 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001728
1729 def setUp(self):
1730 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001731 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001732 DatagramHandlerTest.setUp(self)
1733
1734 def tearDown(self):
1735 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001736 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001737
Vinay Sajip7367d082011-05-02 13:17:27 +01001738class SysLogHandlerTest(BaseTest):
1739
1740 """Test for SysLogHandler using UDP."""
1741
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001742 server_class = TestUDPServer
1743 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001744
Vinay Sajip7367d082011-05-02 13:17:27 +01001745 def setUp(self):
1746 """Set up a UDP server to receive log messages, and a SysLogHandler
1747 pointing to that server's address and port."""
1748 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001749 # Issue #29177: deal with errors that happen during setup
1750 self.server = self.sl_hdlr = self.server_exception = None
1751 try:
1752 self.server = server = self.server_class(self.address,
1753 self.handle_datagram, 0.01)
1754 server.start()
1755 # Uncomment next line to test error recovery in setUp()
1756 # raise OSError('dummy error raised')
1757 except OSError as e:
1758 self.server_exception = e
1759 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001760 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001761 hcls = logging.handlers.SysLogHandler
1762 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001763 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001764 else:
1765 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001766 self.log_output = ''
1767 self.root_logger.removeHandler(self.root_logger.handlers[0])
1768 self.root_logger.addHandler(self.sl_hdlr)
1769 self.handled = threading.Event()
1770
1771 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001772 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001773 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001774 if self.server:
1775 self.server.stop(2.0)
1776 if self.sl_hdlr:
1777 self.root_logger.removeHandler(self.sl_hdlr)
1778 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001779 finally:
1780 BaseTest.tearDown(self)
1781
1782 def handle_datagram(self, request):
1783 self.log_output = request.packet
1784 self.handled.set()
1785
1786 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001787 if self.server_exception:
1788 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001789 # The log message sent to the SysLogHandler is properly received.
1790 logger = logging.getLogger("slh")
1791 logger.error("sp\xe4m")
1792 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001793 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001794 self.handled.clear()
1795 self.sl_hdlr.append_nul = False
1796 logger.error("sp\xe4m")
1797 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001798 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001799 self.handled.clear()
1800 self.sl_hdlr.ident = "h\xe4m-"
1801 logger.error("sp\xe4m")
1802 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001803 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001804
Victor Stinnerec5a8602014-06-02 14:41:51 +02001805@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001806class UnixSysLogHandlerTest(SysLogHandlerTest):
1807
1808 """Test for SysLogHandler with Unix sockets."""
1809
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001810 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001811 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001812
1813 def setUp(self):
1814 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001815 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001816 SysLogHandlerTest.setUp(self)
1817
1818 def tearDown(self):
1819 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001820 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001821
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001822@unittest.skipUnless(support.IPV6_ENABLED,
1823 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001824class IPv6SysLogHandlerTest(SysLogHandlerTest):
1825
1826 """Test for SysLogHandler with IPv6 host."""
1827
1828 server_class = TestUDPServer
1829 address = ('::1', 0)
1830
1831 def setUp(self):
1832 self.server_class.address_family = socket.AF_INET6
1833 super(IPv6SysLogHandlerTest, self).setUp()
1834
1835 def tearDown(self):
1836 self.server_class.address_family = socket.AF_INET
1837 super(IPv6SysLogHandlerTest, self).tearDown()
1838
Vinay Sajip7367d082011-05-02 13:17:27 +01001839class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001840 """Test for HTTPHandler."""
1841
1842 def setUp(self):
1843 """Set up an HTTP server to receive log messages, and a HTTPHandler
1844 pointing to that server's address and port."""
1845 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001846 self.handled = threading.Event()
1847
Vinay Sajip7367d082011-05-02 13:17:27 +01001848 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001849 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001850 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001851 if self.command == 'POST':
1852 try:
1853 rlen = int(request.headers['Content-Length'])
1854 self.post_data = request.rfile.read(rlen)
1855 except:
1856 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001857 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001858 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001859 self.handled.set()
1860
1861 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001862 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001863 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001864 root_logger = self.root_logger
1865 root_logger.removeHandler(self.root_logger.handlers[0])
1866 for secure in (False, True):
1867 addr = ('localhost', 0)
1868 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001869 try:
1870 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001871 except ImportError:
1872 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001873 else:
1874 here = os.path.dirname(__file__)
1875 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001876 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001877 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001878
1879 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001880 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001881 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001882 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001883 self.server = server = TestHTTPServer(addr, self.handle_request,
1884 0.01, sslctx=sslctx)
1885 server.start()
1886 server.ready.wait()
1887 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001888 secure_client = secure and sslctx
1889 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001890 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001891 context=context,
1892 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001893 self.log_data = None
1894 root_logger.addHandler(self.h_hdlr)
1895
1896 for method in ('GET', 'POST'):
1897 self.h_hdlr.method = method
1898 self.handled.clear()
1899 msg = "sp\xe4m"
1900 logger.error(msg)
1901 self.handled.wait()
1902 self.assertEqual(self.log_data.path, '/frob')
1903 self.assertEqual(self.command, method)
1904 if method == 'GET':
1905 d = parse_qs(self.log_data.query)
1906 else:
1907 d = parse_qs(self.post_data.decode('utf-8'))
1908 self.assertEqual(d['name'], ['http'])
1909 self.assertEqual(d['funcName'], ['test_output'])
1910 self.assertEqual(d['msg'], [msg])
1911
1912 self.server.stop(2.0)
1913 self.root_logger.removeHandler(self.h_hdlr)
1914 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001915
Christian Heimes180510d2008-03-03 19:15:45 +00001916class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001917
Christian Heimes180510d2008-03-03 19:15:45 +00001918 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001919
Christian Heimes180510d2008-03-03 19:15:45 +00001920 def setUp(self):
1921 """Create a dict to remember potentially destroyed objects."""
1922 BaseTest.setUp(self)
1923 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001924
Christian Heimes180510d2008-03-03 19:15:45 +00001925 def _watch_for_survival(self, *args):
1926 """Watch the given objects for survival, by creating weakrefs to
1927 them."""
1928 for obj in args:
1929 key = id(obj), repr(obj)
1930 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001931
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001932 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001933 """Assert that all objects watched for survival have survived."""
1934 # Trigger cycle breaking.
1935 gc.collect()
1936 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001937 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001938 if ref() is None:
1939 dead.append(repr_)
1940 if dead:
1941 self.fail("%d objects should have survived "
1942 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001943
Christian Heimes180510d2008-03-03 19:15:45 +00001944 def test_persistent_loggers(self):
1945 # Logger objects are persistent and retain their configuration, even
1946 # if visible references are destroyed.
1947 self.root_logger.setLevel(logging.INFO)
1948 foo = logging.getLogger("foo")
1949 self._watch_for_survival(foo)
1950 foo.setLevel(logging.DEBUG)
1951 self.root_logger.debug(self.next_message())
1952 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001953 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001954 ('foo', 'DEBUG', '2'),
1955 ])
1956 del foo
1957 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001958 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001959 # foo has retained its settings.
1960 bar = logging.getLogger("foo")
1961 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001962 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001963 ('foo', 'DEBUG', '2'),
1964 ('foo', 'DEBUG', '3'),
1965 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001966
Benjamin Petersonf91df042009-02-13 02:50:59 +00001967
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001968class EncodingTest(BaseTest):
1969 def test_encoding_plain_file(self):
1970 # In Python 2.x, a plain file object is treated as having no encoding.
1971 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001972 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1973 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001974 # the non-ascii data we write to the log.
1975 data = "foo\x80"
1976 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001977 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001978 log.addHandler(handler)
1979 try:
1980 # write non-ascii data to the log.
1981 log.warning(data)
1982 finally:
1983 log.removeHandler(handler)
1984 handler.close()
1985 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001986 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001987 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001988 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001989 finally:
1990 f.close()
1991 finally:
1992 if os.path.isfile(fn):
1993 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001994
Benjamin Petersonf91df042009-02-13 02:50:59 +00001995 def test_encoding_cyrillic_unicode(self):
1996 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03001997 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00001998 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03001999 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00002000 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00002001 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00002002 stream = io.BytesIO()
2003 writer = writer_class(stream, 'strict')
2004 handler = logging.StreamHandler(writer)
2005 log.addHandler(handler)
2006 try:
2007 log.warning(message)
2008 finally:
2009 log.removeHandler(handler)
2010 handler.close()
2011 # check we wrote exactly those bytes, ignoring trailing \n etc
2012 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03002013 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00002014 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
2015
2016
Georg Brandlf9734072008-12-07 15:30:06 +00002017class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00002018
Georg Brandlf9734072008-12-07 15:30:06 +00002019 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00002020 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00002021 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002022 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002023 warnings.filterwarnings("always", category=UserWarning)
2024 stream = io.StringIO()
2025 h = logging.StreamHandler(stream)
2026 logger = logging.getLogger("py.warnings")
2027 logger.addHandler(h)
2028 warnings.warn("I'm warning you...")
2029 logger.removeHandler(h)
2030 s = stream.getvalue()
2031 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002032 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00002033
Mike53f7a7c2017-12-14 14:04:53 +03002034 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002035 a_file = io.StringIO()
2036 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
2037 a_file, "Dummy line")
2038 s = a_file.getvalue()
2039 a_file.close()
2040 self.assertEqual(s,
2041 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
2042
2043 def test_warnings_no_handlers(self):
2044 with warnings.catch_warnings():
2045 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002046 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002047
2048 # confirm our assumption: no loggers are set
2049 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002050 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002051
2052 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002053 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002054 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002055
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002056
2057def formatFunc(format, datefmt=None):
2058 return logging.Formatter(format, datefmt)
2059
2060def handlerFunc():
2061 return logging.StreamHandler()
2062
2063class CustomHandler(logging.StreamHandler):
2064 pass
2065
2066class ConfigDictTest(BaseTest):
2067
2068 """Reading logging config from a dictionary."""
2069
Xtreak087570a2018-07-02 14:27:46 +05302070 check_no_resource_warning = support.check_no_resource_warning
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002071 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002072
2073 # config0 is a standard configuration.
2074 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002075 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002076 'formatters': {
2077 'form1' : {
2078 'format' : '%(levelname)s ++ %(message)s',
2079 },
2080 },
2081 'handlers' : {
2082 'hand1' : {
2083 'class' : 'logging.StreamHandler',
2084 'formatter' : 'form1',
2085 'level' : 'NOTSET',
2086 'stream' : 'ext://sys.stdout',
2087 },
2088 },
2089 'root' : {
2090 'level' : 'WARNING',
2091 'handlers' : ['hand1'],
2092 },
2093 }
2094
2095 # config1 adds a little to the standard configuration.
2096 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002097 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002098 'formatters': {
2099 'form1' : {
2100 'format' : '%(levelname)s ++ %(message)s',
2101 },
2102 },
2103 'handlers' : {
2104 'hand1' : {
2105 'class' : 'logging.StreamHandler',
2106 'formatter' : 'form1',
2107 'level' : 'NOTSET',
2108 'stream' : 'ext://sys.stdout',
2109 },
2110 },
2111 'loggers' : {
2112 'compiler.parser' : {
2113 'level' : 'DEBUG',
2114 'handlers' : ['hand1'],
2115 },
2116 },
2117 'root' : {
2118 'level' : 'WARNING',
2119 },
2120 }
2121
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002122 # config1a moves the handler to the root. Used with config8a
2123 config1a = {
2124 'version': 1,
2125 'formatters': {
2126 'form1' : {
2127 'format' : '%(levelname)s ++ %(message)s',
2128 },
2129 },
2130 'handlers' : {
2131 'hand1' : {
2132 'class' : 'logging.StreamHandler',
2133 'formatter' : 'form1',
2134 'level' : 'NOTSET',
2135 'stream' : 'ext://sys.stdout',
2136 },
2137 },
2138 'loggers' : {
2139 'compiler.parser' : {
2140 'level' : 'DEBUG',
2141 },
2142 },
2143 'root' : {
2144 'level' : 'WARNING',
2145 'handlers' : ['hand1'],
2146 },
2147 }
2148
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002149 # config2 has a subtle configuration error that should be reported
2150 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002151 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002152 'formatters': {
2153 'form1' : {
2154 'format' : '%(levelname)s ++ %(message)s',
2155 },
2156 },
2157 'handlers' : {
2158 'hand1' : {
2159 'class' : 'logging.StreamHandler',
2160 'formatter' : 'form1',
2161 'level' : 'NOTSET',
2162 'stream' : 'ext://sys.stdbout',
2163 },
2164 },
2165 'loggers' : {
2166 'compiler.parser' : {
2167 'level' : 'DEBUG',
2168 'handlers' : ['hand1'],
2169 },
2170 },
2171 'root' : {
2172 'level' : 'WARNING',
2173 },
2174 }
2175
Mike53f7a7c2017-12-14 14:04:53 +03002176 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002177 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002178 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002179 'formatters': {
2180 'form1' : {
2181 'format' : '%(levelname)s ++ %(message)s',
2182 },
2183 },
2184 'handlers' : {
2185 'hand1' : {
2186 'class' : 'logging.StreamHandler',
2187 'formatter' : 'form1',
2188 'level' : 'NTOSET',
2189 'stream' : 'ext://sys.stdout',
2190 },
2191 },
2192 'loggers' : {
2193 'compiler.parser' : {
2194 'level' : 'DEBUG',
2195 'handlers' : ['hand1'],
2196 },
2197 },
2198 'root' : {
2199 'level' : 'WARNING',
2200 },
2201 }
2202
2203
Mike53f7a7c2017-12-14 14:04:53 +03002204 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002205 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002206 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002207 'formatters': {
2208 'form1' : {
2209 'format' : '%(levelname)s ++ %(message)s',
2210 },
2211 },
2212 'handlers' : {
2213 'hand1' : {
2214 'class' : 'logging.StreamHandler',
2215 'formatter' : 'form1',
2216 'level' : 'NOTSET',
2217 'stream' : 'ext://sys.stdout',
2218 },
2219 },
2220 'loggers' : {
2221 'compiler.parser' : {
2222 'level' : 'DEBUG',
2223 'handlers' : ['hand1'],
2224 },
2225 },
2226 'root' : {
2227 'level' : 'WRANING',
2228 },
2229 }
2230
2231 # config3 has a less subtle configuration error
2232 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002233 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002234 'formatters': {
2235 'form1' : {
2236 'format' : '%(levelname)s ++ %(message)s',
2237 },
2238 },
2239 'handlers' : {
2240 'hand1' : {
2241 'class' : 'logging.StreamHandler',
2242 'formatter' : 'misspelled_name',
2243 'level' : 'NOTSET',
2244 'stream' : 'ext://sys.stdout',
2245 },
2246 },
2247 'loggers' : {
2248 'compiler.parser' : {
2249 'level' : 'DEBUG',
2250 'handlers' : ['hand1'],
2251 },
2252 },
2253 'root' : {
2254 'level' : 'WARNING',
2255 },
2256 }
2257
2258 # config4 specifies a custom formatter class to be loaded
2259 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002260 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002261 'formatters': {
2262 'form1' : {
2263 '()' : __name__ + '.ExceptionFormatter',
2264 'format' : '%(levelname)s:%(name)s:%(message)s',
2265 },
2266 },
2267 'handlers' : {
2268 'hand1' : {
2269 'class' : 'logging.StreamHandler',
2270 'formatter' : 'form1',
2271 'level' : 'NOTSET',
2272 'stream' : 'ext://sys.stdout',
2273 },
2274 },
2275 'root' : {
2276 'level' : 'NOTSET',
2277 'handlers' : ['hand1'],
2278 },
2279 }
2280
2281 # As config4 but using an actual callable rather than a string
2282 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002283 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002284 'formatters': {
2285 'form1' : {
2286 '()' : ExceptionFormatter,
2287 'format' : '%(levelname)s:%(name)s:%(message)s',
2288 },
2289 'form2' : {
2290 '()' : __name__ + '.formatFunc',
2291 'format' : '%(levelname)s:%(name)s:%(message)s',
2292 },
2293 'form3' : {
2294 '()' : formatFunc,
2295 'format' : '%(levelname)s:%(name)s:%(message)s',
2296 },
2297 },
2298 'handlers' : {
2299 'hand1' : {
2300 'class' : 'logging.StreamHandler',
2301 'formatter' : 'form1',
2302 'level' : 'NOTSET',
2303 'stream' : 'ext://sys.stdout',
2304 },
2305 'hand2' : {
2306 '()' : handlerFunc,
2307 },
2308 },
2309 'root' : {
2310 'level' : 'NOTSET',
2311 'handlers' : ['hand1'],
2312 },
2313 }
2314
2315 # config5 specifies a custom handler class to be loaded
2316 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002317 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002318 'formatters': {
2319 'form1' : {
2320 'format' : '%(levelname)s ++ %(message)s',
2321 },
2322 },
2323 'handlers' : {
2324 'hand1' : {
2325 'class' : __name__ + '.CustomHandler',
2326 'formatter' : 'form1',
2327 'level' : 'NOTSET',
2328 'stream' : 'ext://sys.stdout',
2329 },
2330 },
2331 'loggers' : {
2332 'compiler.parser' : {
2333 'level' : 'DEBUG',
2334 'handlers' : ['hand1'],
2335 },
2336 },
2337 'root' : {
2338 'level' : 'WARNING',
2339 },
2340 }
2341
2342 # config6 specifies a custom handler class to be loaded
2343 # but has bad arguments
2344 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002345 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002346 'formatters': {
2347 'form1' : {
2348 'format' : '%(levelname)s ++ %(message)s',
2349 },
2350 },
2351 'handlers' : {
2352 'hand1' : {
2353 'class' : __name__ + '.CustomHandler',
2354 'formatter' : 'form1',
2355 'level' : 'NOTSET',
2356 'stream' : 'ext://sys.stdout',
2357 '9' : 'invalid parameter name',
2358 },
2359 },
2360 'loggers' : {
2361 'compiler.parser' : {
2362 'level' : 'DEBUG',
2363 'handlers' : ['hand1'],
2364 },
2365 },
2366 'root' : {
2367 'level' : 'WARNING',
2368 },
2369 }
2370
Mike53f7a7c2017-12-14 14:04:53 +03002371 # config 7 does not define compiler.parser but defines compiler.lexer
2372 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002373 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002374 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002375 'formatters': {
2376 'form1' : {
2377 'format' : '%(levelname)s ++ %(message)s',
2378 },
2379 },
2380 'handlers' : {
2381 'hand1' : {
2382 'class' : 'logging.StreamHandler',
2383 'formatter' : 'form1',
2384 'level' : 'NOTSET',
2385 'stream' : 'ext://sys.stdout',
2386 },
2387 },
2388 'loggers' : {
2389 'compiler.lexer' : {
2390 'level' : 'DEBUG',
2391 'handlers' : ['hand1'],
2392 },
2393 },
2394 'root' : {
2395 'level' : 'WARNING',
2396 },
2397 }
2398
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002399 # config8 defines both compiler and compiler.lexer
2400 # so compiler.parser should not be disabled (since
2401 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002402 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002403 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002404 'disable_existing_loggers' : False,
2405 'formatters': {
2406 'form1' : {
2407 'format' : '%(levelname)s ++ %(message)s',
2408 },
2409 },
2410 'handlers' : {
2411 'hand1' : {
2412 'class' : 'logging.StreamHandler',
2413 'formatter' : 'form1',
2414 'level' : 'NOTSET',
2415 'stream' : 'ext://sys.stdout',
2416 },
2417 },
2418 'loggers' : {
2419 'compiler' : {
2420 'level' : 'DEBUG',
2421 'handlers' : ['hand1'],
2422 },
2423 'compiler.lexer' : {
2424 },
2425 },
2426 'root' : {
2427 'level' : 'WARNING',
2428 },
2429 }
2430
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002431 # config8a disables existing loggers
2432 config8a = {
2433 'version': 1,
2434 'disable_existing_loggers' : True,
2435 'formatters': {
2436 'form1' : {
2437 'format' : '%(levelname)s ++ %(message)s',
2438 },
2439 },
2440 'handlers' : {
2441 'hand1' : {
2442 'class' : 'logging.StreamHandler',
2443 'formatter' : 'form1',
2444 'level' : 'NOTSET',
2445 'stream' : 'ext://sys.stdout',
2446 },
2447 },
2448 'loggers' : {
2449 'compiler' : {
2450 'level' : 'DEBUG',
2451 'handlers' : ['hand1'],
2452 },
2453 'compiler.lexer' : {
2454 },
2455 },
2456 'root' : {
2457 'level' : 'WARNING',
2458 },
2459 }
2460
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002461 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002462 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002463 'formatters': {
2464 'form1' : {
2465 'format' : '%(levelname)s ++ %(message)s',
2466 },
2467 },
2468 'handlers' : {
2469 'hand1' : {
2470 'class' : 'logging.StreamHandler',
2471 'formatter' : 'form1',
2472 'level' : 'WARNING',
2473 'stream' : 'ext://sys.stdout',
2474 },
2475 },
2476 'loggers' : {
2477 'compiler.parser' : {
2478 'level' : 'WARNING',
2479 'handlers' : ['hand1'],
2480 },
2481 },
2482 'root' : {
2483 'level' : 'NOTSET',
2484 },
2485 }
2486
2487 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002488 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002489 'incremental' : True,
2490 'handlers' : {
2491 'hand1' : {
2492 'level' : 'WARNING',
2493 },
2494 },
2495 'loggers' : {
2496 'compiler.parser' : {
2497 'level' : 'INFO',
2498 },
2499 },
2500 }
2501
2502 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002503 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002504 'incremental' : True,
2505 'handlers' : {
2506 'hand1' : {
2507 'level' : 'INFO',
2508 },
2509 },
2510 'loggers' : {
2511 'compiler.parser' : {
2512 'level' : 'INFO',
2513 },
2514 },
2515 }
2516
Mike53f7a7c2017-12-14 14:04:53 +03002517 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002518 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002519 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002520 'formatters': {
2521 'form1' : {
2522 'format' : '%(levelname)s ++ %(message)s',
2523 },
2524 },
2525 'filters' : {
2526 'filt1' : {
2527 'name' : 'compiler.parser',
2528 },
2529 },
2530 'handlers' : {
2531 'hand1' : {
2532 'class' : 'logging.StreamHandler',
2533 'formatter' : 'form1',
2534 'level' : 'NOTSET',
2535 'stream' : 'ext://sys.stdout',
2536 'filters' : ['filt1'],
2537 },
2538 },
2539 'loggers' : {
2540 'compiler.parser' : {
2541 'level' : 'DEBUG',
2542 'filters' : ['filt1'],
2543 },
2544 },
2545 'root' : {
2546 'level' : 'WARNING',
2547 'handlers' : ['hand1'],
2548 },
2549 }
2550
Mike53f7a7c2017-12-14 14:04:53 +03002551 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002552 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002553 'version': 1,
2554 'true_formatters': {
2555 'form1' : {
2556 'format' : '%(levelname)s ++ %(message)s',
2557 },
2558 },
2559 'handler_configs': {
2560 'hand1' : {
2561 'class' : 'logging.StreamHandler',
2562 'formatter' : 'form1',
2563 'level' : 'NOTSET',
2564 'stream' : 'ext://sys.stdout',
2565 },
2566 },
2567 'formatters' : 'cfg://true_formatters',
2568 'handlers' : {
2569 'hand1' : 'cfg://handler_configs[hand1]',
2570 },
2571 'loggers' : {
2572 'compiler.parser' : {
2573 'level' : 'DEBUG',
2574 'handlers' : ['hand1'],
2575 },
2576 },
2577 'root' : {
2578 'level' : 'WARNING',
2579 },
2580 }
2581
Mike53f7a7c2017-12-14 14:04:53 +03002582 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002583 config12 = {
2584 'true_formatters': {
2585 'form1' : {
2586 'format' : '%(levelname)s ++ %(message)s',
2587 },
2588 },
2589 'handler_configs': {
2590 'hand1' : {
2591 'class' : 'logging.StreamHandler',
2592 'formatter' : 'form1',
2593 'level' : 'NOTSET',
2594 'stream' : 'ext://sys.stdout',
2595 },
2596 },
2597 'formatters' : 'cfg://true_formatters',
2598 'handlers' : {
2599 'hand1' : 'cfg://handler_configs[hand1]',
2600 },
2601 'loggers' : {
2602 'compiler.parser' : {
2603 'level' : 'DEBUG',
2604 'handlers' : ['hand1'],
2605 },
2606 },
2607 'root' : {
2608 'level' : 'WARNING',
2609 },
2610 }
2611
Mike53f7a7c2017-12-14 14:04:53 +03002612 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002613 config13 = {
2614 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002615 'true_formatters': {
2616 'form1' : {
2617 'format' : '%(levelname)s ++ %(message)s',
2618 },
2619 },
2620 'handler_configs': {
2621 'hand1' : {
2622 'class' : 'logging.StreamHandler',
2623 'formatter' : 'form1',
2624 'level' : 'NOTSET',
2625 'stream' : 'ext://sys.stdout',
2626 },
2627 },
2628 'formatters' : 'cfg://true_formatters',
2629 'handlers' : {
2630 'hand1' : 'cfg://handler_configs[hand1]',
2631 },
2632 'loggers' : {
2633 'compiler.parser' : {
2634 'level' : 'DEBUG',
2635 'handlers' : ['hand1'],
2636 },
2637 },
2638 'root' : {
2639 'level' : 'WARNING',
2640 },
2641 }
2642
Vinay Sajip8d270232012-11-15 14:20:18 +00002643 # As config0, but with properties
2644 config14 = {
2645 'version': 1,
2646 'formatters': {
2647 'form1' : {
2648 'format' : '%(levelname)s ++ %(message)s',
2649 },
2650 },
2651 'handlers' : {
2652 'hand1' : {
2653 'class' : 'logging.StreamHandler',
2654 'formatter' : 'form1',
2655 'level' : 'NOTSET',
2656 'stream' : 'ext://sys.stdout',
2657 '.': {
2658 'foo': 'bar',
2659 'terminator': '!\n',
2660 }
2661 },
2662 },
2663 'root' : {
2664 'level' : 'WARNING',
2665 'handlers' : ['hand1'],
2666 },
2667 }
2668
Vinay Sajip3f885b52013-03-22 15:19:54 +00002669 out_of_order = {
2670 "version": 1,
2671 "formatters": {
2672 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002673 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2674 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002675 }
2676 },
2677 "handlers": {
2678 "fileGlobal": {
2679 "class": "logging.StreamHandler",
2680 "level": "DEBUG",
2681 "formatter": "mySimpleFormatter"
2682 },
2683 "bufferGlobal": {
2684 "class": "logging.handlers.MemoryHandler",
2685 "capacity": 5,
2686 "formatter": "mySimpleFormatter",
2687 "target": "fileGlobal",
2688 "level": "DEBUG"
2689 }
2690 },
2691 "loggers": {
2692 "mymodule": {
2693 "level": "DEBUG",
2694 "handlers": ["bufferGlobal"],
2695 "propagate": "true"
2696 }
2697 }
2698 }
2699
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002700 def apply_config(self, conf):
2701 logging.config.dictConfig(conf)
2702
2703 def test_config0_ok(self):
2704 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002705 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002706 self.apply_config(self.config0)
2707 logger = logging.getLogger()
2708 # Won't output anything
2709 logger.info(self.next_message())
2710 # Outputs a message
2711 logger.error(self.next_message())
2712 self.assert_log_lines([
2713 ('ERROR', '2'),
2714 ], stream=output)
2715 # Original logger output is empty.
2716 self.assert_log_lines([])
2717
2718 def test_config1_ok(self, config=config1):
2719 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002720 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002721 self.apply_config(config)
2722 logger = logging.getLogger("compiler.parser")
2723 # Both will output a message
2724 logger.info(self.next_message())
2725 logger.error(self.next_message())
2726 self.assert_log_lines([
2727 ('INFO', '1'),
2728 ('ERROR', '2'),
2729 ], stream=output)
2730 # Original logger output is empty.
2731 self.assert_log_lines([])
2732
2733 def test_config2_failure(self):
2734 # A simple config which overrides the default settings.
2735 self.assertRaises(Exception, self.apply_config, self.config2)
2736
2737 def test_config2a_failure(self):
2738 # A simple config which overrides the default settings.
2739 self.assertRaises(Exception, self.apply_config, self.config2a)
2740
2741 def test_config2b_failure(self):
2742 # A simple config which overrides the default settings.
2743 self.assertRaises(Exception, self.apply_config, self.config2b)
2744
2745 def test_config3_failure(self):
2746 # A simple config which overrides the default settings.
2747 self.assertRaises(Exception, self.apply_config, self.config3)
2748
2749 def test_config4_ok(self):
2750 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002751 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002752 self.apply_config(self.config4)
2753 #logger = logging.getLogger()
2754 try:
2755 raise RuntimeError()
2756 except RuntimeError:
2757 logging.exception("just testing")
2758 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002759 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002760 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2761 # Original logger output is empty
2762 self.assert_log_lines([])
2763
2764 def test_config4a_ok(self):
2765 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002766 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002767 self.apply_config(self.config4a)
2768 #logger = logging.getLogger()
2769 try:
2770 raise RuntimeError()
2771 except RuntimeError:
2772 logging.exception("just testing")
2773 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002774 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002775 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2776 # Original logger output is empty
2777 self.assert_log_lines([])
2778
2779 def test_config5_ok(self):
2780 self.test_config1_ok(config=self.config5)
2781
2782 def test_config6_failure(self):
2783 self.assertRaises(Exception, self.apply_config, self.config6)
2784
2785 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002786 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002787 self.apply_config(self.config1)
2788 logger = logging.getLogger("compiler.parser")
2789 # Both will output a message
2790 logger.info(self.next_message())
2791 logger.error(self.next_message())
2792 self.assert_log_lines([
2793 ('INFO', '1'),
2794 ('ERROR', '2'),
2795 ], stream=output)
2796 # Original logger output is empty.
2797 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002798 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002799 self.apply_config(self.config7)
2800 logger = logging.getLogger("compiler.parser")
2801 self.assertTrue(logger.disabled)
2802 logger = logging.getLogger("compiler.lexer")
2803 # Both will output a message
2804 logger.info(self.next_message())
2805 logger.error(self.next_message())
2806 self.assert_log_lines([
2807 ('INFO', '3'),
2808 ('ERROR', '4'),
2809 ], stream=output)
2810 # Original logger output is empty.
2811 self.assert_log_lines([])
2812
Mike53f7a7c2017-12-14 14:04:53 +03002813 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002814 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002815 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002816 self.apply_config(self.config1)
2817 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002818 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002819 logger.info(self.next_message())
2820 logger.error(self.next_message())
2821 self.assert_log_lines([
2822 ('INFO', '1'),
2823 ('ERROR', '2'),
2824 ], stream=output)
2825 # Original logger output is empty.
2826 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002827 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002828 self.apply_config(self.config8)
2829 logger = logging.getLogger("compiler.parser")
2830 self.assertFalse(logger.disabled)
2831 # Both will output a message
2832 logger.info(self.next_message())
2833 logger.error(self.next_message())
2834 logger = logging.getLogger("compiler.lexer")
2835 # Both will output a message
2836 logger.info(self.next_message())
2837 logger.error(self.next_message())
2838 self.assert_log_lines([
2839 ('INFO', '3'),
2840 ('ERROR', '4'),
2841 ('INFO', '5'),
2842 ('ERROR', '6'),
2843 ], stream=output)
2844 # Original logger output is empty.
2845 self.assert_log_lines([])
2846
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002847 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002848 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002849 self.apply_config(self.config1a)
2850 logger = logging.getLogger("compiler.parser")
2851 # See issue #11424. compiler-hyphenated sorts
2852 # between compiler and compiler.xyz and this
2853 # was preventing compiler.xyz from being included
2854 # in the child loggers of compiler because of an
2855 # overzealous loop termination condition.
2856 hyphenated = logging.getLogger('compiler-hyphenated')
2857 # All will output a message
2858 logger.info(self.next_message())
2859 logger.error(self.next_message())
2860 hyphenated.critical(self.next_message())
2861 self.assert_log_lines([
2862 ('INFO', '1'),
2863 ('ERROR', '2'),
2864 ('CRITICAL', '3'),
2865 ], stream=output)
2866 # Original logger output is empty.
2867 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002868 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002869 self.apply_config(self.config8a)
2870 logger = logging.getLogger("compiler.parser")
2871 self.assertFalse(logger.disabled)
2872 # Both will output a message
2873 logger.info(self.next_message())
2874 logger.error(self.next_message())
2875 logger = logging.getLogger("compiler.lexer")
2876 # Both will output a message
2877 logger.info(self.next_message())
2878 logger.error(self.next_message())
2879 # Will not appear
2880 hyphenated.critical(self.next_message())
2881 self.assert_log_lines([
2882 ('INFO', '4'),
2883 ('ERROR', '5'),
2884 ('INFO', '6'),
2885 ('ERROR', '7'),
2886 ], stream=output)
2887 # Original logger output is empty.
2888 self.assert_log_lines([])
2889
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002891 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002892 self.apply_config(self.config9)
2893 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03002894 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002895 logger.info(self.next_message())
2896 self.assert_log_lines([], stream=output)
2897 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03002898 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002899 logger.info(self.next_message())
2900 self.assert_log_lines([], stream=output)
2901 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03002902 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002903 logger.info(self.next_message())
2904 self.assert_log_lines([
2905 ('INFO', '3'),
2906 ], stream=output)
2907
2908 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002909 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002910 self.apply_config(self.config10)
2911 logger = logging.getLogger("compiler.parser")
2912 logger.warning(self.next_message())
2913 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002914 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002915 logger.warning(self.next_message())
2916 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002917 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002918 logger.warning(self.next_message())
2919 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002920 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002921 logger.error(self.next_message())
2922 self.assert_log_lines([
2923 ('WARNING', '1'),
2924 ('ERROR', '4'),
2925 ], stream=output)
2926
2927 def test_config11_ok(self):
2928 self.test_config1_ok(self.config11)
2929
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002930 def test_config12_failure(self):
2931 self.assertRaises(Exception, self.apply_config, self.config12)
2932
2933 def test_config13_failure(self):
2934 self.assertRaises(Exception, self.apply_config, self.config13)
2935
Vinay Sajip8d270232012-11-15 14:20:18 +00002936 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002937 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002938 self.apply_config(self.config14)
2939 h = logging._handlers['hand1']
2940 self.assertEqual(h.foo, 'bar')
2941 self.assertEqual(h.terminator, '!\n')
2942 logging.warning('Exclamation')
2943 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2944
Xtreak087570a2018-07-02 14:27:46 +05302945 def test_config15_ok(self):
2946
2947 def cleanup(h1, fn):
2948 h1.close()
2949 os.remove(fn)
2950
2951 with self.check_no_resource_warning():
2952 fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
2953 os.close(fd)
2954
2955 config = {
2956 "version": 1,
2957 "handlers": {
2958 "file": {
2959 "class": "logging.FileHandler",
2960 "filename": fn
2961 }
2962 },
2963 "root": {
2964 "handlers": ["file"]
2965 }
2966 }
2967
2968 self.apply_config(config)
2969 self.apply_config(config)
2970
2971 handler = logging.root.handlers[0]
2972 self.addCleanup(cleanup, handler, fn)
2973
Vinay Sajip4ded5512012-10-02 15:56:16 +01002974 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002975 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002976 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002977 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002978 t.start()
2979 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002980 # Now get the port allocated
2981 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002982 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002983 try:
2984 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2985 sock.settimeout(2.0)
2986 sock.connect(('localhost', port))
2987
2988 slen = struct.pack('>L', len(text))
2989 s = slen + text
2990 sentsofar = 0
2991 left = len(s)
2992 while left > 0:
2993 sent = sock.send(s[sentsofar:])
2994 sentsofar += sent
2995 left -= sent
2996 sock.close()
2997 finally:
2998 t.ready.wait(2.0)
2999 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07003000 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003001
3002 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003003 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003004 self.setup_via_listener(json.dumps(self.config10))
3005 logger = logging.getLogger("compiler.parser")
3006 logger.warning(self.next_message())
3007 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03003008 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003009 logger.warning(self.next_message())
3010 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03003011 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003012 logger.warning(self.next_message())
3013 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03003014 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003015 logger.error(self.next_message())
3016 self.assert_log_lines([
3017 ('WARNING', '1'),
3018 ('ERROR', '4'),
3019 ], stream=output)
3020
3021 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003022 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003023 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
3024 logger = logging.getLogger("compiler.parser")
3025 # Both will output a message
3026 logger.info(self.next_message())
3027 logger.error(self.next_message())
3028 self.assert_log_lines([
3029 ('INFO', '1'),
3030 ('ERROR', '2'),
3031 ], stream=output)
3032 # Original logger output is empty.
3033 self.assert_log_lines([])
3034
Vinay Sajip4ded5512012-10-02 15:56:16 +01003035 def test_listen_verify(self):
3036
3037 def verify_fail(stuff):
3038 return None
3039
3040 def verify_reverse(stuff):
3041 return stuff[::-1]
3042
3043 logger = logging.getLogger("compiler.parser")
3044 to_send = textwrap.dedent(ConfigFileTest.config1)
3045 # First, specify a verification function that will fail.
3046 # We expect to see no output, since our configuration
3047 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01003048 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003049 self.setup_via_listener(to_send, verify_fail)
3050 # Both will output a message
3051 logger.info(self.next_message())
3052 logger.error(self.next_message())
3053 self.assert_log_lines([], stream=output)
3054 # Original logger output has the stuff we logged.
3055 self.assert_log_lines([
3056 ('INFO', '1'),
3057 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003058 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003059
3060 # Now, perform no verification. Our configuration
3061 # should take effect.
3062
Vinay Sajip1feedb42014-05-31 08:19:12 +01003063 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003064 self.setup_via_listener(to_send) # no verify callable specified
3065 logger = logging.getLogger("compiler.parser")
3066 # Both will output a message
3067 logger.info(self.next_message())
3068 logger.error(self.next_message())
3069 self.assert_log_lines([
3070 ('INFO', '3'),
3071 ('ERROR', '4'),
3072 ], stream=output)
3073 # Original logger output still has the stuff we logged before.
3074 self.assert_log_lines([
3075 ('INFO', '1'),
3076 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003077 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003078
3079 # Now, perform verification which transforms the bytes.
3080
Vinay Sajip1feedb42014-05-31 08:19:12 +01003081 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003082 self.setup_via_listener(to_send[::-1], verify_reverse)
3083 logger = logging.getLogger("compiler.parser")
3084 # Both will output a message
3085 logger.info(self.next_message())
3086 logger.error(self.next_message())
3087 self.assert_log_lines([
3088 ('INFO', '5'),
3089 ('ERROR', '6'),
3090 ], stream=output)
3091 # Original logger output still has the stuff we logged before.
3092 self.assert_log_lines([
3093 ('INFO', '1'),
3094 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003095 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003096
Vinay Sajip3f885b52013-03-22 15:19:54 +00003097 def test_out_of_order(self):
3098 self.apply_config(self.out_of_order)
3099 handler = logging.getLogger('mymodule').handlers[0]
3100 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003101 self.assertIsInstance(handler.formatter._style,
3102 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003103
Vinay Sajip373baef2011-04-26 20:05:24 +01003104 def test_baseconfig(self):
3105 d = {
3106 'atuple': (1, 2, 3),
3107 'alist': ['a', 'b', 'c'],
3108 'adict': {'d': 'e', 'f': 3 },
3109 'nest1': ('g', ('h', 'i'), 'j'),
3110 'nest2': ['k', ['l', 'm'], 'n'],
3111 'nest3': ['o', 'cfg://alist', 'p'],
3112 }
3113 bc = logging.config.BaseConfigurator(d)
3114 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3115 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3116 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3117 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3118 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3119 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3120 v = bc.convert('cfg://nest3')
3121 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3122 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3123 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3124 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003125
3126class ManagerTest(BaseTest):
3127 def test_manager_loggerclass(self):
3128 logged = []
3129
3130 class MyLogger(logging.Logger):
3131 def _log(self, level, msg, args, exc_info=None, extra=None):
3132 logged.append(msg)
3133
3134 man = logging.Manager(None)
3135 self.assertRaises(TypeError, man.setLoggerClass, int)
3136 man.setLoggerClass(MyLogger)
3137 logger = man.getLogger('test')
3138 logger.warning('should appear in logged')
3139 logging.warning('should not appear in logged')
3140
3141 self.assertEqual(logged, ['should appear in logged'])
3142
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003143 def test_set_log_record_factory(self):
3144 man = logging.Manager(None)
3145 expected = object()
3146 man.setLogRecordFactory(expected)
3147 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003148
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003149class ChildLoggerTest(BaseTest):
3150 def test_child_loggers(self):
3151 r = logging.getLogger()
3152 l1 = logging.getLogger('abc')
3153 l2 = logging.getLogger('def.ghi')
3154 c1 = r.getChild('xyz')
3155 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003156 self.assertIs(c1, logging.getLogger('xyz'))
3157 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003158 c1 = l1.getChild('def')
3159 c2 = c1.getChild('ghi')
3160 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003161 self.assertIs(c1, logging.getLogger('abc.def'))
3162 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3163 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003164
3165
Vinay Sajip6fac8172010-10-19 20:44:14 +00003166class DerivedLogRecord(logging.LogRecord):
3167 pass
3168
Vinay Sajip61561522010-12-03 11:50:38 +00003169class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003170
3171 def setUp(self):
3172 class CheckingFilter(logging.Filter):
3173 def __init__(self, cls):
3174 self.cls = cls
3175
3176 def filter(self, record):
3177 t = type(record)
3178 if t is not self.cls:
3179 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3180 self.cls)
3181 raise TypeError(msg)
3182 return True
3183
3184 BaseTest.setUp(self)
3185 self.filter = CheckingFilter(DerivedLogRecord)
3186 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003187 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003188
3189 def tearDown(self):
3190 self.root_logger.removeFilter(self.filter)
3191 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003192 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003193
3194 def test_logrecord_class(self):
3195 self.assertRaises(TypeError, self.root_logger.warning,
3196 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003197 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003198 self.root_logger.error(self.next_message())
3199 self.assert_log_lines([
3200 ('root', 'ERROR', '2'),
3201 ])
3202
3203
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003204class QueueHandlerTest(BaseTest):
3205 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003206 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003207
3208 def setUp(self):
3209 BaseTest.setUp(self)
3210 self.queue = queue.Queue(-1)
3211 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003212 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003213 self.que_logger = logging.getLogger('que')
3214 self.que_logger.propagate = False
3215 self.que_logger.setLevel(logging.WARNING)
3216 self.que_logger.addHandler(self.que_hdlr)
3217
3218 def tearDown(self):
3219 self.que_hdlr.close()
3220 BaseTest.tearDown(self)
3221
3222 def test_queue_handler(self):
3223 self.que_logger.debug(self.next_message())
3224 self.assertRaises(queue.Empty, self.queue.get_nowait)
3225 self.que_logger.info(self.next_message())
3226 self.assertRaises(queue.Empty, self.queue.get_nowait)
3227 msg = self.next_message()
3228 self.que_logger.warning(msg)
3229 data = self.queue.get_nowait()
3230 self.assertTrue(isinstance(data, logging.LogRecord))
3231 self.assertEqual(data.name, self.que_logger.name)
3232 self.assertEqual((data.msg, data.args), (msg, None))
3233
favlladfe3442017-08-01 20:12:26 +02003234 def test_formatting(self):
3235 msg = self.next_message()
3236 levelname = logging.getLevelName(logging.WARNING)
3237 log_format_str = '{name} -> {levelname}: {message}'
3238 formatted_msg = log_format_str.format(name=self.name,
3239 levelname=levelname, message=msg)
3240 formatter = logging.Formatter(self.log_format)
3241 self.que_hdlr.setFormatter(formatter)
3242 self.que_logger.warning(msg)
3243 log_record = self.queue.get_nowait()
3244 self.assertEqual(formatted_msg, log_record.msg)
3245 self.assertEqual(formatted_msg, log_record.message)
3246
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003247 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3248 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003249 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003250 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003251 listener = logging.handlers.QueueListener(self.queue, handler)
3252 listener.start()
3253 try:
3254 self.que_logger.warning(self.next_message())
3255 self.que_logger.error(self.next_message())
3256 self.que_logger.critical(self.next_message())
3257 finally:
3258 listener.stop()
3259 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3260 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3261 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003262 handler.close()
3263
3264 # Now test with respect_handler_level set
3265
3266 handler = support.TestHandler(support.Matcher())
3267 handler.setLevel(logging.CRITICAL)
3268 listener = logging.handlers.QueueListener(self.queue, handler,
3269 respect_handler_level=True)
3270 listener.start()
3271 try:
3272 self.que_logger.warning(self.next_message())
3273 self.que_logger.error(self.next_message())
3274 self.que_logger.critical(self.next_message())
3275 finally:
3276 listener.stop()
3277 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3278 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3279 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3280
Vinay Sajipd61910c2016-09-08 01:13:39 +01003281if hasattr(logging.handlers, 'QueueListener'):
3282 import multiprocessing
3283 from unittest.mock import patch
3284
3285 class QueueListenerTest(BaseTest):
3286 """
3287 Tests based on patch submitted for issue #27930. Ensure that
3288 QueueListener handles all log messages.
3289 """
3290
3291 repeat = 20
3292
3293 @staticmethod
3294 def setup_and_log(log_queue, ident):
3295 """
3296 Creates a logger with a QueueHandler that logs to a queue read by a
3297 QueueListener. Starts the listener, logs five messages, and stops
3298 the listener.
3299 """
3300 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3301 logger.setLevel(logging.DEBUG)
3302 handler = logging.handlers.QueueHandler(log_queue)
3303 logger.addHandler(handler)
3304 listener = logging.handlers.QueueListener(log_queue)
3305 listener.start()
3306
3307 logger.info('one')
3308 logger.info('two')
3309 logger.info('three')
3310 logger.info('four')
3311 logger.info('five')
3312
3313 listener.stop()
3314 logger.removeHandler(handler)
3315 handler.close()
3316
3317 @patch.object(logging.handlers.QueueListener, 'handle')
3318 def test_handle_called_with_queue_queue(self, mock_handle):
3319 for i in range(self.repeat):
3320 log_queue = queue.Queue()
3321 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3322 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3323 'correct number of handled log messages')
3324
3325 @patch.object(logging.handlers.QueueListener, 'handle')
3326 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003327 # Issue 28668: The multiprocessing (mp) module is not functional
3328 # when the mp.synchronize module cannot be imported.
3329 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003330 for i in range(self.repeat):
3331 log_queue = multiprocessing.Queue()
3332 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003333 log_queue.close()
3334 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003335 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3336 'correct number of handled log messages')
3337
3338 @staticmethod
3339 def get_all_from_queue(log_queue):
3340 try:
3341 while True:
3342 yield log_queue.get_nowait()
3343 except queue.Empty:
3344 return []
3345
3346 def test_no_messages_in_queue_after_stop(self):
3347 """
3348 Five messages are logged then the QueueListener is stopped. This
3349 test then gets everything off the queue. Failure of this test
3350 indicates that messages were not registered on the queue until
3351 _after_ the QueueListener stopped.
3352 """
xdegayebf2b65e2017-12-01 08:08:49 +01003353 # Issue 28668: The multiprocessing (mp) module is not functional
3354 # when the mp.synchronize module cannot be imported.
3355 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003356 for i in range(self.repeat):
3357 queue = multiprocessing.Queue()
3358 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3359 # time.sleep(1)
3360 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003361 queue.close()
3362 queue.join_thread()
3363
Vinay Sajipd61910c2016-09-08 01:13:39 +01003364 expected = [[], [logging.handlers.QueueListener._sentinel]]
3365 self.assertIn(items, expected,
3366 'Found unexpected messages in queue: %s' % (
3367 [m.msg if isinstance(m, logging.LogRecord)
3368 else m for m in items]))
3369
Vinay Sajipe723e962011-04-15 22:27:17 +01003370
Vinay Sajip37eb3382011-04-26 20:26:41 +01003371ZERO = datetime.timedelta(0)
3372
3373class UTC(datetime.tzinfo):
3374 def utcoffset(self, dt):
3375 return ZERO
3376
3377 dst = utcoffset
3378
3379 def tzname(self, dt):
3380 return 'UTC'
3381
3382utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003383
Vinay Sajipa39c5712010-10-25 13:57:39 +00003384class FormatterTest(unittest.TestCase):
3385 def setUp(self):
3386 self.common = {
3387 'name': 'formatter.test',
3388 'level': logging.DEBUG,
3389 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3390 'lineno': 42,
3391 'exc_info': None,
3392 'func': None,
3393 'msg': 'Message with %d %s',
3394 'args': (2, 'placeholders'),
3395 }
3396 self.variants = {
3397 }
3398
3399 def get_record(self, name=None):
3400 result = dict(self.common)
3401 if name is not None:
3402 result.update(self.variants[name])
3403 return logging.makeLogRecord(result)
3404
3405 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003406 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003407 r = self.get_record()
3408 f = logging.Formatter('${%(message)s}')
3409 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3410 f = logging.Formatter('%(random)s')
3411 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003412 self.assertFalse(f.usesTime())
3413 f = logging.Formatter('%(asctime)s')
3414 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003415 f = logging.Formatter('%(asctime)-15s')
3416 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003417 f = logging.Formatter('asctime')
3418 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003419
3420 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003421 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003422 r = self.get_record()
3423 f = logging.Formatter('$%{message}%$', style='{')
3424 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3425 f = logging.Formatter('{random}', style='{')
3426 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003427 self.assertFalse(f.usesTime())
3428 f = logging.Formatter('{asctime}', style='{')
3429 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003430 f = logging.Formatter('{asctime!s:15}', style='{')
3431 self.assertTrue(f.usesTime())
3432 f = logging.Formatter('{asctime:15}', style='{')
3433 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003434 f = logging.Formatter('asctime', style='{')
3435 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003436
3437 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003438 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003439 r = self.get_record()
3440 f = logging.Formatter('$message', style='$')
3441 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3442 f = logging.Formatter('$$%${message}%$$', style='$')
3443 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3444 f = logging.Formatter('${random}', style='$')
3445 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003446 self.assertFalse(f.usesTime())
3447 f = logging.Formatter('${asctime}', style='$')
3448 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003449 f = logging.Formatter('${asctime', style='$')
3450 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003451 f = logging.Formatter('$asctime', style='$')
3452 self.assertTrue(f.usesTime())
3453 f = logging.Formatter('asctime', style='$')
3454 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003455
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003456 def test_invalid_style(self):
3457 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3458
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003459 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003460 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003461 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3462 # We use None to indicate we want the local timezone
3463 # We're essentially converting a UTC time to local time
3464 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003465 r.msecs = 123
3466 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003467 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003468 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3469 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003470 f.format(r)
3471 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3472
3473class TestBufferingFormatter(logging.BufferingFormatter):
3474 def formatHeader(self, records):
3475 return '[(%d)' % len(records)
3476
3477 def formatFooter(self, records):
3478 return '(%d)]' % len(records)
3479
3480class BufferingFormatterTest(unittest.TestCase):
3481 def setUp(self):
3482 self.records = [
3483 logging.makeLogRecord({'msg': 'one'}),
3484 logging.makeLogRecord({'msg': 'two'}),
3485 ]
3486
3487 def test_default(self):
3488 f = logging.BufferingFormatter()
3489 self.assertEqual('', f.format([]))
3490 self.assertEqual('onetwo', f.format(self.records))
3491
3492 def test_custom(self):
3493 f = TestBufferingFormatter()
3494 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3495 lf = logging.Formatter('<%(message)s>')
3496 f = TestBufferingFormatter(lf)
3497 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003498
3499class ExceptionTest(BaseTest):
3500 def test_formatting(self):
3501 r = self.root_logger
3502 h = RecordingHandler()
3503 r.addHandler(h)
3504 try:
3505 raise RuntimeError('deliberate mistake')
3506 except:
3507 logging.exception('failed', stack_info=True)
3508 r.removeHandler(h)
3509 h.close()
3510 r = h.records[0]
3511 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3512 'call last):\n'))
3513 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3514 'deliberate mistake'))
3515 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3516 'call last):\n'))
3517 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3518 'stack_info=True)'))
3519
3520
Vinay Sajip5a27d402010-12-10 11:42:57 +00003521class LastResortTest(BaseTest):
3522 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003523 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003524 root = self.root_logger
3525 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003526 old_lastresort = logging.lastResort
3527 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003528
Vinay Sajip5a27d402010-12-10 11:42:57 +00003529 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003530 with support.captured_stderr() as stderr:
3531 root.debug('This should not appear')
3532 self.assertEqual(stderr.getvalue(), '')
3533 root.warning('Final chance!')
3534 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3535
3536 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003537 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003538 with support.captured_stderr() as stderr:
3539 root.warning('Final chance!')
3540 msg = 'No handlers could be found for logger "root"\n'
3541 self.assertEqual(stderr.getvalue(), msg)
3542
Vinay Sajip5a27d402010-12-10 11:42:57 +00003543 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003544 with support.captured_stderr() as stderr:
3545 root.warning('Final chance!')
3546 self.assertEqual(stderr.getvalue(), '')
3547
3548 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003549 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003550 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003551 with support.captured_stderr() as stderr:
3552 root.warning('Final chance!')
3553 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003554 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003555 root.addHandler(self.root_hdlr)
3556 logging.lastResort = old_lastresort
3557 logging.raiseExceptions = old_raise_exceptions
3558
3559
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003560class FakeHandler:
3561
3562 def __init__(self, identifier, called):
3563 for method in ('acquire', 'flush', 'close', 'release'):
3564 setattr(self, method, self.record_call(identifier, method, called))
3565
3566 def record_call(self, identifier, method_name, called):
3567 def inner():
3568 called.append('{} - {}'.format(identifier, method_name))
3569 return inner
3570
3571
3572class RecordingHandler(logging.NullHandler):
3573
3574 def __init__(self, *args, **kwargs):
3575 super(RecordingHandler, self).__init__(*args, **kwargs)
3576 self.records = []
3577
3578 def handle(self, record):
3579 """Keep track of all the emitted records."""
3580 self.records.append(record)
3581
3582
3583class ShutdownTest(BaseTest):
3584
Vinay Sajip5e66b162011-04-20 15:41:14 +01003585 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003586
3587 def setUp(self):
3588 super(ShutdownTest, self).setUp()
3589 self.called = []
3590
3591 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003592 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003593
3594 def raise_error(self, error):
3595 def inner():
3596 raise error()
3597 return inner
3598
3599 def test_no_failure(self):
3600 # create some fake handlers
3601 handler0 = FakeHandler(0, self.called)
3602 handler1 = FakeHandler(1, self.called)
3603 handler2 = FakeHandler(2, self.called)
3604
3605 # create live weakref to those handlers
3606 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3607
3608 logging.shutdown(handlerList=list(handlers))
3609
3610 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3611 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3612 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3613 self.assertEqual(expected, self.called)
3614
3615 def _test_with_failure_in_method(self, method, error):
3616 handler = FakeHandler(0, self.called)
3617 setattr(handler, method, self.raise_error(error))
3618 handlers = [logging.weakref.ref(handler)]
3619
3620 logging.shutdown(handlerList=list(handlers))
3621
3622 self.assertEqual('0 - release', self.called[-1])
3623
3624 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003625 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003626
3627 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003628 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003629
3630 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003631 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003632
3633 def test_with_valueerror_in_acquire(self):
3634 self._test_with_failure_in_method('acquire', ValueError)
3635
3636 def test_with_valueerror_in_flush(self):
3637 self._test_with_failure_in_method('flush', ValueError)
3638
3639 def test_with_valueerror_in_close(self):
3640 self._test_with_failure_in_method('close', ValueError)
3641
3642 def test_with_other_error_in_acquire_without_raise(self):
3643 logging.raiseExceptions = False
3644 self._test_with_failure_in_method('acquire', IndexError)
3645
3646 def test_with_other_error_in_flush_without_raise(self):
3647 logging.raiseExceptions = False
3648 self._test_with_failure_in_method('flush', IndexError)
3649
3650 def test_with_other_error_in_close_without_raise(self):
3651 logging.raiseExceptions = False
3652 self._test_with_failure_in_method('close', IndexError)
3653
3654 def test_with_other_error_in_acquire_with_raise(self):
3655 logging.raiseExceptions = True
3656 self.assertRaises(IndexError, self._test_with_failure_in_method,
3657 'acquire', IndexError)
3658
3659 def test_with_other_error_in_flush_with_raise(self):
3660 logging.raiseExceptions = True
3661 self.assertRaises(IndexError, self._test_with_failure_in_method,
3662 'flush', IndexError)
3663
3664 def test_with_other_error_in_close_with_raise(self):
3665 logging.raiseExceptions = True
3666 self.assertRaises(IndexError, self._test_with_failure_in_method,
3667 'close', IndexError)
3668
3669
3670class ModuleLevelMiscTest(BaseTest):
3671
Vinay Sajip5e66b162011-04-20 15:41:14 +01003672 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003673
3674 def test_disable(self):
3675 old_disable = logging.root.manager.disable
3676 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003677 self.assertEqual(old_disable, 0)
3678 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003679
3680 logging.disable(83)
3681 self.assertEqual(logging.root.manager.disable, 83)
3682
Vinay Sajipd489ac92016-12-31 11:40:11 +00003683 # test the default value introduced in 3.7
3684 # (Issue #28524)
3685 logging.disable()
3686 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3687
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003688 def _test_log(self, method, level=None):
3689 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003690 support.patch(self, logging, 'basicConfig',
3691 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003692
3693 recording = RecordingHandler()
3694 logging.root.addHandler(recording)
3695
3696 log_method = getattr(logging, method)
3697 if level is not None:
3698 log_method(level, "test me: %r", recording)
3699 else:
3700 log_method("test me: %r", recording)
3701
3702 self.assertEqual(len(recording.records), 1)
3703 record = recording.records[0]
3704 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3705
3706 expected_level = level if level is not None else getattr(logging, method.upper())
3707 self.assertEqual(record.levelno, expected_level)
3708
3709 # basicConfig was not called!
3710 self.assertEqual(called, [])
3711
3712 def test_log(self):
3713 self._test_log('log', logging.ERROR)
3714
3715 def test_debug(self):
3716 self._test_log('debug')
3717
3718 def test_info(self):
3719 self._test_log('info')
3720
3721 def test_warning(self):
3722 self._test_log('warning')
3723
3724 def test_error(self):
3725 self._test_log('error')
3726
3727 def test_critical(self):
3728 self._test_log('critical')
3729
3730 def test_set_logger_class(self):
3731 self.assertRaises(TypeError, logging.setLoggerClass, object)
3732
3733 class MyLogger(logging.Logger):
3734 pass
3735
3736 logging.setLoggerClass(MyLogger)
3737 self.assertEqual(logging.getLoggerClass(), MyLogger)
3738
3739 logging.setLoggerClass(logging.Logger)
3740 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3741
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003742 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003743 def test_logging_at_shutdown(self):
3744 # Issue #20037
3745 code = """if 1:
3746 import logging
3747
3748 class A:
3749 def __del__(self):
3750 try:
3751 raise ValueError("some error")
3752 except Exception:
3753 logging.exception("exception in __del__")
3754
3755 a = A()"""
3756 rc, out, err = assert_python_ok("-c", code)
3757 err = err.decode()
3758 self.assertIn("exception in __del__", err)
3759 self.assertIn("ValueError: some error", err)
3760
3761
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003762class LogRecordTest(BaseTest):
3763 def test_str_rep(self):
3764 r = logging.makeLogRecord({})
3765 s = str(r)
3766 self.assertTrue(s.startswith('<LogRecord: '))
3767 self.assertTrue(s.endswith('>'))
3768
3769 def test_dict_arg(self):
3770 h = RecordingHandler()
3771 r = logging.getLogger()
3772 r.addHandler(h)
3773 d = {'less' : 'more' }
3774 logging.warning('less is %(less)s', d)
3775 self.assertIs(h.records[0].args, d)
3776 self.assertEqual(h.records[0].message, 'less is more')
3777 r.removeHandler(h)
3778 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003779
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003780 def test_multiprocessing(self):
3781 r = logging.makeLogRecord({})
3782 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003783 try:
3784 import multiprocessing as mp
3785 r = logging.makeLogRecord({})
3786 self.assertEqual(r.processName, mp.current_process().name)
3787 except ImportError:
3788 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003789
3790 def test_optional(self):
3791 r = logging.makeLogRecord({})
3792 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003793 NOT_NONE(r.thread)
3794 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003795 NOT_NONE(r.process)
3796 NOT_NONE(r.processName)
3797 log_threads = logging.logThreads
3798 log_processes = logging.logProcesses
3799 log_multiprocessing = logging.logMultiprocessing
3800 try:
3801 logging.logThreads = False
3802 logging.logProcesses = False
3803 logging.logMultiprocessing = False
3804 r = logging.makeLogRecord({})
3805 NONE = self.assertIsNone
3806 NONE(r.thread)
3807 NONE(r.threadName)
3808 NONE(r.process)
3809 NONE(r.processName)
3810 finally:
3811 logging.logThreads = log_threads
3812 logging.logProcesses = log_processes
3813 logging.logMultiprocessing = log_multiprocessing
3814
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003815class BasicConfigTest(unittest.TestCase):
3816
Vinay Sajip95bf5042011-04-20 11:50:56 +01003817 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003818
3819 def setUp(self):
3820 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003821 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003822 self.saved_handlers = logging._handlers.copy()
3823 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003824 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003825 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003826 logging.root.handlers = []
3827
3828 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003829 for h in logging.root.handlers[:]:
3830 logging.root.removeHandler(h)
3831 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003832 super(BasicConfigTest, self).tearDown()
3833
Vinay Sajip3def7e02011-04-20 10:58:06 +01003834 def cleanup(self):
3835 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003836 logging._handlers.clear()
3837 logging._handlers.update(self.saved_handlers)
3838 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003839 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003840
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003841 def test_no_kwargs(self):
3842 logging.basicConfig()
3843
3844 # handler defaults to a StreamHandler to sys.stderr
3845 self.assertEqual(len(logging.root.handlers), 1)
3846 handler = logging.root.handlers[0]
3847 self.assertIsInstance(handler, logging.StreamHandler)
3848 self.assertEqual(handler.stream, sys.stderr)
3849
3850 formatter = handler.formatter
3851 # format defaults to logging.BASIC_FORMAT
3852 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3853 # datefmt defaults to None
3854 self.assertIsNone(formatter.datefmt)
3855 # style defaults to %
3856 self.assertIsInstance(formatter._style, logging.PercentStyle)
3857
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003858 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003859 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003860
Vinay Sajip1fd12022014-01-13 21:59:56 +00003861 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003862 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003863 logging.basicConfig(stream=sys.stdout, style="{")
3864 logging.error("Log an error")
3865 sys.stdout.seek(0)
3866 self.assertEqual(output.getvalue().strip(),
3867 "ERROR:root:Log an error")
3868
3869 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003870 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003871 logging.basicConfig(stream=sys.stdout, style="$")
3872 logging.error("Log an error")
3873 sys.stdout.seek(0)
3874 self.assertEqual(output.getvalue().strip(),
3875 "ERROR:root:Log an error")
3876
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003877 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003878
3879 def cleanup(h1, h2, fn):
3880 h1.close()
3881 h2.close()
3882 os.remove(fn)
3883
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003884 logging.basicConfig(filename='test.log')
3885
3886 self.assertEqual(len(logging.root.handlers), 1)
3887 handler = logging.root.handlers[0]
3888 self.assertIsInstance(handler, logging.FileHandler)
3889
3890 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003891 self.assertEqual(handler.stream.mode, expected.stream.mode)
3892 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003893 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003894
3895 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003896
3897 def cleanup(h1, h2, fn):
3898 h1.close()
3899 h2.close()
3900 os.remove(fn)
3901
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003902 logging.basicConfig(filename='test.log', filemode='wb')
3903
3904 handler = logging.root.handlers[0]
3905 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003906 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003907 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003908
3909 def test_stream(self):
3910 stream = io.StringIO()
3911 self.addCleanup(stream.close)
3912 logging.basicConfig(stream=stream)
3913
3914 self.assertEqual(len(logging.root.handlers), 1)
3915 handler = logging.root.handlers[0]
3916 self.assertIsInstance(handler, logging.StreamHandler)
3917 self.assertEqual(handler.stream, stream)
3918
3919 def test_format(self):
3920 logging.basicConfig(format='foo')
3921
3922 formatter = logging.root.handlers[0].formatter
3923 self.assertEqual(formatter._style._fmt, 'foo')
3924
3925 def test_datefmt(self):
3926 logging.basicConfig(datefmt='bar')
3927
3928 formatter = logging.root.handlers[0].formatter
3929 self.assertEqual(formatter.datefmt, 'bar')
3930
3931 def test_style(self):
3932 logging.basicConfig(style='$')
3933
3934 formatter = logging.root.handlers[0].formatter
3935 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3936
3937 def test_level(self):
3938 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003939 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003940
3941 logging.basicConfig(level=57)
3942 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003943 # Test that second call has no effect
3944 logging.basicConfig(level=58)
3945 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003946
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003947 def test_incompatible(self):
3948 assertRaises = self.assertRaises
3949 handlers = [logging.StreamHandler()]
3950 stream = sys.stderr
3951 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3952 stream=stream)
3953 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3954 handlers=handlers)
3955 assertRaises(ValueError, logging.basicConfig, stream=stream,
3956 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003957 # Issue 23207: test for invalid kwargs
3958 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3959 # Should pop both filename and filemode even if filename is None
3960 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003961
3962 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003963 handlers = [
3964 logging.StreamHandler(),
3965 logging.StreamHandler(sys.stdout),
3966 logging.StreamHandler(),
3967 ]
3968 f = logging.Formatter()
3969 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003970 logging.basicConfig(handlers=handlers)
3971 self.assertIs(handlers[0], logging.root.handlers[0])
3972 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003973 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003974 self.assertIsNotNone(handlers[0].formatter)
3975 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003976 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003977 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3978
Dong-hee Nacf67d6a2018-06-25 13:11:09 +09003979 def test_force(self):
3980 old_string_io = io.StringIO()
3981 new_string_io = io.StringIO()
3982 old_handlers = [logging.StreamHandler(old_string_io)]
3983 new_handlers = [logging.StreamHandler(new_string_io)]
3984 logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
3985 logging.warning('warn')
3986 logging.info('info')
3987 logging.debug('debug')
3988 self.assertEqual(len(logging.root.handlers), 1)
3989 logging.basicConfig(level=logging.INFO, handlers=new_handlers,
3990 force=True)
3991 logging.warning('warn')
3992 logging.info('info')
3993 logging.debug('debug')
3994 self.assertEqual(len(logging.root.handlers), 1)
3995 self.assertEqual(old_string_io.getvalue().strip(),
3996 'WARNING:root:warn')
3997 self.assertEqual(new_string_io.getvalue().strip(),
3998 'WARNING:root:warn\nINFO:root:info')
3999
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004000 def _test_log(self, method, level=None):
4001 # logging.root has no handlers so basicConfig should be called
4002 called = []
4003
4004 old_basic_config = logging.basicConfig
4005 def my_basic_config(*a, **kw):
4006 old_basic_config()
4007 old_level = logging.root.level
4008 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004009 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004010 called.append((a, kw))
4011
Vinay Sajip1feedb42014-05-31 08:19:12 +01004012 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004013
4014 log_method = getattr(logging, method)
4015 if level is not None:
4016 log_method(level, "test me")
4017 else:
4018 log_method("test me")
4019
4020 # basicConfig was called with no arguments
4021 self.assertEqual(called, [((), {})])
4022
4023 def test_log(self):
4024 self._test_log('log', logging.WARNING)
4025
4026 def test_debug(self):
4027 self._test_log('debug')
4028
4029 def test_info(self):
4030 self._test_log('info')
4031
4032 def test_warning(self):
4033 self._test_log('warning')
4034
4035 def test_error(self):
4036 self._test_log('error')
4037
4038 def test_critical(self):
4039 self._test_log('critical')
4040
4041
4042class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004043 def setUp(self):
4044 super(LoggerAdapterTest, self).setUp()
4045 old_handler_list = logging._handlerList[:]
4046
4047 self.recording = RecordingHandler()
4048 self.logger = logging.root
4049 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004050 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004051 self.addCleanup(self.recording.close)
4052
4053 def cleanup():
4054 logging._handlerList[:] = old_handler_list
4055
4056 self.addCleanup(cleanup)
4057 self.addCleanup(logging.shutdown)
4058 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
4059
4060 def test_exception(self):
4061 msg = 'testing exception: %r'
4062 exc = None
4063 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004064 1 / 0
4065 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004066 exc = e
4067 self.adapter.exception(msg, self.recording)
4068
4069 self.assertEqual(len(self.recording.records), 1)
4070 record = self.recording.records[0]
4071 self.assertEqual(record.levelno, logging.ERROR)
4072 self.assertEqual(record.msg, msg)
4073 self.assertEqual(record.args, (self.recording,))
4074 self.assertEqual(record.exc_info,
4075 (exc.__class__, exc, exc.__traceback__))
4076
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01004077 def test_exception_excinfo(self):
4078 try:
4079 1 / 0
4080 except ZeroDivisionError as e:
4081 exc = e
4082
4083 self.adapter.exception('exc_info test', exc_info=exc)
4084
4085 self.assertEqual(len(self.recording.records), 1)
4086 record = self.recording.records[0]
4087 self.assertEqual(record.exc_info,
4088 (exc.__class__, exc, exc.__traceback__))
4089
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004090 def test_critical(self):
4091 msg = 'critical test! %r'
4092 self.adapter.critical(msg, self.recording)
4093
4094 self.assertEqual(len(self.recording.records), 1)
4095 record = self.recording.records[0]
4096 self.assertEqual(record.levelno, logging.CRITICAL)
4097 self.assertEqual(record.msg, msg)
4098 self.assertEqual(record.args, (self.recording,))
4099
4100 def test_is_enabled_for(self):
4101 old_disable = self.adapter.logger.manager.disable
4102 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004103 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4104 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004105 self.assertFalse(self.adapter.isEnabledFor(32))
4106
4107 def test_has_handlers(self):
4108 self.assertTrue(self.adapter.hasHandlers())
4109
4110 for handler in self.logger.handlers:
4111 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004112
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004113 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004114 self.assertFalse(self.adapter.hasHandlers())
4115
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004116 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004117 class Adapter(logging.LoggerAdapter):
4118 prefix = 'Adapter'
4119
4120 def process(self, msg, kwargs):
4121 return f"{self.prefix} {msg}", kwargs
4122
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004123 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004124 adapter = Adapter(logger=self.logger, extra=None)
4125 adapter_adapter = Adapter(logger=adapter, extra=None)
4126 adapter_adapter.prefix = 'AdapterAdapter'
4127 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004128 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004129 self.assertEqual(len(self.recording.records), 1)
4130 record = self.recording.records[0]
4131 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004132 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004133 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004134 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004135 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004136 self.assertIs(self.logger.manager, orig_manager)
4137 temp_manager = object()
4138 try:
4139 adapter_adapter.manager = temp_manager
4140 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004141 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004142 self.assertIs(self.logger.manager, temp_manager)
4143 finally:
4144 adapter_adapter.manager = orig_manager
4145 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004146 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004147 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004148
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004149
4150class LoggerTest(BaseTest):
4151
4152 def setUp(self):
4153 super(LoggerTest, self).setUp()
4154 self.recording = RecordingHandler()
4155 self.logger = logging.Logger(name='blah')
4156 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004157 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004158 self.addCleanup(self.recording.close)
4159 self.addCleanup(logging.shutdown)
4160
4161 def test_set_invalid_level(self):
4162 self.assertRaises(TypeError, self.logger.setLevel, object())
4163
4164 def test_exception(self):
4165 msg = 'testing exception: %r'
4166 exc = None
4167 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004168 1 / 0
4169 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004170 exc = e
4171 self.logger.exception(msg, self.recording)
4172
4173 self.assertEqual(len(self.recording.records), 1)
4174 record = self.recording.records[0]
4175 self.assertEqual(record.levelno, logging.ERROR)
4176 self.assertEqual(record.msg, msg)
4177 self.assertEqual(record.args, (self.recording,))
4178 self.assertEqual(record.exc_info,
4179 (exc.__class__, exc, exc.__traceback__))
4180
4181 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004182 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004183 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004184
4185 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004186 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004187 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004188
4189 def test_find_caller_with_stack_info(self):
4190 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004191 support.patch(self, logging.traceback, 'print_stack',
4192 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004193
4194 self.logger.findCaller(stack_info=True)
4195
4196 self.assertEqual(len(called), 1)
4197 self.assertEqual('Stack (most recent call last):\n', called[0])
4198
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004199 def test_find_caller_with_stacklevel(self):
4200 the_level = 1
4201
4202 def innermost():
4203 self.logger.warning('test', stacklevel=the_level)
4204
4205 def inner():
4206 innermost()
4207
4208 def outer():
4209 inner()
4210
4211 records = self.recording.records
4212 outer()
4213 self.assertEqual(records[-1].funcName, 'innermost')
4214 lineno = records[-1].lineno
4215 the_level += 1
4216 outer()
4217 self.assertEqual(records[-1].funcName, 'inner')
4218 self.assertGreater(records[-1].lineno, lineno)
4219 lineno = records[-1].lineno
4220 the_level += 1
4221 outer()
4222 self.assertEqual(records[-1].funcName, 'outer')
4223 self.assertGreater(records[-1].lineno, lineno)
4224 lineno = records[-1].lineno
4225 the_level += 1
4226 outer()
4227 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4228 self.assertGreater(records[-1].lineno, lineno)
4229
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004230 def test_make_record_with_extra_overwrite(self):
4231 name = 'my record'
4232 level = 13
4233 fn = lno = msg = args = exc_info = func = sinfo = None
4234 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4235 exc_info, func, sinfo)
4236
4237 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4238 extra = {key: 'some value'}
4239 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4240 fn, lno, msg, args, exc_info,
4241 extra=extra, sinfo=sinfo)
4242
4243 def test_make_record_with_extra_no_overwrite(self):
4244 name = 'my record'
4245 level = 13
4246 fn = lno = msg = args = exc_info = func = sinfo = None
4247 extra = {'valid_key': 'some value'}
4248 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4249 exc_info, extra=extra, sinfo=sinfo)
4250 self.assertIn('valid_key', result.__dict__)
4251
4252 def test_has_handlers(self):
4253 self.assertTrue(self.logger.hasHandlers())
4254
4255 for handler in self.logger.handlers:
4256 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004257 self.assertFalse(self.logger.hasHandlers())
4258
4259 def test_has_handlers_no_propagate(self):
4260 child_logger = logging.getLogger('blah.child')
4261 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004262 self.assertFalse(child_logger.hasHandlers())
4263
4264 def test_is_enabled_for(self):
4265 old_disable = self.logger.manager.disable
4266 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004267 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004268 self.assertFalse(self.logger.isEnabledFor(22))
4269
Timo Furrer6e3ca642018-06-01 09:29:46 +02004270 def test_is_enabled_for_disabled_logger(self):
4271 old_disabled = self.logger.disabled
4272 old_disable = self.logger.manager.disable
4273
4274 self.logger.disabled = True
4275 self.logger.manager.disable = 21
4276
4277 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4278 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4279
4280 self.assertFalse(self.logger.isEnabledFor(22))
4281
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004282 def test_root_logger_aliases(self):
4283 root = logging.getLogger()
4284 self.assertIs(root, logging.root)
4285 self.assertIs(root, logging.getLogger(None))
4286 self.assertIs(root, logging.getLogger(''))
4287 self.assertIs(root, logging.getLogger('foo').root)
4288 self.assertIs(root, logging.getLogger('foo.bar').root)
4289 self.assertIs(root, logging.getLogger('foo').parent)
4290
4291 self.assertIsNot(root, logging.getLogger('\0'))
4292 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4293
4294 def test_invalid_names(self):
4295 self.assertRaises(TypeError, logging.getLogger, any)
4296 self.assertRaises(TypeError, logging.getLogger, b'foo')
4297
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004298 def test_pickling(self):
4299 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4300 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4301 logger = logging.getLogger(name)
4302 s = pickle.dumps(logger, proto)
4303 unpickled = pickle.loads(s)
4304 self.assertIs(unpickled, logger)
4305
Avram Lubkin78c18a92017-07-30 05:36:33 -04004306 def test_caching(self):
4307 root = self.root_logger
4308 logger1 = logging.getLogger("abc")
4309 logger2 = logging.getLogger("abc.def")
4310
4311 # Set root logger level and ensure cache is empty
4312 root.setLevel(logging.ERROR)
4313 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4314 self.assertEqual(logger2._cache, {})
4315
4316 # Ensure cache is populated and calls are consistent
4317 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4318 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4319 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4320 self.assertEqual(root._cache, {})
4321 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4322
4323 # Ensure root cache gets populated
4324 self.assertEqual(root._cache, {})
4325 self.assertTrue(root.isEnabledFor(logging.ERROR))
4326 self.assertEqual(root._cache, {logging.ERROR: True})
4327
4328 # Set parent logger level and ensure caches are emptied
4329 logger1.setLevel(logging.CRITICAL)
4330 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4331 self.assertEqual(logger2._cache, {})
4332
4333 # Ensure logger2 uses parent logger's effective level
4334 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4335
4336 # Set level to NOTSET and ensure caches are empty
4337 logger2.setLevel(logging.NOTSET)
4338 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4339 self.assertEqual(logger2._cache, {})
4340 self.assertEqual(logger1._cache, {})
4341 self.assertEqual(root._cache, {})
4342
4343 # Verify logger2 follows parent and not root
4344 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4345 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4346 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4347 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4348 self.assertTrue(root.isEnabledFor(logging.ERROR))
4349
4350 # Disable logging in manager and ensure caches are clear
4351 logging.disable()
4352 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4353 self.assertEqual(logger2._cache, {})
4354 self.assertEqual(logger1._cache, {})
4355 self.assertEqual(root._cache, {})
4356
4357 # Ensure no loggers are enabled
4358 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4359 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4360 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4361
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004362
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004363class BaseFileTest(BaseTest):
4364 "Base class for handler tests that write log files"
4365
4366 def setUp(self):
4367 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004368 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4369 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004370 self.rmfiles = []
4371
4372 def tearDown(self):
4373 for fn in self.rmfiles:
4374 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004375 if os.path.exists(self.fn):
4376 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004377 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004378
4379 def assertLogFile(self, filename):
4380 "Assert a log file is there and register it for deletion"
4381 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004382 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004383 self.rmfiles.append(filename)
4384
4385
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004386class FileHandlerTest(BaseFileTest):
4387 def test_delay(self):
4388 os.unlink(self.fn)
4389 fh = logging.FileHandler(self.fn, delay=True)
4390 self.assertIsNone(fh.stream)
4391 self.assertFalse(os.path.exists(self.fn))
4392 fh.handle(logging.makeLogRecord({}))
4393 self.assertIsNotNone(fh.stream)
4394 self.assertTrue(os.path.exists(self.fn))
4395 fh.close()
4396
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004397class RotatingFileHandlerTest(BaseFileTest):
4398 def next_rec(self):
4399 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4400 self.next_message(), None, None, None)
4401
4402 def test_should_not_rollover(self):
4403 # If maxbytes is zero rollover never occurs
4404 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4405 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004406 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004407
4408 def test_should_rollover(self):
4409 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4410 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004411 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004412
4413 def test_file_created(self):
4414 # checks that the file is created and assumes it was created
4415 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004416 rh = logging.handlers.RotatingFileHandler(self.fn)
4417 rh.emit(self.next_rec())
4418 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004419 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004420
4421 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004422 def namer(name):
4423 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004424 rh = logging.handlers.RotatingFileHandler(
4425 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004426 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004427 rh.emit(self.next_rec())
4428 self.assertLogFile(self.fn)
4429 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004430 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004431 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004432 self.assertLogFile(namer(self.fn + ".2"))
4433 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4434 rh.close()
4435
Vinay Sajip1feedb42014-05-31 08:19:12 +01004436 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004437 def test_rotator(self):
4438 def namer(name):
4439 return name + ".gz"
4440
4441 def rotator(source, dest):
4442 with open(source, "rb") as sf:
4443 data = sf.read()
4444 compressed = zlib.compress(data, 9)
4445 with open(dest, "wb") as df:
4446 df.write(compressed)
4447 os.remove(source)
4448
4449 rh = logging.handlers.RotatingFileHandler(
4450 self.fn, backupCount=2, maxBytes=1)
4451 rh.rotator = rotator
4452 rh.namer = namer
4453 m1 = self.next_rec()
4454 rh.emit(m1)
4455 self.assertLogFile(self.fn)
4456 m2 = self.next_rec()
4457 rh.emit(m2)
4458 fn = namer(self.fn + ".1")
4459 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004460 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004461 with open(fn, "rb") as f:
4462 compressed = f.read()
4463 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004464 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004465 rh.emit(self.next_rec())
4466 fn = namer(self.fn + ".2")
4467 self.assertLogFile(fn)
4468 with open(fn, "rb") as f:
4469 compressed = f.read()
4470 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004471 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004472 rh.emit(self.next_rec())
4473 fn = namer(self.fn + ".2")
4474 with open(fn, "rb") as f:
4475 compressed = f.read()
4476 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004477 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004478 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004479 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004480
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004481class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004482 # other test methods added below
4483 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004484 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4485 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004486 fmt = logging.Formatter('%(asctime)s %(message)s')
4487 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004488 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004489 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004490 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004491 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004492 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004493 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004494 fh.close()
4495 # At this point, we should have a recent rotated file which we
4496 # can test for the existence of. However, in practice, on some
4497 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004498 # in time to go to look for the log file. So, we go back a fair
4499 # bit, and stop as soon as we see a rotated file. In theory this
4500 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004501 found = False
4502 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004503 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004504 for secs in range(GO_BACK):
4505 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004506 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4507 found = os.path.exists(fn)
4508 if found:
4509 self.rmfiles.append(fn)
4510 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004511 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4512 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004513 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004514 dn, fn = os.path.split(self.fn)
4515 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004516 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4517 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004518 for f in files:
4519 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004520 path = os.path.join(dn, f)
4521 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004522 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004523 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004524
Vinay Sajip0372e102011-05-05 12:59:14 +01004525 def test_invalid(self):
4526 assertRaises = self.assertRaises
4527 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004528 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004529 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004530 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004531 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004532 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004533
Vinay Sajipa7130792013-04-12 17:04:23 +01004534 def test_compute_rollover_daily_attime(self):
4535 currentTime = 0
4536 atTime = datetime.time(12, 0, 0)
4537 rh = logging.handlers.TimedRotatingFileHandler(
4538 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4539 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004540 try:
4541 actual = rh.computeRollover(currentTime)
4542 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004543
Vinay Sajipd86ac962013-04-14 12:20:46 +01004544 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4545 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4546 finally:
4547 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004548
Vinay Sajip10e8c492013-05-18 10:19:54 -07004549 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004550 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004551 currentTime = int(time.time())
4552 today = currentTime - currentTime % 86400
4553
Vinay Sajipa7130792013-04-12 17:04:23 +01004554 atTime = datetime.time(12, 0, 0)
4555
Vinay Sajip10e8c492013-05-18 10:19:54 -07004556 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004557 for day in range(7):
4558 rh = logging.handlers.TimedRotatingFileHandler(
4559 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4560 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004561 try:
4562 if wday > day:
4563 # The rollover day has already passed this week, so we
4564 # go over into next week
4565 expected = (7 - wday + day)
4566 else:
4567 expected = (day - wday)
4568 # At this point expected is in days from now, convert to seconds
4569 expected *= 24 * 60 * 60
4570 # Add in the rollover time
4571 expected += 12 * 60 * 60
4572 # Add in adjustment for today
4573 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004574 actual = rh.computeRollover(today)
4575 if actual != expected:
4576 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004577 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004578 self.assertEqual(actual, expected)
4579 if day == wday:
4580 # goes into following week
4581 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004582 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004583 if actual != expected:
4584 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004585 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004586 self.assertEqual(actual, expected)
4587 finally:
4588 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004589
4590
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004591def secs(**kw):
4592 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4593
4594for when, exp in (('S', 1),
4595 ('M', 60),
4596 ('H', 60 * 60),
4597 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004598 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004599 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004600 ('W0', secs(days=4, hours=24)),
4601 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004602 def test_compute_rollover(self, when=when, exp=exp):
4603 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004604 self.fn, when=when, interval=1, backupCount=0, utc=True)
4605 currentTime = 0.0
4606 actual = rh.computeRollover(currentTime)
4607 if exp != actual:
4608 # Failures occur on some systems for MIDNIGHT and W0.
4609 # Print detailed calculation for MIDNIGHT so we can try to see
4610 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004611 if when == 'MIDNIGHT':
4612 try:
4613 if rh.utc:
4614 t = time.gmtime(currentTime)
4615 else:
4616 t = time.localtime(currentTime)
4617 currentHour = t[3]
4618 currentMinute = t[4]
4619 currentSecond = t[5]
4620 # r is the number of seconds left between now and midnight
4621 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4622 currentMinute) * 60 +
4623 currentSecond)
4624 result = currentTime + r
4625 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4626 print('currentHour: %s' % currentHour, file=sys.stderr)
4627 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4628 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4629 print('r: %s' % r, file=sys.stderr)
4630 print('result: %s' % result, file=sys.stderr)
4631 except Exception:
4632 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4633 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004634 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004635 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4636
Vinay Sajip60ccd822011-05-09 17:32:09 +01004637
Vinay Sajip223349c2015-10-01 20:37:54 +01004638@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004639class NTEventLogHandlerTest(BaseTest):
4640 def test_basic(self):
4641 logtype = 'Application'
4642 elh = win32evtlog.OpenEventLog(None, logtype)
4643 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004644
4645 try:
4646 h = logging.handlers.NTEventLogHandler('test_logging')
4647 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004648 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004649 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004650 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004651
Vinay Sajip60ccd822011-05-09 17:32:09 +01004652 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4653 h.handle(r)
4654 h.close()
4655 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004656 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004657 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4658 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4659 found = False
4660 GO_BACK = 100
4661 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4662 for e in events:
4663 if e.SourceName != 'test_logging':
4664 continue
4665 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4666 if msg != 'Test Log Message\r\n':
4667 continue
4668 found = True
4669 break
4670 msg = 'Record not found in event log, went back %d records' % GO_BACK
4671 self.assertTrue(found, msg=msg)
4672
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004673
4674class MiscTestCase(unittest.TestCase):
4675 def test__all__(self):
4676 blacklist = {'logThreads', 'logMultiprocessing',
4677 'logProcesses', 'currentframe',
4678 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4679 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004680 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004681 support.check__all__(self, logging, blacklist=blacklist)
4682
4683
Christian Heimes180510d2008-03-03 19:15:45 +00004684# Set the locale to the platform-dependent default. I have no idea
4685# why the test does this, but in any case we save the current locale
4686# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004687@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004688def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004689 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004690 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4691 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4692 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4693 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4694 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4695 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4696 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4697 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004698 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004699 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004700 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004701 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004702 ]
4703 if hasattr(logging.handlers, 'QueueListener'):
4704 tests.append(QueueListenerTest)
4705 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004706
Christian Heimes180510d2008-03-03 19:15:45 +00004707if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004708 test_main()