blob: 85c82251e95abbb0e3ae6723b108d04cda463126 [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
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 from http.server import HTTPServer, BaseHTTPRequestHandler
55 import smtpd
56 from urllib.parse import urlparse, parse_qs
57 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010058 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000059except ImportError:
60 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010061try:
Vinay Sajip223349c2015-10-01 20:37:54 +010062 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010063except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010064 win32evtlog = win32evtlogutil = pywintypes = None
65
Eric V. Smith851cad72012-03-11 22:46:04 -070066try:
67 import zlib
68except ImportError:
69 pass
Christian Heimes18c66892008-02-17 13:31:39 +000070
Christian Heimes180510d2008-03-03 19:15:45 +000071class BaseTest(unittest.TestCase):
72
73 """Base class for logging tests."""
74
75 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030076 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000077 message_num = 0
78
79 def setUp(self):
80 """Setup the default logging stream to an internal StringIO instance,
81 so that we can examine log output as we want."""
82 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000083 logging._acquireLock()
84 try:
Christian Heimes180510d2008-03-03 19:15:45 +000085 self.saved_handlers = logging._handlers.copy()
86 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000087 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070088 self.saved_name_to_level = logging._nameToLevel.copy()
89 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.logger_states = logger_states = {}
91 for name in saved_loggers:
92 logger_states[name] = getattr(saved_loggers[name],
93 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000094 finally:
95 logging._releaseLock()
96
Florent Xicluna5252f9f2011-11-07 19:43:05 +010097 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000098 self.logger1 = logging.getLogger("\xab\xd7\xbb")
99 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000100
Christian Heimes180510d2008-03-03 19:15:45 +0000101 self.root_logger = logging.getLogger("")
102 self.original_logging_level = self.root_logger.getEffectiveLevel()
103
104 self.stream = io.StringIO()
105 self.root_logger.setLevel(logging.DEBUG)
106 self.root_hdlr = logging.StreamHandler(self.stream)
107 self.root_formatter = logging.Formatter(self.log_format)
108 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000109 if self.logger1.hasHandlers():
110 hlist = self.logger1.handlers + self.root_logger.handlers
111 raise AssertionError('Unexpected handlers: %s' % hlist)
112 if self.logger2.hasHandlers():
113 hlist = self.logger2.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000115 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000116 self.assertTrue(self.logger1.hasHandlers())
117 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000118
119 def tearDown(self):
120 """Remove our logging stream, and restore the original logging
121 level."""
122 self.stream.close()
123 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000124 while self.root_logger.handlers:
125 h = self.root_logger.handlers[0]
126 self.root_logger.removeHandler(h)
127 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000128 self.root_logger.setLevel(self.original_logging_level)
129 logging._acquireLock()
130 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700131 logging._levelToName.clear()
132 logging._levelToName.update(self.saved_level_to_name)
133 logging._nameToLevel.clear()
134 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000135 logging._handlers.clear()
136 logging._handlers.update(self.saved_handlers)
137 logging._handlerList[:] = self.saved_handler_list
138 loggerDict = logging.getLogger().manager.loggerDict
139 loggerDict.clear()
140 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000141 logger_states = self.logger_states
142 for name in self.logger_states:
143 if logger_states[name] is not None:
144 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000145 finally:
146 logging._releaseLock()
147
Vinay Sajip4ded5512012-10-02 15:56:16 +0100148 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000149 """Match the collected log lines against the regular expression
150 self.expected_log_pat, and compare the extracted group values to
151 the expected_values list of tuples."""
152 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100153 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300154 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100155 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000156 for actual, expected in zip(actual_lines, expected_values):
157 match = pat.search(actual)
158 if not match:
159 self.fail("Log line does not match expected pattern:\n" +
160 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000161 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000162 s = stream.read()
163 if s:
164 self.fail("Remaining output at end of log stream:\n" + s)
165
166 def next_message(self):
167 """Generate a message consisting solely of an auto-incrementing
168 integer."""
169 self.message_num += 1
170 return "%d" % self.message_num
171
172
173class BuiltinLevelsTest(BaseTest):
174 """Test builtin levels and their inheritance."""
175
176 def test_flat(self):
177 #Logging levels in a flat logger namespace.
178 m = self.next_message
179
180 ERR = logging.getLogger("ERR")
181 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000182 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000183 INF.setLevel(logging.INFO)
184 DEB = logging.getLogger("DEB")
185 DEB.setLevel(logging.DEBUG)
186
187 # These should log.
188 ERR.log(logging.CRITICAL, m())
189 ERR.error(m())
190
191 INF.log(logging.CRITICAL, m())
192 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100193 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000194 INF.info(m())
195
196 DEB.log(logging.CRITICAL, m())
197 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100198 DEB.warning(m())
199 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 DEB.debug(m())
201
202 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100203 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 ERR.info(m())
205 ERR.debug(m())
206
207 INF.debug(m())
208
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000209 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ('ERR', 'CRITICAL', '1'),
211 ('ERR', 'ERROR', '2'),
212 ('INF', 'CRITICAL', '3'),
213 ('INF', 'ERROR', '4'),
214 ('INF', 'WARNING', '5'),
215 ('INF', 'INFO', '6'),
216 ('DEB', 'CRITICAL', '7'),
217 ('DEB', 'ERROR', '8'),
218 ('DEB', 'WARNING', '9'),
219 ('DEB', 'INFO', '10'),
220 ('DEB', 'DEBUG', '11'),
221 ])
222
223 def test_nested_explicit(self):
224 # Logging levels in a nested namespace, all explicitly set.
225 m = self.next_message
226
227 INF = logging.getLogger("INF")
228 INF.setLevel(logging.INFO)
229 INF_ERR = logging.getLogger("INF.ERR")
230 INF_ERR.setLevel(logging.ERROR)
231
232 # These should log.
233 INF_ERR.log(logging.CRITICAL, m())
234 INF_ERR.error(m())
235
236 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100237 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000238 INF_ERR.info(m())
239 INF_ERR.debug(m())
240
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000241 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000242 ('INF.ERR', 'CRITICAL', '1'),
243 ('INF.ERR', 'ERROR', '2'),
244 ])
245
246 def test_nested_inherited(self):
247 #Logging levels in a nested namespace, inherited from parent loggers.
248 m = self.next_message
249
250 INF = logging.getLogger("INF")
251 INF.setLevel(logging.INFO)
252 INF_ERR = logging.getLogger("INF.ERR")
253 INF_ERR.setLevel(logging.ERROR)
254 INF_UNDEF = logging.getLogger("INF.UNDEF")
255 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
256 UNDEF = logging.getLogger("UNDEF")
257
258 # These should log.
259 INF_UNDEF.log(logging.CRITICAL, m())
260 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100261 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000262 INF_UNDEF.info(m())
263 INF_ERR_UNDEF.log(logging.CRITICAL, m())
264 INF_ERR_UNDEF.error(m())
265
266 # These should not log.
267 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100268 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000269 INF_ERR_UNDEF.info(m())
270 INF_ERR_UNDEF.debug(m())
271
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000272 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000273 ('INF.UNDEF', 'CRITICAL', '1'),
274 ('INF.UNDEF', 'ERROR', '2'),
275 ('INF.UNDEF', 'WARNING', '3'),
276 ('INF.UNDEF', 'INFO', '4'),
277 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
278 ('INF.ERR.UNDEF', 'ERROR', '6'),
279 ])
280
281 def test_nested_with_virtual_parent(self):
282 # Logging levels when some parent does not exist yet.
283 m = self.next_message
284
285 INF = logging.getLogger("INF")
286 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
287 CHILD = logging.getLogger("INF.BADPARENT")
288 INF.setLevel(logging.INFO)
289
290 # These should log.
291 GRANDCHILD.log(logging.FATAL, m())
292 GRANDCHILD.info(m())
293 CHILD.log(logging.FATAL, m())
294 CHILD.info(m())
295
296 # These should not log.
297 GRANDCHILD.debug(m())
298 CHILD.debug(m())
299
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000300 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000301 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
302 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
303 ('INF.BADPARENT', 'CRITICAL', '3'),
304 ('INF.BADPARENT', 'INFO', '4'),
305 ])
306
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100307 def test_regression_22386(self):
308 """See issue #22386 for more information."""
309 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
310 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000311
Vinay Sajip8b866d52017-01-11 06:57:55 +0000312 def test_regression_29220(self):
313 """See issue #29220 for more information."""
314 logging.addLevelName(logging.INFO, '')
315 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
316 self.assertEqual(logging.getLevelName(logging.INFO), '')
317
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100318 def test_issue27935(self):
319 fatal = logging.getLevelName('FATAL')
320 self.assertEqual(fatal, logging.FATAL)
321
Vinay Sajip924aaae2017-01-11 17:35:36 +0000322 def test_regression_29220(self):
323 """See issue #29220 for more information."""
324 logging.addLevelName(logging.INFO, '')
325 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
326 self.assertEqual(logging.getLevelName(logging.INFO), '')
327 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
328 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
329
Christian Heimes180510d2008-03-03 19:15:45 +0000330class BasicFilterTest(BaseTest):
331
332 """Test the bundled Filter class."""
333
334 def test_filter(self):
335 # Only messages satisfying the specified criteria pass through the
336 # filter.
337 filter_ = logging.Filter("spam.eggs")
338 handler = self.root_logger.handlers[0]
339 try:
340 handler.addFilter(filter_)
341 spam = logging.getLogger("spam")
342 spam_eggs = logging.getLogger("spam.eggs")
343 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
344 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
345
346 spam.info(self.next_message())
347 spam_eggs.info(self.next_message()) # Good.
348 spam_eggs_fish.info(self.next_message()) # Good.
349 spam_bakedbeans.info(self.next_message())
350
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000351 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000352 ('spam.eggs', 'INFO', '2'),
353 ('spam.eggs.fish', 'INFO', '3'),
354 ])
355 finally:
356 handler.removeFilter(filter_)
357
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000358 def test_callable_filter(self):
359 # Only messages satisfying the specified criteria pass through the
360 # filter.
361
362 def filterfunc(record):
363 parts = record.name.split('.')
364 prefix = '.'.join(parts[:2])
365 return prefix == 'spam.eggs'
366
367 handler = self.root_logger.handlers[0]
368 try:
369 handler.addFilter(filterfunc)
370 spam = logging.getLogger("spam")
371 spam_eggs = logging.getLogger("spam.eggs")
372 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
373 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
374
375 spam.info(self.next_message())
376 spam_eggs.info(self.next_message()) # Good.
377 spam_eggs_fish.info(self.next_message()) # Good.
378 spam_bakedbeans.info(self.next_message())
379
380 self.assert_log_lines([
381 ('spam.eggs', 'INFO', '2'),
382 ('spam.eggs.fish', 'INFO', '3'),
383 ])
384 finally:
385 handler.removeFilter(filterfunc)
386
Vinay Sajip985ef872011-04-26 19:34:04 +0100387 def test_empty_filter(self):
388 f = logging.Filter()
389 r = logging.makeLogRecord({'name': 'spam.eggs'})
390 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000391
392#
393# First, we define our levels. There can be as many as you want - the only
394# limitations are that they should be integers, the lowest should be > 0 and
395# larger values mean less information being logged. If you need specific
396# level values which do not fit into these limitations, you can use a
397# mapping dictionary to convert between your application levels and the
398# logging system.
399#
400SILENT = 120
401TACITURN = 119
402TERSE = 118
403EFFUSIVE = 117
404SOCIABLE = 116
405VERBOSE = 115
406TALKATIVE = 114
407GARRULOUS = 113
408CHATTERBOX = 112
409BORING = 111
410
411LEVEL_RANGE = range(BORING, SILENT + 1)
412
413#
414# Next, we define names for our levels. You don't need to do this - in which
415# case the system will use "Level n" to denote the text for the level.
416#
417my_logging_levels = {
418 SILENT : 'Silent',
419 TACITURN : 'Taciturn',
420 TERSE : 'Terse',
421 EFFUSIVE : 'Effusive',
422 SOCIABLE : 'Sociable',
423 VERBOSE : 'Verbose',
424 TALKATIVE : 'Talkative',
425 GARRULOUS : 'Garrulous',
426 CHATTERBOX : 'Chatterbox',
427 BORING : 'Boring',
428}
429
430class GarrulousFilter(logging.Filter):
431
432 """A filter which blocks garrulous messages."""
433
434 def filter(self, record):
435 return record.levelno != GARRULOUS
436
437class VerySpecificFilter(logging.Filter):
438
439 """A filter which blocks sociable and taciturn messages."""
440
441 def filter(self, record):
442 return record.levelno not in [SOCIABLE, TACITURN]
443
444
445class CustomLevelsAndFiltersTest(BaseTest):
446
447 """Test various filtering possibilities with custom logging levels."""
448
449 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300450 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000451
452 def setUp(self):
453 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000454 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000455 logging.addLevelName(k, v)
456
457 def log_at_all_levels(self, logger):
458 for lvl in LEVEL_RANGE:
459 logger.log(lvl, self.next_message())
460
461 def test_logger_filter(self):
462 # Filter at logger level.
463 self.root_logger.setLevel(VERBOSE)
464 # Levels >= 'Verbose' are good.
465 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000466 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000467 ('Verbose', '5'),
468 ('Sociable', '6'),
469 ('Effusive', '7'),
470 ('Terse', '8'),
471 ('Taciturn', '9'),
472 ('Silent', '10'),
473 ])
474
475 def test_handler_filter(self):
476 # Filter at handler level.
477 self.root_logger.handlers[0].setLevel(SOCIABLE)
478 try:
479 # Levels >= 'Sociable' are good.
480 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000481 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000482 ('Sociable', '6'),
483 ('Effusive', '7'),
484 ('Terse', '8'),
485 ('Taciturn', '9'),
486 ('Silent', '10'),
487 ])
488 finally:
489 self.root_logger.handlers[0].setLevel(logging.NOTSET)
490
491 def test_specific_filters(self):
492 # Set a specific filter object on the handler, and then add another
493 # filter object on the logger itself.
494 handler = self.root_logger.handlers[0]
495 specific_filter = None
496 garr = GarrulousFilter()
497 handler.addFilter(garr)
498 try:
499 self.log_at_all_levels(self.root_logger)
500 first_lines = [
501 # Notice how 'Garrulous' is missing
502 ('Boring', '1'),
503 ('Chatterbox', '2'),
504 ('Talkative', '4'),
505 ('Verbose', '5'),
506 ('Sociable', '6'),
507 ('Effusive', '7'),
508 ('Terse', '8'),
509 ('Taciturn', '9'),
510 ('Silent', '10'),
511 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000512 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000513
514 specific_filter = VerySpecificFilter()
515 self.root_logger.addFilter(specific_filter)
516 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000517 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000518 # Not only 'Garrulous' is still missing, but also 'Sociable'
519 # and 'Taciturn'
520 ('Boring', '11'),
521 ('Chatterbox', '12'),
522 ('Talkative', '14'),
523 ('Verbose', '15'),
524 ('Effusive', '17'),
525 ('Terse', '18'),
526 ('Silent', '20'),
527 ])
528 finally:
529 if specific_filter:
530 self.root_logger.removeFilter(specific_filter)
531 handler.removeFilter(garr)
532
533
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100534class HandlerTest(BaseTest):
535 def test_name(self):
536 h = logging.Handler()
537 h.name = 'generic'
538 self.assertEqual(h.name, 'generic')
539 h.name = 'anothergeneric'
540 self.assertEqual(h.name, 'anothergeneric')
541 self.assertRaises(NotImplementedError, h.emit, None)
542
Vinay Sajip5a35b062011-04-27 11:31:14 +0100543 def test_builtin_handlers(self):
544 # We can't actually *use* too many handlers in the tests,
545 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200546 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 for existing in (True, False):
548 fd, fn = tempfile.mkstemp()
549 os.close(fd)
550 if not existing:
551 os.unlink(fn)
552 h = logging.handlers.WatchedFileHandler(fn, delay=True)
553 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100554 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100555 self.assertEqual(dev, -1)
556 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100557 r = logging.makeLogRecord({'msg': 'Test'})
558 h.handle(r)
559 # Now remove the file.
560 os.unlink(fn)
561 self.assertFalse(os.path.exists(fn))
562 # The next call should recreate the file.
563 h.handle(r)
564 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100565 else:
566 self.assertEqual(h.dev, -1)
567 self.assertEqual(h.ino, -1)
568 h.close()
569 if existing:
570 os.unlink(fn)
571 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100572 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100573 else:
574 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100575 try:
576 h = logging.handlers.SysLogHandler(sockname)
577 self.assertEqual(h.facility, h.LOG_USER)
578 self.assertTrue(h.unixsocket)
579 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200580 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100581 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100582 for method in ('GET', 'POST', 'PUT'):
583 if method == 'PUT':
584 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
585 'localhost', '/log', method)
586 else:
587 h = logging.handlers.HTTPHandler('localhost', '/log', method)
588 h.close()
589 h = logging.handlers.BufferingHandler(0)
590 r = logging.makeLogRecord({})
591 self.assertTrue(h.shouldFlush(r))
592 h.close()
593 h = logging.handlers.BufferingHandler(1)
594 self.assertFalse(h.shouldFlush(r))
595 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100596
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100597 def test_path_objects(self):
598 """
599 Test that Path objects are accepted as filename arguments to handlers.
600
601 See Issue #27493.
602 """
603 fd, fn = tempfile.mkstemp()
604 os.close(fd)
605 os.unlink(fn)
606 pfn = pathlib.Path(fn)
607 cases = (
608 (logging.FileHandler, (pfn, 'w')),
609 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
610 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
611 )
612 if sys.platform in ('linux', 'darwin'):
613 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
614 for cls, args in cases:
615 h = cls(*args)
616 self.assertTrue(os.path.exists(fn))
617 h.close()
618 os.unlink(fn)
619
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100620 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100621 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200622 @support.reap_threads
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623 def test_race(self):
624 # Issue #14632 refers.
625 def remove_loop(fname, tries):
626 for _ in range(tries):
627 try:
628 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000629 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100630 except OSError:
631 pass
632 time.sleep(0.004 * random.randint(0, 4))
633
Vinay Sajipc94871a2012-04-25 10:51:35 +0100634 del_count = 500
635 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100636
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000637 self.handle_time = None
638 self.deletion_time = None
639
Vinay Sajipa5798de2012-04-24 23:33:33 +0100640 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100641 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
642 os.close(fd)
643 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
644 remover.daemon = True
645 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100646 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100647 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
648 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100649 try:
650 for _ in range(log_count):
651 time.sleep(0.005)
652 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000653 try:
654 self.handle_time = time.time()
655 h.handle(r)
656 except Exception:
657 print('Deleted at %s, '
658 'opened at %s' % (self.deletion_time,
659 self.handle_time))
660 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100661 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100662 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100663 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100664 if os.path.exists(fn):
665 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100666
667
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100668class BadStream(object):
669 def write(self, data):
670 raise RuntimeError('deliberate mistake')
671
672class TestStreamHandler(logging.StreamHandler):
673 def handleError(self, record):
674 self.error_record = record
675
676class StreamHandlerTest(BaseTest):
677 def test_error_handling(self):
678 h = TestStreamHandler(BadStream())
679 r = logging.makeLogRecord({})
680 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100681
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100682 try:
683 h.handle(r)
684 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100685
Vinay Sajip985ef872011-04-26 19:34:04 +0100686 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687 with support.captured_stderr() as stderr:
688 h.handle(r)
689 msg = '\nRuntimeError: deliberate mistake\n'
690 self.assertIn(msg, stderr.getvalue())
691
Vinay Sajip985ef872011-04-26 19:34:04 +0100692 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100693 with support.captured_stderr() as stderr:
694 h.handle(r)
695 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100696 finally:
697 logging.raiseExceptions = old_raise
698
Vinay Sajip7367d082011-05-02 13:17:27 +0100699# -- The following section could be moved into a server_helper.py module
700# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100701
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100703 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100704 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100705 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100706
Vinay Sajipce7c9782011-05-17 07:15:53 +0100707 :param addr: A (host, port) tuple which the server listens on.
708 You can specify a port value of zero: the server's
709 *port* attribute will hold the actual port number
710 used, which can be used in client connections.
711 :param handler: A callable which will be called to process
712 incoming messages. The handler will be passed
713 the client address tuple, who the message is from,
714 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100715 :param poll_interval: The interval, in seconds, used in the underlying
716 :func:`select` or :func:`poll` call by
717 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100718 :param sockmap: A dictionary which will be used to hold
719 :class:`asyncore.dispatcher` instances used by
720 :func:`asyncore.loop`. This avoids changing the
721 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100722 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100723
724 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400725 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
726 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100727 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100728 self._handler = handler
729 self._thread = None
730 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100731
Vinay Sajipce7c9782011-05-17 07:15:53 +0100732 def process_message(self, peer, mailfrom, rcpttos, data):
733 """
734 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 Typically, this will be a test case method.
737 :param peer: The client (host, port) tuple.
738 :param mailfrom: The address of the sender.
739 :param rcpttos: The addresses of the recipients.
740 :param data: The message.
741 """
742 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100743
Vinay Sajipce7c9782011-05-17 07:15:53 +0100744 def start(self):
745 """
746 Start the server running on a separate daemon thread.
747 """
748 self._thread = t = threading.Thread(target=self.serve_forever,
749 args=(self.poll_interval,))
750 t.setDaemon(True)
751 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100752
Vinay Sajipce7c9782011-05-17 07:15:53 +0100753 def serve_forever(self, poll_interval):
754 """
755 Run the :mod:`asyncore` loop until normal termination
756 conditions arise.
757 :param poll_interval: The interval, in seconds, used in the underlying
758 :func:`select` or :func:`poll` call by
759 :func:`asyncore.loop`.
760 """
761 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100762 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200763 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100764 # On FreeBSD 8, closing the server repeatably
765 # raises this error. We swallow it if the
766 # server has been closed.
767 if self.connected or self.accepting:
768 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def stop(self, timeout=None):
771 """
772 Stop the thread by closing the server instance.
773 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100774
Vinay Sajipce7c9782011-05-17 07:15:53 +0100775 :param timeout: How long to wait for the server thread
776 to terminate.
777 """
778 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100779 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200780 alive = self._thread.is_alive()
Vinay Sajip7367d082011-05-02 13:17:27 +0100781 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200782 if alive:
783 self.fail("join() timed out")
Vinay Sajip7367d082011-05-02 13:17:27 +0100784
Vinay Sajipce7c9782011-05-17 07:15:53 +0100785 class ControlMixin(object):
786 """
787 This mixin is used to start a server on a separate thread, and
788 shut it down programmatically. Request handling is simplified - instead
789 of needing to derive a suitable RequestHandler subclass, you just
790 provide a callable which will be passed each received request to be
791 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100792
Vinay Sajipce7c9782011-05-17 07:15:53 +0100793 :param handler: A handler callable which will be called with a
794 single parameter - the request - in order to
795 process the request. This handler is called on the
796 server thread, effectively meaning that requests are
797 processed serially. While not quite Web scale ;-),
798 this should be fine for testing applications.
799 :param poll_interval: The polling interval in seconds.
800 """
801 def __init__(self, handler, poll_interval):
802 self._thread = None
803 self.poll_interval = poll_interval
804 self._handler = handler
805 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Vinay Sajipce7c9782011-05-17 07:15:53 +0100807 def start(self):
808 """
809 Create a daemon thread to run the server, and start it.
810 """
811 self._thread = t = threading.Thread(target=self.serve_forever,
812 args=(self.poll_interval,))
813 t.setDaemon(True)
814 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100815
Vinay Sajipce7c9782011-05-17 07:15:53 +0100816 def serve_forever(self, poll_interval):
817 """
818 Run the server. Set the ready flag before entering the
819 service loop.
820 """
821 self.ready.set()
822 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100823
Vinay Sajipce7c9782011-05-17 07:15:53 +0100824 def stop(self, timeout=None):
825 """
826 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100827
Vinay Sajipce7c9782011-05-17 07:15:53 +0100828 :param timeout: How long to wait for the server thread
829 to terminate.
830 """
831 self.shutdown()
832 if self._thread is not None:
833 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200834 alive = self._thread.is_alive()
Vinay Sajipce7c9782011-05-17 07:15:53 +0100835 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200836 if alive:
837 self.fail("join() timed out")
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 self.server_close()
839 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 class TestHTTPServer(ControlMixin, HTTPServer):
842 """
843 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100844
Vinay Sajipce7c9782011-05-17 07:15:53 +0100845 :param addr: A tuple with the IP address and port to listen on.
846 :param handler: A handler callable which will be called with a
847 single parameter - the request - in order to
848 process the request.
849 :param poll_interval: The polling interval in seconds.
850 :param log: Pass ``True`` to enable log messages.
851 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100852 def __init__(self, addr, handler, poll_interval=0.5,
853 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100854 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
855 def __getattr__(self, name, default=None):
856 if name.startswith('do_'):
857 return self.process_request
858 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100859
Vinay Sajipce7c9782011-05-17 07:15:53 +0100860 def process_request(self):
861 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100862
Vinay Sajipce7c9782011-05-17 07:15:53 +0100863 def log_message(self, format, *args):
864 if log:
865 super(DelegatingHTTPRequestHandler,
866 self).log_message(format, *args)
867 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
868 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100869 self.sslctx = sslctx
870
871 def get_request(self):
872 try:
873 sock, addr = self.socket.accept()
874 if self.sslctx:
875 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200876 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100877 # socket errors are silenced by the caller, print them here
878 sys.stderr.write("Got an error:\n%s\n" % e)
879 raise
880 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100881
Vinay Sajipce7c9782011-05-17 07:15:53 +0100882 class TestTCPServer(ControlMixin, ThreadingTCPServer):
883 """
884 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100885
Vinay Sajipce7c9782011-05-17 07:15:53 +0100886 :param addr: A tuple with the IP address and port to listen on.
887 :param handler: A handler callable which will be called with a single
888 parameter - the request - in order to process the request.
889 :param poll_interval: The polling interval in seconds.
890 :bind_and_activate: If True (the default), binds the server and starts it
891 listening. If False, you need to call
892 :meth:`server_bind` and :meth:`server_activate` at
893 some later time before calling :meth:`start`, so that
894 the server will set up the socket and listen on it.
895 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100896
Vinay Sajipce7c9782011-05-17 07:15:53 +0100897 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100898
Vinay Sajipce7c9782011-05-17 07:15:53 +0100899 def __init__(self, addr, handler, poll_interval=0.5,
900 bind_and_activate=True):
901 class DelegatingTCPRequestHandler(StreamRequestHandler):
902
903 def handle(self):
904 self.server._handler(self)
905 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
906 bind_and_activate)
907 ControlMixin.__init__(self, handler, poll_interval)
908
909 def server_bind(self):
910 super(TestTCPServer, self).server_bind()
911 self.port = self.socket.getsockname()[1]
912
913 class TestUDPServer(ControlMixin, ThreadingUDPServer):
914 """
915 A UDP server which is controllable using :class:`ControlMixin`.
916
917 :param addr: A tuple with the IP address and port to listen on.
918 :param handler: A handler callable which will be called with a
919 single parameter - the request - in order to
920 process the request.
921 :param poll_interval: The polling interval for shutdown requests,
922 in seconds.
923 :bind_and_activate: If True (the default), binds the server and
924 starts it listening. If False, you need to
925 call :meth:`server_bind` and
926 :meth:`server_activate` at some later time
927 before calling :meth:`start`, so that the server will
928 set up the socket and listen on it.
929 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100930 def __init__(self, addr, handler, poll_interval=0.5,
931 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100932 class DelegatingUDPRequestHandler(DatagramRequestHandler):
933
934 def handle(self):
935 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100936
937 def finish(self):
938 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100939 if data:
940 try:
941 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200942 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100943 if not self.server._closed:
944 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100945
Vinay Sajip3ef12292011-05-23 23:00:42 +0100946 ThreadingUDPServer.__init__(self, addr,
947 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100948 bind_and_activate)
949 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100950 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100951
952 def server_bind(self):
953 super(TestUDPServer, self).server_bind()
954 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100955
Vinay Sajipba980db2011-05-23 21:37:54 +0100956 def server_close(self):
957 super(TestUDPServer, self).server_close()
958 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100959
Victor Stinnerec5a8602014-06-02 14:41:51 +0200960 if hasattr(socket, "AF_UNIX"):
961 class TestUnixStreamServer(TestTCPServer):
962 address_family = socket.AF_UNIX
963
964 class TestUnixDatagramServer(TestUDPServer):
965 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100966
Vinay Sajip7367d082011-05-02 13:17:27 +0100967# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100968
Vinay Sajipce7c9782011-05-17 07:15:53 +0100969@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100970class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000971 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200972
973 @support.reap_threads
Vinay Sajipa463d252011-04-30 21:52:48 +0100974 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100975 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800976 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100977 sockmap)
978 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800979 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000980 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
981 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100982 self.assertEqual(h.toaddrs, ['you'])
983 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100984 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100985 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100986 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000987 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100988 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000989 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100990 self.assertEqual(len(self.messages), 1)
991 peer, mailfrom, rcpttos, data = self.messages[0]
992 self.assertEqual(mailfrom, 'me')
993 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100994 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100995 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100996 h.close()
997
998 def process_message(self, *args):
999 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001000 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001001
Christian Heimes180510d2008-03-03 19:15:45 +00001002class MemoryHandlerTest(BaseTest):
1003
1004 """Tests for the MemoryHandler."""
1005
1006 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001007 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001008
1009 def setUp(self):
1010 BaseTest.setUp(self)
1011 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001012 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001013 self.mem_logger = logging.getLogger('mem')
1014 self.mem_logger.propagate = 0
1015 self.mem_logger.addHandler(self.mem_hdlr)
1016
1017 def tearDown(self):
1018 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001019 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001020
1021 def test_flush(self):
1022 # The memory handler flushes to its target handler based on specific
1023 # criteria (message count and message level).
1024 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001025 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001026 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001027 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001028 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001029 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001030 lines = [
1031 ('DEBUG', '1'),
1032 ('INFO', '2'),
1033 ('WARNING', '3'),
1034 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001035 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001036 for n in (4, 14):
1037 for i in range(9):
1038 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001039 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001040 # This will flush because it's the 10th message since the last
1041 # flush.
1042 self.mem_logger.debug(self.next_message())
1043 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001044 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001045
1046 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001047 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001048
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001049 def test_flush_on_close(self):
1050 """
1051 Test that the flush-on-close configuration works as expected.
1052 """
1053 self.mem_logger.debug(self.next_message())
1054 self.assert_log_lines([])
1055 self.mem_logger.info(self.next_message())
1056 self.assert_log_lines([])
1057 self.mem_logger.removeHandler(self.mem_hdlr)
1058 # Default behaviour is to flush on close. Check that it happens.
1059 self.mem_hdlr.close()
1060 lines = [
1061 ('DEBUG', '1'),
1062 ('INFO', '2'),
1063 ]
1064 self.assert_log_lines(lines)
1065 # Now configure for flushing not to be done on close.
1066 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1067 self.root_hdlr,
1068 False)
1069 self.mem_logger.addHandler(self.mem_hdlr)
1070 self.mem_logger.debug(self.next_message())
1071 self.assert_log_lines(lines) # no change
1072 self.mem_logger.info(self.next_message())
1073 self.assert_log_lines(lines) # no change
1074 self.mem_logger.removeHandler(self.mem_hdlr)
1075 self.mem_hdlr.close()
1076 # assert that no new lines have been added
1077 self.assert_log_lines(lines) # no change
1078
Christian Heimes180510d2008-03-03 19:15:45 +00001079
1080class ExceptionFormatter(logging.Formatter):
1081 """A special exception formatter."""
1082 def formatException(self, ei):
1083 return "Got a [%s]" % ei[0].__name__
1084
1085
1086class ConfigFileTest(BaseTest):
1087
1088 """Reading logging config from a .ini-style config file."""
1089
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001090 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001091
1092 # config0 is a standard configuration.
1093 config0 = """
1094 [loggers]
1095 keys=root
1096
1097 [handlers]
1098 keys=hand1
1099
1100 [formatters]
1101 keys=form1
1102
1103 [logger_root]
1104 level=WARNING
1105 handlers=hand1
1106
1107 [handler_hand1]
1108 class=StreamHandler
1109 level=NOTSET
1110 formatter=form1
1111 args=(sys.stdout,)
1112
1113 [formatter_form1]
1114 format=%(levelname)s ++ %(message)s
1115 datefmt=
1116 """
1117
1118 # config1 adds a little to the standard configuration.
1119 config1 = """
1120 [loggers]
1121 keys=root,parser
1122
1123 [handlers]
1124 keys=hand1
1125
1126 [formatters]
1127 keys=form1
1128
1129 [logger_root]
1130 level=WARNING
1131 handlers=
1132
1133 [logger_parser]
1134 level=DEBUG
1135 handlers=hand1
1136 propagate=1
1137 qualname=compiler.parser
1138
1139 [handler_hand1]
1140 class=StreamHandler
1141 level=NOTSET
1142 formatter=form1
1143 args=(sys.stdout,)
1144
1145 [formatter_form1]
1146 format=%(levelname)s ++ %(message)s
1147 datefmt=
1148 """
1149
Vinay Sajip3f84b072011-03-07 17:49:33 +00001150 # config1a moves the handler to the root.
1151 config1a = """
1152 [loggers]
1153 keys=root,parser
1154
1155 [handlers]
1156 keys=hand1
1157
1158 [formatters]
1159 keys=form1
1160
1161 [logger_root]
1162 level=WARNING
1163 handlers=hand1
1164
1165 [logger_parser]
1166 level=DEBUG
1167 handlers=
1168 propagate=1
1169 qualname=compiler.parser
1170
1171 [handler_hand1]
1172 class=StreamHandler
1173 level=NOTSET
1174 formatter=form1
1175 args=(sys.stdout,)
1176
1177 [formatter_form1]
1178 format=%(levelname)s ++ %(message)s
1179 datefmt=
1180 """
1181
Christian Heimes180510d2008-03-03 19:15:45 +00001182 # config2 has a subtle configuration error that should be reported
1183 config2 = config1.replace("sys.stdout", "sys.stbout")
1184
1185 # config3 has a less subtle configuration error
1186 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1187
1188 # config4 specifies a custom formatter class to be loaded
1189 config4 = """
1190 [loggers]
1191 keys=root
1192
1193 [handlers]
1194 keys=hand1
1195
1196 [formatters]
1197 keys=form1
1198
1199 [logger_root]
1200 level=NOTSET
1201 handlers=hand1
1202
1203 [handler_hand1]
1204 class=StreamHandler
1205 level=NOTSET
1206 formatter=form1
1207 args=(sys.stdout,)
1208
1209 [formatter_form1]
1210 class=""" + __name__ + """.ExceptionFormatter
1211 format=%(levelname)s:%(name)s:%(message)s
1212 datefmt=
1213 """
1214
Georg Brandl3dbca812008-07-23 16:10:53 +00001215 # config5 specifies a custom handler class to be loaded
1216 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1217
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001218 # config6 uses ', ' delimiters in the handlers and formatters sections
1219 config6 = """
1220 [loggers]
1221 keys=root,parser
1222
1223 [handlers]
1224 keys=hand1, hand2
1225
1226 [formatters]
1227 keys=form1, form2
1228
1229 [logger_root]
1230 level=WARNING
1231 handlers=
1232
1233 [logger_parser]
1234 level=DEBUG
1235 handlers=hand1
1236 propagate=1
1237 qualname=compiler.parser
1238
1239 [handler_hand1]
1240 class=StreamHandler
1241 level=NOTSET
1242 formatter=form1
1243 args=(sys.stdout,)
1244
1245 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001246 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001247 level=NOTSET
1248 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001249 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001250
1251 [formatter_form1]
1252 format=%(levelname)s ++ %(message)s
1253 datefmt=
1254
1255 [formatter_form2]
1256 format=%(message)s
1257 datefmt=
1258 """
1259
Vinay Sajip3f84b072011-03-07 17:49:33 +00001260 # config7 adds a compiler logger.
1261 config7 = """
1262 [loggers]
1263 keys=root,parser,compiler
1264
1265 [handlers]
1266 keys=hand1
1267
1268 [formatters]
1269 keys=form1
1270
1271 [logger_root]
1272 level=WARNING
1273 handlers=hand1
1274
1275 [logger_compiler]
1276 level=DEBUG
1277 handlers=
1278 propagate=1
1279 qualname=compiler
1280
1281 [logger_parser]
1282 level=DEBUG
1283 handlers=
1284 propagate=1
1285 qualname=compiler.parser
1286
1287 [handler_hand1]
1288 class=StreamHandler
1289 level=NOTSET
1290 formatter=form1
1291 args=(sys.stdout,)
1292
1293 [formatter_form1]
1294 format=%(levelname)s ++ %(message)s
1295 datefmt=
1296 """
1297
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001298 disable_test = """
1299 [loggers]
1300 keys=root
1301
1302 [handlers]
1303 keys=screen
1304
1305 [formatters]
1306 keys=
1307
1308 [logger_root]
1309 level=DEBUG
1310 handlers=screen
1311
1312 [handler_screen]
1313 level=DEBUG
1314 class=StreamHandler
1315 args=(sys.stdout,)
1316 formatter=
1317 """
1318
1319 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001320 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001321 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001322
1323 def test_config0_ok(self):
1324 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001325 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001326 self.apply_config(self.config0)
1327 logger = logging.getLogger()
1328 # Won't output anything
1329 logger.info(self.next_message())
1330 # Outputs a message
1331 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001332 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001333 ('ERROR', '2'),
1334 ], stream=output)
1335 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001336 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001337
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001338 def test_config0_using_cp_ok(self):
1339 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001340 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001341 file = io.StringIO(textwrap.dedent(self.config0))
1342 cp = configparser.ConfigParser()
1343 cp.read_file(file)
1344 logging.config.fileConfig(cp)
1345 logger = logging.getLogger()
1346 # Won't output anything
1347 logger.info(self.next_message())
1348 # Outputs a message
1349 logger.error(self.next_message())
1350 self.assert_log_lines([
1351 ('ERROR', '2'),
1352 ], stream=output)
1353 # Original logger output is empty.
1354 self.assert_log_lines([])
1355
Georg Brandl3dbca812008-07-23 16:10:53 +00001356 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001357 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001358 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001359 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001360 logger = logging.getLogger("compiler.parser")
1361 # Both will output a message
1362 logger.info(self.next_message())
1363 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001364 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001365 ('INFO', '1'),
1366 ('ERROR', '2'),
1367 ], stream=output)
1368 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001369 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001370
1371 def test_config2_failure(self):
1372 # A simple config file which overrides the default settings.
1373 self.assertRaises(Exception, self.apply_config, self.config2)
1374
1375 def test_config3_failure(self):
1376 # A simple config file which overrides the default settings.
1377 self.assertRaises(Exception, self.apply_config, self.config3)
1378
1379 def test_config4_ok(self):
1380 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001381 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001382 self.apply_config(self.config4)
1383 logger = logging.getLogger()
1384 try:
1385 raise RuntimeError()
1386 except RuntimeError:
1387 logging.exception("just testing")
1388 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001389 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001390 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1391 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001392 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001393
Georg Brandl3dbca812008-07-23 16:10:53 +00001394 def test_config5_ok(self):
1395 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001396
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001397 def test_config6_ok(self):
1398 self.test_config1_ok(config=self.config6)
1399
Vinay Sajip3f84b072011-03-07 17:49:33 +00001400 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001401 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001402 self.apply_config(self.config1a)
1403 logger = logging.getLogger("compiler.parser")
1404 # See issue #11424. compiler-hyphenated sorts
1405 # between compiler and compiler.xyz and this
1406 # was preventing compiler.xyz from being included
1407 # in the child loggers of compiler because of an
1408 # overzealous loop termination condition.
1409 hyphenated = logging.getLogger('compiler-hyphenated')
1410 # All will output a message
1411 logger.info(self.next_message())
1412 logger.error(self.next_message())
1413 hyphenated.critical(self.next_message())
1414 self.assert_log_lines([
1415 ('INFO', '1'),
1416 ('ERROR', '2'),
1417 ('CRITICAL', '3'),
1418 ], stream=output)
1419 # Original logger output is empty.
1420 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001421 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001422 self.apply_config(self.config7)
1423 logger = logging.getLogger("compiler.parser")
1424 self.assertFalse(logger.disabled)
1425 # Both will output a message
1426 logger.info(self.next_message())
1427 logger.error(self.next_message())
1428 logger = logging.getLogger("compiler.lexer")
1429 # Both will output a message
1430 logger.info(self.next_message())
1431 logger.error(self.next_message())
1432 # Will not appear
1433 hyphenated.critical(self.next_message())
1434 self.assert_log_lines([
1435 ('INFO', '4'),
1436 ('ERROR', '5'),
1437 ('INFO', '6'),
1438 ('ERROR', '7'),
1439 ], stream=output)
1440 # Original logger output is empty.
1441 self.assert_log_lines([])
1442
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001443 def test_logger_disabling(self):
1444 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001445 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001446 self.assertFalse(logger.disabled)
1447 self.apply_config(self.disable_test)
1448 self.assertTrue(logger.disabled)
1449 self.apply_config(self.disable_test, disable_existing_loggers=False)
1450 self.assertFalse(logger.disabled)
1451
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001452
Victor Stinner45df8202010-04-28 22:31:17 +00001453@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001454class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001455
Christian Heimes180510d2008-03-03 19:15:45 +00001456 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001457
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001458 if threading:
1459 server_class = TestTCPServer
1460 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001461
Christian Heimes180510d2008-03-03 19:15:45 +00001462 def setUp(self):
1463 """Set up a TCP server to receive log messages, and a SocketHandler
1464 pointing to that server's address and port."""
1465 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001466 # Issue #29177: deal with errors that happen during setup
1467 self.server = self.sock_hdlr = self.server_exception = None
1468 try:
1469 self.server = server = self.server_class(self.address,
1470 self.handle_socket, 0.01)
1471 server.start()
1472 # Uncomment next line to test error recovery in setUp()
1473 # raise OSError('dummy error raised')
1474 except OSError as e:
1475 self.server_exception = e
1476 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001477 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001478 hcls = logging.handlers.SocketHandler
1479 if isinstance(server.server_address, tuple):
1480 self.sock_hdlr = hcls('localhost', server.port)
1481 else:
1482 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001483 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001484 self.root_logger.removeHandler(self.root_logger.handlers[0])
1485 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001486 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001487
Christian Heimes180510d2008-03-03 19:15:45 +00001488 def tearDown(self):
1489 """Shutdown the TCP server."""
1490 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001491 if self.server:
1492 self.server.stop(2.0)
1493 if self.sock_hdlr:
1494 self.root_logger.removeHandler(self.sock_hdlr)
1495 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001496 finally:
1497 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001498
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 def handle_socket(self, request):
1500 conn = request.connection
1501 while True:
1502 chunk = conn.recv(4)
1503 if len(chunk) < 4:
1504 break
1505 slen = struct.unpack(">L", chunk)[0]
1506 chunk = conn.recv(slen)
1507 while len(chunk) < slen:
1508 chunk = chunk + conn.recv(slen - len(chunk))
1509 obj = pickle.loads(chunk)
1510 record = logging.makeLogRecord(obj)
1511 self.log_output += record.msg + '\n'
1512 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001513
Christian Heimes180510d2008-03-03 19:15:45 +00001514 def test_output(self):
1515 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001516 if self.server_exception:
1517 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001518 logger = logging.getLogger("tcp")
1519 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001520 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001521 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001522 self.handled.acquire()
1523 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001524
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001525 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001526 if self.server_exception:
1527 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001528 # Avoid timing-related failures due to SocketHandler's own hard-wired
1529 # one-second timeout on socket.create_connection() (issue #16264).
1530 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001531 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001532 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001533 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001534 try:
1535 raise RuntimeError('Deliberate mistake')
1536 except RuntimeError:
1537 self.root_logger.exception('Never sent')
1538 self.root_logger.error('Never sent, either')
1539 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001540 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001541 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1542 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001543
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001544def _get_temp_domain_socket():
1545 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1546 os.close(fd)
1547 # just need a name - file can't be present, or we'll get an
1548 # 'address already in use' error.
1549 os.remove(fn)
1550 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001551
Victor Stinnerec5a8602014-06-02 14:41:51 +02001552@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001553@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001554class UnixSocketHandlerTest(SocketHandlerTest):
1555
1556 """Test for SocketHandler with unix sockets."""
1557
Victor Stinnerec5a8602014-06-02 14:41:51 +02001558 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001559 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001560
1561 def setUp(self):
1562 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001563 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 SocketHandlerTest.setUp(self)
1565
1566 def tearDown(self):
1567 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001568 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001569
1570@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001571class DatagramHandlerTest(BaseTest):
1572
1573 """Test for DatagramHandler."""
1574
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001575 if threading:
1576 server_class = TestUDPServer
1577 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001578
Vinay Sajip7367d082011-05-02 13:17:27 +01001579 def setUp(self):
1580 """Set up a UDP server to receive log messages, and a DatagramHandler
1581 pointing to that server's address and port."""
1582 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001583 # Issue #29177: deal with errors that happen during setup
1584 self.server = self.sock_hdlr = self.server_exception = None
1585 try:
1586 self.server = server = self.server_class(self.address,
1587 self.handle_datagram, 0.01)
1588 server.start()
1589 # Uncomment next line to test error recovery in setUp()
1590 # raise OSError('dummy error raised')
1591 except OSError as e:
1592 self.server_exception = e
1593 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001594 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001595 hcls = logging.handlers.DatagramHandler
1596 if isinstance(server.server_address, tuple):
1597 self.sock_hdlr = hcls('localhost', server.port)
1598 else:
1599 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001600 self.log_output = ''
1601 self.root_logger.removeHandler(self.root_logger.handlers[0])
1602 self.root_logger.addHandler(self.sock_hdlr)
1603 self.handled = threading.Event()
1604
1605 def tearDown(self):
1606 """Shutdown the UDP server."""
1607 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001608 if self.server:
1609 self.server.stop(2.0)
1610 if self.sock_hdlr:
1611 self.root_logger.removeHandler(self.sock_hdlr)
1612 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001613 finally:
1614 BaseTest.tearDown(self)
1615
1616 def handle_datagram(self, request):
1617 slen = struct.pack('>L', 0) # length of prefix
1618 packet = request.packet[len(slen):]
1619 obj = pickle.loads(packet)
1620 record = logging.makeLogRecord(obj)
1621 self.log_output += record.msg + '\n'
1622 self.handled.set()
1623
1624 def test_output(self):
1625 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001626 if self.server_exception:
1627 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001628 logger = logging.getLogger("udp")
1629 logger.error("spam")
1630 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001631 self.handled.clear()
1632 logger.error("eggs")
1633 self.handled.wait()
1634 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001635
Victor Stinnerec5a8602014-06-02 14:41:51 +02001636@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001637@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001638class UnixDatagramHandlerTest(DatagramHandlerTest):
1639
1640 """Test for DatagramHandler using Unix sockets."""
1641
Victor Stinnerec5a8602014-06-02 14:41:51 +02001642 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001643 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001644
1645 def setUp(self):
1646 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001647 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001648 DatagramHandlerTest.setUp(self)
1649
1650 def tearDown(self):
1651 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001652 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001653
1654@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001655class SysLogHandlerTest(BaseTest):
1656
1657 """Test for SysLogHandler using UDP."""
1658
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001659 if threading:
1660 server_class = TestUDPServer
1661 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001662
Vinay Sajip7367d082011-05-02 13:17:27 +01001663 def setUp(self):
1664 """Set up a UDP server to receive log messages, and a SysLogHandler
1665 pointing to that server's address and port."""
1666 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001667 # Issue #29177: deal with errors that happen during setup
1668 self.server = self.sl_hdlr = self.server_exception = None
1669 try:
1670 self.server = server = self.server_class(self.address,
1671 self.handle_datagram, 0.01)
1672 server.start()
1673 # Uncomment next line to test error recovery in setUp()
1674 # raise OSError('dummy error raised')
1675 except OSError as e:
1676 self.server_exception = e
1677 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001678 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001679 hcls = logging.handlers.SysLogHandler
1680 if isinstance(server.server_address, tuple):
1681 self.sl_hdlr = hcls(('localhost', server.port))
1682 else:
1683 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001684 self.log_output = ''
1685 self.root_logger.removeHandler(self.root_logger.handlers[0])
1686 self.root_logger.addHandler(self.sl_hdlr)
1687 self.handled = threading.Event()
1688
1689 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001690 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001691 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001692 if self.server:
1693 self.server.stop(2.0)
1694 if self.sl_hdlr:
1695 self.root_logger.removeHandler(self.sl_hdlr)
1696 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001697 finally:
1698 BaseTest.tearDown(self)
1699
1700 def handle_datagram(self, request):
1701 self.log_output = request.packet
1702 self.handled.set()
1703
1704 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001705 if self.server_exception:
1706 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001707 # The log message sent to the SysLogHandler is properly received.
1708 logger = logging.getLogger("slh")
1709 logger.error("sp\xe4m")
1710 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001711 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001712 self.handled.clear()
1713 self.sl_hdlr.append_nul = False
1714 logger.error("sp\xe4m")
1715 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001716 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001717 self.handled.clear()
1718 self.sl_hdlr.ident = "h\xe4m-"
1719 logger.error("sp\xe4m")
1720 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001721 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001722
Victor Stinnerec5a8602014-06-02 14:41:51 +02001723@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001724@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001725class UnixSysLogHandlerTest(SysLogHandlerTest):
1726
1727 """Test for SysLogHandler with Unix sockets."""
1728
Victor Stinnerec5a8602014-06-02 14:41:51 +02001729 if threading and 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
Vinay Sajip5421f352013-09-27 18:18:28 +01001741@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001742class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001743 """Test for HTTPHandler."""
1744
1745 def setUp(self):
1746 """Set up an HTTP server to receive log messages, and a HTTPHandler
1747 pointing to that server's address and port."""
1748 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001749 self.handled = threading.Event()
1750
Vinay Sajip7367d082011-05-02 13:17:27 +01001751 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001752 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001753 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001754 if self.command == 'POST':
1755 try:
1756 rlen = int(request.headers['Content-Length'])
1757 self.post_data = request.rfile.read(rlen)
1758 except:
1759 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001760 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001761 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001762 self.handled.set()
1763
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02001764 @support.reap_threads
Vinay Sajip7367d082011-05-02 13:17:27 +01001765 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001766 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001767 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001768 root_logger = self.root_logger
1769 root_logger.removeHandler(self.root_logger.handlers[0])
1770 for secure in (False, True):
1771 addr = ('localhost', 0)
1772 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001773 try:
1774 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001775 except ImportError:
1776 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001777 else:
1778 here = os.path.dirname(__file__)
1779 localhost_cert = os.path.join(here, "keycert.pem")
1780 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1781 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001782
1783 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001784 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001785 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001786 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001787 self.server = server = TestHTTPServer(addr, self.handle_request,
1788 0.01, sslctx=sslctx)
1789 server.start()
1790 server.ready.wait()
1791 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001792 secure_client = secure and sslctx
1793 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001794 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001795 context=context,
1796 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001797 self.log_data = None
1798 root_logger.addHandler(self.h_hdlr)
1799
1800 for method in ('GET', 'POST'):
1801 self.h_hdlr.method = method
1802 self.handled.clear()
1803 msg = "sp\xe4m"
1804 logger.error(msg)
1805 self.handled.wait()
1806 self.assertEqual(self.log_data.path, '/frob')
1807 self.assertEqual(self.command, method)
1808 if method == 'GET':
1809 d = parse_qs(self.log_data.query)
1810 else:
1811 d = parse_qs(self.post_data.decode('utf-8'))
1812 self.assertEqual(d['name'], ['http'])
1813 self.assertEqual(d['funcName'], ['test_output'])
1814 self.assertEqual(d['msg'], [msg])
1815
1816 self.server.stop(2.0)
1817 self.root_logger.removeHandler(self.h_hdlr)
1818 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001819
Christian Heimes180510d2008-03-03 19:15:45 +00001820class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001821
Christian Heimes180510d2008-03-03 19:15:45 +00001822 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001823
Christian Heimes180510d2008-03-03 19:15:45 +00001824 def setUp(self):
1825 """Create a dict to remember potentially destroyed objects."""
1826 BaseTest.setUp(self)
1827 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001828
Christian Heimes180510d2008-03-03 19:15:45 +00001829 def _watch_for_survival(self, *args):
1830 """Watch the given objects for survival, by creating weakrefs to
1831 them."""
1832 for obj in args:
1833 key = id(obj), repr(obj)
1834 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001835
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001836 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001837 """Assert that all objects watched for survival have survived."""
1838 # Trigger cycle breaking.
1839 gc.collect()
1840 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001841 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001842 if ref() is None:
1843 dead.append(repr_)
1844 if dead:
1845 self.fail("%d objects should have survived "
1846 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001847
Christian Heimes180510d2008-03-03 19:15:45 +00001848 def test_persistent_loggers(self):
1849 # Logger objects are persistent and retain their configuration, even
1850 # if visible references are destroyed.
1851 self.root_logger.setLevel(logging.INFO)
1852 foo = logging.getLogger("foo")
1853 self._watch_for_survival(foo)
1854 foo.setLevel(logging.DEBUG)
1855 self.root_logger.debug(self.next_message())
1856 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001857 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001858 ('foo', 'DEBUG', '2'),
1859 ])
1860 del foo
1861 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001862 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001863 # foo has retained its settings.
1864 bar = logging.getLogger("foo")
1865 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001866 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001867 ('foo', 'DEBUG', '2'),
1868 ('foo', 'DEBUG', '3'),
1869 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001870
Benjamin Petersonf91df042009-02-13 02:50:59 +00001871
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001872class EncodingTest(BaseTest):
1873 def test_encoding_plain_file(self):
1874 # In Python 2.x, a plain file object is treated as having no encoding.
1875 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001876 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1877 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001878 # the non-ascii data we write to the log.
1879 data = "foo\x80"
1880 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001881 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001882 log.addHandler(handler)
1883 try:
1884 # write non-ascii data to the log.
1885 log.warning(data)
1886 finally:
1887 log.removeHandler(handler)
1888 handler.close()
1889 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001890 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001891 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001892 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001893 finally:
1894 f.close()
1895 finally:
1896 if os.path.isfile(fn):
1897 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001898
Benjamin Petersonf91df042009-02-13 02:50:59 +00001899 def test_encoding_cyrillic_unicode(self):
1900 log = logging.getLogger("test")
1901 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1902 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1903 #Ensure it's written in a Cyrillic encoding
1904 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001905 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001906 stream = io.BytesIO()
1907 writer = writer_class(stream, 'strict')
1908 handler = logging.StreamHandler(writer)
1909 log.addHandler(handler)
1910 try:
1911 log.warning(message)
1912 finally:
1913 log.removeHandler(handler)
1914 handler.close()
1915 # check we wrote exactly those bytes, ignoring trailing \n etc
1916 s = stream.getvalue()
1917 #Compare against what the data should be when encoded in CP-1251
1918 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1919
1920
Georg Brandlf9734072008-12-07 15:30:06 +00001921class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001922
Georg Brandlf9734072008-12-07 15:30:06 +00001923 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001924 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001925 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001926 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001927 warnings.filterwarnings("always", category=UserWarning)
1928 stream = io.StringIO()
1929 h = logging.StreamHandler(stream)
1930 logger = logging.getLogger("py.warnings")
1931 logger.addHandler(h)
1932 warnings.warn("I'm warning you...")
1933 logger.removeHandler(h)
1934 s = stream.getvalue()
1935 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001936 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001937
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001938 #See if an explicit file uses the original implementation
1939 a_file = io.StringIO()
1940 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1941 a_file, "Dummy line")
1942 s = a_file.getvalue()
1943 a_file.close()
1944 self.assertEqual(s,
1945 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1946
1947 def test_warnings_no_handlers(self):
1948 with warnings.catch_warnings():
1949 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001950 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001951
1952 # confirm our assumption: no loggers are set
1953 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001954 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001955
1956 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001957 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001958 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001959
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001960
1961def formatFunc(format, datefmt=None):
1962 return logging.Formatter(format, datefmt)
1963
1964def handlerFunc():
1965 return logging.StreamHandler()
1966
1967class CustomHandler(logging.StreamHandler):
1968 pass
1969
1970class ConfigDictTest(BaseTest):
1971
1972 """Reading logging config from a dictionary."""
1973
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001974 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001975
1976 # config0 is a standard configuration.
1977 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001978 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001979 'formatters': {
1980 'form1' : {
1981 'format' : '%(levelname)s ++ %(message)s',
1982 },
1983 },
1984 'handlers' : {
1985 'hand1' : {
1986 'class' : 'logging.StreamHandler',
1987 'formatter' : 'form1',
1988 'level' : 'NOTSET',
1989 'stream' : 'ext://sys.stdout',
1990 },
1991 },
1992 'root' : {
1993 'level' : 'WARNING',
1994 'handlers' : ['hand1'],
1995 },
1996 }
1997
1998 # config1 adds a little to the standard configuration.
1999 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002000 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002001 'formatters': {
2002 'form1' : {
2003 'format' : '%(levelname)s ++ %(message)s',
2004 },
2005 },
2006 'handlers' : {
2007 'hand1' : {
2008 'class' : 'logging.StreamHandler',
2009 'formatter' : 'form1',
2010 'level' : 'NOTSET',
2011 'stream' : 'ext://sys.stdout',
2012 },
2013 },
2014 'loggers' : {
2015 'compiler.parser' : {
2016 'level' : 'DEBUG',
2017 'handlers' : ['hand1'],
2018 },
2019 },
2020 'root' : {
2021 'level' : 'WARNING',
2022 },
2023 }
2024
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002025 # config1a moves the handler to the root. Used with config8a
2026 config1a = {
2027 'version': 1,
2028 'formatters': {
2029 'form1' : {
2030 'format' : '%(levelname)s ++ %(message)s',
2031 },
2032 },
2033 'handlers' : {
2034 'hand1' : {
2035 'class' : 'logging.StreamHandler',
2036 'formatter' : 'form1',
2037 'level' : 'NOTSET',
2038 'stream' : 'ext://sys.stdout',
2039 },
2040 },
2041 'loggers' : {
2042 'compiler.parser' : {
2043 'level' : 'DEBUG',
2044 },
2045 },
2046 'root' : {
2047 'level' : 'WARNING',
2048 'handlers' : ['hand1'],
2049 },
2050 }
2051
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002052 # config2 has a subtle configuration error that should be reported
2053 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002054 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002055 'formatters': {
2056 'form1' : {
2057 'format' : '%(levelname)s ++ %(message)s',
2058 },
2059 },
2060 'handlers' : {
2061 'hand1' : {
2062 'class' : 'logging.StreamHandler',
2063 'formatter' : 'form1',
2064 'level' : 'NOTSET',
2065 'stream' : 'ext://sys.stdbout',
2066 },
2067 },
2068 'loggers' : {
2069 'compiler.parser' : {
2070 'level' : 'DEBUG',
2071 'handlers' : ['hand1'],
2072 },
2073 },
2074 'root' : {
2075 'level' : 'WARNING',
2076 },
2077 }
2078
2079 #As config1 but with a misspelt level on a handler
2080 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002081 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002082 'formatters': {
2083 'form1' : {
2084 'format' : '%(levelname)s ++ %(message)s',
2085 },
2086 },
2087 'handlers' : {
2088 'hand1' : {
2089 'class' : 'logging.StreamHandler',
2090 'formatter' : 'form1',
2091 'level' : 'NTOSET',
2092 'stream' : 'ext://sys.stdout',
2093 },
2094 },
2095 'loggers' : {
2096 'compiler.parser' : {
2097 'level' : 'DEBUG',
2098 'handlers' : ['hand1'],
2099 },
2100 },
2101 'root' : {
2102 'level' : 'WARNING',
2103 },
2104 }
2105
2106
2107 #As config1 but with a misspelt level on a logger
2108 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002109 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002110 'formatters': {
2111 'form1' : {
2112 'format' : '%(levelname)s ++ %(message)s',
2113 },
2114 },
2115 'handlers' : {
2116 'hand1' : {
2117 'class' : 'logging.StreamHandler',
2118 'formatter' : 'form1',
2119 'level' : 'NOTSET',
2120 'stream' : 'ext://sys.stdout',
2121 },
2122 },
2123 'loggers' : {
2124 'compiler.parser' : {
2125 'level' : 'DEBUG',
2126 'handlers' : ['hand1'],
2127 },
2128 },
2129 'root' : {
2130 'level' : 'WRANING',
2131 },
2132 }
2133
2134 # config3 has a less subtle configuration error
2135 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002136 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002137 'formatters': {
2138 'form1' : {
2139 'format' : '%(levelname)s ++ %(message)s',
2140 },
2141 },
2142 'handlers' : {
2143 'hand1' : {
2144 'class' : 'logging.StreamHandler',
2145 'formatter' : 'misspelled_name',
2146 'level' : 'NOTSET',
2147 'stream' : 'ext://sys.stdout',
2148 },
2149 },
2150 'loggers' : {
2151 'compiler.parser' : {
2152 'level' : 'DEBUG',
2153 'handlers' : ['hand1'],
2154 },
2155 },
2156 'root' : {
2157 'level' : 'WARNING',
2158 },
2159 }
2160
2161 # config4 specifies a custom formatter class to be loaded
2162 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002163 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002164 'formatters': {
2165 'form1' : {
2166 '()' : __name__ + '.ExceptionFormatter',
2167 'format' : '%(levelname)s:%(name)s:%(message)s',
2168 },
2169 },
2170 'handlers' : {
2171 'hand1' : {
2172 'class' : 'logging.StreamHandler',
2173 'formatter' : 'form1',
2174 'level' : 'NOTSET',
2175 'stream' : 'ext://sys.stdout',
2176 },
2177 },
2178 'root' : {
2179 'level' : 'NOTSET',
2180 'handlers' : ['hand1'],
2181 },
2182 }
2183
2184 # As config4 but using an actual callable rather than a string
2185 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002186 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002187 'formatters': {
2188 'form1' : {
2189 '()' : ExceptionFormatter,
2190 'format' : '%(levelname)s:%(name)s:%(message)s',
2191 },
2192 'form2' : {
2193 '()' : __name__ + '.formatFunc',
2194 'format' : '%(levelname)s:%(name)s:%(message)s',
2195 },
2196 'form3' : {
2197 '()' : formatFunc,
2198 'format' : '%(levelname)s:%(name)s:%(message)s',
2199 },
2200 },
2201 'handlers' : {
2202 'hand1' : {
2203 'class' : 'logging.StreamHandler',
2204 'formatter' : 'form1',
2205 'level' : 'NOTSET',
2206 'stream' : 'ext://sys.stdout',
2207 },
2208 'hand2' : {
2209 '()' : handlerFunc,
2210 },
2211 },
2212 'root' : {
2213 'level' : 'NOTSET',
2214 'handlers' : ['hand1'],
2215 },
2216 }
2217
2218 # config5 specifies a custom handler class to be loaded
2219 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002220 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002221 'formatters': {
2222 'form1' : {
2223 'format' : '%(levelname)s ++ %(message)s',
2224 },
2225 },
2226 'handlers' : {
2227 'hand1' : {
2228 'class' : __name__ + '.CustomHandler',
2229 'formatter' : 'form1',
2230 'level' : 'NOTSET',
2231 'stream' : 'ext://sys.stdout',
2232 },
2233 },
2234 'loggers' : {
2235 'compiler.parser' : {
2236 'level' : 'DEBUG',
2237 'handlers' : ['hand1'],
2238 },
2239 },
2240 'root' : {
2241 'level' : 'WARNING',
2242 },
2243 }
2244
2245 # config6 specifies a custom handler class to be loaded
2246 # but has bad arguments
2247 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002248 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002249 'formatters': {
2250 'form1' : {
2251 'format' : '%(levelname)s ++ %(message)s',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : __name__ + '.CustomHandler',
2257 'formatter' : 'form1',
2258 'level' : 'NOTSET',
2259 'stream' : 'ext://sys.stdout',
2260 '9' : 'invalid parameter name',
2261 },
2262 },
2263 'loggers' : {
2264 'compiler.parser' : {
2265 'level' : 'DEBUG',
2266 'handlers' : ['hand1'],
2267 },
2268 },
2269 'root' : {
2270 'level' : 'WARNING',
2271 },
2272 }
2273
2274 #config 7 does not define compiler.parser but defines compiler.lexer
2275 #so compiler.parser should be disabled after applying it
2276 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002277 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002278 'formatters': {
2279 'form1' : {
2280 'format' : '%(levelname)s ++ %(message)s',
2281 },
2282 },
2283 'handlers' : {
2284 'hand1' : {
2285 'class' : 'logging.StreamHandler',
2286 'formatter' : 'form1',
2287 'level' : 'NOTSET',
2288 'stream' : 'ext://sys.stdout',
2289 },
2290 },
2291 'loggers' : {
2292 'compiler.lexer' : {
2293 'level' : 'DEBUG',
2294 'handlers' : ['hand1'],
2295 },
2296 },
2297 'root' : {
2298 'level' : 'WARNING',
2299 },
2300 }
2301
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002302 # config8 defines both compiler and compiler.lexer
2303 # so compiler.parser should not be disabled (since
2304 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002305 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002306 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002307 'disable_existing_loggers' : False,
2308 'formatters': {
2309 'form1' : {
2310 'format' : '%(levelname)s ++ %(message)s',
2311 },
2312 },
2313 'handlers' : {
2314 'hand1' : {
2315 'class' : 'logging.StreamHandler',
2316 'formatter' : 'form1',
2317 'level' : 'NOTSET',
2318 'stream' : 'ext://sys.stdout',
2319 },
2320 },
2321 'loggers' : {
2322 'compiler' : {
2323 'level' : 'DEBUG',
2324 'handlers' : ['hand1'],
2325 },
2326 'compiler.lexer' : {
2327 },
2328 },
2329 'root' : {
2330 'level' : 'WARNING',
2331 },
2332 }
2333
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002334 # config8a disables existing loggers
2335 config8a = {
2336 'version': 1,
2337 'disable_existing_loggers' : True,
2338 'formatters': {
2339 'form1' : {
2340 'format' : '%(levelname)s ++ %(message)s',
2341 },
2342 },
2343 'handlers' : {
2344 'hand1' : {
2345 'class' : 'logging.StreamHandler',
2346 'formatter' : 'form1',
2347 'level' : 'NOTSET',
2348 'stream' : 'ext://sys.stdout',
2349 },
2350 },
2351 'loggers' : {
2352 'compiler' : {
2353 'level' : 'DEBUG',
2354 'handlers' : ['hand1'],
2355 },
2356 'compiler.lexer' : {
2357 },
2358 },
2359 'root' : {
2360 'level' : 'WARNING',
2361 },
2362 }
2363
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002364 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002365 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002366 'formatters': {
2367 'form1' : {
2368 'format' : '%(levelname)s ++ %(message)s',
2369 },
2370 },
2371 'handlers' : {
2372 'hand1' : {
2373 'class' : 'logging.StreamHandler',
2374 'formatter' : 'form1',
2375 'level' : 'WARNING',
2376 'stream' : 'ext://sys.stdout',
2377 },
2378 },
2379 'loggers' : {
2380 'compiler.parser' : {
2381 'level' : 'WARNING',
2382 'handlers' : ['hand1'],
2383 },
2384 },
2385 'root' : {
2386 'level' : 'NOTSET',
2387 },
2388 }
2389
2390 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002391 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002392 'incremental' : True,
2393 'handlers' : {
2394 'hand1' : {
2395 'level' : 'WARNING',
2396 },
2397 },
2398 'loggers' : {
2399 'compiler.parser' : {
2400 'level' : 'INFO',
2401 },
2402 },
2403 }
2404
2405 config9b = {
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' : 'INFO',
2411 },
2412 },
2413 'loggers' : {
2414 'compiler.parser' : {
2415 'level' : 'INFO',
2416 },
2417 },
2418 }
2419
2420 #As config1 but with a filter added
2421 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002422 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002423 'formatters': {
2424 'form1' : {
2425 'format' : '%(levelname)s ++ %(message)s',
2426 },
2427 },
2428 'filters' : {
2429 'filt1' : {
2430 'name' : 'compiler.parser',
2431 },
2432 },
2433 'handlers' : {
2434 'hand1' : {
2435 'class' : 'logging.StreamHandler',
2436 'formatter' : 'form1',
2437 'level' : 'NOTSET',
2438 'stream' : 'ext://sys.stdout',
2439 'filters' : ['filt1'],
2440 },
2441 },
2442 'loggers' : {
2443 'compiler.parser' : {
2444 'level' : 'DEBUG',
2445 'filters' : ['filt1'],
2446 },
2447 },
2448 'root' : {
2449 'level' : 'WARNING',
2450 'handlers' : ['hand1'],
2451 },
2452 }
2453
2454 #As config1 but using cfg:// references
2455 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002456 'version': 1,
2457 'true_formatters': {
2458 'form1' : {
2459 'format' : '%(levelname)s ++ %(message)s',
2460 },
2461 },
2462 'handler_configs': {
2463 'hand1' : {
2464 'class' : 'logging.StreamHandler',
2465 'formatter' : 'form1',
2466 'level' : 'NOTSET',
2467 'stream' : 'ext://sys.stdout',
2468 },
2469 },
2470 'formatters' : 'cfg://true_formatters',
2471 'handlers' : {
2472 'hand1' : 'cfg://handler_configs[hand1]',
2473 },
2474 'loggers' : {
2475 'compiler.parser' : {
2476 'level' : 'DEBUG',
2477 'handlers' : ['hand1'],
2478 },
2479 },
2480 'root' : {
2481 'level' : 'WARNING',
2482 },
2483 }
2484
2485 #As config11 but missing the version key
2486 config12 = {
2487 'true_formatters': {
2488 'form1' : {
2489 'format' : '%(levelname)s ++ %(message)s',
2490 },
2491 },
2492 'handler_configs': {
2493 'hand1' : {
2494 'class' : 'logging.StreamHandler',
2495 'formatter' : 'form1',
2496 'level' : 'NOTSET',
2497 'stream' : 'ext://sys.stdout',
2498 },
2499 },
2500 'formatters' : 'cfg://true_formatters',
2501 'handlers' : {
2502 'hand1' : 'cfg://handler_configs[hand1]',
2503 },
2504 'loggers' : {
2505 'compiler.parser' : {
2506 'level' : 'DEBUG',
2507 'handlers' : ['hand1'],
2508 },
2509 },
2510 'root' : {
2511 'level' : 'WARNING',
2512 },
2513 }
2514
2515 #As config11 but using an unsupported version
2516 config13 = {
2517 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002518 'true_formatters': {
2519 'form1' : {
2520 'format' : '%(levelname)s ++ %(message)s',
2521 },
2522 },
2523 'handler_configs': {
2524 'hand1' : {
2525 'class' : 'logging.StreamHandler',
2526 'formatter' : 'form1',
2527 'level' : 'NOTSET',
2528 'stream' : 'ext://sys.stdout',
2529 },
2530 },
2531 'formatters' : 'cfg://true_formatters',
2532 'handlers' : {
2533 'hand1' : 'cfg://handler_configs[hand1]',
2534 },
2535 'loggers' : {
2536 'compiler.parser' : {
2537 'level' : 'DEBUG',
2538 'handlers' : ['hand1'],
2539 },
2540 },
2541 'root' : {
2542 'level' : 'WARNING',
2543 },
2544 }
2545
Vinay Sajip8d270232012-11-15 14:20:18 +00002546 # As config0, but with properties
2547 config14 = {
2548 'version': 1,
2549 'formatters': {
2550 'form1' : {
2551 'format' : '%(levelname)s ++ %(message)s',
2552 },
2553 },
2554 'handlers' : {
2555 'hand1' : {
2556 'class' : 'logging.StreamHandler',
2557 'formatter' : 'form1',
2558 'level' : 'NOTSET',
2559 'stream' : 'ext://sys.stdout',
2560 '.': {
2561 'foo': 'bar',
2562 'terminator': '!\n',
2563 }
2564 },
2565 },
2566 'root' : {
2567 'level' : 'WARNING',
2568 'handlers' : ['hand1'],
2569 },
2570 }
2571
Vinay Sajip3f885b52013-03-22 15:19:54 +00002572 out_of_order = {
2573 "version": 1,
2574 "formatters": {
2575 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002576 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2577 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002578 }
2579 },
2580 "handlers": {
2581 "fileGlobal": {
2582 "class": "logging.StreamHandler",
2583 "level": "DEBUG",
2584 "formatter": "mySimpleFormatter"
2585 },
2586 "bufferGlobal": {
2587 "class": "logging.handlers.MemoryHandler",
2588 "capacity": 5,
2589 "formatter": "mySimpleFormatter",
2590 "target": "fileGlobal",
2591 "level": "DEBUG"
2592 }
2593 },
2594 "loggers": {
2595 "mymodule": {
2596 "level": "DEBUG",
2597 "handlers": ["bufferGlobal"],
2598 "propagate": "true"
2599 }
2600 }
2601 }
2602
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002603 def apply_config(self, conf):
2604 logging.config.dictConfig(conf)
2605
2606 def test_config0_ok(self):
2607 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002608 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002609 self.apply_config(self.config0)
2610 logger = logging.getLogger()
2611 # Won't output anything
2612 logger.info(self.next_message())
2613 # Outputs a message
2614 logger.error(self.next_message())
2615 self.assert_log_lines([
2616 ('ERROR', '2'),
2617 ], stream=output)
2618 # Original logger output is empty.
2619 self.assert_log_lines([])
2620
2621 def test_config1_ok(self, config=config1):
2622 # A config defining a sub-parser as well.
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(config)
2625 logger = logging.getLogger("compiler.parser")
2626 # Both will output a message
2627 logger.info(self.next_message())
2628 logger.error(self.next_message())
2629 self.assert_log_lines([
2630 ('INFO', '1'),
2631 ('ERROR', '2'),
2632 ], stream=output)
2633 # Original logger output is empty.
2634 self.assert_log_lines([])
2635
2636 def test_config2_failure(self):
2637 # A simple config which overrides the default settings.
2638 self.assertRaises(Exception, self.apply_config, self.config2)
2639
2640 def test_config2a_failure(self):
2641 # A simple config which overrides the default settings.
2642 self.assertRaises(Exception, self.apply_config, self.config2a)
2643
2644 def test_config2b_failure(self):
2645 # A simple config which overrides the default settings.
2646 self.assertRaises(Exception, self.apply_config, self.config2b)
2647
2648 def test_config3_failure(self):
2649 # A simple config which overrides the default settings.
2650 self.assertRaises(Exception, self.apply_config, self.config3)
2651
2652 def test_config4_ok(self):
2653 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002654 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002655 self.apply_config(self.config4)
2656 #logger = logging.getLogger()
2657 try:
2658 raise RuntimeError()
2659 except RuntimeError:
2660 logging.exception("just testing")
2661 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002662 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002663 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2664 # Original logger output is empty
2665 self.assert_log_lines([])
2666
2667 def test_config4a_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.config4a)
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_config5_ok(self):
2683 self.test_config1_ok(config=self.config5)
2684
2685 def test_config6_failure(self):
2686 self.assertRaises(Exception, self.apply_config, self.config6)
2687
2688 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002689 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002690 self.apply_config(self.config1)
2691 logger = logging.getLogger("compiler.parser")
2692 # Both will output a message
2693 logger.info(self.next_message())
2694 logger.error(self.next_message())
2695 self.assert_log_lines([
2696 ('INFO', '1'),
2697 ('ERROR', '2'),
2698 ], stream=output)
2699 # Original logger output is empty.
2700 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002701 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002702 self.apply_config(self.config7)
2703 logger = logging.getLogger("compiler.parser")
2704 self.assertTrue(logger.disabled)
2705 logger = logging.getLogger("compiler.lexer")
2706 # Both will output a message
2707 logger.info(self.next_message())
2708 logger.error(self.next_message())
2709 self.assert_log_lines([
2710 ('INFO', '3'),
2711 ('ERROR', '4'),
2712 ], stream=output)
2713 # Original logger output is empty.
2714 self.assert_log_lines([])
2715
2716 #Same as test_config_7_ok but don't disable old loggers.
2717 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002718 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002719 self.apply_config(self.config1)
2720 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002721 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002722 logger.info(self.next_message())
2723 logger.error(self.next_message())
2724 self.assert_log_lines([
2725 ('INFO', '1'),
2726 ('ERROR', '2'),
2727 ], stream=output)
2728 # Original logger output is empty.
2729 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002730 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002731 self.apply_config(self.config8)
2732 logger = logging.getLogger("compiler.parser")
2733 self.assertFalse(logger.disabled)
2734 # Both will output a message
2735 logger.info(self.next_message())
2736 logger.error(self.next_message())
2737 logger = logging.getLogger("compiler.lexer")
2738 # Both will output a message
2739 logger.info(self.next_message())
2740 logger.error(self.next_message())
2741 self.assert_log_lines([
2742 ('INFO', '3'),
2743 ('ERROR', '4'),
2744 ('INFO', '5'),
2745 ('ERROR', '6'),
2746 ], stream=output)
2747 # Original logger output is empty.
2748 self.assert_log_lines([])
2749
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002750 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002751 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002752 self.apply_config(self.config1a)
2753 logger = logging.getLogger("compiler.parser")
2754 # See issue #11424. compiler-hyphenated sorts
2755 # between compiler and compiler.xyz and this
2756 # was preventing compiler.xyz from being included
2757 # in the child loggers of compiler because of an
2758 # overzealous loop termination condition.
2759 hyphenated = logging.getLogger('compiler-hyphenated')
2760 # All will output a message
2761 logger.info(self.next_message())
2762 logger.error(self.next_message())
2763 hyphenated.critical(self.next_message())
2764 self.assert_log_lines([
2765 ('INFO', '1'),
2766 ('ERROR', '2'),
2767 ('CRITICAL', '3'),
2768 ], stream=output)
2769 # Original logger output is empty.
2770 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002771 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002772 self.apply_config(self.config8a)
2773 logger = logging.getLogger("compiler.parser")
2774 self.assertFalse(logger.disabled)
2775 # Both will output a message
2776 logger.info(self.next_message())
2777 logger.error(self.next_message())
2778 logger = logging.getLogger("compiler.lexer")
2779 # Both will output a message
2780 logger.info(self.next_message())
2781 logger.error(self.next_message())
2782 # Will not appear
2783 hyphenated.critical(self.next_message())
2784 self.assert_log_lines([
2785 ('INFO', '4'),
2786 ('ERROR', '5'),
2787 ('INFO', '6'),
2788 ('ERROR', '7'),
2789 ], stream=output)
2790 # Original logger output is empty.
2791 self.assert_log_lines([])
2792
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002793 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002794 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002795 self.apply_config(self.config9)
2796 logger = logging.getLogger("compiler.parser")
2797 #Nothing will be output since both handler and logger are set to WARNING
2798 logger.info(self.next_message())
2799 self.assert_log_lines([], stream=output)
2800 self.apply_config(self.config9a)
2801 #Nothing will be output since both handler is still set to WARNING
2802 logger.info(self.next_message())
2803 self.assert_log_lines([], stream=output)
2804 self.apply_config(self.config9b)
2805 #Message should now be output
2806 logger.info(self.next_message())
2807 self.assert_log_lines([
2808 ('INFO', '3'),
2809 ], stream=output)
2810
2811 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002812 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002813 self.apply_config(self.config10)
2814 logger = logging.getLogger("compiler.parser")
2815 logger.warning(self.next_message())
2816 logger = logging.getLogger('compiler')
2817 #Not output, because filtered
2818 logger.warning(self.next_message())
2819 logger = logging.getLogger('compiler.lexer')
2820 #Not output, because filtered
2821 logger.warning(self.next_message())
2822 logger = logging.getLogger("compiler.parser.codegen")
2823 #Output, as not filtered
2824 logger.error(self.next_message())
2825 self.assert_log_lines([
2826 ('WARNING', '1'),
2827 ('ERROR', '4'),
2828 ], stream=output)
2829
2830 def test_config11_ok(self):
2831 self.test_config1_ok(self.config11)
2832
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002833 def test_config12_failure(self):
2834 self.assertRaises(Exception, self.apply_config, self.config12)
2835
2836 def test_config13_failure(self):
2837 self.assertRaises(Exception, self.apply_config, self.config13)
2838
Vinay Sajip8d270232012-11-15 14:20:18 +00002839 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002840 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002841 self.apply_config(self.config14)
2842 h = logging._handlers['hand1']
2843 self.assertEqual(h.foo, 'bar')
2844 self.assertEqual(h.terminator, '!\n')
2845 logging.warning('Exclamation')
2846 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2847
Victor Stinner45df8202010-04-28 22:31:17 +00002848 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002849 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002850 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002851 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002852 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002853 t.start()
2854 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002855 # Now get the port allocated
2856 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002857 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002858 try:
2859 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2860 sock.settimeout(2.0)
2861 sock.connect(('localhost', port))
2862
2863 slen = struct.pack('>L', len(text))
2864 s = slen + text
2865 sentsofar = 0
2866 left = len(s)
2867 while left > 0:
2868 sent = sock.send(s[sentsofar:])
2869 sentsofar += sent
2870 left -= sent
2871 sock.close()
2872 finally:
2873 t.ready.wait(2.0)
2874 logging.config.stopListening()
2875 t.join(2.0)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002876 if t.is_alive():
2877 self.fail("join() timed out")
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002878
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002879 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002880 @support.reap_threads
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002881 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002882 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002883 self.setup_via_listener(json.dumps(self.config10))
2884 logger = logging.getLogger("compiler.parser")
2885 logger.warning(self.next_message())
2886 logger = logging.getLogger('compiler')
2887 #Not output, because filtered
2888 logger.warning(self.next_message())
2889 logger = logging.getLogger('compiler.lexer')
2890 #Not output, because filtered
2891 logger.warning(self.next_message())
2892 logger = logging.getLogger("compiler.parser.codegen")
2893 #Output, as not filtered
2894 logger.error(self.next_message())
2895 self.assert_log_lines([
2896 ('WARNING', '1'),
2897 ('ERROR', '4'),
2898 ], stream=output)
2899
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002900 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002901 @support.reap_threads
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002902 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002903 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002904 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2905 logger = logging.getLogger("compiler.parser")
2906 # Both will output a message
2907 logger.info(self.next_message())
2908 logger.error(self.next_message())
2909 self.assert_log_lines([
2910 ('INFO', '1'),
2911 ('ERROR', '2'),
2912 ], stream=output)
2913 # Original logger output is empty.
2914 self.assert_log_lines([])
2915
Vinay Sajip4ded5512012-10-02 15:56:16 +01002916 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002917 @support.reap_threads
Vinay Sajip4ded5512012-10-02 15:56:16 +01002918 def test_listen_verify(self):
2919
2920 def verify_fail(stuff):
2921 return None
2922
2923 def verify_reverse(stuff):
2924 return stuff[::-1]
2925
2926 logger = logging.getLogger("compiler.parser")
2927 to_send = textwrap.dedent(ConfigFileTest.config1)
2928 # First, specify a verification function that will fail.
2929 # We expect to see no output, since our configuration
2930 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002931 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002932 self.setup_via_listener(to_send, verify_fail)
2933 # Both will output a message
2934 logger.info(self.next_message())
2935 logger.error(self.next_message())
2936 self.assert_log_lines([], stream=output)
2937 # Original logger output has the stuff we logged.
2938 self.assert_log_lines([
2939 ('INFO', '1'),
2940 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002941 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002942
2943 # Now, perform no verification. Our configuration
2944 # should take effect.
2945
Vinay Sajip1feedb42014-05-31 08:19:12 +01002946 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002947 self.setup_via_listener(to_send) # no verify callable specified
2948 logger = logging.getLogger("compiler.parser")
2949 # Both will output a message
2950 logger.info(self.next_message())
2951 logger.error(self.next_message())
2952 self.assert_log_lines([
2953 ('INFO', '3'),
2954 ('ERROR', '4'),
2955 ], stream=output)
2956 # Original logger output still has the stuff we logged before.
2957 self.assert_log_lines([
2958 ('INFO', '1'),
2959 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002960 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002961
2962 # Now, perform verification which transforms the bytes.
2963
Vinay Sajip1feedb42014-05-31 08:19:12 +01002964 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002965 self.setup_via_listener(to_send[::-1], verify_reverse)
2966 logger = logging.getLogger("compiler.parser")
2967 # Both will output a message
2968 logger.info(self.next_message())
2969 logger.error(self.next_message())
2970 self.assert_log_lines([
2971 ('INFO', '5'),
2972 ('ERROR', '6'),
2973 ], stream=output)
2974 # Original logger output still has the stuff we logged before.
2975 self.assert_log_lines([
2976 ('INFO', '1'),
2977 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002978 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002979
Vinay Sajip3f885b52013-03-22 15:19:54 +00002980 def test_out_of_order(self):
2981 self.apply_config(self.out_of_order)
2982 handler = logging.getLogger('mymodule').handlers[0]
2983 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002984 self.assertIsInstance(handler.formatter._style,
2985 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002986
Vinay Sajip373baef2011-04-26 20:05:24 +01002987 def test_baseconfig(self):
2988 d = {
2989 'atuple': (1, 2, 3),
2990 'alist': ['a', 'b', 'c'],
2991 'adict': {'d': 'e', 'f': 3 },
2992 'nest1': ('g', ('h', 'i'), 'j'),
2993 'nest2': ['k', ['l', 'm'], 'n'],
2994 'nest3': ['o', 'cfg://alist', 'p'],
2995 }
2996 bc = logging.config.BaseConfigurator(d)
2997 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2998 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2999 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3000 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3001 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3002 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3003 v = bc.convert('cfg://nest3')
3004 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3005 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3006 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3007 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003008
3009class ManagerTest(BaseTest):
3010 def test_manager_loggerclass(self):
3011 logged = []
3012
3013 class MyLogger(logging.Logger):
3014 def _log(self, level, msg, args, exc_info=None, extra=None):
3015 logged.append(msg)
3016
3017 man = logging.Manager(None)
3018 self.assertRaises(TypeError, man.setLoggerClass, int)
3019 man.setLoggerClass(MyLogger)
3020 logger = man.getLogger('test')
3021 logger.warning('should appear in logged')
3022 logging.warning('should not appear in logged')
3023
3024 self.assertEqual(logged, ['should appear in logged'])
3025
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003026 def test_set_log_record_factory(self):
3027 man = logging.Manager(None)
3028 expected = object()
3029 man.setLogRecordFactory(expected)
3030 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003031
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003032class ChildLoggerTest(BaseTest):
3033 def test_child_loggers(self):
3034 r = logging.getLogger()
3035 l1 = logging.getLogger('abc')
3036 l2 = logging.getLogger('def.ghi')
3037 c1 = r.getChild('xyz')
3038 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003039 self.assertIs(c1, logging.getLogger('xyz'))
3040 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003041 c1 = l1.getChild('def')
3042 c2 = c1.getChild('ghi')
3043 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003044 self.assertIs(c1, logging.getLogger('abc.def'))
3045 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3046 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003047
3048
Vinay Sajip6fac8172010-10-19 20:44:14 +00003049class DerivedLogRecord(logging.LogRecord):
3050 pass
3051
Vinay Sajip61561522010-12-03 11:50:38 +00003052class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003053
3054 def setUp(self):
3055 class CheckingFilter(logging.Filter):
3056 def __init__(self, cls):
3057 self.cls = cls
3058
3059 def filter(self, record):
3060 t = type(record)
3061 if t is not self.cls:
3062 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3063 self.cls)
3064 raise TypeError(msg)
3065 return True
3066
3067 BaseTest.setUp(self)
3068 self.filter = CheckingFilter(DerivedLogRecord)
3069 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003070 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003071
3072 def tearDown(self):
3073 self.root_logger.removeFilter(self.filter)
3074 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003075 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003076
3077 def test_logrecord_class(self):
3078 self.assertRaises(TypeError, self.root_logger.warning,
3079 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003080 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003081 self.root_logger.error(self.next_message())
3082 self.assert_log_lines([
3083 ('root', 'ERROR', '2'),
3084 ])
3085
3086
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003087class QueueHandlerTest(BaseTest):
3088 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003089 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003090
3091 def setUp(self):
3092 BaseTest.setUp(self)
3093 self.queue = queue.Queue(-1)
3094 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3095 self.que_logger = logging.getLogger('que')
3096 self.que_logger.propagate = False
3097 self.que_logger.setLevel(logging.WARNING)
3098 self.que_logger.addHandler(self.que_hdlr)
3099
3100 def tearDown(self):
3101 self.que_hdlr.close()
3102 BaseTest.tearDown(self)
3103
3104 def test_queue_handler(self):
3105 self.que_logger.debug(self.next_message())
3106 self.assertRaises(queue.Empty, self.queue.get_nowait)
3107 self.que_logger.info(self.next_message())
3108 self.assertRaises(queue.Empty, self.queue.get_nowait)
3109 msg = self.next_message()
3110 self.que_logger.warning(msg)
3111 data = self.queue.get_nowait()
3112 self.assertTrue(isinstance(data, logging.LogRecord))
3113 self.assertEqual(data.name, self.que_logger.name)
3114 self.assertEqual((data.msg, data.args), (msg, None))
3115
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003116 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3117 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003118 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003119 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003120 listener = logging.handlers.QueueListener(self.queue, handler)
3121 listener.start()
3122 try:
3123 self.que_logger.warning(self.next_message())
3124 self.que_logger.error(self.next_message())
3125 self.que_logger.critical(self.next_message())
3126 finally:
3127 listener.stop()
3128 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3129 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3130 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003131 handler.close()
3132
3133 # Now test with respect_handler_level set
3134
3135 handler = support.TestHandler(support.Matcher())
3136 handler.setLevel(logging.CRITICAL)
3137 listener = logging.handlers.QueueListener(self.queue, handler,
3138 respect_handler_level=True)
3139 listener.start()
3140 try:
3141 self.que_logger.warning(self.next_message())
3142 self.que_logger.error(self.next_message())
3143 self.que_logger.critical(self.next_message())
3144 finally:
3145 listener.stop()
3146 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3147 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3148 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3149
Vinay Sajipd61910c2016-09-08 01:13:39 +01003150if hasattr(logging.handlers, 'QueueListener'):
3151 import multiprocessing
3152 from unittest.mock import patch
3153
3154 class QueueListenerTest(BaseTest):
3155 """
3156 Tests based on patch submitted for issue #27930. Ensure that
3157 QueueListener handles all log messages.
3158 """
3159
3160 repeat = 20
3161
3162 @staticmethod
3163 def setup_and_log(log_queue, ident):
3164 """
3165 Creates a logger with a QueueHandler that logs to a queue read by a
3166 QueueListener. Starts the listener, logs five messages, and stops
3167 the listener.
3168 """
3169 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3170 logger.setLevel(logging.DEBUG)
3171 handler = logging.handlers.QueueHandler(log_queue)
3172 logger.addHandler(handler)
3173 listener = logging.handlers.QueueListener(log_queue)
3174 listener.start()
3175
3176 logger.info('one')
3177 logger.info('two')
3178 logger.info('three')
3179 logger.info('four')
3180 logger.info('five')
3181
3182 listener.stop()
3183 logger.removeHandler(handler)
3184 handler.close()
3185
3186 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003187 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003188 def test_handle_called_with_queue_queue(self, mock_handle):
3189 for i in range(self.repeat):
3190 log_queue = queue.Queue()
3191 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3192 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3193 'correct number of handled log messages')
3194
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003195 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003196 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003197 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003198 def test_handle_called_with_mp_queue(self, mock_handle):
3199 for i in range(self.repeat):
3200 log_queue = multiprocessing.Queue()
3201 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003202 log_queue.close()
3203 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003204 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3205 'correct number of handled log messages')
3206
3207 @staticmethod
3208 def get_all_from_queue(log_queue):
3209 try:
3210 while True:
3211 yield log_queue.get_nowait()
3212 except queue.Empty:
3213 return []
3214
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003215 @support.requires_multiprocessing_queue
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003216 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003217 def test_no_messages_in_queue_after_stop(self):
3218 """
3219 Five messages are logged then the QueueListener is stopped. This
3220 test then gets everything off the queue. Failure of this test
3221 indicates that messages were not registered on the queue until
3222 _after_ the QueueListener stopped.
3223 """
3224 for i in range(self.repeat):
3225 queue = multiprocessing.Queue()
3226 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3227 # time.sleep(1)
3228 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003229 queue.close()
3230 queue.join_thread()
3231
Vinay Sajipd61910c2016-09-08 01:13:39 +01003232 expected = [[], [logging.handlers.QueueListener._sentinel]]
3233 self.assertIn(items, expected,
3234 'Found unexpected messages in queue: %s' % (
3235 [m.msg if isinstance(m, logging.LogRecord)
3236 else m for m in items]))
3237
Vinay Sajipe723e962011-04-15 22:27:17 +01003238
Vinay Sajip37eb3382011-04-26 20:26:41 +01003239ZERO = datetime.timedelta(0)
3240
3241class UTC(datetime.tzinfo):
3242 def utcoffset(self, dt):
3243 return ZERO
3244
3245 dst = utcoffset
3246
3247 def tzname(self, dt):
3248 return 'UTC'
3249
3250utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003251
Vinay Sajipa39c5712010-10-25 13:57:39 +00003252class FormatterTest(unittest.TestCase):
3253 def setUp(self):
3254 self.common = {
3255 'name': 'formatter.test',
3256 'level': logging.DEBUG,
3257 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3258 'lineno': 42,
3259 'exc_info': None,
3260 'func': None,
3261 'msg': 'Message with %d %s',
3262 'args': (2, 'placeholders'),
3263 }
3264 self.variants = {
3265 }
3266
3267 def get_record(self, name=None):
3268 result = dict(self.common)
3269 if name is not None:
3270 result.update(self.variants[name])
3271 return logging.makeLogRecord(result)
3272
3273 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003274 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003275 r = self.get_record()
3276 f = logging.Formatter('${%(message)s}')
3277 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3278 f = logging.Formatter('%(random)s')
3279 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003280 self.assertFalse(f.usesTime())
3281 f = logging.Formatter('%(asctime)s')
3282 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003283 f = logging.Formatter('%(asctime)-15s')
3284 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003285 f = logging.Formatter('asctime')
3286 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003287
3288 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003289 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003290 r = self.get_record()
3291 f = logging.Formatter('$%{message}%$', style='{')
3292 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3293 f = logging.Formatter('{random}', style='{')
3294 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003295 self.assertFalse(f.usesTime())
3296 f = logging.Formatter('{asctime}', style='{')
3297 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003298 f = logging.Formatter('{asctime!s:15}', style='{')
3299 self.assertTrue(f.usesTime())
3300 f = logging.Formatter('{asctime:15}', style='{')
3301 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003302 f = logging.Formatter('asctime', style='{')
3303 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003304
3305 def test_dollars(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('$$%${message}%$$', style='$')
3311 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3312 f = logging.Formatter('${random}', style='$')
3313 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003314 self.assertFalse(f.usesTime())
3315 f = logging.Formatter('${asctime}', style='$')
3316 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003317 f = logging.Formatter('${asctime', style='$')
3318 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003319 f = logging.Formatter('$asctime', style='$')
3320 self.assertTrue(f.usesTime())
3321 f = logging.Formatter('asctime', style='$')
3322 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003323
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003324 def test_invalid_style(self):
3325 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3326
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003327 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003328 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003329 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3330 # We use None to indicate we want the local timezone
3331 # We're essentially converting a UTC time to local time
3332 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003333 r.msecs = 123
3334 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003335 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003336 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3337 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003338 f.format(r)
3339 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3340
3341class TestBufferingFormatter(logging.BufferingFormatter):
3342 def formatHeader(self, records):
3343 return '[(%d)' % len(records)
3344
3345 def formatFooter(self, records):
3346 return '(%d)]' % len(records)
3347
3348class BufferingFormatterTest(unittest.TestCase):
3349 def setUp(self):
3350 self.records = [
3351 logging.makeLogRecord({'msg': 'one'}),
3352 logging.makeLogRecord({'msg': 'two'}),
3353 ]
3354
3355 def test_default(self):
3356 f = logging.BufferingFormatter()
3357 self.assertEqual('', f.format([]))
3358 self.assertEqual('onetwo', f.format(self.records))
3359
3360 def test_custom(self):
3361 f = TestBufferingFormatter()
3362 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3363 lf = logging.Formatter('<%(message)s>')
3364 f = TestBufferingFormatter(lf)
3365 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003366
3367class ExceptionTest(BaseTest):
3368 def test_formatting(self):
3369 r = self.root_logger
3370 h = RecordingHandler()
3371 r.addHandler(h)
3372 try:
3373 raise RuntimeError('deliberate mistake')
3374 except:
3375 logging.exception('failed', stack_info=True)
3376 r.removeHandler(h)
3377 h.close()
3378 r = h.records[0]
3379 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3380 'call last):\n'))
3381 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3382 'deliberate mistake'))
3383 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3384 'call last):\n'))
3385 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3386 'stack_info=True)'))
3387
3388
Vinay Sajip5a27d402010-12-10 11:42:57 +00003389class LastResortTest(BaseTest):
3390 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003391 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003392 root = self.root_logger
3393 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003394 old_lastresort = logging.lastResort
3395 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003396
Vinay Sajip5a27d402010-12-10 11:42:57 +00003397 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003398 with support.captured_stderr() as stderr:
3399 root.debug('This should not appear')
3400 self.assertEqual(stderr.getvalue(), '')
3401 root.warning('Final chance!')
3402 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3403
3404 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003405 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003406 with support.captured_stderr() as stderr:
3407 root.warning('Final chance!')
3408 msg = 'No handlers could be found for logger "root"\n'
3409 self.assertEqual(stderr.getvalue(), msg)
3410
Vinay Sajip5a27d402010-12-10 11:42:57 +00003411 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003412 with support.captured_stderr() as stderr:
3413 root.warning('Final chance!')
3414 self.assertEqual(stderr.getvalue(), '')
3415
3416 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003417 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003418 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003419 with support.captured_stderr() as stderr:
3420 root.warning('Final chance!')
3421 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003422 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003423 root.addHandler(self.root_hdlr)
3424 logging.lastResort = old_lastresort
3425 logging.raiseExceptions = old_raise_exceptions
3426
3427
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003428class FakeHandler:
3429
3430 def __init__(self, identifier, called):
3431 for method in ('acquire', 'flush', 'close', 'release'):
3432 setattr(self, method, self.record_call(identifier, method, called))
3433
3434 def record_call(self, identifier, method_name, called):
3435 def inner():
3436 called.append('{} - {}'.format(identifier, method_name))
3437 return inner
3438
3439
3440class RecordingHandler(logging.NullHandler):
3441
3442 def __init__(self, *args, **kwargs):
3443 super(RecordingHandler, self).__init__(*args, **kwargs)
3444 self.records = []
3445
3446 def handle(self, record):
3447 """Keep track of all the emitted records."""
3448 self.records.append(record)
3449
3450
3451class ShutdownTest(BaseTest):
3452
Vinay Sajip5e66b162011-04-20 15:41:14 +01003453 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003454
3455 def setUp(self):
3456 super(ShutdownTest, self).setUp()
3457 self.called = []
3458
3459 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003460 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003461
3462 def raise_error(self, error):
3463 def inner():
3464 raise error()
3465 return inner
3466
3467 def test_no_failure(self):
3468 # create some fake handlers
3469 handler0 = FakeHandler(0, self.called)
3470 handler1 = FakeHandler(1, self.called)
3471 handler2 = FakeHandler(2, self.called)
3472
3473 # create live weakref to those handlers
3474 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3475
3476 logging.shutdown(handlerList=list(handlers))
3477
3478 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3479 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3480 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3481 self.assertEqual(expected, self.called)
3482
3483 def _test_with_failure_in_method(self, method, error):
3484 handler = FakeHandler(0, self.called)
3485 setattr(handler, method, self.raise_error(error))
3486 handlers = [logging.weakref.ref(handler)]
3487
3488 logging.shutdown(handlerList=list(handlers))
3489
3490 self.assertEqual('0 - release', self.called[-1])
3491
3492 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003493 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494
3495 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003496 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003497
3498 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003499 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003500
3501 def test_with_valueerror_in_acquire(self):
3502 self._test_with_failure_in_method('acquire', ValueError)
3503
3504 def test_with_valueerror_in_flush(self):
3505 self._test_with_failure_in_method('flush', ValueError)
3506
3507 def test_with_valueerror_in_close(self):
3508 self._test_with_failure_in_method('close', ValueError)
3509
3510 def test_with_other_error_in_acquire_without_raise(self):
3511 logging.raiseExceptions = False
3512 self._test_with_failure_in_method('acquire', IndexError)
3513
3514 def test_with_other_error_in_flush_without_raise(self):
3515 logging.raiseExceptions = False
3516 self._test_with_failure_in_method('flush', IndexError)
3517
3518 def test_with_other_error_in_close_without_raise(self):
3519 logging.raiseExceptions = False
3520 self._test_with_failure_in_method('close', IndexError)
3521
3522 def test_with_other_error_in_acquire_with_raise(self):
3523 logging.raiseExceptions = True
3524 self.assertRaises(IndexError, self._test_with_failure_in_method,
3525 'acquire', IndexError)
3526
3527 def test_with_other_error_in_flush_with_raise(self):
3528 logging.raiseExceptions = True
3529 self.assertRaises(IndexError, self._test_with_failure_in_method,
3530 'flush', IndexError)
3531
3532 def test_with_other_error_in_close_with_raise(self):
3533 logging.raiseExceptions = True
3534 self.assertRaises(IndexError, self._test_with_failure_in_method,
3535 'close', IndexError)
3536
3537
3538class ModuleLevelMiscTest(BaseTest):
3539
Vinay Sajip5e66b162011-04-20 15:41:14 +01003540 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003541
3542 def test_disable(self):
3543 old_disable = logging.root.manager.disable
3544 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003545 self.assertEqual(old_disable, 0)
3546 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547
3548 logging.disable(83)
3549 self.assertEqual(logging.root.manager.disable, 83)
3550
Vinay Sajipd489ac92016-12-31 11:40:11 +00003551 # test the default value introduced in 3.7
3552 # (Issue #28524)
3553 logging.disable()
3554 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3555
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003556 def _test_log(self, method, level=None):
3557 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003558 support.patch(self, logging, 'basicConfig',
3559 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003560
3561 recording = RecordingHandler()
3562 logging.root.addHandler(recording)
3563
3564 log_method = getattr(logging, method)
3565 if level is not None:
3566 log_method(level, "test me: %r", recording)
3567 else:
3568 log_method("test me: %r", recording)
3569
3570 self.assertEqual(len(recording.records), 1)
3571 record = recording.records[0]
3572 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3573
3574 expected_level = level if level is not None else getattr(logging, method.upper())
3575 self.assertEqual(record.levelno, expected_level)
3576
3577 # basicConfig was not called!
3578 self.assertEqual(called, [])
3579
3580 def test_log(self):
3581 self._test_log('log', logging.ERROR)
3582
3583 def test_debug(self):
3584 self._test_log('debug')
3585
3586 def test_info(self):
3587 self._test_log('info')
3588
3589 def test_warning(self):
3590 self._test_log('warning')
3591
3592 def test_error(self):
3593 self._test_log('error')
3594
3595 def test_critical(self):
3596 self._test_log('critical')
3597
3598 def test_set_logger_class(self):
3599 self.assertRaises(TypeError, logging.setLoggerClass, object)
3600
3601 class MyLogger(logging.Logger):
3602 pass
3603
3604 logging.setLoggerClass(MyLogger)
3605 self.assertEqual(logging.getLoggerClass(), MyLogger)
3606
3607 logging.setLoggerClass(logging.Logger)
3608 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3609
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003610 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003611 def test_logging_at_shutdown(self):
3612 # Issue #20037
3613 code = """if 1:
3614 import logging
3615
3616 class A:
3617 def __del__(self):
3618 try:
3619 raise ValueError("some error")
3620 except Exception:
3621 logging.exception("exception in __del__")
3622
3623 a = A()"""
3624 rc, out, err = assert_python_ok("-c", code)
3625 err = err.decode()
3626 self.assertIn("exception in __del__", err)
3627 self.assertIn("ValueError: some error", err)
3628
3629
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003630class LogRecordTest(BaseTest):
3631 def test_str_rep(self):
3632 r = logging.makeLogRecord({})
3633 s = str(r)
3634 self.assertTrue(s.startswith('<LogRecord: '))
3635 self.assertTrue(s.endswith('>'))
3636
3637 def test_dict_arg(self):
3638 h = RecordingHandler()
3639 r = logging.getLogger()
3640 r.addHandler(h)
3641 d = {'less' : 'more' }
3642 logging.warning('less is %(less)s', d)
3643 self.assertIs(h.records[0].args, d)
3644 self.assertEqual(h.records[0].message, 'less is more')
3645 r.removeHandler(h)
3646 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003647
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003648 def test_multiprocessing(self):
3649 r = logging.makeLogRecord({})
3650 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003651 try:
3652 import multiprocessing as mp
3653 r = logging.makeLogRecord({})
3654 self.assertEqual(r.processName, mp.current_process().name)
3655 except ImportError:
3656 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003657
3658 def test_optional(self):
3659 r = logging.makeLogRecord({})
3660 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003661 if threading:
3662 NOT_NONE(r.thread)
3663 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003664 NOT_NONE(r.process)
3665 NOT_NONE(r.processName)
3666 log_threads = logging.logThreads
3667 log_processes = logging.logProcesses
3668 log_multiprocessing = logging.logMultiprocessing
3669 try:
3670 logging.logThreads = False
3671 logging.logProcesses = False
3672 logging.logMultiprocessing = False
3673 r = logging.makeLogRecord({})
3674 NONE = self.assertIsNone
3675 NONE(r.thread)
3676 NONE(r.threadName)
3677 NONE(r.process)
3678 NONE(r.processName)
3679 finally:
3680 logging.logThreads = log_threads
3681 logging.logProcesses = log_processes
3682 logging.logMultiprocessing = log_multiprocessing
3683
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003684class BasicConfigTest(unittest.TestCase):
3685
Vinay Sajip95bf5042011-04-20 11:50:56 +01003686 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003687
3688 def setUp(self):
3689 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003690 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003691 self.saved_handlers = logging._handlers.copy()
3692 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003693 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003694 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003695 logging.root.handlers = []
3696
3697 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003698 for h in logging.root.handlers[:]:
3699 logging.root.removeHandler(h)
3700 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003701 super(BasicConfigTest, self).tearDown()
3702
Vinay Sajip3def7e02011-04-20 10:58:06 +01003703 def cleanup(self):
3704 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003705 logging._handlers.clear()
3706 logging._handlers.update(self.saved_handlers)
3707 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003708 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003709
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003710 def test_no_kwargs(self):
3711 logging.basicConfig()
3712
3713 # handler defaults to a StreamHandler to sys.stderr
3714 self.assertEqual(len(logging.root.handlers), 1)
3715 handler = logging.root.handlers[0]
3716 self.assertIsInstance(handler, logging.StreamHandler)
3717 self.assertEqual(handler.stream, sys.stderr)
3718
3719 formatter = handler.formatter
3720 # format defaults to logging.BASIC_FORMAT
3721 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3722 # datefmt defaults to None
3723 self.assertIsNone(formatter.datefmt)
3724 # style defaults to %
3725 self.assertIsInstance(formatter._style, logging.PercentStyle)
3726
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003727 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003728 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003729
Vinay Sajip1fd12022014-01-13 21:59:56 +00003730 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003731 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003732 logging.basicConfig(stream=sys.stdout, style="{")
3733 logging.error("Log an error")
3734 sys.stdout.seek(0)
3735 self.assertEqual(output.getvalue().strip(),
3736 "ERROR:root:Log an error")
3737
3738 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003739 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003740 logging.basicConfig(stream=sys.stdout, style="$")
3741 logging.error("Log an error")
3742 sys.stdout.seek(0)
3743 self.assertEqual(output.getvalue().strip(),
3744 "ERROR:root:Log an error")
3745
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003746 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003747
3748 def cleanup(h1, h2, fn):
3749 h1.close()
3750 h2.close()
3751 os.remove(fn)
3752
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003753 logging.basicConfig(filename='test.log')
3754
3755 self.assertEqual(len(logging.root.handlers), 1)
3756 handler = logging.root.handlers[0]
3757 self.assertIsInstance(handler, logging.FileHandler)
3758
3759 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003760 self.assertEqual(handler.stream.mode, expected.stream.mode)
3761 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003762 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003763
3764 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003765
3766 def cleanup(h1, h2, fn):
3767 h1.close()
3768 h2.close()
3769 os.remove(fn)
3770
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003771 logging.basicConfig(filename='test.log', filemode='wb')
3772
3773 handler = logging.root.handlers[0]
3774 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003775 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003776 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003777
3778 def test_stream(self):
3779 stream = io.StringIO()
3780 self.addCleanup(stream.close)
3781 logging.basicConfig(stream=stream)
3782
3783 self.assertEqual(len(logging.root.handlers), 1)
3784 handler = logging.root.handlers[0]
3785 self.assertIsInstance(handler, logging.StreamHandler)
3786 self.assertEqual(handler.stream, stream)
3787
3788 def test_format(self):
3789 logging.basicConfig(format='foo')
3790
3791 formatter = logging.root.handlers[0].formatter
3792 self.assertEqual(formatter._style._fmt, 'foo')
3793
3794 def test_datefmt(self):
3795 logging.basicConfig(datefmt='bar')
3796
3797 formatter = logging.root.handlers[0].formatter
3798 self.assertEqual(formatter.datefmt, 'bar')
3799
3800 def test_style(self):
3801 logging.basicConfig(style='$')
3802
3803 formatter = logging.root.handlers[0].formatter
3804 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3805
3806 def test_level(self):
3807 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003808 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003809
3810 logging.basicConfig(level=57)
3811 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003812 # Test that second call has no effect
3813 logging.basicConfig(level=58)
3814 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003815
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003816 def test_incompatible(self):
3817 assertRaises = self.assertRaises
3818 handlers = [logging.StreamHandler()]
3819 stream = sys.stderr
3820 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3821 stream=stream)
3822 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3823 handlers=handlers)
3824 assertRaises(ValueError, logging.basicConfig, stream=stream,
3825 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003826 # Issue 23207: test for invalid kwargs
3827 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3828 # Should pop both filename and filemode even if filename is None
3829 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003830
3831 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003832 handlers = [
3833 logging.StreamHandler(),
3834 logging.StreamHandler(sys.stdout),
3835 logging.StreamHandler(),
3836 ]
3837 f = logging.Formatter()
3838 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003839 logging.basicConfig(handlers=handlers)
3840 self.assertIs(handlers[0], logging.root.handlers[0])
3841 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003842 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003843 self.assertIsNotNone(handlers[0].formatter)
3844 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003845 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003846 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3847
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003848 def _test_log(self, method, level=None):
3849 # logging.root has no handlers so basicConfig should be called
3850 called = []
3851
3852 old_basic_config = logging.basicConfig
3853 def my_basic_config(*a, **kw):
3854 old_basic_config()
3855 old_level = logging.root.level
3856 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003857 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003858 called.append((a, kw))
3859
Vinay Sajip1feedb42014-05-31 08:19:12 +01003860 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003861
3862 log_method = getattr(logging, method)
3863 if level is not None:
3864 log_method(level, "test me")
3865 else:
3866 log_method("test me")
3867
3868 # basicConfig was called with no arguments
3869 self.assertEqual(called, [((), {})])
3870
3871 def test_log(self):
3872 self._test_log('log', logging.WARNING)
3873
3874 def test_debug(self):
3875 self._test_log('debug')
3876
3877 def test_info(self):
3878 self._test_log('info')
3879
3880 def test_warning(self):
3881 self._test_log('warning')
3882
3883 def test_error(self):
3884 self._test_log('error')
3885
3886 def test_critical(self):
3887 self._test_log('critical')
3888
3889
3890class LoggerAdapterTest(unittest.TestCase):
3891
3892 def setUp(self):
3893 super(LoggerAdapterTest, self).setUp()
3894 old_handler_list = logging._handlerList[:]
3895
3896 self.recording = RecordingHandler()
3897 self.logger = logging.root
3898 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003899 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003900 self.addCleanup(self.recording.close)
3901
3902 def cleanup():
3903 logging._handlerList[:] = old_handler_list
3904
3905 self.addCleanup(cleanup)
3906 self.addCleanup(logging.shutdown)
3907 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3908
3909 def test_exception(self):
3910 msg = 'testing exception: %r'
3911 exc = None
3912 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003913 1 / 0
3914 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003915 exc = e
3916 self.adapter.exception(msg, self.recording)
3917
3918 self.assertEqual(len(self.recording.records), 1)
3919 record = self.recording.records[0]
3920 self.assertEqual(record.levelno, logging.ERROR)
3921 self.assertEqual(record.msg, msg)
3922 self.assertEqual(record.args, (self.recording,))
3923 self.assertEqual(record.exc_info,
3924 (exc.__class__, exc, exc.__traceback__))
3925
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003926 def test_exception_excinfo(self):
3927 try:
3928 1 / 0
3929 except ZeroDivisionError as e:
3930 exc = e
3931
3932 self.adapter.exception('exc_info test', exc_info=exc)
3933
3934 self.assertEqual(len(self.recording.records), 1)
3935 record = self.recording.records[0]
3936 self.assertEqual(record.exc_info,
3937 (exc.__class__, exc, exc.__traceback__))
3938
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003939 def test_critical(self):
3940 msg = 'critical test! %r'
3941 self.adapter.critical(msg, self.recording)
3942
3943 self.assertEqual(len(self.recording.records), 1)
3944 record = self.recording.records[0]
3945 self.assertEqual(record.levelno, logging.CRITICAL)
3946 self.assertEqual(record.msg, msg)
3947 self.assertEqual(record.args, (self.recording,))
3948
3949 def test_is_enabled_for(self):
3950 old_disable = self.adapter.logger.manager.disable
3951 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003952 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3953 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003954 self.assertFalse(self.adapter.isEnabledFor(32))
3955
3956 def test_has_handlers(self):
3957 self.assertTrue(self.adapter.hasHandlers())
3958
3959 for handler in self.logger.handlers:
3960 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003961
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003962 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003963 self.assertFalse(self.adapter.hasHandlers())
3964
3965
3966class LoggerTest(BaseTest):
3967
3968 def setUp(self):
3969 super(LoggerTest, self).setUp()
3970 self.recording = RecordingHandler()
3971 self.logger = logging.Logger(name='blah')
3972 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003973 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003974 self.addCleanup(self.recording.close)
3975 self.addCleanup(logging.shutdown)
3976
3977 def test_set_invalid_level(self):
3978 self.assertRaises(TypeError, self.logger.setLevel, object())
3979
3980 def test_exception(self):
3981 msg = 'testing exception: %r'
3982 exc = None
3983 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003984 1 / 0
3985 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003986 exc = e
3987 self.logger.exception(msg, self.recording)
3988
3989 self.assertEqual(len(self.recording.records), 1)
3990 record = self.recording.records[0]
3991 self.assertEqual(record.levelno, logging.ERROR)
3992 self.assertEqual(record.msg, msg)
3993 self.assertEqual(record.args, (self.recording,))
3994 self.assertEqual(record.exc_info,
3995 (exc.__class__, exc, exc.__traceback__))
3996
3997 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003998 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003999 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004000
4001 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004002 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004003 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004004
4005 def test_find_caller_with_stack_info(self):
4006 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004007 support.patch(self, logging.traceback, 'print_stack',
4008 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004009
4010 self.logger.findCaller(stack_info=True)
4011
4012 self.assertEqual(len(called), 1)
4013 self.assertEqual('Stack (most recent call last):\n', called[0])
4014
4015 def test_make_record_with_extra_overwrite(self):
4016 name = 'my record'
4017 level = 13
4018 fn = lno = msg = args = exc_info = func = sinfo = None
4019 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4020 exc_info, func, sinfo)
4021
4022 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4023 extra = {key: 'some value'}
4024 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4025 fn, lno, msg, args, exc_info,
4026 extra=extra, sinfo=sinfo)
4027
4028 def test_make_record_with_extra_no_overwrite(self):
4029 name = 'my record'
4030 level = 13
4031 fn = lno = msg = args = exc_info = func = sinfo = None
4032 extra = {'valid_key': 'some value'}
4033 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4034 exc_info, extra=extra, sinfo=sinfo)
4035 self.assertIn('valid_key', result.__dict__)
4036
4037 def test_has_handlers(self):
4038 self.assertTrue(self.logger.hasHandlers())
4039
4040 for handler in self.logger.handlers:
4041 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004042 self.assertFalse(self.logger.hasHandlers())
4043
4044 def test_has_handlers_no_propagate(self):
4045 child_logger = logging.getLogger('blah.child')
4046 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004047 self.assertFalse(child_logger.hasHandlers())
4048
4049 def test_is_enabled_for(self):
4050 old_disable = self.logger.manager.disable
4051 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004052 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004053 self.assertFalse(self.logger.isEnabledFor(22))
4054
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004055 def test_root_logger_aliases(self):
4056 root = logging.getLogger()
4057 self.assertIs(root, logging.root)
4058 self.assertIs(root, logging.getLogger(None))
4059 self.assertIs(root, logging.getLogger(''))
4060 self.assertIs(root, logging.getLogger('foo').root)
4061 self.assertIs(root, logging.getLogger('foo.bar').root)
4062 self.assertIs(root, logging.getLogger('foo').parent)
4063
4064 self.assertIsNot(root, logging.getLogger('\0'))
4065 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4066
4067 def test_invalid_names(self):
4068 self.assertRaises(TypeError, logging.getLogger, any)
4069 self.assertRaises(TypeError, logging.getLogger, b'foo')
4070
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004071
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004072class BaseFileTest(BaseTest):
4073 "Base class for handler tests that write log files"
4074
4075 def setUp(self):
4076 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004077 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4078 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004079 self.rmfiles = []
4080
4081 def tearDown(self):
4082 for fn in self.rmfiles:
4083 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004084 if os.path.exists(self.fn):
4085 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004086 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004087
4088 def assertLogFile(self, filename):
4089 "Assert a log file is there and register it for deletion"
4090 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004091 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004092 self.rmfiles.append(filename)
4093
4094
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004095class FileHandlerTest(BaseFileTest):
4096 def test_delay(self):
4097 os.unlink(self.fn)
4098 fh = logging.FileHandler(self.fn, delay=True)
4099 self.assertIsNone(fh.stream)
4100 self.assertFalse(os.path.exists(self.fn))
4101 fh.handle(logging.makeLogRecord({}))
4102 self.assertIsNotNone(fh.stream)
4103 self.assertTrue(os.path.exists(self.fn))
4104 fh.close()
4105
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004106class RotatingFileHandlerTest(BaseFileTest):
4107 def next_rec(self):
4108 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4109 self.next_message(), None, None, None)
4110
4111 def test_should_not_rollover(self):
4112 # If maxbytes is zero rollover never occurs
4113 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4114 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004115 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004116
4117 def test_should_rollover(self):
4118 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4119 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004120 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004121
4122 def test_file_created(self):
4123 # checks that the file is created and assumes it was created
4124 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004125 rh = logging.handlers.RotatingFileHandler(self.fn)
4126 rh.emit(self.next_rec())
4127 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004128 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004129
4130 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004131 def namer(name):
4132 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004133 rh = logging.handlers.RotatingFileHandler(
4134 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004135 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004136 rh.emit(self.next_rec())
4137 self.assertLogFile(self.fn)
4138 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004139 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004140 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004141 self.assertLogFile(namer(self.fn + ".2"))
4142 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4143 rh.close()
4144
Vinay Sajip1feedb42014-05-31 08:19:12 +01004145 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004146 def test_rotator(self):
4147 def namer(name):
4148 return name + ".gz"
4149
4150 def rotator(source, dest):
4151 with open(source, "rb") as sf:
4152 data = sf.read()
4153 compressed = zlib.compress(data, 9)
4154 with open(dest, "wb") as df:
4155 df.write(compressed)
4156 os.remove(source)
4157
4158 rh = logging.handlers.RotatingFileHandler(
4159 self.fn, backupCount=2, maxBytes=1)
4160 rh.rotator = rotator
4161 rh.namer = namer
4162 m1 = self.next_rec()
4163 rh.emit(m1)
4164 self.assertLogFile(self.fn)
4165 m2 = self.next_rec()
4166 rh.emit(m2)
4167 fn = namer(self.fn + ".1")
4168 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004169 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004170 with open(fn, "rb") as f:
4171 compressed = f.read()
4172 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004173 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004174 rh.emit(self.next_rec())
4175 fn = namer(self.fn + ".2")
4176 self.assertLogFile(fn)
4177 with open(fn, "rb") as f:
4178 compressed = f.read()
4179 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004180 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004181 rh.emit(self.next_rec())
4182 fn = namer(self.fn + ".2")
4183 with open(fn, "rb") as f:
4184 compressed = f.read()
4185 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004186 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004187 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004188 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004189
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004190class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004191 # other test methods added below
4192 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004193 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4194 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004195 fmt = logging.Formatter('%(asctime)s %(message)s')
4196 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004197 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004198 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004199 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004200 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004201 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004202 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004203 fh.close()
4204 # At this point, we should have a recent rotated file which we
4205 # can test for the existence of. However, in practice, on some
4206 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004207 # in time to go to look for the log file. So, we go back a fair
4208 # bit, and stop as soon as we see a rotated file. In theory this
4209 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004210 found = False
4211 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004212 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004213 for secs in range(GO_BACK):
4214 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004215 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4216 found = os.path.exists(fn)
4217 if found:
4218 self.rmfiles.append(fn)
4219 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004220 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4221 if not found:
4222 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004223 dn, fn = os.path.split(self.fn)
4224 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004225 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4226 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004227 for f in files:
4228 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004229 path = os.path.join(dn, f)
4230 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004231 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004232 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004233
Vinay Sajip0372e102011-05-05 12:59:14 +01004234 def test_invalid(self):
4235 assertRaises = self.assertRaises
4236 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004237 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004238 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004239 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004240 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004241 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004242
Vinay Sajipa7130792013-04-12 17:04:23 +01004243 def test_compute_rollover_daily_attime(self):
4244 currentTime = 0
4245 atTime = datetime.time(12, 0, 0)
4246 rh = logging.handlers.TimedRotatingFileHandler(
4247 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4248 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004249 try:
4250 actual = rh.computeRollover(currentTime)
4251 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004252
Vinay Sajipd86ac962013-04-14 12:20:46 +01004253 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4254 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4255 finally:
4256 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004257
Vinay Sajip10e8c492013-05-18 10:19:54 -07004258 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004259 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004260 currentTime = int(time.time())
4261 today = currentTime - currentTime % 86400
4262
Vinay Sajipa7130792013-04-12 17:04:23 +01004263 atTime = datetime.time(12, 0, 0)
4264
Vinay Sajip10e8c492013-05-18 10:19:54 -07004265 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004266 for day in range(7):
4267 rh = logging.handlers.TimedRotatingFileHandler(
4268 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4269 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004270 try:
4271 if wday > day:
4272 # The rollover day has already passed this week, so we
4273 # go over into next week
4274 expected = (7 - wday + day)
4275 else:
4276 expected = (day - wday)
4277 # At this point expected is in days from now, convert to seconds
4278 expected *= 24 * 60 * 60
4279 # Add in the rollover time
4280 expected += 12 * 60 * 60
4281 # Add in adjustment for today
4282 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004283 actual = rh.computeRollover(today)
4284 if actual != expected:
4285 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004286 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004287 self.assertEqual(actual, expected)
4288 if day == wday:
4289 # goes into following week
4290 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004291 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004292 if actual != expected:
4293 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004294 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004295 self.assertEqual(actual, expected)
4296 finally:
4297 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004298
4299
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004300def secs(**kw):
4301 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4302
4303for when, exp in (('S', 1),
4304 ('M', 60),
4305 ('H', 60 * 60),
4306 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004307 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004308 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004309 ('W0', secs(days=4, hours=24)),
4310 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004311 def test_compute_rollover(self, when=when, exp=exp):
4312 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004313 self.fn, when=when, interval=1, backupCount=0, utc=True)
4314 currentTime = 0.0
4315 actual = rh.computeRollover(currentTime)
4316 if exp != actual:
4317 # Failures occur on some systems for MIDNIGHT and W0.
4318 # Print detailed calculation for MIDNIGHT so we can try to see
4319 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004320 if when == 'MIDNIGHT':
4321 try:
4322 if rh.utc:
4323 t = time.gmtime(currentTime)
4324 else:
4325 t = time.localtime(currentTime)
4326 currentHour = t[3]
4327 currentMinute = t[4]
4328 currentSecond = t[5]
4329 # r is the number of seconds left between now and midnight
4330 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4331 currentMinute) * 60 +
4332 currentSecond)
4333 result = currentTime + r
4334 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4335 print('currentHour: %s' % currentHour, file=sys.stderr)
4336 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4337 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4338 print('r: %s' % r, file=sys.stderr)
4339 print('result: %s' % result, file=sys.stderr)
4340 except Exception:
4341 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4342 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004343 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004344 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4345
Vinay Sajip60ccd822011-05-09 17:32:09 +01004346
Vinay Sajip223349c2015-10-01 20:37:54 +01004347@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004348class NTEventLogHandlerTest(BaseTest):
4349 def test_basic(self):
4350 logtype = 'Application'
4351 elh = win32evtlog.OpenEventLog(None, logtype)
4352 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004353
4354 try:
4355 h = logging.handlers.NTEventLogHandler('test_logging')
4356 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004357 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004358 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004359 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004360
Vinay Sajip60ccd822011-05-09 17:32:09 +01004361 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4362 h.handle(r)
4363 h.close()
4364 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004365 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004366 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4367 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4368 found = False
4369 GO_BACK = 100
4370 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4371 for e in events:
4372 if e.SourceName != 'test_logging':
4373 continue
4374 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4375 if msg != 'Test Log Message\r\n':
4376 continue
4377 found = True
4378 break
4379 msg = 'Record not found in event log, went back %d records' % GO_BACK
4380 self.assertTrue(found, msg=msg)
4381
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004382
4383class MiscTestCase(unittest.TestCase):
4384 def test__all__(self):
4385 blacklist = {'logThreads', 'logMultiprocessing',
4386 'logProcesses', 'currentframe',
4387 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4388 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004389 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004390 support.check__all__(self, logging, blacklist=blacklist)
4391
4392
Christian Heimes180510d2008-03-03 19:15:45 +00004393# Set the locale to the platform-dependent default. I have no idea
4394# why the test does this, but in any case we save the current locale
4395# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004396@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004397def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004398 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004399 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4400 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4401 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4402 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4403 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4404 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4405 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4406 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4407 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4408 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004409 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004410 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004411 ]
4412 if hasattr(logging.handlers, 'QueueListener'):
4413 tests.append(QueueListenerTest)
4414 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004415
Christian Heimes180510d2008-03-03 19:15:45 +00004416if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004417 test_main()