blob: fb0de9de046c7efb4a7260c1e0a965f31284581a [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):
181 #Logging levels in a flat logger namespace.
182 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):
251 #Logging levels in a nested namespace, inherited from parent loggers.
252 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 """
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200776 try:
777 asyncore.loop(poll_interval, map=self._map)
778 except OSError:
779 # On FreeBSD 8, closing the server repeatably
780 # raises this error. We swallow it if the
781 # server has been closed.
782 if self.connected or self.accepting:
783 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100784
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200785 def stop(self, timeout=None):
786 """
787 Stop the thread by closing the server instance.
788 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100789
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200790 :param timeout: How long to wait for the server thread
791 to terminate.
792 """
793 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700794 support.join_thread(self._thread, timeout)
795 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200796 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100797
Vinay Sajip7367d082011-05-02 13:17:27 +0100798
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200799class ControlMixin(object):
800 """
801 This mixin is used to start a server on a separate thread, and
802 shut it down programmatically. Request handling is simplified - instead
803 of needing to derive a suitable RequestHandler subclass, you just
804 provide a callable which will be passed each received request to be
805 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200807 :param handler: A handler callable which will be called with a
808 single parameter - the request - in order to
809 process the request. This handler is called on the
810 server thread, effectively meaning that requests are
811 processed serially. While not quite Web scale ;-),
812 this should be fine for testing applications.
813 :param poll_interval: The polling interval in seconds.
814 """
815 def __init__(self, handler, poll_interval):
816 self._thread = None
817 self.poll_interval = poll_interval
818 self._handler = handler
819 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100820
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200821 def start(self):
822 """
823 Create a daemon thread to run the server, and start it.
824 """
825 self._thread = t = threading.Thread(target=self.serve_forever,
826 args=(self.poll_interval,))
827 t.setDaemon(True)
828 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100829
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200830 def serve_forever(self, poll_interval):
831 """
832 Run the server. Set the ready flag before entering the
833 service loop.
834 """
835 self.ready.set()
836 super(ControlMixin, self).serve_forever(poll_interval)
837
838 def stop(self, timeout=None):
839 """
840 Tell the server thread to stop, and wait for it to do so.
841
842 :param timeout: How long to wait for the server thread
843 to terminate.
844 """
845 self.shutdown()
846 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700847 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100848 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200849 self.server_close()
850 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200852class TestHTTPServer(ControlMixin, HTTPServer):
853 """
854 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100855
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200856 :param addr: A tuple with the IP address and port to listen on.
857 :param handler: A handler callable which will be called with a
858 single parameter - the request - in order to
859 process the request.
860 :param poll_interval: The polling interval in seconds.
861 :param log: Pass ``True`` to enable log messages.
862 """
863 def __init__(self, addr, handler, poll_interval=0.5,
864 log=False, sslctx=None):
865 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
866 def __getattr__(self, name, default=None):
867 if name.startswith('do_'):
868 return self.process_request
869 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100870
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200871 def process_request(self):
872 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100873
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200874 def log_message(self, format, *args):
875 if log:
876 super(DelegatingHTTPRequestHandler,
877 self).log_message(format, *args)
878 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
879 ControlMixin.__init__(self, handler, poll_interval)
880 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100881
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200882 def get_request(self):
883 try:
884 sock, addr = self.socket.accept()
885 if self.sslctx:
886 sock = self.sslctx.wrap_socket(sock, server_side=True)
887 except OSError as e:
888 # socket errors are silenced by the caller, print them here
889 sys.stderr.write("Got an error:\n%s\n" % e)
890 raise
891 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100892
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200893class TestTCPServer(ControlMixin, ThreadingTCPServer):
894 """
895 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100896
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200897 :param addr: A tuple with the IP address and port to listen on.
898 :param handler: A handler callable which will be called with a single
899 parameter - the request - in order to process the request.
900 :param poll_interval: The polling interval in seconds.
901 :bind_and_activate: If True (the default), binds the server and starts it
902 listening. If False, you need to call
903 :meth:`server_bind` and :meth:`server_activate` at
904 some later time before calling :meth:`start`, so that
905 the server will set up the socket and listen on it.
906 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200908 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100909
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200910 def __init__(self, addr, handler, poll_interval=0.5,
911 bind_and_activate=True):
912 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100913
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200914 def handle(self):
915 self.server._handler(self)
916 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
917 bind_and_activate)
918 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100919
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200920 def server_bind(self):
921 super(TestTCPServer, self).server_bind()
922 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100923
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200924class TestUDPServer(ControlMixin, ThreadingUDPServer):
925 """
926 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100927
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200928 :param addr: A tuple with the IP address and port to listen on.
929 :param handler: A handler callable which will be called with a
930 single parameter - the request - in order to
931 process the request.
932 :param poll_interval: The polling interval for shutdown requests,
933 in seconds.
934 :bind_and_activate: If True (the default), binds the server and
935 starts it listening. If False, you need to
936 call :meth:`server_bind` and
937 :meth:`server_activate` at some later time
938 before calling :meth:`start`, so that the server will
939 set up the socket and listen on it.
940 """
941 def __init__(self, addr, handler, poll_interval=0.5,
942 bind_and_activate=True):
943 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100944
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200945 def handle(self):
946 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100947
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200948 def finish(self):
949 data = self.wfile.getvalue()
950 if data:
951 try:
952 super(DelegatingUDPRequestHandler, self).finish()
953 except OSError:
954 if not self.server._closed:
955 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100956
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200957 ThreadingUDPServer.__init__(self, addr,
958 DelegatingUDPRequestHandler,
959 bind_and_activate)
960 ControlMixin.__init__(self, handler, poll_interval)
961 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100962
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200963 def server_bind(self):
964 super(TestUDPServer, self).server_bind()
965 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100966
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200967 def server_close(self):
968 super(TestUDPServer, self).server_close()
969 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +0100970
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200971if hasattr(socket, "AF_UNIX"):
972 class TestUnixStreamServer(TestTCPServer):
973 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +0100974
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200975 class TestUnixDatagramServer(TestUDPServer):
976 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100977
Vinay Sajip7367d082011-05-02 13:17:27 +0100978# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100979
980class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000981 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200982
Vinay Sajipa463d252011-04-30 21:52:48 +0100983 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100984 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800985 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100986 sockmap)
987 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800988 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000989 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
990 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100991 self.assertEqual(h.toaddrs, ['you'])
992 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100993 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100994 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100995 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000996 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100997 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000998 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100999 self.assertEqual(len(self.messages), 1)
1000 peer, mailfrom, rcpttos, data = self.messages[0]
1001 self.assertEqual(mailfrom, 'me')
1002 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001003 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001004 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001005 h.close()
1006
1007 def process_message(self, *args):
1008 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001009 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001010
Christian Heimes180510d2008-03-03 19:15:45 +00001011class MemoryHandlerTest(BaseTest):
1012
1013 """Tests for the MemoryHandler."""
1014
1015 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001016 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001017
1018 def setUp(self):
1019 BaseTest.setUp(self)
1020 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001021 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001022 self.mem_logger = logging.getLogger('mem')
1023 self.mem_logger.propagate = 0
1024 self.mem_logger.addHandler(self.mem_hdlr)
1025
1026 def tearDown(self):
1027 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001028 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001029
1030 def test_flush(self):
1031 # The memory handler flushes to its target handler based on specific
1032 # criteria (message count and message level).
1033 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001034 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001035 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001036 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001037 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001038 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001039 lines = [
1040 ('DEBUG', '1'),
1041 ('INFO', '2'),
1042 ('WARNING', '3'),
1043 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001044 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001045 for n in (4, 14):
1046 for i in range(9):
1047 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001048 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001049 # This will flush because it's the 10th message since the last
1050 # flush.
1051 self.mem_logger.debug(self.next_message())
1052 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001053 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001054
1055 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001056 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001057
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001058 def test_flush_on_close(self):
1059 """
1060 Test that the flush-on-close configuration works as expected.
1061 """
1062 self.mem_logger.debug(self.next_message())
1063 self.assert_log_lines([])
1064 self.mem_logger.info(self.next_message())
1065 self.assert_log_lines([])
1066 self.mem_logger.removeHandler(self.mem_hdlr)
1067 # Default behaviour is to flush on close. Check that it happens.
1068 self.mem_hdlr.close()
1069 lines = [
1070 ('DEBUG', '1'),
1071 ('INFO', '2'),
1072 ]
1073 self.assert_log_lines(lines)
1074 # Now configure for flushing not to be done on close.
1075 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1076 self.root_hdlr,
1077 False)
1078 self.mem_logger.addHandler(self.mem_hdlr)
1079 self.mem_logger.debug(self.next_message())
1080 self.assert_log_lines(lines) # no change
1081 self.mem_logger.info(self.next_message())
1082 self.assert_log_lines(lines) # no change
1083 self.mem_logger.removeHandler(self.mem_hdlr)
1084 self.mem_hdlr.close()
1085 # assert that no new lines have been added
1086 self.assert_log_lines(lines) # no change
1087
Christian Heimes180510d2008-03-03 19:15:45 +00001088
1089class ExceptionFormatter(logging.Formatter):
1090 """A special exception formatter."""
1091 def formatException(self, ei):
1092 return "Got a [%s]" % ei[0].__name__
1093
1094
1095class ConfigFileTest(BaseTest):
1096
1097 """Reading logging config from a .ini-style config file."""
1098
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001099 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001100
1101 # config0 is a standard configuration.
1102 config0 = """
1103 [loggers]
1104 keys=root
1105
1106 [handlers]
1107 keys=hand1
1108
1109 [formatters]
1110 keys=form1
1111
1112 [logger_root]
1113 level=WARNING
1114 handlers=hand1
1115
1116 [handler_hand1]
1117 class=StreamHandler
1118 level=NOTSET
1119 formatter=form1
1120 args=(sys.stdout,)
1121
1122 [formatter_form1]
1123 format=%(levelname)s ++ %(message)s
1124 datefmt=
1125 """
1126
1127 # config1 adds a little to the standard configuration.
1128 config1 = """
1129 [loggers]
1130 keys=root,parser
1131
1132 [handlers]
1133 keys=hand1
1134
1135 [formatters]
1136 keys=form1
1137
1138 [logger_root]
1139 level=WARNING
1140 handlers=
1141
1142 [logger_parser]
1143 level=DEBUG
1144 handlers=hand1
1145 propagate=1
1146 qualname=compiler.parser
1147
1148 [handler_hand1]
1149 class=StreamHandler
1150 level=NOTSET
1151 formatter=form1
1152 args=(sys.stdout,)
1153
1154 [formatter_form1]
1155 format=%(levelname)s ++ %(message)s
1156 datefmt=
1157 """
1158
Vinay Sajip3f84b072011-03-07 17:49:33 +00001159 # config1a moves the handler to the root.
1160 config1a = """
1161 [loggers]
1162 keys=root,parser
1163
1164 [handlers]
1165 keys=hand1
1166
1167 [formatters]
1168 keys=form1
1169
1170 [logger_root]
1171 level=WARNING
1172 handlers=hand1
1173
1174 [logger_parser]
1175 level=DEBUG
1176 handlers=
1177 propagate=1
1178 qualname=compiler.parser
1179
1180 [handler_hand1]
1181 class=StreamHandler
1182 level=NOTSET
1183 formatter=form1
1184 args=(sys.stdout,)
1185
1186 [formatter_form1]
1187 format=%(levelname)s ++ %(message)s
1188 datefmt=
1189 """
1190
Christian Heimes180510d2008-03-03 19:15:45 +00001191 # config2 has a subtle configuration error that should be reported
1192 config2 = config1.replace("sys.stdout", "sys.stbout")
1193
1194 # config3 has a less subtle configuration error
1195 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1196
1197 # config4 specifies a custom formatter class to be loaded
1198 config4 = """
1199 [loggers]
1200 keys=root
1201
1202 [handlers]
1203 keys=hand1
1204
1205 [formatters]
1206 keys=form1
1207
1208 [logger_root]
1209 level=NOTSET
1210 handlers=hand1
1211
1212 [handler_hand1]
1213 class=StreamHandler
1214 level=NOTSET
1215 formatter=form1
1216 args=(sys.stdout,)
1217
1218 [formatter_form1]
1219 class=""" + __name__ + """.ExceptionFormatter
1220 format=%(levelname)s:%(name)s:%(message)s
1221 datefmt=
1222 """
1223
Georg Brandl3dbca812008-07-23 16:10:53 +00001224 # config5 specifies a custom handler class to be loaded
1225 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1226
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001227 # config6 uses ', ' delimiters in the handlers and formatters sections
1228 config6 = """
1229 [loggers]
1230 keys=root,parser
1231
1232 [handlers]
1233 keys=hand1, hand2
1234
1235 [formatters]
1236 keys=form1, form2
1237
1238 [logger_root]
1239 level=WARNING
1240 handlers=
1241
1242 [logger_parser]
1243 level=DEBUG
1244 handlers=hand1
1245 propagate=1
1246 qualname=compiler.parser
1247
1248 [handler_hand1]
1249 class=StreamHandler
1250 level=NOTSET
1251 formatter=form1
1252 args=(sys.stdout,)
1253
1254 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001255 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001256 level=NOTSET
1257 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001258 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001259
1260 [formatter_form1]
1261 format=%(levelname)s ++ %(message)s
1262 datefmt=
1263
1264 [formatter_form2]
1265 format=%(message)s
1266 datefmt=
1267 """
1268
Preston Landers6ea56d22017-08-02 15:44:28 -05001269 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001270 config7 = """
1271 [loggers]
1272 keys=root,parser,compiler
1273
1274 [handlers]
1275 keys=hand1
1276
1277 [formatters]
1278 keys=form1
1279
1280 [logger_root]
1281 level=WARNING
1282 handlers=hand1
1283
1284 [logger_compiler]
1285 level=DEBUG
1286 handlers=
1287 propagate=1
1288 qualname=compiler
1289
1290 [logger_parser]
1291 level=DEBUG
1292 handlers=
1293 propagate=1
1294 qualname=compiler.parser
1295
1296 [handler_hand1]
1297 class=StreamHandler
1298 level=NOTSET
1299 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001300 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001301
1302 [formatter_form1]
1303 format=%(levelname)s ++ %(message)s
1304 datefmt=
1305 """
1306
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001307 disable_test = """
1308 [loggers]
1309 keys=root
1310
1311 [handlers]
1312 keys=screen
1313
1314 [formatters]
1315 keys=
1316
1317 [logger_root]
1318 level=DEBUG
1319 handlers=screen
1320
1321 [handler_screen]
1322 level=DEBUG
1323 class=StreamHandler
1324 args=(sys.stdout,)
1325 formatter=
1326 """
1327
1328 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001329 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001330 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001331
1332 def test_config0_ok(self):
1333 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001334 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001335 self.apply_config(self.config0)
1336 logger = logging.getLogger()
1337 # Won't output anything
1338 logger.info(self.next_message())
1339 # Outputs a message
1340 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001341 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001342 ('ERROR', '2'),
1343 ], stream=output)
1344 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001345 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001346
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001347 def test_config0_using_cp_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:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001350 file = io.StringIO(textwrap.dedent(self.config0))
1351 cp = configparser.ConfigParser()
1352 cp.read_file(file)
1353 logging.config.fileConfig(cp)
1354 logger = logging.getLogger()
1355 # Won't output anything
1356 logger.info(self.next_message())
1357 # Outputs a message
1358 logger.error(self.next_message())
1359 self.assert_log_lines([
1360 ('ERROR', '2'),
1361 ], stream=output)
1362 # Original logger output is empty.
1363 self.assert_log_lines([])
1364
Georg Brandl3dbca812008-07-23 16:10:53 +00001365 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001366 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001367 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001368 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001369 logger = logging.getLogger("compiler.parser")
1370 # Both will output a message
1371 logger.info(self.next_message())
1372 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001373 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001374 ('INFO', '1'),
1375 ('ERROR', '2'),
1376 ], stream=output)
1377 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001378 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001379
1380 def test_config2_failure(self):
1381 # A simple config file which overrides the default settings.
1382 self.assertRaises(Exception, self.apply_config, self.config2)
1383
1384 def test_config3_failure(self):
1385 # A simple config file which overrides the default settings.
1386 self.assertRaises(Exception, self.apply_config, self.config3)
1387
1388 def test_config4_ok(self):
1389 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001390 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001391 self.apply_config(self.config4)
1392 logger = logging.getLogger()
1393 try:
1394 raise RuntimeError()
1395 except RuntimeError:
1396 logging.exception("just testing")
1397 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001398 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001399 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1400 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001401 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001402
Georg Brandl3dbca812008-07-23 16:10:53 +00001403 def test_config5_ok(self):
1404 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001405
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001406 def test_config6_ok(self):
1407 self.test_config1_ok(config=self.config6)
1408
Vinay Sajip3f84b072011-03-07 17:49:33 +00001409 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001410 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001411 self.apply_config(self.config1a)
1412 logger = logging.getLogger("compiler.parser")
1413 # See issue #11424. compiler-hyphenated sorts
1414 # between compiler and compiler.xyz and this
1415 # was preventing compiler.xyz from being included
1416 # in the child loggers of compiler because of an
1417 # overzealous loop termination condition.
1418 hyphenated = logging.getLogger('compiler-hyphenated')
1419 # All will output a message
1420 logger.info(self.next_message())
1421 logger.error(self.next_message())
1422 hyphenated.critical(self.next_message())
1423 self.assert_log_lines([
1424 ('INFO', '1'),
1425 ('ERROR', '2'),
1426 ('CRITICAL', '3'),
1427 ], stream=output)
1428 # Original logger output is empty.
1429 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001430 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001431 self.apply_config(self.config7)
1432 logger = logging.getLogger("compiler.parser")
1433 self.assertFalse(logger.disabled)
1434 # Both will output a message
1435 logger.info(self.next_message())
1436 logger.error(self.next_message())
1437 logger = logging.getLogger("compiler.lexer")
1438 # Both will output a message
1439 logger.info(self.next_message())
1440 logger.error(self.next_message())
1441 # Will not appear
1442 hyphenated.critical(self.next_message())
1443 self.assert_log_lines([
1444 ('INFO', '4'),
1445 ('ERROR', '5'),
1446 ('INFO', '6'),
1447 ('ERROR', '7'),
1448 ], stream=output)
1449 # Original logger output is empty.
1450 self.assert_log_lines([])
1451
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001452 def test_logger_disabling(self):
1453 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001454 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001455 self.assertFalse(logger.disabled)
1456 self.apply_config(self.disable_test)
1457 self.assertTrue(logger.disabled)
1458 self.apply_config(self.disable_test, disable_existing_loggers=False)
1459 self.assertFalse(logger.disabled)
1460
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001461
Christian Heimes180510d2008-03-03 19:15:45 +00001462class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001463
Christian Heimes180510d2008-03-03 19:15:45 +00001464 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001465
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001466 server_class = TestTCPServer
1467 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001468
Christian Heimes180510d2008-03-03 19:15:45 +00001469 def setUp(self):
1470 """Set up a TCP server to receive log messages, and a SocketHandler
1471 pointing to that server's address and port."""
1472 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001473 # Issue #29177: deal with errors that happen during setup
1474 self.server = self.sock_hdlr = self.server_exception = None
1475 try:
1476 self.server = server = self.server_class(self.address,
1477 self.handle_socket, 0.01)
1478 server.start()
1479 # Uncomment next line to test error recovery in setUp()
1480 # raise OSError('dummy error raised')
1481 except OSError as e:
1482 self.server_exception = e
1483 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001484 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001485 hcls = logging.handlers.SocketHandler
1486 if isinstance(server.server_address, tuple):
1487 self.sock_hdlr = hcls('localhost', server.port)
1488 else:
1489 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001490 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001491 self.root_logger.removeHandler(self.root_logger.handlers[0])
1492 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001493 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001494
Christian Heimes180510d2008-03-03 19:15:45 +00001495 def tearDown(self):
1496 """Shutdown the TCP server."""
1497 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001498 if self.sock_hdlr:
1499 self.root_logger.removeHandler(self.sock_hdlr)
1500 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001501 if self.server:
1502 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001503 finally:
1504 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001505
Vinay Sajip7367d082011-05-02 13:17:27 +01001506 def handle_socket(self, request):
1507 conn = request.connection
1508 while True:
1509 chunk = conn.recv(4)
1510 if len(chunk) < 4:
1511 break
1512 slen = struct.unpack(">L", chunk)[0]
1513 chunk = conn.recv(slen)
1514 while len(chunk) < slen:
1515 chunk = chunk + conn.recv(slen - len(chunk))
1516 obj = pickle.loads(chunk)
1517 record = logging.makeLogRecord(obj)
1518 self.log_output += record.msg + '\n'
1519 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001520
Christian Heimes180510d2008-03-03 19:15:45 +00001521 def test_output(self):
1522 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001523 if self.server_exception:
1524 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001525 logger = logging.getLogger("tcp")
1526 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001527 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001528 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001529 self.handled.acquire()
1530 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001531
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001532 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001533 if self.server_exception:
1534 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001535 # Avoid timing-related failures due to SocketHandler's own hard-wired
1536 # one-second timeout on socket.create_connection() (issue #16264).
1537 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001538 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001539 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001540 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001541 try:
1542 raise RuntimeError('Deliberate mistake')
1543 except RuntimeError:
1544 self.root_logger.exception('Never sent')
1545 self.root_logger.error('Never sent, either')
1546 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001547 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001548 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1549 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001550
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001551def _get_temp_domain_socket():
1552 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1553 os.close(fd)
1554 # just need a name - file can't be present, or we'll get an
1555 # 'address already in use' error.
1556 os.remove(fn)
1557 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001558
Victor Stinnerec5a8602014-06-02 14:41:51 +02001559@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001560class UnixSocketHandlerTest(SocketHandlerTest):
1561
1562 """Test for SocketHandler with unix sockets."""
1563
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001564 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001565 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001566
1567 def setUp(self):
1568 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001569 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001570 SocketHandlerTest.setUp(self)
1571
1572 def tearDown(self):
1573 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001574 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001575
Vinay Sajip7367d082011-05-02 13:17:27 +01001576class DatagramHandlerTest(BaseTest):
1577
1578 """Test for DatagramHandler."""
1579
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001580 server_class = TestUDPServer
1581 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001582
Vinay Sajip7367d082011-05-02 13:17:27 +01001583 def setUp(self):
1584 """Set up a UDP server to receive log messages, and a DatagramHandler
1585 pointing to that server's address and port."""
1586 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001587 # Issue #29177: deal with errors that happen during setup
1588 self.server = self.sock_hdlr = self.server_exception = None
1589 try:
1590 self.server = server = self.server_class(self.address,
1591 self.handle_datagram, 0.01)
1592 server.start()
1593 # Uncomment next line to test error recovery in setUp()
1594 # raise OSError('dummy error raised')
1595 except OSError as e:
1596 self.server_exception = e
1597 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001598 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001599 hcls = logging.handlers.DatagramHandler
1600 if isinstance(server.server_address, tuple):
1601 self.sock_hdlr = hcls('localhost', server.port)
1602 else:
1603 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001604 self.log_output = ''
1605 self.root_logger.removeHandler(self.root_logger.handlers[0])
1606 self.root_logger.addHandler(self.sock_hdlr)
1607 self.handled = threading.Event()
1608
1609 def tearDown(self):
1610 """Shutdown the UDP server."""
1611 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001612 if self.server:
1613 self.server.stop(2.0)
1614 if self.sock_hdlr:
1615 self.root_logger.removeHandler(self.sock_hdlr)
1616 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001617 finally:
1618 BaseTest.tearDown(self)
1619
1620 def handle_datagram(self, request):
1621 slen = struct.pack('>L', 0) # length of prefix
1622 packet = request.packet[len(slen):]
1623 obj = pickle.loads(packet)
1624 record = logging.makeLogRecord(obj)
1625 self.log_output += record.msg + '\n'
1626 self.handled.set()
1627
1628 def test_output(self):
1629 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001630 if self.server_exception:
1631 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001632 logger = logging.getLogger("udp")
1633 logger.error("spam")
1634 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001635 self.handled.clear()
1636 logger.error("eggs")
1637 self.handled.wait()
1638 self.assertEqual(self.log_output, "spam\neggs\n")
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 UnixDatagramHandlerTest(DatagramHandlerTest):
1642
1643 """Test for DatagramHandler using 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 = TestUnixDatagramServer
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 DatagramHandlerTest.setUp(self)
1652
1653 def tearDown(self):
1654 DatagramHandlerTest.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 SysLogHandlerTest(BaseTest):
1658
1659 """Test for SysLogHandler using UDP."""
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 SysLogHandler
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.sl_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.SysLogHandler
1681 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001682 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001683 else:
1684 self.sl_hdlr = hcls(server.server_address)
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.sl_hdlr)
1688 self.handled = threading.Event()
1689
1690 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001691 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001692 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001693 if self.server:
1694 self.server.stop(2.0)
1695 if self.sl_hdlr:
1696 self.root_logger.removeHandler(self.sl_hdlr)
1697 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001698 finally:
1699 BaseTest.tearDown(self)
1700
1701 def handle_datagram(self, request):
1702 self.log_output = request.packet
1703 self.handled.set()
1704
1705 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001706 if self.server_exception:
1707 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001708 # The log message sent to the SysLogHandler is properly received.
1709 logger = logging.getLogger("slh")
1710 logger.error("sp\xe4m")
1711 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001712 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001713 self.handled.clear()
1714 self.sl_hdlr.append_nul = False
1715 logger.error("sp\xe4m")
1716 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001717 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001718 self.handled.clear()
1719 self.sl_hdlr.ident = "h\xe4m-"
1720 logger.error("sp\xe4m")
1721 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001722 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001723
Victor Stinnerec5a8602014-06-02 14:41:51 +02001724@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001725class UnixSysLogHandlerTest(SysLogHandlerTest):
1726
1727 """Test for SysLogHandler with Unix sockets."""
1728
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001729 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001730 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001731
1732 def setUp(self):
1733 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001734 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001735 SysLogHandlerTest.setUp(self)
1736
1737 def tearDown(self):
1738 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001739 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001740
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001741@unittest.skipUnless(support.IPV6_ENABLED,
1742 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001743class IPv6SysLogHandlerTest(SysLogHandlerTest):
1744
1745 """Test for SysLogHandler with IPv6 host."""
1746
1747 server_class = TestUDPServer
1748 address = ('::1', 0)
1749
1750 def setUp(self):
1751 self.server_class.address_family = socket.AF_INET6
1752 super(IPv6SysLogHandlerTest, self).setUp()
1753
1754 def tearDown(self):
1755 self.server_class.address_family = socket.AF_INET
1756 super(IPv6SysLogHandlerTest, self).tearDown()
1757
Vinay Sajip7367d082011-05-02 13:17:27 +01001758class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001759 """Test for HTTPHandler."""
1760
1761 def setUp(self):
1762 """Set up an HTTP server to receive log messages, and a HTTPHandler
1763 pointing to that server's address and port."""
1764 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001765 self.handled = threading.Event()
1766
Vinay Sajip7367d082011-05-02 13:17:27 +01001767 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001768 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001769 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001770 if self.command == 'POST':
1771 try:
1772 rlen = int(request.headers['Content-Length'])
1773 self.post_data = request.rfile.read(rlen)
1774 except:
1775 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001776 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001777 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001778 self.handled.set()
1779
1780 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001781 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001782 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001783 root_logger = self.root_logger
1784 root_logger.removeHandler(self.root_logger.handlers[0])
1785 for secure in (False, True):
1786 addr = ('localhost', 0)
1787 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001788 try:
1789 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001790 except ImportError:
1791 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001792 else:
1793 here = os.path.dirname(__file__)
1794 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001795 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001796 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001797
1798 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001799 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001800 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001801 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001802 self.server = server = TestHTTPServer(addr, self.handle_request,
1803 0.01, sslctx=sslctx)
1804 server.start()
1805 server.ready.wait()
1806 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001807 secure_client = secure and sslctx
1808 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001809 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001810 context=context,
1811 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001812 self.log_data = None
1813 root_logger.addHandler(self.h_hdlr)
1814
1815 for method in ('GET', 'POST'):
1816 self.h_hdlr.method = method
1817 self.handled.clear()
1818 msg = "sp\xe4m"
1819 logger.error(msg)
1820 self.handled.wait()
1821 self.assertEqual(self.log_data.path, '/frob')
1822 self.assertEqual(self.command, method)
1823 if method == 'GET':
1824 d = parse_qs(self.log_data.query)
1825 else:
1826 d = parse_qs(self.post_data.decode('utf-8'))
1827 self.assertEqual(d['name'], ['http'])
1828 self.assertEqual(d['funcName'], ['test_output'])
1829 self.assertEqual(d['msg'], [msg])
1830
1831 self.server.stop(2.0)
1832 self.root_logger.removeHandler(self.h_hdlr)
1833 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001834
Christian Heimes180510d2008-03-03 19:15:45 +00001835class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001836
Christian Heimes180510d2008-03-03 19:15:45 +00001837 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001838
Christian Heimes180510d2008-03-03 19:15:45 +00001839 def setUp(self):
1840 """Create a dict to remember potentially destroyed objects."""
1841 BaseTest.setUp(self)
1842 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001843
Christian Heimes180510d2008-03-03 19:15:45 +00001844 def _watch_for_survival(self, *args):
1845 """Watch the given objects for survival, by creating weakrefs to
1846 them."""
1847 for obj in args:
1848 key = id(obj), repr(obj)
1849 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001850
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001851 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001852 """Assert that all objects watched for survival have survived."""
1853 # Trigger cycle breaking.
1854 gc.collect()
1855 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001856 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001857 if ref() is None:
1858 dead.append(repr_)
1859 if dead:
1860 self.fail("%d objects should have survived "
1861 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001862
Christian Heimes180510d2008-03-03 19:15:45 +00001863 def test_persistent_loggers(self):
1864 # Logger objects are persistent and retain their configuration, even
1865 # if visible references are destroyed.
1866 self.root_logger.setLevel(logging.INFO)
1867 foo = logging.getLogger("foo")
1868 self._watch_for_survival(foo)
1869 foo.setLevel(logging.DEBUG)
1870 self.root_logger.debug(self.next_message())
1871 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001872 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001873 ('foo', 'DEBUG', '2'),
1874 ])
1875 del foo
1876 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001877 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001878 # foo has retained its settings.
1879 bar = logging.getLogger("foo")
1880 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001881 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001882 ('foo', 'DEBUG', '2'),
1883 ('foo', 'DEBUG', '3'),
1884 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001885
Benjamin Petersonf91df042009-02-13 02:50:59 +00001886
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001887class EncodingTest(BaseTest):
1888 def test_encoding_plain_file(self):
1889 # In Python 2.x, a plain file object is treated as having no encoding.
1890 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001891 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1892 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001893 # the non-ascii data we write to the log.
1894 data = "foo\x80"
1895 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001896 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001897 log.addHandler(handler)
1898 try:
1899 # write non-ascii data to the log.
1900 log.warning(data)
1901 finally:
1902 log.removeHandler(handler)
1903 handler.close()
1904 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001905 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001906 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001907 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001908 finally:
1909 f.close()
1910 finally:
1911 if os.path.isfile(fn):
1912 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001913
Benjamin Petersonf91df042009-02-13 02:50:59 +00001914 def test_encoding_cyrillic_unicode(self):
1915 log = logging.getLogger("test")
1916 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1917 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1918 #Ensure it's written in a Cyrillic encoding
1919 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001920 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001921 stream = io.BytesIO()
1922 writer = writer_class(stream, 'strict')
1923 handler = logging.StreamHandler(writer)
1924 log.addHandler(handler)
1925 try:
1926 log.warning(message)
1927 finally:
1928 log.removeHandler(handler)
1929 handler.close()
1930 # check we wrote exactly those bytes, ignoring trailing \n etc
1931 s = stream.getvalue()
1932 #Compare against what the data should be when encoded in CP-1251
1933 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1934
1935
Georg Brandlf9734072008-12-07 15:30:06 +00001936class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001937
Georg Brandlf9734072008-12-07 15:30:06 +00001938 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001939 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001940 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001941 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001942 warnings.filterwarnings("always", category=UserWarning)
1943 stream = io.StringIO()
1944 h = logging.StreamHandler(stream)
1945 logger = logging.getLogger("py.warnings")
1946 logger.addHandler(h)
1947 warnings.warn("I'm warning you...")
1948 logger.removeHandler(h)
1949 s = stream.getvalue()
1950 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001951 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001952
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001953 #See if an explicit file uses the original implementation
1954 a_file = io.StringIO()
1955 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1956 a_file, "Dummy line")
1957 s = a_file.getvalue()
1958 a_file.close()
1959 self.assertEqual(s,
1960 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1961
1962 def test_warnings_no_handlers(self):
1963 with warnings.catch_warnings():
1964 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001965 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001966
1967 # confirm our assumption: no loggers are set
1968 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001969 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001970
1971 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001972 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001973 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001974
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001975
1976def formatFunc(format, datefmt=None):
1977 return logging.Formatter(format, datefmt)
1978
1979def handlerFunc():
1980 return logging.StreamHandler()
1981
1982class CustomHandler(logging.StreamHandler):
1983 pass
1984
1985class ConfigDictTest(BaseTest):
1986
1987 """Reading logging config from a dictionary."""
1988
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001989 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001990
1991 # config0 is a standard configuration.
1992 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001993 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001994 'formatters': {
1995 'form1' : {
1996 'format' : '%(levelname)s ++ %(message)s',
1997 },
1998 },
1999 'handlers' : {
2000 'hand1' : {
2001 'class' : 'logging.StreamHandler',
2002 'formatter' : 'form1',
2003 'level' : 'NOTSET',
2004 'stream' : 'ext://sys.stdout',
2005 },
2006 },
2007 'root' : {
2008 'level' : 'WARNING',
2009 'handlers' : ['hand1'],
2010 },
2011 }
2012
2013 # config1 adds a little to the standard configuration.
2014 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002015 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002016 'formatters': {
2017 'form1' : {
2018 'format' : '%(levelname)s ++ %(message)s',
2019 },
2020 },
2021 'handlers' : {
2022 'hand1' : {
2023 'class' : 'logging.StreamHandler',
2024 'formatter' : 'form1',
2025 'level' : 'NOTSET',
2026 'stream' : 'ext://sys.stdout',
2027 },
2028 },
2029 'loggers' : {
2030 'compiler.parser' : {
2031 'level' : 'DEBUG',
2032 'handlers' : ['hand1'],
2033 },
2034 },
2035 'root' : {
2036 'level' : 'WARNING',
2037 },
2038 }
2039
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002040 # config1a moves the handler to the root. Used with config8a
2041 config1a = {
2042 'version': 1,
2043 'formatters': {
2044 'form1' : {
2045 'format' : '%(levelname)s ++ %(message)s',
2046 },
2047 },
2048 'handlers' : {
2049 'hand1' : {
2050 'class' : 'logging.StreamHandler',
2051 'formatter' : 'form1',
2052 'level' : 'NOTSET',
2053 'stream' : 'ext://sys.stdout',
2054 },
2055 },
2056 'loggers' : {
2057 'compiler.parser' : {
2058 'level' : 'DEBUG',
2059 },
2060 },
2061 'root' : {
2062 'level' : 'WARNING',
2063 'handlers' : ['hand1'],
2064 },
2065 }
2066
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002067 # config2 has a subtle configuration error that should be reported
2068 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002069 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002070 'formatters': {
2071 'form1' : {
2072 'format' : '%(levelname)s ++ %(message)s',
2073 },
2074 },
2075 'handlers' : {
2076 'hand1' : {
2077 'class' : 'logging.StreamHandler',
2078 'formatter' : 'form1',
2079 'level' : 'NOTSET',
2080 'stream' : 'ext://sys.stdbout',
2081 },
2082 },
2083 'loggers' : {
2084 'compiler.parser' : {
2085 'level' : 'DEBUG',
2086 'handlers' : ['hand1'],
2087 },
2088 },
2089 'root' : {
2090 'level' : 'WARNING',
2091 },
2092 }
2093
2094 #As config1 but with a misspelt level on a handler
2095 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002097 'formatters': {
2098 'form1' : {
2099 'format' : '%(levelname)s ++ %(message)s',
2100 },
2101 },
2102 'handlers' : {
2103 'hand1' : {
2104 'class' : 'logging.StreamHandler',
2105 'formatter' : 'form1',
2106 'level' : 'NTOSET',
2107 'stream' : 'ext://sys.stdout',
2108 },
2109 },
2110 'loggers' : {
2111 'compiler.parser' : {
2112 'level' : 'DEBUG',
2113 'handlers' : ['hand1'],
2114 },
2115 },
2116 'root' : {
2117 'level' : 'WARNING',
2118 },
2119 }
2120
2121
2122 #As config1 but with a misspelt level on a logger
2123 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002124 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125 '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 'handlers' : ['hand1'],
2142 },
2143 },
2144 'root' : {
2145 'level' : 'WRANING',
2146 },
2147 }
2148
2149 # config3 has a less subtle configuration error
2150 config3 = {
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' : 'misspelled_name',
2161 'level' : 'NOTSET',
2162 'stream' : 'ext://sys.stdout',
2163 },
2164 },
2165 'loggers' : {
2166 'compiler.parser' : {
2167 'level' : 'DEBUG',
2168 'handlers' : ['hand1'],
2169 },
2170 },
2171 'root' : {
2172 'level' : 'WARNING',
2173 },
2174 }
2175
2176 # config4 specifies a custom formatter class to be loaded
2177 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002178 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002179 'formatters': {
2180 'form1' : {
2181 '()' : __name__ + '.ExceptionFormatter',
2182 'format' : '%(levelname)s:%(name)s:%(message)s',
2183 },
2184 },
2185 'handlers' : {
2186 'hand1' : {
2187 'class' : 'logging.StreamHandler',
2188 'formatter' : 'form1',
2189 'level' : 'NOTSET',
2190 'stream' : 'ext://sys.stdout',
2191 },
2192 },
2193 'root' : {
2194 'level' : 'NOTSET',
2195 'handlers' : ['hand1'],
2196 },
2197 }
2198
2199 # As config4 but using an actual callable rather than a string
2200 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002201 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002202 'formatters': {
2203 'form1' : {
2204 '()' : ExceptionFormatter,
2205 'format' : '%(levelname)s:%(name)s:%(message)s',
2206 },
2207 'form2' : {
2208 '()' : __name__ + '.formatFunc',
2209 'format' : '%(levelname)s:%(name)s:%(message)s',
2210 },
2211 'form3' : {
2212 '()' : formatFunc,
2213 'format' : '%(levelname)s:%(name)s:%(message)s',
2214 },
2215 },
2216 'handlers' : {
2217 'hand1' : {
2218 'class' : 'logging.StreamHandler',
2219 'formatter' : 'form1',
2220 'level' : 'NOTSET',
2221 'stream' : 'ext://sys.stdout',
2222 },
2223 'hand2' : {
2224 '()' : handlerFunc,
2225 },
2226 },
2227 'root' : {
2228 'level' : 'NOTSET',
2229 'handlers' : ['hand1'],
2230 },
2231 }
2232
2233 # config5 specifies a custom handler class to be loaded
2234 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002235 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002236 'formatters': {
2237 'form1' : {
2238 'format' : '%(levelname)s ++ %(message)s',
2239 },
2240 },
2241 'handlers' : {
2242 'hand1' : {
2243 'class' : __name__ + '.CustomHandler',
2244 'formatter' : 'form1',
2245 'level' : 'NOTSET',
2246 'stream' : 'ext://sys.stdout',
2247 },
2248 },
2249 'loggers' : {
2250 'compiler.parser' : {
2251 'level' : 'DEBUG',
2252 'handlers' : ['hand1'],
2253 },
2254 },
2255 'root' : {
2256 'level' : 'WARNING',
2257 },
2258 }
2259
2260 # config6 specifies a custom handler class to be loaded
2261 # but has bad arguments
2262 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002263 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002264 'formatters': {
2265 'form1' : {
2266 'format' : '%(levelname)s ++ %(message)s',
2267 },
2268 },
2269 'handlers' : {
2270 'hand1' : {
2271 'class' : __name__ + '.CustomHandler',
2272 'formatter' : 'form1',
2273 'level' : 'NOTSET',
2274 'stream' : 'ext://sys.stdout',
2275 '9' : 'invalid parameter name',
2276 },
2277 },
2278 'loggers' : {
2279 'compiler.parser' : {
2280 'level' : 'DEBUG',
2281 'handlers' : ['hand1'],
2282 },
2283 },
2284 'root' : {
2285 'level' : 'WARNING',
2286 },
2287 }
2288
2289 #config 7 does not define compiler.parser but defines compiler.lexer
2290 #so compiler.parser should be disabled after applying it
2291 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002292 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002293 'formatters': {
2294 'form1' : {
2295 'format' : '%(levelname)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 },
2306 'loggers' : {
2307 'compiler.lexer' : {
2308 'level' : 'DEBUG',
2309 'handlers' : ['hand1'],
2310 },
2311 },
2312 'root' : {
2313 'level' : 'WARNING',
2314 },
2315 }
2316
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002317 # config8 defines both compiler and compiler.lexer
2318 # so compiler.parser should not be disabled (since
2319 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002320 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002321 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002322 'disable_existing_loggers' : False,
2323 'formatters': {
2324 'form1' : {
2325 'format' : '%(levelname)s ++ %(message)s',
2326 },
2327 },
2328 'handlers' : {
2329 'hand1' : {
2330 'class' : 'logging.StreamHandler',
2331 'formatter' : 'form1',
2332 'level' : 'NOTSET',
2333 'stream' : 'ext://sys.stdout',
2334 },
2335 },
2336 'loggers' : {
2337 'compiler' : {
2338 'level' : 'DEBUG',
2339 'handlers' : ['hand1'],
2340 },
2341 'compiler.lexer' : {
2342 },
2343 },
2344 'root' : {
2345 'level' : 'WARNING',
2346 },
2347 }
2348
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002349 # config8a disables existing loggers
2350 config8a = {
2351 'version': 1,
2352 'disable_existing_loggers' : True,
2353 'formatters': {
2354 'form1' : {
2355 'format' : '%(levelname)s ++ %(message)s',
2356 },
2357 },
2358 'handlers' : {
2359 'hand1' : {
2360 'class' : 'logging.StreamHandler',
2361 'formatter' : 'form1',
2362 'level' : 'NOTSET',
2363 'stream' : 'ext://sys.stdout',
2364 },
2365 },
2366 'loggers' : {
2367 'compiler' : {
2368 'level' : 'DEBUG',
2369 'handlers' : ['hand1'],
2370 },
2371 'compiler.lexer' : {
2372 },
2373 },
2374 'root' : {
2375 'level' : 'WARNING',
2376 },
2377 }
2378
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002379 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002380 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002381 'formatters': {
2382 'form1' : {
2383 'format' : '%(levelname)s ++ %(message)s',
2384 },
2385 },
2386 'handlers' : {
2387 'hand1' : {
2388 'class' : 'logging.StreamHandler',
2389 'formatter' : 'form1',
2390 'level' : 'WARNING',
2391 'stream' : 'ext://sys.stdout',
2392 },
2393 },
2394 'loggers' : {
2395 'compiler.parser' : {
2396 'level' : 'WARNING',
2397 'handlers' : ['hand1'],
2398 },
2399 },
2400 'root' : {
2401 'level' : 'NOTSET',
2402 },
2403 }
2404
2405 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002406 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002407 'incremental' : True,
2408 'handlers' : {
2409 'hand1' : {
2410 'level' : 'WARNING',
2411 },
2412 },
2413 'loggers' : {
2414 'compiler.parser' : {
2415 'level' : 'INFO',
2416 },
2417 },
2418 }
2419
2420 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002421 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002422 'incremental' : True,
2423 'handlers' : {
2424 'hand1' : {
2425 'level' : 'INFO',
2426 },
2427 },
2428 'loggers' : {
2429 'compiler.parser' : {
2430 'level' : 'INFO',
2431 },
2432 },
2433 }
2434
2435 #As config1 but with a filter added
2436 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002437 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002438 'formatters': {
2439 'form1' : {
2440 'format' : '%(levelname)s ++ %(message)s',
2441 },
2442 },
2443 'filters' : {
2444 'filt1' : {
2445 'name' : 'compiler.parser',
2446 },
2447 },
2448 'handlers' : {
2449 'hand1' : {
2450 'class' : 'logging.StreamHandler',
2451 'formatter' : 'form1',
2452 'level' : 'NOTSET',
2453 'stream' : 'ext://sys.stdout',
2454 'filters' : ['filt1'],
2455 },
2456 },
2457 'loggers' : {
2458 'compiler.parser' : {
2459 'level' : 'DEBUG',
2460 'filters' : ['filt1'],
2461 },
2462 },
2463 'root' : {
2464 'level' : 'WARNING',
2465 'handlers' : ['hand1'],
2466 },
2467 }
2468
2469 #As config1 but using cfg:// references
2470 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002471 'version': 1,
2472 'true_formatters': {
2473 'form1' : {
2474 'format' : '%(levelname)s ++ %(message)s',
2475 },
2476 },
2477 'handler_configs': {
2478 'hand1' : {
2479 'class' : 'logging.StreamHandler',
2480 'formatter' : 'form1',
2481 'level' : 'NOTSET',
2482 'stream' : 'ext://sys.stdout',
2483 },
2484 },
2485 'formatters' : 'cfg://true_formatters',
2486 'handlers' : {
2487 'hand1' : 'cfg://handler_configs[hand1]',
2488 },
2489 'loggers' : {
2490 'compiler.parser' : {
2491 'level' : 'DEBUG',
2492 'handlers' : ['hand1'],
2493 },
2494 },
2495 'root' : {
2496 'level' : 'WARNING',
2497 },
2498 }
2499
2500 #As config11 but missing the version key
2501 config12 = {
2502 'true_formatters': {
2503 'form1' : {
2504 'format' : '%(levelname)s ++ %(message)s',
2505 },
2506 },
2507 'handler_configs': {
2508 'hand1' : {
2509 'class' : 'logging.StreamHandler',
2510 'formatter' : 'form1',
2511 'level' : 'NOTSET',
2512 'stream' : 'ext://sys.stdout',
2513 },
2514 },
2515 'formatters' : 'cfg://true_formatters',
2516 'handlers' : {
2517 'hand1' : 'cfg://handler_configs[hand1]',
2518 },
2519 'loggers' : {
2520 'compiler.parser' : {
2521 'level' : 'DEBUG',
2522 'handlers' : ['hand1'],
2523 },
2524 },
2525 'root' : {
2526 'level' : 'WARNING',
2527 },
2528 }
2529
2530 #As config11 but using an unsupported version
2531 config13 = {
2532 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002533 'true_formatters': {
2534 'form1' : {
2535 'format' : '%(levelname)s ++ %(message)s',
2536 },
2537 },
2538 'handler_configs': {
2539 'hand1' : {
2540 'class' : 'logging.StreamHandler',
2541 'formatter' : 'form1',
2542 'level' : 'NOTSET',
2543 'stream' : 'ext://sys.stdout',
2544 },
2545 },
2546 'formatters' : 'cfg://true_formatters',
2547 'handlers' : {
2548 'hand1' : 'cfg://handler_configs[hand1]',
2549 },
2550 'loggers' : {
2551 'compiler.parser' : {
2552 'level' : 'DEBUG',
2553 'handlers' : ['hand1'],
2554 },
2555 },
2556 'root' : {
2557 'level' : 'WARNING',
2558 },
2559 }
2560
Vinay Sajip8d270232012-11-15 14:20:18 +00002561 # As config0, but with properties
2562 config14 = {
2563 'version': 1,
2564 'formatters': {
2565 'form1' : {
2566 'format' : '%(levelname)s ++ %(message)s',
2567 },
2568 },
2569 'handlers' : {
2570 'hand1' : {
2571 'class' : 'logging.StreamHandler',
2572 'formatter' : 'form1',
2573 'level' : 'NOTSET',
2574 'stream' : 'ext://sys.stdout',
2575 '.': {
2576 'foo': 'bar',
2577 'terminator': '!\n',
2578 }
2579 },
2580 },
2581 'root' : {
2582 'level' : 'WARNING',
2583 'handlers' : ['hand1'],
2584 },
2585 }
2586
Vinay Sajip3f885b52013-03-22 15:19:54 +00002587 out_of_order = {
2588 "version": 1,
2589 "formatters": {
2590 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002591 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2592 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002593 }
2594 },
2595 "handlers": {
2596 "fileGlobal": {
2597 "class": "logging.StreamHandler",
2598 "level": "DEBUG",
2599 "formatter": "mySimpleFormatter"
2600 },
2601 "bufferGlobal": {
2602 "class": "logging.handlers.MemoryHandler",
2603 "capacity": 5,
2604 "formatter": "mySimpleFormatter",
2605 "target": "fileGlobal",
2606 "level": "DEBUG"
2607 }
2608 },
2609 "loggers": {
2610 "mymodule": {
2611 "level": "DEBUG",
2612 "handlers": ["bufferGlobal"],
2613 "propagate": "true"
2614 }
2615 }
2616 }
2617
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002618 def apply_config(self, conf):
2619 logging.config.dictConfig(conf)
2620
2621 def test_config0_ok(self):
2622 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002623 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002624 self.apply_config(self.config0)
2625 logger = logging.getLogger()
2626 # Won't output anything
2627 logger.info(self.next_message())
2628 # Outputs a message
2629 logger.error(self.next_message())
2630 self.assert_log_lines([
2631 ('ERROR', '2'),
2632 ], stream=output)
2633 # Original logger output is empty.
2634 self.assert_log_lines([])
2635
2636 def test_config1_ok(self, config=config1):
2637 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002638 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002639 self.apply_config(config)
2640 logger = logging.getLogger("compiler.parser")
2641 # Both will output a message
2642 logger.info(self.next_message())
2643 logger.error(self.next_message())
2644 self.assert_log_lines([
2645 ('INFO', '1'),
2646 ('ERROR', '2'),
2647 ], stream=output)
2648 # Original logger output is empty.
2649 self.assert_log_lines([])
2650
2651 def test_config2_failure(self):
2652 # A simple config which overrides the default settings.
2653 self.assertRaises(Exception, self.apply_config, self.config2)
2654
2655 def test_config2a_failure(self):
2656 # A simple config which overrides the default settings.
2657 self.assertRaises(Exception, self.apply_config, self.config2a)
2658
2659 def test_config2b_failure(self):
2660 # A simple config which overrides the default settings.
2661 self.assertRaises(Exception, self.apply_config, self.config2b)
2662
2663 def test_config3_failure(self):
2664 # A simple config which overrides the default settings.
2665 self.assertRaises(Exception, self.apply_config, self.config3)
2666
2667 def test_config4_ok(self):
2668 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002669 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002670 self.apply_config(self.config4)
2671 #logger = logging.getLogger()
2672 try:
2673 raise RuntimeError()
2674 except RuntimeError:
2675 logging.exception("just testing")
2676 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002677 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2679 # Original logger output is empty
2680 self.assert_log_lines([])
2681
2682 def test_config4a_ok(self):
2683 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002684 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002685 self.apply_config(self.config4a)
2686 #logger = logging.getLogger()
2687 try:
2688 raise RuntimeError()
2689 except RuntimeError:
2690 logging.exception("just testing")
2691 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002692 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002693 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2694 # Original logger output is empty
2695 self.assert_log_lines([])
2696
2697 def test_config5_ok(self):
2698 self.test_config1_ok(config=self.config5)
2699
2700 def test_config6_failure(self):
2701 self.assertRaises(Exception, self.apply_config, self.config6)
2702
2703 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002704 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002705 self.apply_config(self.config1)
2706 logger = logging.getLogger("compiler.parser")
2707 # Both will output a message
2708 logger.info(self.next_message())
2709 logger.error(self.next_message())
2710 self.assert_log_lines([
2711 ('INFO', '1'),
2712 ('ERROR', '2'),
2713 ], stream=output)
2714 # Original logger output is empty.
2715 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002716 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002717 self.apply_config(self.config7)
2718 logger = logging.getLogger("compiler.parser")
2719 self.assertTrue(logger.disabled)
2720 logger = logging.getLogger("compiler.lexer")
2721 # Both will output a message
2722 logger.info(self.next_message())
2723 logger.error(self.next_message())
2724 self.assert_log_lines([
2725 ('INFO', '3'),
2726 ('ERROR', '4'),
2727 ], stream=output)
2728 # Original logger output is empty.
2729 self.assert_log_lines([])
2730
2731 #Same as test_config_7_ok but don't disable old loggers.
2732 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002733 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002734 self.apply_config(self.config1)
2735 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002736 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002737 logger.info(self.next_message())
2738 logger.error(self.next_message())
2739 self.assert_log_lines([
2740 ('INFO', '1'),
2741 ('ERROR', '2'),
2742 ], stream=output)
2743 # Original logger output is empty.
2744 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002745 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002746 self.apply_config(self.config8)
2747 logger = logging.getLogger("compiler.parser")
2748 self.assertFalse(logger.disabled)
2749 # Both will output a message
2750 logger.info(self.next_message())
2751 logger.error(self.next_message())
2752 logger = logging.getLogger("compiler.lexer")
2753 # Both will output a message
2754 logger.info(self.next_message())
2755 logger.error(self.next_message())
2756 self.assert_log_lines([
2757 ('INFO', '3'),
2758 ('ERROR', '4'),
2759 ('INFO', '5'),
2760 ('ERROR', '6'),
2761 ], stream=output)
2762 # Original logger output is empty.
2763 self.assert_log_lines([])
2764
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002765 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002766 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002767 self.apply_config(self.config1a)
2768 logger = logging.getLogger("compiler.parser")
2769 # See issue #11424. compiler-hyphenated sorts
2770 # between compiler and compiler.xyz and this
2771 # was preventing compiler.xyz from being included
2772 # in the child loggers of compiler because of an
2773 # overzealous loop termination condition.
2774 hyphenated = logging.getLogger('compiler-hyphenated')
2775 # All will output a message
2776 logger.info(self.next_message())
2777 logger.error(self.next_message())
2778 hyphenated.critical(self.next_message())
2779 self.assert_log_lines([
2780 ('INFO', '1'),
2781 ('ERROR', '2'),
2782 ('CRITICAL', '3'),
2783 ], stream=output)
2784 # Original logger output is empty.
2785 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002786 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002787 self.apply_config(self.config8a)
2788 logger = logging.getLogger("compiler.parser")
2789 self.assertFalse(logger.disabled)
2790 # Both will output a message
2791 logger.info(self.next_message())
2792 logger.error(self.next_message())
2793 logger = logging.getLogger("compiler.lexer")
2794 # Both will output a message
2795 logger.info(self.next_message())
2796 logger.error(self.next_message())
2797 # Will not appear
2798 hyphenated.critical(self.next_message())
2799 self.assert_log_lines([
2800 ('INFO', '4'),
2801 ('ERROR', '5'),
2802 ('INFO', '6'),
2803 ('ERROR', '7'),
2804 ], stream=output)
2805 # Original logger output is empty.
2806 self.assert_log_lines([])
2807
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002808 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002809 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002810 self.apply_config(self.config9)
2811 logger = logging.getLogger("compiler.parser")
2812 #Nothing will be output since both handler and logger are set to WARNING
2813 logger.info(self.next_message())
2814 self.assert_log_lines([], stream=output)
2815 self.apply_config(self.config9a)
2816 #Nothing will be output since both handler is still set to WARNING
2817 logger.info(self.next_message())
2818 self.assert_log_lines([], stream=output)
2819 self.apply_config(self.config9b)
2820 #Message should now be output
2821 logger.info(self.next_message())
2822 self.assert_log_lines([
2823 ('INFO', '3'),
2824 ], stream=output)
2825
2826 def test_config_10_ok(self):
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.config10)
2829 logger = logging.getLogger("compiler.parser")
2830 logger.warning(self.next_message())
2831 logger = logging.getLogger('compiler')
2832 #Not output, because filtered
2833 logger.warning(self.next_message())
2834 logger = logging.getLogger('compiler.lexer')
2835 #Not output, because filtered
2836 logger.warning(self.next_message())
2837 logger = logging.getLogger("compiler.parser.codegen")
2838 #Output, as not filtered
2839 logger.error(self.next_message())
2840 self.assert_log_lines([
2841 ('WARNING', '1'),
2842 ('ERROR', '4'),
2843 ], stream=output)
2844
2845 def test_config11_ok(self):
2846 self.test_config1_ok(self.config11)
2847
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002848 def test_config12_failure(self):
2849 self.assertRaises(Exception, self.apply_config, self.config12)
2850
2851 def test_config13_failure(self):
2852 self.assertRaises(Exception, self.apply_config, self.config13)
2853
Vinay Sajip8d270232012-11-15 14:20:18 +00002854 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002855 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002856 self.apply_config(self.config14)
2857 h = logging._handlers['hand1']
2858 self.assertEqual(h.foo, 'bar')
2859 self.assertEqual(h.terminator, '!\n')
2860 logging.warning('Exclamation')
2861 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2862
Vinay Sajip4ded5512012-10-02 15:56:16 +01002863 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002864 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002865 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002866 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002867 t.start()
2868 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002869 # Now get the port allocated
2870 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002871 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002872 try:
2873 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2874 sock.settimeout(2.0)
2875 sock.connect(('localhost', port))
2876
2877 slen = struct.pack('>L', len(text))
2878 s = slen + text
2879 sentsofar = 0
2880 left = len(s)
2881 while left > 0:
2882 sent = sock.send(s[sentsofar:])
2883 sentsofar += sent
2884 left -= sent
2885 sock.close()
2886 finally:
2887 t.ready.wait(2.0)
2888 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07002889 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890
2891 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002892 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002893 self.setup_via_listener(json.dumps(self.config10))
2894 logger = logging.getLogger("compiler.parser")
2895 logger.warning(self.next_message())
2896 logger = logging.getLogger('compiler')
2897 #Not output, because filtered
2898 logger.warning(self.next_message())
2899 logger = logging.getLogger('compiler.lexer')
2900 #Not output, because filtered
2901 logger.warning(self.next_message())
2902 logger = logging.getLogger("compiler.parser.codegen")
2903 #Output, as not filtered
2904 logger.error(self.next_message())
2905 self.assert_log_lines([
2906 ('WARNING', '1'),
2907 ('ERROR', '4'),
2908 ], stream=output)
2909
2910 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002911 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002912 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2913 logger = logging.getLogger("compiler.parser")
2914 # Both will output a message
2915 logger.info(self.next_message())
2916 logger.error(self.next_message())
2917 self.assert_log_lines([
2918 ('INFO', '1'),
2919 ('ERROR', '2'),
2920 ], stream=output)
2921 # Original logger output is empty.
2922 self.assert_log_lines([])
2923
Vinay Sajip4ded5512012-10-02 15:56:16 +01002924 def test_listen_verify(self):
2925
2926 def verify_fail(stuff):
2927 return None
2928
2929 def verify_reverse(stuff):
2930 return stuff[::-1]
2931
2932 logger = logging.getLogger("compiler.parser")
2933 to_send = textwrap.dedent(ConfigFileTest.config1)
2934 # First, specify a verification function that will fail.
2935 # We expect to see no output, since our configuration
2936 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002937 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002938 self.setup_via_listener(to_send, verify_fail)
2939 # Both will output a message
2940 logger.info(self.next_message())
2941 logger.error(self.next_message())
2942 self.assert_log_lines([], stream=output)
2943 # Original logger output has the stuff we logged.
2944 self.assert_log_lines([
2945 ('INFO', '1'),
2946 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002947 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002948
2949 # Now, perform no verification. Our configuration
2950 # should take effect.
2951
Vinay Sajip1feedb42014-05-31 08:19:12 +01002952 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002953 self.setup_via_listener(to_send) # no verify callable specified
2954 logger = logging.getLogger("compiler.parser")
2955 # Both will output a message
2956 logger.info(self.next_message())
2957 logger.error(self.next_message())
2958 self.assert_log_lines([
2959 ('INFO', '3'),
2960 ('ERROR', '4'),
2961 ], stream=output)
2962 # Original logger output still has the stuff we logged before.
2963 self.assert_log_lines([
2964 ('INFO', '1'),
2965 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002966 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002967
2968 # Now, perform verification which transforms the bytes.
2969
Vinay Sajip1feedb42014-05-31 08:19:12 +01002970 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002971 self.setup_via_listener(to_send[::-1], verify_reverse)
2972 logger = logging.getLogger("compiler.parser")
2973 # Both will output a message
2974 logger.info(self.next_message())
2975 logger.error(self.next_message())
2976 self.assert_log_lines([
2977 ('INFO', '5'),
2978 ('ERROR', '6'),
2979 ], stream=output)
2980 # Original logger output still has the stuff we logged before.
2981 self.assert_log_lines([
2982 ('INFO', '1'),
2983 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002984 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002985
Vinay Sajip3f885b52013-03-22 15:19:54 +00002986 def test_out_of_order(self):
2987 self.apply_config(self.out_of_order)
2988 handler = logging.getLogger('mymodule').handlers[0]
2989 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002990 self.assertIsInstance(handler.formatter._style,
2991 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002992
Vinay Sajip373baef2011-04-26 20:05:24 +01002993 def test_baseconfig(self):
2994 d = {
2995 'atuple': (1, 2, 3),
2996 'alist': ['a', 'b', 'c'],
2997 'adict': {'d': 'e', 'f': 3 },
2998 'nest1': ('g', ('h', 'i'), 'j'),
2999 'nest2': ['k', ['l', 'm'], 'n'],
3000 'nest3': ['o', 'cfg://alist', 'p'],
3001 }
3002 bc = logging.config.BaseConfigurator(d)
3003 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3004 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3005 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3006 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3007 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3008 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3009 v = bc.convert('cfg://nest3')
3010 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3011 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3012 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3013 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003014
3015class ManagerTest(BaseTest):
3016 def test_manager_loggerclass(self):
3017 logged = []
3018
3019 class MyLogger(logging.Logger):
3020 def _log(self, level, msg, args, exc_info=None, extra=None):
3021 logged.append(msg)
3022
3023 man = logging.Manager(None)
3024 self.assertRaises(TypeError, man.setLoggerClass, int)
3025 man.setLoggerClass(MyLogger)
3026 logger = man.getLogger('test')
3027 logger.warning('should appear in logged')
3028 logging.warning('should not appear in logged')
3029
3030 self.assertEqual(logged, ['should appear in logged'])
3031
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003032 def test_set_log_record_factory(self):
3033 man = logging.Manager(None)
3034 expected = object()
3035 man.setLogRecordFactory(expected)
3036 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003037
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003038class ChildLoggerTest(BaseTest):
3039 def test_child_loggers(self):
3040 r = logging.getLogger()
3041 l1 = logging.getLogger('abc')
3042 l2 = logging.getLogger('def.ghi')
3043 c1 = r.getChild('xyz')
3044 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003045 self.assertIs(c1, logging.getLogger('xyz'))
3046 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003047 c1 = l1.getChild('def')
3048 c2 = c1.getChild('ghi')
3049 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003050 self.assertIs(c1, logging.getLogger('abc.def'))
3051 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3052 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003053
3054
Vinay Sajip6fac8172010-10-19 20:44:14 +00003055class DerivedLogRecord(logging.LogRecord):
3056 pass
3057
Vinay Sajip61561522010-12-03 11:50:38 +00003058class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003059
3060 def setUp(self):
3061 class CheckingFilter(logging.Filter):
3062 def __init__(self, cls):
3063 self.cls = cls
3064
3065 def filter(self, record):
3066 t = type(record)
3067 if t is not self.cls:
3068 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3069 self.cls)
3070 raise TypeError(msg)
3071 return True
3072
3073 BaseTest.setUp(self)
3074 self.filter = CheckingFilter(DerivedLogRecord)
3075 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003076 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003077
3078 def tearDown(self):
3079 self.root_logger.removeFilter(self.filter)
3080 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003081 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003082
3083 def test_logrecord_class(self):
3084 self.assertRaises(TypeError, self.root_logger.warning,
3085 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003086 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003087 self.root_logger.error(self.next_message())
3088 self.assert_log_lines([
3089 ('root', 'ERROR', '2'),
3090 ])
3091
3092
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003093class QueueHandlerTest(BaseTest):
3094 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003095 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003096
3097 def setUp(self):
3098 BaseTest.setUp(self)
3099 self.queue = queue.Queue(-1)
3100 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003101 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003102 self.que_logger = logging.getLogger('que')
3103 self.que_logger.propagate = False
3104 self.que_logger.setLevel(logging.WARNING)
3105 self.que_logger.addHandler(self.que_hdlr)
3106
3107 def tearDown(self):
3108 self.que_hdlr.close()
3109 BaseTest.tearDown(self)
3110
3111 def test_queue_handler(self):
3112 self.que_logger.debug(self.next_message())
3113 self.assertRaises(queue.Empty, self.queue.get_nowait)
3114 self.que_logger.info(self.next_message())
3115 self.assertRaises(queue.Empty, self.queue.get_nowait)
3116 msg = self.next_message()
3117 self.que_logger.warning(msg)
3118 data = self.queue.get_nowait()
3119 self.assertTrue(isinstance(data, logging.LogRecord))
3120 self.assertEqual(data.name, self.que_logger.name)
3121 self.assertEqual((data.msg, data.args), (msg, None))
3122
favlladfe3442017-08-01 20:12:26 +02003123 def test_formatting(self):
3124 msg = self.next_message()
3125 levelname = logging.getLevelName(logging.WARNING)
3126 log_format_str = '{name} -> {levelname}: {message}'
3127 formatted_msg = log_format_str.format(name=self.name,
3128 levelname=levelname, message=msg)
3129 formatter = logging.Formatter(self.log_format)
3130 self.que_hdlr.setFormatter(formatter)
3131 self.que_logger.warning(msg)
3132 log_record = self.queue.get_nowait()
3133 self.assertEqual(formatted_msg, log_record.msg)
3134 self.assertEqual(formatted_msg, log_record.message)
3135
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003136 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3137 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003138 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003139 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003140 listener = logging.handlers.QueueListener(self.queue, handler)
3141 listener.start()
3142 try:
3143 self.que_logger.warning(self.next_message())
3144 self.que_logger.error(self.next_message())
3145 self.que_logger.critical(self.next_message())
3146 finally:
3147 listener.stop()
3148 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3149 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3150 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003151 handler.close()
3152
3153 # Now test with respect_handler_level set
3154
3155 handler = support.TestHandler(support.Matcher())
3156 handler.setLevel(logging.CRITICAL)
3157 listener = logging.handlers.QueueListener(self.queue, handler,
3158 respect_handler_level=True)
3159 listener.start()
3160 try:
3161 self.que_logger.warning(self.next_message())
3162 self.que_logger.error(self.next_message())
3163 self.que_logger.critical(self.next_message())
3164 finally:
3165 listener.stop()
3166 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3167 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3168 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3169
Vinay Sajipd61910c2016-09-08 01:13:39 +01003170if hasattr(logging.handlers, 'QueueListener'):
3171 import multiprocessing
3172 from unittest.mock import patch
3173
3174 class QueueListenerTest(BaseTest):
3175 """
3176 Tests based on patch submitted for issue #27930. Ensure that
3177 QueueListener handles all log messages.
3178 """
3179
3180 repeat = 20
3181
3182 @staticmethod
3183 def setup_and_log(log_queue, ident):
3184 """
3185 Creates a logger with a QueueHandler that logs to a queue read by a
3186 QueueListener. Starts the listener, logs five messages, and stops
3187 the listener.
3188 """
3189 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3190 logger.setLevel(logging.DEBUG)
3191 handler = logging.handlers.QueueHandler(log_queue)
3192 logger.addHandler(handler)
3193 listener = logging.handlers.QueueListener(log_queue)
3194 listener.start()
3195
3196 logger.info('one')
3197 logger.info('two')
3198 logger.info('three')
3199 logger.info('four')
3200 logger.info('five')
3201
3202 listener.stop()
3203 logger.removeHandler(handler)
3204 handler.close()
3205
3206 @patch.object(logging.handlers.QueueListener, 'handle')
3207 def test_handle_called_with_queue_queue(self, mock_handle):
3208 for i in range(self.repeat):
3209 log_queue = queue.Queue()
3210 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3211 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3212 'correct number of handled log messages')
3213
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003214 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003215 @patch.object(logging.handlers.QueueListener, 'handle')
3216 def test_handle_called_with_mp_queue(self, mock_handle):
3217 for i in range(self.repeat):
3218 log_queue = multiprocessing.Queue()
3219 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003220 log_queue.close()
3221 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003222 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3223 'correct number of handled log messages')
3224
3225 @staticmethod
3226 def get_all_from_queue(log_queue):
3227 try:
3228 while True:
3229 yield log_queue.get_nowait()
3230 except queue.Empty:
3231 return []
3232
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003233 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003234 def test_no_messages_in_queue_after_stop(self):
3235 """
3236 Five messages are logged then the QueueListener is stopped. This
3237 test then gets everything off the queue. Failure of this test
3238 indicates that messages were not registered on the queue until
3239 _after_ the QueueListener stopped.
3240 """
3241 for i in range(self.repeat):
3242 queue = multiprocessing.Queue()
3243 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3244 # time.sleep(1)
3245 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003246 queue.close()
3247 queue.join_thread()
3248
Vinay Sajipd61910c2016-09-08 01:13:39 +01003249 expected = [[], [logging.handlers.QueueListener._sentinel]]
3250 self.assertIn(items, expected,
3251 'Found unexpected messages in queue: %s' % (
3252 [m.msg if isinstance(m, logging.LogRecord)
3253 else m for m in items]))
3254
Vinay Sajipe723e962011-04-15 22:27:17 +01003255
Vinay Sajip37eb3382011-04-26 20:26:41 +01003256ZERO = datetime.timedelta(0)
3257
3258class UTC(datetime.tzinfo):
3259 def utcoffset(self, dt):
3260 return ZERO
3261
3262 dst = utcoffset
3263
3264 def tzname(self, dt):
3265 return 'UTC'
3266
3267utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003268
Vinay Sajipa39c5712010-10-25 13:57:39 +00003269class FormatterTest(unittest.TestCase):
3270 def setUp(self):
3271 self.common = {
3272 'name': 'formatter.test',
3273 'level': logging.DEBUG,
3274 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3275 'lineno': 42,
3276 'exc_info': None,
3277 'func': None,
3278 'msg': 'Message with %d %s',
3279 'args': (2, 'placeholders'),
3280 }
3281 self.variants = {
3282 }
3283
3284 def get_record(self, name=None):
3285 result = dict(self.common)
3286 if name is not None:
3287 result.update(self.variants[name])
3288 return logging.makeLogRecord(result)
3289
3290 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003291 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003292 r = self.get_record()
3293 f = logging.Formatter('${%(message)s}')
3294 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3295 f = logging.Formatter('%(random)s')
3296 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003297 self.assertFalse(f.usesTime())
3298 f = logging.Formatter('%(asctime)s')
3299 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003300 f = logging.Formatter('%(asctime)-15s')
3301 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003302 f = logging.Formatter('asctime')
3303 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003304
3305 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003306 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003307 r = self.get_record()
3308 f = logging.Formatter('$%{message}%$', style='{')
3309 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3310 f = logging.Formatter('{random}', style='{')
3311 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003312 self.assertFalse(f.usesTime())
3313 f = logging.Formatter('{asctime}', style='{')
3314 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003315 f = logging.Formatter('{asctime!s:15}', style='{')
3316 self.assertTrue(f.usesTime())
3317 f = logging.Formatter('{asctime:15}', style='{')
3318 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003319 f = logging.Formatter('asctime', style='{')
3320 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003321
3322 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003323 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003324 r = self.get_record()
3325 f = logging.Formatter('$message', style='$')
3326 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3327 f = logging.Formatter('$$%${message}%$$', style='$')
3328 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3329 f = logging.Formatter('${random}', style='$')
3330 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003331 self.assertFalse(f.usesTime())
3332 f = logging.Formatter('${asctime}', style='$')
3333 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003334 f = logging.Formatter('${asctime', style='$')
3335 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003336 f = logging.Formatter('$asctime', style='$')
3337 self.assertTrue(f.usesTime())
3338 f = logging.Formatter('asctime', style='$')
3339 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003340
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003341 def test_invalid_style(self):
3342 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3343
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003344 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003345 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003346 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3347 # We use None to indicate we want the local timezone
3348 # We're essentially converting a UTC time to local time
3349 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003350 r.msecs = 123
3351 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003352 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003353 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3354 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003355 f.format(r)
3356 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3357
3358class TestBufferingFormatter(logging.BufferingFormatter):
3359 def formatHeader(self, records):
3360 return '[(%d)' % len(records)
3361
3362 def formatFooter(self, records):
3363 return '(%d)]' % len(records)
3364
3365class BufferingFormatterTest(unittest.TestCase):
3366 def setUp(self):
3367 self.records = [
3368 logging.makeLogRecord({'msg': 'one'}),
3369 logging.makeLogRecord({'msg': 'two'}),
3370 ]
3371
3372 def test_default(self):
3373 f = logging.BufferingFormatter()
3374 self.assertEqual('', f.format([]))
3375 self.assertEqual('onetwo', f.format(self.records))
3376
3377 def test_custom(self):
3378 f = TestBufferingFormatter()
3379 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3380 lf = logging.Formatter('<%(message)s>')
3381 f = TestBufferingFormatter(lf)
3382 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003383
3384class ExceptionTest(BaseTest):
3385 def test_formatting(self):
3386 r = self.root_logger
3387 h = RecordingHandler()
3388 r.addHandler(h)
3389 try:
3390 raise RuntimeError('deliberate mistake')
3391 except:
3392 logging.exception('failed', stack_info=True)
3393 r.removeHandler(h)
3394 h.close()
3395 r = h.records[0]
3396 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3397 'call last):\n'))
3398 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3399 'deliberate mistake'))
3400 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3401 'call last):\n'))
3402 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3403 'stack_info=True)'))
3404
3405
Vinay Sajip5a27d402010-12-10 11:42:57 +00003406class LastResortTest(BaseTest):
3407 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003408 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003409 root = self.root_logger
3410 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003411 old_lastresort = logging.lastResort
3412 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003413
Vinay Sajip5a27d402010-12-10 11:42:57 +00003414 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003415 with support.captured_stderr() as stderr:
3416 root.debug('This should not appear')
3417 self.assertEqual(stderr.getvalue(), '')
3418 root.warning('Final chance!')
3419 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3420
3421 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003422 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003423 with support.captured_stderr() as stderr:
3424 root.warning('Final chance!')
3425 msg = 'No handlers could be found for logger "root"\n'
3426 self.assertEqual(stderr.getvalue(), msg)
3427
Vinay Sajip5a27d402010-12-10 11:42:57 +00003428 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003429 with support.captured_stderr() as stderr:
3430 root.warning('Final chance!')
3431 self.assertEqual(stderr.getvalue(), '')
3432
3433 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003434 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003435 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003436 with support.captured_stderr() as stderr:
3437 root.warning('Final chance!')
3438 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003439 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003440 root.addHandler(self.root_hdlr)
3441 logging.lastResort = old_lastresort
3442 logging.raiseExceptions = old_raise_exceptions
3443
3444
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003445class FakeHandler:
3446
3447 def __init__(self, identifier, called):
3448 for method in ('acquire', 'flush', 'close', 'release'):
3449 setattr(self, method, self.record_call(identifier, method, called))
3450
3451 def record_call(self, identifier, method_name, called):
3452 def inner():
3453 called.append('{} - {}'.format(identifier, method_name))
3454 return inner
3455
3456
3457class RecordingHandler(logging.NullHandler):
3458
3459 def __init__(self, *args, **kwargs):
3460 super(RecordingHandler, self).__init__(*args, **kwargs)
3461 self.records = []
3462
3463 def handle(self, record):
3464 """Keep track of all the emitted records."""
3465 self.records.append(record)
3466
3467
3468class ShutdownTest(BaseTest):
3469
Vinay Sajip5e66b162011-04-20 15:41:14 +01003470 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003471
3472 def setUp(self):
3473 super(ShutdownTest, self).setUp()
3474 self.called = []
3475
3476 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003477 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003478
3479 def raise_error(self, error):
3480 def inner():
3481 raise error()
3482 return inner
3483
3484 def test_no_failure(self):
3485 # create some fake handlers
3486 handler0 = FakeHandler(0, self.called)
3487 handler1 = FakeHandler(1, self.called)
3488 handler2 = FakeHandler(2, self.called)
3489
3490 # create live weakref to those handlers
3491 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3492
3493 logging.shutdown(handlerList=list(handlers))
3494
3495 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3496 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3497 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3498 self.assertEqual(expected, self.called)
3499
3500 def _test_with_failure_in_method(self, method, error):
3501 handler = FakeHandler(0, self.called)
3502 setattr(handler, method, self.raise_error(error))
3503 handlers = [logging.weakref.ref(handler)]
3504
3505 logging.shutdown(handlerList=list(handlers))
3506
3507 self.assertEqual('0 - release', self.called[-1])
3508
3509 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003510 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003511
3512 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003513 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003514
3515 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003516 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003517
3518 def test_with_valueerror_in_acquire(self):
3519 self._test_with_failure_in_method('acquire', ValueError)
3520
3521 def test_with_valueerror_in_flush(self):
3522 self._test_with_failure_in_method('flush', ValueError)
3523
3524 def test_with_valueerror_in_close(self):
3525 self._test_with_failure_in_method('close', ValueError)
3526
3527 def test_with_other_error_in_acquire_without_raise(self):
3528 logging.raiseExceptions = False
3529 self._test_with_failure_in_method('acquire', IndexError)
3530
3531 def test_with_other_error_in_flush_without_raise(self):
3532 logging.raiseExceptions = False
3533 self._test_with_failure_in_method('flush', IndexError)
3534
3535 def test_with_other_error_in_close_without_raise(self):
3536 logging.raiseExceptions = False
3537 self._test_with_failure_in_method('close', IndexError)
3538
3539 def test_with_other_error_in_acquire_with_raise(self):
3540 logging.raiseExceptions = True
3541 self.assertRaises(IndexError, self._test_with_failure_in_method,
3542 'acquire', IndexError)
3543
3544 def test_with_other_error_in_flush_with_raise(self):
3545 logging.raiseExceptions = True
3546 self.assertRaises(IndexError, self._test_with_failure_in_method,
3547 'flush', IndexError)
3548
3549 def test_with_other_error_in_close_with_raise(self):
3550 logging.raiseExceptions = True
3551 self.assertRaises(IndexError, self._test_with_failure_in_method,
3552 'close', IndexError)
3553
3554
3555class ModuleLevelMiscTest(BaseTest):
3556
Vinay Sajip5e66b162011-04-20 15:41:14 +01003557 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003558
3559 def test_disable(self):
3560 old_disable = logging.root.manager.disable
3561 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003562 self.assertEqual(old_disable, 0)
3563 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003564
3565 logging.disable(83)
3566 self.assertEqual(logging.root.manager.disable, 83)
3567
Vinay Sajipd489ac92016-12-31 11:40:11 +00003568 # test the default value introduced in 3.7
3569 # (Issue #28524)
3570 logging.disable()
3571 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3572
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003573 def _test_log(self, method, level=None):
3574 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003575 support.patch(self, logging, 'basicConfig',
3576 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003577
3578 recording = RecordingHandler()
3579 logging.root.addHandler(recording)
3580
3581 log_method = getattr(logging, method)
3582 if level is not None:
3583 log_method(level, "test me: %r", recording)
3584 else:
3585 log_method("test me: %r", recording)
3586
3587 self.assertEqual(len(recording.records), 1)
3588 record = recording.records[0]
3589 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3590
3591 expected_level = level if level is not None else getattr(logging, method.upper())
3592 self.assertEqual(record.levelno, expected_level)
3593
3594 # basicConfig was not called!
3595 self.assertEqual(called, [])
3596
3597 def test_log(self):
3598 self._test_log('log', logging.ERROR)
3599
3600 def test_debug(self):
3601 self._test_log('debug')
3602
3603 def test_info(self):
3604 self._test_log('info')
3605
3606 def test_warning(self):
3607 self._test_log('warning')
3608
3609 def test_error(self):
3610 self._test_log('error')
3611
3612 def test_critical(self):
3613 self._test_log('critical')
3614
3615 def test_set_logger_class(self):
3616 self.assertRaises(TypeError, logging.setLoggerClass, object)
3617
3618 class MyLogger(logging.Logger):
3619 pass
3620
3621 logging.setLoggerClass(MyLogger)
3622 self.assertEqual(logging.getLoggerClass(), MyLogger)
3623
3624 logging.setLoggerClass(logging.Logger)
3625 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3626
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003627 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003628 def test_logging_at_shutdown(self):
3629 # Issue #20037
3630 code = """if 1:
3631 import logging
3632
3633 class A:
3634 def __del__(self):
3635 try:
3636 raise ValueError("some error")
3637 except Exception:
3638 logging.exception("exception in __del__")
3639
3640 a = A()"""
3641 rc, out, err = assert_python_ok("-c", code)
3642 err = err.decode()
3643 self.assertIn("exception in __del__", err)
3644 self.assertIn("ValueError: some error", err)
3645
3646
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003647class LogRecordTest(BaseTest):
3648 def test_str_rep(self):
3649 r = logging.makeLogRecord({})
3650 s = str(r)
3651 self.assertTrue(s.startswith('<LogRecord: '))
3652 self.assertTrue(s.endswith('>'))
3653
3654 def test_dict_arg(self):
3655 h = RecordingHandler()
3656 r = logging.getLogger()
3657 r.addHandler(h)
3658 d = {'less' : 'more' }
3659 logging.warning('less is %(less)s', d)
3660 self.assertIs(h.records[0].args, d)
3661 self.assertEqual(h.records[0].message, 'less is more')
3662 r.removeHandler(h)
3663 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003664
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003665 def test_multiprocessing(self):
3666 r = logging.makeLogRecord({})
3667 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003668 try:
3669 import multiprocessing as mp
3670 r = logging.makeLogRecord({})
3671 self.assertEqual(r.processName, mp.current_process().name)
3672 except ImportError:
3673 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003674
3675 def test_optional(self):
3676 r = logging.makeLogRecord({})
3677 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003678 NOT_NONE(r.thread)
3679 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003680 NOT_NONE(r.process)
3681 NOT_NONE(r.processName)
3682 log_threads = logging.logThreads
3683 log_processes = logging.logProcesses
3684 log_multiprocessing = logging.logMultiprocessing
3685 try:
3686 logging.logThreads = False
3687 logging.logProcesses = False
3688 logging.logMultiprocessing = False
3689 r = logging.makeLogRecord({})
3690 NONE = self.assertIsNone
3691 NONE(r.thread)
3692 NONE(r.threadName)
3693 NONE(r.process)
3694 NONE(r.processName)
3695 finally:
3696 logging.logThreads = log_threads
3697 logging.logProcesses = log_processes
3698 logging.logMultiprocessing = log_multiprocessing
3699
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003700class BasicConfigTest(unittest.TestCase):
3701
Vinay Sajip95bf5042011-04-20 11:50:56 +01003702 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003703
3704 def setUp(self):
3705 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003706 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003707 self.saved_handlers = logging._handlers.copy()
3708 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003709 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003710 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003711 logging.root.handlers = []
3712
3713 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003714 for h in logging.root.handlers[:]:
3715 logging.root.removeHandler(h)
3716 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003717 super(BasicConfigTest, self).tearDown()
3718
Vinay Sajip3def7e02011-04-20 10:58:06 +01003719 def cleanup(self):
3720 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003721 logging._handlers.clear()
3722 logging._handlers.update(self.saved_handlers)
3723 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003724 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003725
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003726 def test_no_kwargs(self):
3727 logging.basicConfig()
3728
3729 # handler defaults to a StreamHandler to sys.stderr
3730 self.assertEqual(len(logging.root.handlers), 1)
3731 handler = logging.root.handlers[0]
3732 self.assertIsInstance(handler, logging.StreamHandler)
3733 self.assertEqual(handler.stream, sys.stderr)
3734
3735 formatter = handler.formatter
3736 # format defaults to logging.BASIC_FORMAT
3737 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3738 # datefmt defaults to None
3739 self.assertIsNone(formatter.datefmt)
3740 # style defaults to %
3741 self.assertIsInstance(formatter._style, logging.PercentStyle)
3742
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003743 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003744 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003745
Vinay Sajip1fd12022014-01-13 21:59:56 +00003746 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003747 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003748 logging.basicConfig(stream=sys.stdout, style="{")
3749 logging.error("Log an error")
3750 sys.stdout.seek(0)
3751 self.assertEqual(output.getvalue().strip(),
3752 "ERROR:root:Log an error")
3753
3754 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003755 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003756 logging.basicConfig(stream=sys.stdout, style="$")
3757 logging.error("Log an error")
3758 sys.stdout.seek(0)
3759 self.assertEqual(output.getvalue().strip(),
3760 "ERROR:root:Log an error")
3761
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003762 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003763
3764 def cleanup(h1, h2, fn):
3765 h1.close()
3766 h2.close()
3767 os.remove(fn)
3768
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003769 logging.basicConfig(filename='test.log')
3770
3771 self.assertEqual(len(logging.root.handlers), 1)
3772 handler = logging.root.handlers[0]
3773 self.assertIsInstance(handler, logging.FileHandler)
3774
3775 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003776 self.assertEqual(handler.stream.mode, expected.stream.mode)
3777 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003778 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003779
3780 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003781
3782 def cleanup(h1, h2, fn):
3783 h1.close()
3784 h2.close()
3785 os.remove(fn)
3786
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003787 logging.basicConfig(filename='test.log', filemode='wb')
3788
3789 handler = logging.root.handlers[0]
3790 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003791 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003792 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003793
3794 def test_stream(self):
3795 stream = io.StringIO()
3796 self.addCleanup(stream.close)
3797 logging.basicConfig(stream=stream)
3798
3799 self.assertEqual(len(logging.root.handlers), 1)
3800 handler = logging.root.handlers[0]
3801 self.assertIsInstance(handler, logging.StreamHandler)
3802 self.assertEqual(handler.stream, stream)
3803
3804 def test_format(self):
3805 logging.basicConfig(format='foo')
3806
3807 formatter = logging.root.handlers[0].formatter
3808 self.assertEqual(formatter._style._fmt, 'foo')
3809
3810 def test_datefmt(self):
3811 logging.basicConfig(datefmt='bar')
3812
3813 formatter = logging.root.handlers[0].formatter
3814 self.assertEqual(formatter.datefmt, 'bar')
3815
3816 def test_style(self):
3817 logging.basicConfig(style='$')
3818
3819 formatter = logging.root.handlers[0].formatter
3820 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3821
3822 def test_level(self):
3823 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003824 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825
3826 logging.basicConfig(level=57)
3827 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003828 # Test that second call has no effect
3829 logging.basicConfig(level=58)
3830 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003831
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003832 def test_incompatible(self):
3833 assertRaises = self.assertRaises
3834 handlers = [logging.StreamHandler()]
3835 stream = sys.stderr
3836 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3837 stream=stream)
3838 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3839 handlers=handlers)
3840 assertRaises(ValueError, logging.basicConfig, stream=stream,
3841 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003842 # Issue 23207: test for invalid kwargs
3843 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3844 # Should pop both filename and filemode even if filename is None
3845 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003846
3847 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003848 handlers = [
3849 logging.StreamHandler(),
3850 logging.StreamHandler(sys.stdout),
3851 logging.StreamHandler(),
3852 ]
3853 f = logging.Formatter()
3854 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003855 logging.basicConfig(handlers=handlers)
3856 self.assertIs(handlers[0], logging.root.handlers[0])
3857 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003858 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003859 self.assertIsNotNone(handlers[0].formatter)
3860 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003861 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003862 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3863
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003864 def _test_log(self, method, level=None):
3865 # logging.root has no handlers so basicConfig should be called
3866 called = []
3867
3868 old_basic_config = logging.basicConfig
3869 def my_basic_config(*a, **kw):
3870 old_basic_config()
3871 old_level = logging.root.level
3872 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003873 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003874 called.append((a, kw))
3875
Vinay Sajip1feedb42014-05-31 08:19:12 +01003876 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003877
3878 log_method = getattr(logging, method)
3879 if level is not None:
3880 log_method(level, "test me")
3881 else:
3882 log_method("test me")
3883
3884 # basicConfig was called with no arguments
3885 self.assertEqual(called, [((), {})])
3886
3887 def test_log(self):
3888 self._test_log('log', logging.WARNING)
3889
3890 def test_debug(self):
3891 self._test_log('debug')
3892
3893 def test_info(self):
3894 self._test_log('info')
3895
3896 def test_warning(self):
3897 self._test_log('warning')
3898
3899 def test_error(self):
3900 self._test_log('error')
3901
3902 def test_critical(self):
3903 self._test_log('critical')
3904
3905
3906class LoggerAdapterTest(unittest.TestCase):
3907
3908 def setUp(self):
3909 super(LoggerAdapterTest, self).setUp()
3910 old_handler_list = logging._handlerList[:]
3911
3912 self.recording = RecordingHandler()
3913 self.logger = logging.root
3914 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003915 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003916 self.addCleanup(self.recording.close)
3917
3918 def cleanup():
3919 logging._handlerList[:] = old_handler_list
3920
3921 self.addCleanup(cleanup)
3922 self.addCleanup(logging.shutdown)
3923 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3924
3925 def test_exception(self):
3926 msg = 'testing exception: %r'
3927 exc = None
3928 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003929 1 / 0
3930 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003931 exc = e
3932 self.adapter.exception(msg, self.recording)
3933
3934 self.assertEqual(len(self.recording.records), 1)
3935 record = self.recording.records[0]
3936 self.assertEqual(record.levelno, logging.ERROR)
3937 self.assertEqual(record.msg, msg)
3938 self.assertEqual(record.args, (self.recording,))
3939 self.assertEqual(record.exc_info,
3940 (exc.__class__, exc, exc.__traceback__))
3941
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003942 def test_exception_excinfo(self):
3943 try:
3944 1 / 0
3945 except ZeroDivisionError as e:
3946 exc = e
3947
3948 self.adapter.exception('exc_info test', exc_info=exc)
3949
3950 self.assertEqual(len(self.recording.records), 1)
3951 record = self.recording.records[0]
3952 self.assertEqual(record.exc_info,
3953 (exc.__class__, exc, exc.__traceback__))
3954
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003955 def test_critical(self):
3956 msg = 'critical test! %r'
3957 self.adapter.critical(msg, self.recording)
3958
3959 self.assertEqual(len(self.recording.records), 1)
3960 record = self.recording.records[0]
3961 self.assertEqual(record.levelno, logging.CRITICAL)
3962 self.assertEqual(record.msg, msg)
3963 self.assertEqual(record.args, (self.recording,))
3964
3965 def test_is_enabled_for(self):
3966 old_disable = self.adapter.logger.manager.disable
3967 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003968 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3969 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003970 self.assertFalse(self.adapter.isEnabledFor(32))
3971
3972 def test_has_handlers(self):
3973 self.assertTrue(self.adapter.hasHandlers())
3974
3975 for handler in self.logger.handlers:
3976 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003977
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003978 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003979 self.assertFalse(self.adapter.hasHandlers())
3980
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003981 def test_nested(self):
3982 msg = 'Adapters can be nested, yo.'
3983 adapter_adapter = logging.LoggerAdapter(logger=self.adapter, extra=None)
3984 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
3985
3986 self.assertEqual(len(self.recording.records), 1)
3987 record = self.recording.records[0]
3988 self.assertEqual(record.levelno, logging.CRITICAL)
3989 self.assertEqual(record.msg, msg)
3990 self.assertEqual(record.args, (self.recording,))
3991
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003992
3993class LoggerTest(BaseTest):
3994
3995 def setUp(self):
3996 super(LoggerTest, self).setUp()
3997 self.recording = RecordingHandler()
3998 self.logger = logging.Logger(name='blah')
3999 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004000 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004001 self.addCleanup(self.recording.close)
4002 self.addCleanup(logging.shutdown)
4003
4004 def test_set_invalid_level(self):
4005 self.assertRaises(TypeError, self.logger.setLevel, object())
4006
4007 def test_exception(self):
4008 msg = 'testing exception: %r'
4009 exc = None
4010 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004011 1 / 0
4012 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004013 exc = e
4014 self.logger.exception(msg, self.recording)
4015
4016 self.assertEqual(len(self.recording.records), 1)
4017 record = self.recording.records[0]
4018 self.assertEqual(record.levelno, logging.ERROR)
4019 self.assertEqual(record.msg, msg)
4020 self.assertEqual(record.args, (self.recording,))
4021 self.assertEqual(record.exc_info,
4022 (exc.__class__, exc, exc.__traceback__))
4023
4024 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004025 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004026 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004027
4028 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004029 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004030 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004031
4032 def test_find_caller_with_stack_info(self):
4033 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004034 support.patch(self, logging.traceback, 'print_stack',
4035 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004036
4037 self.logger.findCaller(stack_info=True)
4038
4039 self.assertEqual(len(called), 1)
4040 self.assertEqual('Stack (most recent call last):\n', called[0])
4041
4042 def test_make_record_with_extra_overwrite(self):
4043 name = 'my record'
4044 level = 13
4045 fn = lno = msg = args = exc_info = func = sinfo = None
4046 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4047 exc_info, func, sinfo)
4048
4049 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4050 extra = {key: 'some value'}
4051 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4052 fn, lno, msg, args, exc_info,
4053 extra=extra, sinfo=sinfo)
4054
4055 def test_make_record_with_extra_no_overwrite(self):
4056 name = 'my record'
4057 level = 13
4058 fn = lno = msg = args = exc_info = func = sinfo = None
4059 extra = {'valid_key': 'some value'}
4060 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4061 exc_info, extra=extra, sinfo=sinfo)
4062 self.assertIn('valid_key', result.__dict__)
4063
4064 def test_has_handlers(self):
4065 self.assertTrue(self.logger.hasHandlers())
4066
4067 for handler in self.logger.handlers:
4068 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004069 self.assertFalse(self.logger.hasHandlers())
4070
4071 def test_has_handlers_no_propagate(self):
4072 child_logger = logging.getLogger('blah.child')
4073 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004074 self.assertFalse(child_logger.hasHandlers())
4075
4076 def test_is_enabled_for(self):
4077 old_disable = self.logger.manager.disable
4078 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004079 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004080 self.assertFalse(self.logger.isEnabledFor(22))
4081
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004082 def test_root_logger_aliases(self):
4083 root = logging.getLogger()
4084 self.assertIs(root, logging.root)
4085 self.assertIs(root, logging.getLogger(None))
4086 self.assertIs(root, logging.getLogger(''))
4087 self.assertIs(root, logging.getLogger('foo').root)
4088 self.assertIs(root, logging.getLogger('foo.bar').root)
4089 self.assertIs(root, logging.getLogger('foo').parent)
4090
4091 self.assertIsNot(root, logging.getLogger('\0'))
4092 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4093
4094 def test_invalid_names(self):
4095 self.assertRaises(TypeError, logging.getLogger, any)
4096 self.assertRaises(TypeError, logging.getLogger, b'foo')
4097
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004098 def test_pickling(self):
4099 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4100 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4101 logger = logging.getLogger(name)
4102 s = pickle.dumps(logger, proto)
4103 unpickled = pickle.loads(s)
4104 self.assertIs(unpickled, logger)
4105
Avram Lubkin78c18a92017-07-30 05:36:33 -04004106 def test_caching(self):
4107 root = self.root_logger
4108 logger1 = logging.getLogger("abc")
4109 logger2 = logging.getLogger("abc.def")
4110
4111 # Set root logger level and ensure cache is empty
4112 root.setLevel(logging.ERROR)
4113 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4114 self.assertEqual(logger2._cache, {})
4115
4116 # Ensure cache is populated and calls are consistent
4117 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4118 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4119 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4120 self.assertEqual(root._cache, {})
4121 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4122
4123 # Ensure root cache gets populated
4124 self.assertEqual(root._cache, {})
4125 self.assertTrue(root.isEnabledFor(logging.ERROR))
4126 self.assertEqual(root._cache, {logging.ERROR: True})
4127
4128 # Set parent logger level and ensure caches are emptied
4129 logger1.setLevel(logging.CRITICAL)
4130 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4131 self.assertEqual(logger2._cache, {})
4132
4133 # Ensure logger2 uses parent logger's effective level
4134 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4135
4136 # Set level to NOTSET and ensure caches are empty
4137 logger2.setLevel(logging.NOTSET)
4138 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4139 self.assertEqual(logger2._cache, {})
4140 self.assertEqual(logger1._cache, {})
4141 self.assertEqual(root._cache, {})
4142
4143 # Verify logger2 follows parent and not root
4144 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4145 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4146 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4147 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4148 self.assertTrue(root.isEnabledFor(logging.ERROR))
4149
4150 # Disable logging in manager and ensure caches are clear
4151 logging.disable()
4152 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4153 self.assertEqual(logger2._cache, {})
4154 self.assertEqual(logger1._cache, {})
4155 self.assertEqual(root._cache, {})
4156
4157 # Ensure no loggers are enabled
4158 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4159 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4160 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4161
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004162
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004163class BaseFileTest(BaseTest):
4164 "Base class for handler tests that write log files"
4165
4166 def setUp(self):
4167 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004168 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4169 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004170 self.rmfiles = []
4171
4172 def tearDown(self):
4173 for fn in self.rmfiles:
4174 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004175 if os.path.exists(self.fn):
4176 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004177 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004178
4179 def assertLogFile(self, filename):
4180 "Assert a log file is there and register it for deletion"
4181 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004182 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004183 self.rmfiles.append(filename)
4184
4185
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004186class FileHandlerTest(BaseFileTest):
4187 def test_delay(self):
4188 os.unlink(self.fn)
4189 fh = logging.FileHandler(self.fn, delay=True)
4190 self.assertIsNone(fh.stream)
4191 self.assertFalse(os.path.exists(self.fn))
4192 fh.handle(logging.makeLogRecord({}))
4193 self.assertIsNotNone(fh.stream)
4194 self.assertTrue(os.path.exists(self.fn))
4195 fh.close()
4196
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004197class RotatingFileHandlerTest(BaseFileTest):
4198 def next_rec(self):
4199 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4200 self.next_message(), None, None, None)
4201
4202 def test_should_not_rollover(self):
4203 # If maxbytes is zero rollover never occurs
4204 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4205 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004206 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004207
4208 def test_should_rollover(self):
4209 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4210 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004211 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004212
4213 def test_file_created(self):
4214 # checks that the file is created and assumes it was created
4215 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004216 rh = logging.handlers.RotatingFileHandler(self.fn)
4217 rh.emit(self.next_rec())
4218 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004219 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004220
4221 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004222 def namer(name):
4223 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004224 rh = logging.handlers.RotatingFileHandler(
4225 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004226 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004227 rh.emit(self.next_rec())
4228 self.assertLogFile(self.fn)
4229 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004230 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004231 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004232 self.assertLogFile(namer(self.fn + ".2"))
4233 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4234 rh.close()
4235
Vinay Sajip1feedb42014-05-31 08:19:12 +01004236 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004237 def test_rotator(self):
4238 def namer(name):
4239 return name + ".gz"
4240
4241 def rotator(source, dest):
4242 with open(source, "rb") as sf:
4243 data = sf.read()
4244 compressed = zlib.compress(data, 9)
4245 with open(dest, "wb") as df:
4246 df.write(compressed)
4247 os.remove(source)
4248
4249 rh = logging.handlers.RotatingFileHandler(
4250 self.fn, backupCount=2, maxBytes=1)
4251 rh.rotator = rotator
4252 rh.namer = namer
4253 m1 = self.next_rec()
4254 rh.emit(m1)
4255 self.assertLogFile(self.fn)
4256 m2 = self.next_rec()
4257 rh.emit(m2)
4258 fn = namer(self.fn + ".1")
4259 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004260 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004261 with open(fn, "rb") as f:
4262 compressed = f.read()
4263 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004264 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004265 rh.emit(self.next_rec())
4266 fn = namer(self.fn + ".2")
4267 self.assertLogFile(fn)
4268 with open(fn, "rb") as f:
4269 compressed = f.read()
4270 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004271 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004272 rh.emit(self.next_rec())
4273 fn = namer(self.fn + ".2")
4274 with open(fn, "rb") as f:
4275 compressed = f.read()
4276 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004277 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004278 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004279 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004280
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004281class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004282 # other test methods added below
4283 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004284 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4285 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004286 fmt = logging.Formatter('%(asctime)s %(message)s')
4287 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004288 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004289 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004290 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004291 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004292 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004293 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004294 fh.close()
4295 # At this point, we should have a recent rotated file which we
4296 # can test for the existence of. However, in practice, on some
4297 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004298 # in time to go to look for the log file. So, we go back a fair
4299 # bit, and stop as soon as we see a rotated file. In theory this
4300 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004301 found = False
4302 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004303 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004304 for secs in range(GO_BACK):
4305 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004306 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4307 found = os.path.exists(fn)
4308 if found:
4309 self.rmfiles.append(fn)
4310 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004311 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4312 if not found:
4313 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004314 dn, fn = os.path.split(self.fn)
4315 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004316 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4317 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004318 for f in files:
4319 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004320 path = os.path.join(dn, f)
4321 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004322 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004323 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004324
Vinay Sajip0372e102011-05-05 12:59:14 +01004325 def test_invalid(self):
4326 assertRaises = self.assertRaises
4327 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004328 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004329 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004330 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004331 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004332 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004333
Vinay Sajipa7130792013-04-12 17:04:23 +01004334 def test_compute_rollover_daily_attime(self):
4335 currentTime = 0
4336 atTime = datetime.time(12, 0, 0)
4337 rh = logging.handlers.TimedRotatingFileHandler(
4338 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4339 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004340 try:
4341 actual = rh.computeRollover(currentTime)
4342 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004343
Vinay Sajipd86ac962013-04-14 12:20:46 +01004344 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4345 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4346 finally:
4347 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004348
Vinay Sajip10e8c492013-05-18 10:19:54 -07004349 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004350 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004351 currentTime = int(time.time())
4352 today = currentTime - currentTime % 86400
4353
Vinay Sajipa7130792013-04-12 17:04:23 +01004354 atTime = datetime.time(12, 0, 0)
4355
Vinay Sajip10e8c492013-05-18 10:19:54 -07004356 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004357 for day in range(7):
4358 rh = logging.handlers.TimedRotatingFileHandler(
4359 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4360 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004361 try:
4362 if wday > day:
4363 # The rollover day has already passed this week, so we
4364 # go over into next week
4365 expected = (7 - wday + day)
4366 else:
4367 expected = (day - wday)
4368 # At this point expected is in days from now, convert to seconds
4369 expected *= 24 * 60 * 60
4370 # Add in the rollover time
4371 expected += 12 * 60 * 60
4372 # Add in adjustment for today
4373 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004374 actual = rh.computeRollover(today)
4375 if actual != expected:
4376 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004377 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004378 self.assertEqual(actual, expected)
4379 if day == wday:
4380 # goes into following week
4381 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004382 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004383 if actual != expected:
4384 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004385 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004386 self.assertEqual(actual, expected)
4387 finally:
4388 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004389
4390
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004391def secs(**kw):
4392 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4393
4394for when, exp in (('S', 1),
4395 ('M', 60),
4396 ('H', 60 * 60),
4397 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004398 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004399 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004400 ('W0', secs(days=4, hours=24)),
4401 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004402 def test_compute_rollover(self, when=when, exp=exp):
4403 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004404 self.fn, when=when, interval=1, backupCount=0, utc=True)
4405 currentTime = 0.0
4406 actual = rh.computeRollover(currentTime)
4407 if exp != actual:
4408 # Failures occur on some systems for MIDNIGHT and W0.
4409 # Print detailed calculation for MIDNIGHT so we can try to see
4410 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004411 if when == 'MIDNIGHT':
4412 try:
4413 if rh.utc:
4414 t = time.gmtime(currentTime)
4415 else:
4416 t = time.localtime(currentTime)
4417 currentHour = t[3]
4418 currentMinute = t[4]
4419 currentSecond = t[5]
4420 # r is the number of seconds left between now and midnight
4421 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4422 currentMinute) * 60 +
4423 currentSecond)
4424 result = currentTime + r
4425 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4426 print('currentHour: %s' % currentHour, file=sys.stderr)
4427 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4428 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4429 print('r: %s' % r, file=sys.stderr)
4430 print('result: %s' % result, file=sys.stderr)
4431 except Exception:
4432 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4433 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004434 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004435 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4436
Vinay Sajip60ccd822011-05-09 17:32:09 +01004437
Vinay Sajip223349c2015-10-01 20:37:54 +01004438@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004439class NTEventLogHandlerTest(BaseTest):
4440 def test_basic(self):
4441 logtype = 'Application'
4442 elh = win32evtlog.OpenEventLog(None, logtype)
4443 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004444
4445 try:
4446 h = logging.handlers.NTEventLogHandler('test_logging')
4447 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004448 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004449 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004450 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004451
Vinay Sajip60ccd822011-05-09 17:32:09 +01004452 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4453 h.handle(r)
4454 h.close()
4455 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004456 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004457 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4458 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4459 found = False
4460 GO_BACK = 100
4461 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4462 for e in events:
4463 if e.SourceName != 'test_logging':
4464 continue
4465 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4466 if msg != 'Test Log Message\r\n':
4467 continue
4468 found = True
4469 break
4470 msg = 'Record not found in event log, went back %d records' % GO_BACK
4471 self.assertTrue(found, msg=msg)
4472
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004473
4474class MiscTestCase(unittest.TestCase):
4475 def test__all__(self):
4476 blacklist = {'logThreads', 'logMultiprocessing',
4477 'logProcesses', 'currentframe',
4478 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4479 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004480 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004481 support.check__all__(self, logging, blacklist=blacklist)
4482
4483
Christian Heimes180510d2008-03-03 19:15:45 +00004484# Set the locale to the platform-dependent default. I have no idea
4485# why the test does this, but in any case we save the current locale
4486# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004487@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004488def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004489 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004490 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4491 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4492 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4493 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4494 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4495 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4496 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4497 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004498 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004499 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004500 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004501 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004502 ]
4503 if hasattr(logging.handlers, 'QueueListener'):
4504 tests.append(QueueListenerTest)
4505 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004506
Christian Heimes180510d2008-03-03 19:15:45 +00004507if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004508 test_main()