blob: 226532a9792dbd07a7953e2eeafa38ee67ef1937 [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."""
Victor Stinner69669602017-08-18 23:47:54 +020082 self._threading_key = support.threading_setup()
83
Christian Heimes180510d2008-03-03 19:15:45 +000084 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000085 logging._acquireLock()
86 try:
Christian Heimes180510d2008-03-03 19:15:45 +000087 self.saved_handlers = logging._handlers.copy()
88 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070090 self.saved_name_to_level = logging._nameToLevel.copy()
91 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000092 self.logger_states = logger_states = {}
93 for name in saved_loggers:
94 logger_states[name] = getattr(saved_loggers[name],
95 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000096 finally:
97 logging._releaseLock()
98
Florent Xicluna5252f9f2011-11-07 19:43:05 +010099 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000100 self.logger1 = logging.getLogger("\xab\xd7\xbb")
101 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000102
Christian Heimes180510d2008-03-03 19:15:45 +0000103 self.root_logger = logging.getLogger("")
104 self.original_logging_level = self.root_logger.getEffectiveLevel()
105
106 self.stream = io.StringIO()
107 self.root_logger.setLevel(logging.DEBUG)
108 self.root_hdlr = logging.StreamHandler(self.stream)
109 self.root_formatter = logging.Formatter(self.log_format)
110 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000111 if self.logger1.hasHandlers():
112 hlist = self.logger1.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
114 if self.logger2.hasHandlers():
115 hlist = self.logger2.handlers + self.root_logger.handlers
116 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000117 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000118 self.assertTrue(self.logger1.hasHandlers())
119 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000120
121 def tearDown(self):
122 """Remove our logging stream, and restore the original logging
123 level."""
124 self.stream.close()
125 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000126 while self.root_logger.handlers:
127 h = self.root_logger.handlers[0]
128 self.root_logger.removeHandler(h)
129 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000130 self.root_logger.setLevel(self.original_logging_level)
131 logging._acquireLock()
132 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700133 logging._levelToName.clear()
134 logging._levelToName.update(self.saved_level_to_name)
135 logging._nameToLevel.clear()
136 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000137 logging._handlers.clear()
138 logging._handlers.update(self.saved_handlers)
139 logging._handlerList[:] = self.saved_handler_list
Avram Lubkin78c18a92017-07-30 05:36:33 -0400140 manager = logging.getLogger().manager
141 manager.disable = 0
142 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000143 loggerDict.clear()
144 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000145 logger_states = self.logger_states
146 for name in self.logger_states:
147 if logger_states[name] is not None:
148 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000149 finally:
150 logging._releaseLock()
151
Victor Stinner69669602017-08-18 23:47:54 +0200152 self.doCleanups()
153 support.threading_cleanup(*self._threading_key)
154
Vinay Sajip4ded5512012-10-02 15:56:16 +0100155 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000156 """Match the collected log lines against the regular expression
157 self.expected_log_pat, and compare the extracted group values to
158 the expected_values list of tuples."""
159 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100160 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300161 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100162 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000163 for actual, expected in zip(actual_lines, expected_values):
164 match = pat.search(actual)
165 if not match:
166 self.fail("Log line does not match expected pattern:\n" +
167 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000168 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000169 s = stream.read()
170 if s:
171 self.fail("Remaining output at end of log stream:\n" + s)
172
173 def next_message(self):
174 """Generate a message consisting solely of an auto-incrementing
175 integer."""
176 self.message_num += 1
177 return "%d" % self.message_num
178
179
180class BuiltinLevelsTest(BaseTest):
181 """Test builtin levels and their inheritance."""
182
183 def test_flat(self):
184 #Logging levels in a flat logger namespace.
185 m = self.next_message
186
187 ERR = logging.getLogger("ERR")
188 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000189 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000190 INF.setLevel(logging.INFO)
191 DEB = logging.getLogger("DEB")
192 DEB.setLevel(logging.DEBUG)
193
194 # These should log.
195 ERR.log(logging.CRITICAL, m())
196 ERR.error(m())
197
198 INF.log(logging.CRITICAL, m())
199 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100200 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000201 INF.info(m())
202
203 DEB.log(logging.CRITICAL, m())
204 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100205 DEB.warning(m())
206 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000207 DEB.debug(m())
208
209 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100210 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000211 ERR.info(m())
212 ERR.debug(m())
213
214 INF.debug(m())
215
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000216 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000217 ('ERR', 'CRITICAL', '1'),
218 ('ERR', 'ERROR', '2'),
219 ('INF', 'CRITICAL', '3'),
220 ('INF', 'ERROR', '4'),
221 ('INF', 'WARNING', '5'),
222 ('INF', 'INFO', '6'),
223 ('DEB', 'CRITICAL', '7'),
224 ('DEB', 'ERROR', '8'),
225 ('DEB', 'WARNING', '9'),
226 ('DEB', 'INFO', '10'),
227 ('DEB', 'DEBUG', '11'),
228 ])
229
230 def test_nested_explicit(self):
231 # Logging levels in a nested namespace, all explicitly set.
232 m = self.next_message
233
234 INF = logging.getLogger("INF")
235 INF.setLevel(logging.INFO)
236 INF_ERR = logging.getLogger("INF.ERR")
237 INF_ERR.setLevel(logging.ERROR)
238
239 # These should log.
240 INF_ERR.log(logging.CRITICAL, m())
241 INF_ERR.error(m())
242
243 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100244 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000245 INF_ERR.info(m())
246 INF_ERR.debug(m())
247
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000248 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000249 ('INF.ERR', 'CRITICAL', '1'),
250 ('INF.ERR', 'ERROR', '2'),
251 ])
252
253 def test_nested_inherited(self):
254 #Logging levels in a nested namespace, inherited from parent loggers.
255 m = self.next_message
256
257 INF = logging.getLogger("INF")
258 INF.setLevel(logging.INFO)
259 INF_ERR = logging.getLogger("INF.ERR")
260 INF_ERR.setLevel(logging.ERROR)
261 INF_UNDEF = logging.getLogger("INF.UNDEF")
262 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
263 UNDEF = logging.getLogger("UNDEF")
264
265 # These should log.
266 INF_UNDEF.log(logging.CRITICAL, m())
267 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100268 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000269 INF_UNDEF.info(m())
270 INF_ERR_UNDEF.log(logging.CRITICAL, m())
271 INF_ERR_UNDEF.error(m())
272
273 # These should not log.
274 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100275 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000276 INF_ERR_UNDEF.info(m())
277 INF_ERR_UNDEF.debug(m())
278
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000279 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000280 ('INF.UNDEF', 'CRITICAL', '1'),
281 ('INF.UNDEF', 'ERROR', '2'),
282 ('INF.UNDEF', 'WARNING', '3'),
283 ('INF.UNDEF', 'INFO', '4'),
284 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
285 ('INF.ERR.UNDEF', 'ERROR', '6'),
286 ])
287
288 def test_nested_with_virtual_parent(self):
289 # Logging levels when some parent does not exist yet.
290 m = self.next_message
291
292 INF = logging.getLogger("INF")
293 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
294 CHILD = logging.getLogger("INF.BADPARENT")
295 INF.setLevel(logging.INFO)
296
297 # These should log.
298 GRANDCHILD.log(logging.FATAL, m())
299 GRANDCHILD.info(m())
300 CHILD.log(logging.FATAL, m())
301 CHILD.info(m())
302
303 # These should not log.
304 GRANDCHILD.debug(m())
305 CHILD.debug(m())
306
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000307 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000308 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
309 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
310 ('INF.BADPARENT', 'CRITICAL', '3'),
311 ('INF.BADPARENT', 'INFO', '4'),
312 ])
313
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100314 def test_regression_22386(self):
315 """See issue #22386 for more information."""
316 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
317 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000318
Vinay Sajip8b866d52017-01-11 06:57:55 +0000319 def test_regression_29220(self):
320 """See issue #29220 for more information."""
321 logging.addLevelName(logging.INFO, '')
322 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
323 self.assertEqual(logging.getLevelName(logging.INFO), '')
324
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100325 def test_issue27935(self):
326 fatal = logging.getLevelName('FATAL')
327 self.assertEqual(fatal, logging.FATAL)
328
Vinay Sajip924aaae2017-01-11 17:35:36 +0000329 def test_regression_29220(self):
330 """See issue #29220 for more information."""
331 logging.addLevelName(logging.INFO, '')
332 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
333 self.assertEqual(logging.getLevelName(logging.INFO), '')
334 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
335 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
336
Christian Heimes180510d2008-03-03 19:15:45 +0000337class BasicFilterTest(BaseTest):
338
339 """Test the bundled Filter class."""
340
341 def test_filter(self):
342 # Only messages satisfying the specified criteria pass through the
343 # filter.
344 filter_ = logging.Filter("spam.eggs")
345 handler = self.root_logger.handlers[0]
346 try:
347 handler.addFilter(filter_)
348 spam = logging.getLogger("spam")
349 spam_eggs = logging.getLogger("spam.eggs")
350 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
351 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
352
353 spam.info(self.next_message())
354 spam_eggs.info(self.next_message()) # Good.
355 spam_eggs_fish.info(self.next_message()) # Good.
356 spam_bakedbeans.info(self.next_message())
357
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000358 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000359 ('spam.eggs', 'INFO', '2'),
360 ('spam.eggs.fish', 'INFO', '3'),
361 ])
362 finally:
363 handler.removeFilter(filter_)
364
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000365 def test_callable_filter(self):
366 # Only messages satisfying the specified criteria pass through the
367 # filter.
368
369 def filterfunc(record):
370 parts = record.name.split('.')
371 prefix = '.'.join(parts[:2])
372 return prefix == 'spam.eggs'
373
374 handler = self.root_logger.handlers[0]
375 try:
376 handler.addFilter(filterfunc)
377 spam = logging.getLogger("spam")
378 spam_eggs = logging.getLogger("spam.eggs")
379 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
380 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
381
382 spam.info(self.next_message())
383 spam_eggs.info(self.next_message()) # Good.
384 spam_eggs_fish.info(self.next_message()) # Good.
385 spam_bakedbeans.info(self.next_message())
386
387 self.assert_log_lines([
388 ('spam.eggs', 'INFO', '2'),
389 ('spam.eggs.fish', 'INFO', '3'),
390 ])
391 finally:
392 handler.removeFilter(filterfunc)
393
Vinay Sajip985ef872011-04-26 19:34:04 +0100394 def test_empty_filter(self):
395 f = logging.Filter()
396 r = logging.makeLogRecord({'name': 'spam.eggs'})
397 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000398
399#
400# First, we define our levels. There can be as many as you want - the only
401# limitations are that they should be integers, the lowest should be > 0 and
402# larger values mean less information being logged. If you need specific
403# level values which do not fit into these limitations, you can use a
404# mapping dictionary to convert between your application levels and the
405# logging system.
406#
407SILENT = 120
408TACITURN = 119
409TERSE = 118
410EFFUSIVE = 117
411SOCIABLE = 116
412VERBOSE = 115
413TALKATIVE = 114
414GARRULOUS = 113
415CHATTERBOX = 112
416BORING = 111
417
418LEVEL_RANGE = range(BORING, SILENT + 1)
419
420#
421# Next, we define names for our levels. You don't need to do this - in which
422# case the system will use "Level n" to denote the text for the level.
423#
424my_logging_levels = {
425 SILENT : 'Silent',
426 TACITURN : 'Taciturn',
427 TERSE : 'Terse',
428 EFFUSIVE : 'Effusive',
429 SOCIABLE : 'Sociable',
430 VERBOSE : 'Verbose',
431 TALKATIVE : 'Talkative',
432 GARRULOUS : 'Garrulous',
433 CHATTERBOX : 'Chatterbox',
434 BORING : 'Boring',
435}
436
437class GarrulousFilter(logging.Filter):
438
439 """A filter which blocks garrulous messages."""
440
441 def filter(self, record):
442 return record.levelno != GARRULOUS
443
444class VerySpecificFilter(logging.Filter):
445
446 """A filter which blocks sociable and taciturn messages."""
447
448 def filter(self, record):
449 return record.levelno not in [SOCIABLE, TACITURN]
450
451
452class CustomLevelsAndFiltersTest(BaseTest):
453
454 """Test various filtering possibilities with custom logging levels."""
455
456 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300457 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000458
459 def setUp(self):
460 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000461 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000462 logging.addLevelName(k, v)
463
464 def log_at_all_levels(self, logger):
465 for lvl in LEVEL_RANGE:
466 logger.log(lvl, self.next_message())
467
468 def test_logger_filter(self):
469 # Filter at logger level.
470 self.root_logger.setLevel(VERBOSE)
471 # Levels >= 'Verbose' are good.
472 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000473 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000474 ('Verbose', '5'),
475 ('Sociable', '6'),
476 ('Effusive', '7'),
477 ('Terse', '8'),
478 ('Taciturn', '9'),
479 ('Silent', '10'),
480 ])
481
482 def test_handler_filter(self):
483 # Filter at handler level.
484 self.root_logger.handlers[0].setLevel(SOCIABLE)
485 try:
486 # Levels >= 'Sociable' are good.
487 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000488 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000489 ('Sociable', '6'),
490 ('Effusive', '7'),
491 ('Terse', '8'),
492 ('Taciturn', '9'),
493 ('Silent', '10'),
494 ])
495 finally:
496 self.root_logger.handlers[0].setLevel(logging.NOTSET)
497
498 def test_specific_filters(self):
499 # Set a specific filter object on the handler, and then add another
500 # filter object on the logger itself.
501 handler = self.root_logger.handlers[0]
502 specific_filter = None
503 garr = GarrulousFilter()
504 handler.addFilter(garr)
505 try:
506 self.log_at_all_levels(self.root_logger)
507 first_lines = [
508 # Notice how 'Garrulous' is missing
509 ('Boring', '1'),
510 ('Chatterbox', '2'),
511 ('Talkative', '4'),
512 ('Verbose', '5'),
513 ('Sociable', '6'),
514 ('Effusive', '7'),
515 ('Terse', '8'),
516 ('Taciturn', '9'),
517 ('Silent', '10'),
518 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000519 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000520
521 specific_filter = VerySpecificFilter()
522 self.root_logger.addFilter(specific_filter)
523 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000524 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000525 # Not only 'Garrulous' is still missing, but also 'Sociable'
526 # and 'Taciturn'
527 ('Boring', '11'),
528 ('Chatterbox', '12'),
529 ('Talkative', '14'),
530 ('Verbose', '15'),
531 ('Effusive', '17'),
532 ('Terse', '18'),
533 ('Silent', '20'),
534 ])
535 finally:
536 if specific_filter:
537 self.root_logger.removeFilter(specific_filter)
538 handler.removeFilter(garr)
539
540
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100541class HandlerTest(BaseTest):
542 def test_name(self):
543 h = logging.Handler()
544 h.name = 'generic'
545 self.assertEqual(h.name, 'generic')
546 h.name = 'anothergeneric'
547 self.assertEqual(h.name, 'anothergeneric')
548 self.assertRaises(NotImplementedError, h.emit, None)
549
Vinay Sajip5a35b062011-04-27 11:31:14 +0100550 def test_builtin_handlers(self):
551 # We can't actually *use* too many handlers in the tests,
552 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200553 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100554 for existing in (True, False):
555 fd, fn = tempfile.mkstemp()
556 os.close(fd)
557 if not existing:
558 os.unlink(fn)
559 h = logging.handlers.WatchedFileHandler(fn, delay=True)
560 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100561 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100562 self.assertEqual(dev, -1)
563 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100564 r = logging.makeLogRecord({'msg': 'Test'})
565 h.handle(r)
566 # Now remove the file.
567 os.unlink(fn)
568 self.assertFalse(os.path.exists(fn))
569 # The next call should recreate the file.
570 h.handle(r)
571 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100572 else:
573 self.assertEqual(h.dev, -1)
574 self.assertEqual(h.ino, -1)
575 h.close()
576 if existing:
577 os.unlink(fn)
578 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100579 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100580 else:
581 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100582 try:
583 h = logging.handlers.SysLogHandler(sockname)
584 self.assertEqual(h.facility, h.LOG_USER)
585 self.assertTrue(h.unixsocket)
586 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200587 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100588 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100589 for method in ('GET', 'POST', 'PUT'):
590 if method == 'PUT':
591 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
592 'localhost', '/log', method)
593 else:
594 h = logging.handlers.HTTPHandler('localhost', '/log', method)
595 h.close()
596 h = logging.handlers.BufferingHandler(0)
597 r = logging.makeLogRecord({})
598 self.assertTrue(h.shouldFlush(r))
599 h.close()
600 h = logging.handlers.BufferingHandler(1)
601 self.assertFalse(h.shouldFlush(r))
602 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100603
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100604 def test_path_objects(self):
605 """
606 Test that Path objects are accepted as filename arguments to handlers.
607
608 See Issue #27493.
609 """
610 fd, fn = tempfile.mkstemp()
611 os.close(fd)
612 os.unlink(fn)
613 pfn = pathlib.Path(fn)
614 cases = (
615 (logging.FileHandler, (pfn, 'w')),
616 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
617 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
618 )
619 if sys.platform in ('linux', 'darwin'):
620 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
621 for cls, args in cases:
622 h = cls(*args)
623 self.assertTrue(os.path.exists(fn))
624 h.close()
625 os.unlink(fn)
626
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100627 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100628 @unittest.skipUnless(threading, 'Threading required for this test.')
629 def test_race(self):
630 # Issue #14632 refers.
631 def remove_loop(fname, tries):
632 for _ in range(tries):
633 try:
634 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000635 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100636 except OSError:
637 pass
638 time.sleep(0.004 * random.randint(0, 4))
639
Vinay Sajipc94871a2012-04-25 10:51:35 +0100640 del_count = 500
641 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100642
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000643 self.handle_time = None
644 self.deletion_time = None
645
Vinay Sajipa5798de2012-04-24 23:33:33 +0100646 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100647 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
648 os.close(fd)
649 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
650 remover.daemon = True
651 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100652 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100653 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
654 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100655 try:
656 for _ in range(log_count):
657 time.sleep(0.005)
658 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000659 try:
660 self.handle_time = time.time()
661 h.handle(r)
662 except Exception:
663 print('Deleted at %s, '
664 'opened at %s' % (self.deletion_time,
665 self.handle_time))
666 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100667 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100668 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100669 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100670 if os.path.exists(fn):
671 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100672
673
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100674class BadStream(object):
675 def write(self, data):
676 raise RuntimeError('deliberate mistake')
677
678class TestStreamHandler(logging.StreamHandler):
679 def handleError(self, record):
680 self.error_record = record
681
682class StreamHandlerTest(BaseTest):
683 def test_error_handling(self):
684 h = TestStreamHandler(BadStream())
685 r = logging.makeLogRecord({})
686 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100688 try:
689 h.handle(r)
690 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100691
Vinay Sajip985ef872011-04-26 19:34:04 +0100692 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100693 with support.captured_stderr() as stderr:
694 h.handle(r)
695 msg = '\nRuntimeError: deliberate mistake\n'
696 self.assertIn(msg, stderr.getvalue())
697
Vinay Sajip985ef872011-04-26 19:34:04 +0100698 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100699 with support.captured_stderr() as stderr:
700 h.handle(r)
701 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100702 finally:
703 logging.raiseExceptions = old_raise
704
Vinay Sajip2543f502017-07-30 10:41:45 +0100705 def test_stream_setting(self):
706 """
707 Test setting the handler's stream
708 """
709 h = logging.StreamHandler()
710 stream = io.StringIO()
711 old = h.setStream(stream)
712 self.assertIs(old, sys.stderr)
713 actual = h.setStream(old)
714 self.assertIs(actual, stream)
715 # test that setting to existing value returns None
716 actual = h.setStream(old)
717 self.assertIsNone(actual)
718
Vinay Sajip7367d082011-05-02 13:17:27 +0100719# -- The following section could be moved into a server_helper.py module
720# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100721
Vinay Sajipce7c9782011-05-17 07:15:53 +0100722if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100723 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100724 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100726
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 :param addr: A (host, port) tuple which the server listens on.
728 You can specify a port value of zero: the server's
729 *port* attribute will hold the actual port number
730 used, which can be used in client connections.
731 :param handler: A callable which will be called to process
732 incoming messages. The handler will be passed
733 the client address tuple, who the message is from,
734 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100735 :param poll_interval: The interval, in seconds, used in the underlying
736 :func:`select` or :func:`poll` call by
737 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 :param sockmap: A dictionary which will be used to hold
739 :class:`asyncore.dispatcher` instances used by
740 :func:`asyncore.loop`. This avoids changing the
741 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100742 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743
744 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400745 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
746 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100747 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 self._handler = handler
749 self._thread = None
750 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100751
Vinay Sajipce7c9782011-05-17 07:15:53 +0100752 def process_message(self, peer, mailfrom, rcpttos, data):
753 """
754 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100755
Vinay Sajipce7c9782011-05-17 07:15:53 +0100756 Typically, this will be a test case method.
757 :param peer: The client (host, port) tuple.
758 :param mailfrom: The address of the sender.
759 :param rcpttos: The addresses of the recipients.
760 :param data: The message.
761 """
762 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100763
Vinay Sajipce7c9782011-05-17 07:15:53 +0100764 def start(self):
765 """
766 Start the server running on a separate daemon thread.
767 """
768 self._thread = t = threading.Thread(target=self.serve_forever,
769 args=(self.poll_interval,))
770 t.setDaemon(True)
771 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100772
Vinay Sajipce7c9782011-05-17 07:15:53 +0100773 def serve_forever(self, poll_interval):
774 """
775 Run the :mod:`asyncore` loop until normal termination
776 conditions arise.
777 :param poll_interval: The interval, in seconds, used in the underlying
778 :func:`select` or :func:`poll` call by
779 :func:`asyncore.loop`.
780 """
781 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100782 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200783 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100784 # On FreeBSD 8, closing the server repeatably
785 # raises this error. We swallow it if the
786 # server has been closed.
787 if self.connected or self.accepting:
788 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100789
Vinay Sajipce7c9782011-05-17 07:15:53 +0100790 def stop(self, timeout=None):
791 """
792 Stop the thread by closing the server instance.
793 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100794
Vinay Sajipce7c9782011-05-17 07:15:53 +0100795 :param timeout: How long to wait for the server thread
796 to terminate.
797 """
798 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100799 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200800 alive = self._thread.is_alive()
Vinay Sajip7367d082011-05-02 13:17:27 +0100801 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200802 if alive:
803 self.fail("join() timed out")
Vinay Sajip7367d082011-05-02 13:17:27 +0100804
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 class ControlMixin(object):
806 """
807 This mixin is used to start a server on a separate thread, and
808 shut it down programmatically. Request handling is simplified - instead
809 of needing to derive a suitable RequestHandler subclass, you just
810 provide a callable which will be passed each received request to be
811 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100812
Vinay Sajipce7c9782011-05-17 07:15:53 +0100813 :param handler: A handler callable which will be called with a
814 single parameter - the request - in order to
815 process the request. This handler is called on the
816 server thread, effectively meaning that requests are
817 processed serially. While not quite Web scale ;-),
818 this should be fine for testing applications.
819 :param poll_interval: The polling interval in seconds.
820 """
821 def __init__(self, handler, poll_interval):
822 self._thread = None
823 self.poll_interval = poll_interval
824 self._handler = handler
825 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100826
Vinay Sajipce7c9782011-05-17 07:15:53 +0100827 def start(self):
828 """
829 Create a daemon thread to run the server, and start it.
830 """
831 self._thread = t = threading.Thread(target=self.serve_forever,
832 args=(self.poll_interval,))
833 t.setDaemon(True)
834 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100835
Vinay Sajipce7c9782011-05-17 07:15:53 +0100836 def serve_forever(self, poll_interval):
837 """
838 Run the server. Set the ready flag before entering the
839 service loop.
840 """
841 self.ready.set()
842 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100843
Vinay Sajipce7c9782011-05-17 07:15:53 +0100844 def stop(self, timeout=None):
845 """
846 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 :param timeout: How long to wait for the server thread
849 to terminate.
850 """
851 self.shutdown()
852 if self._thread is not None:
853 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200854 alive = self._thread.is_alive()
Vinay Sajipce7c9782011-05-17 07:15:53 +0100855 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200856 if alive:
857 self.fail("join() timed out")
Vinay Sajipce7c9782011-05-17 07:15:53 +0100858 self.server_close()
859 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 class TestHTTPServer(ControlMixin, HTTPServer):
862 """
863 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100864
Vinay Sajipce7c9782011-05-17 07:15:53 +0100865 :param addr: A tuple with the IP address and port to listen on.
866 :param handler: A handler callable which will be called with a
867 single parameter - the request - in order to
868 process the request.
869 :param poll_interval: The polling interval in seconds.
870 :param log: Pass ``True`` to enable log messages.
871 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100872 def __init__(self, addr, handler, poll_interval=0.5,
873 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100874 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
875 def __getattr__(self, name, default=None):
876 if name.startswith('do_'):
877 return self.process_request
878 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100879
Vinay Sajipce7c9782011-05-17 07:15:53 +0100880 def process_request(self):
881 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100882
Vinay Sajipce7c9782011-05-17 07:15:53 +0100883 def log_message(self, format, *args):
884 if log:
885 super(DelegatingHTTPRequestHandler,
886 self).log_message(format, *args)
887 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
888 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100889 self.sslctx = sslctx
890
891 def get_request(self):
892 try:
893 sock, addr = self.socket.accept()
894 if self.sslctx:
895 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200896 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100897 # socket errors are silenced by the caller, print them here
898 sys.stderr.write("Got an error:\n%s\n" % e)
899 raise
900 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100901
Vinay Sajipce7c9782011-05-17 07:15:53 +0100902 class TestTCPServer(ControlMixin, ThreadingTCPServer):
903 """
904 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100905
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906 :param addr: A tuple with the IP address and port to listen on.
907 :param handler: A handler callable which will be called with a single
908 parameter - the request - in order to process the request.
909 :param poll_interval: The polling interval in seconds.
910 :bind_and_activate: If True (the default), binds the server and starts it
911 listening. If False, you need to call
912 :meth:`server_bind` and :meth:`server_activate` at
913 some later time before calling :meth:`start`, so that
914 the server will set up the socket and listen on it.
915 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100916
Vinay Sajipce7c9782011-05-17 07:15:53 +0100917 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100918
Vinay Sajipce7c9782011-05-17 07:15:53 +0100919 def __init__(self, addr, handler, poll_interval=0.5,
920 bind_and_activate=True):
921 class DelegatingTCPRequestHandler(StreamRequestHandler):
922
923 def handle(self):
924 self.server._handler(self)
925 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
926 bind_and_activate)
927 ControlMixin.__init__(self, handler, poll_interval)
928
929 def server_bind(self):
930 super(TestTCPServer, self).server_bind()
931 self.port = self.socket.getsockname()[1]
932
933 class TestUDPServer(ControlMixin, ThreadingUDPServer):
934 """
935 A UDP server which is controllable using :class:`ControlMixin`.
936
937 :param addr: A tuple with the IP address and port to listen on.
938 :param handler: A handler callable which will be called with a
939 single parameter - the request - in order to
940 process the request.
941 :param poll_interval: The polling interval for shutdown requests,
942 in seconds.
943 :bind_and_activate: If True (the default), binds the server and
944 starts it listening. If False, you need to
945 call :meth:`server_bind` and
946 :meth:`server_activate` at some later time
947 before calling :meth:`start`, so that the server will
948 set up the socket and listen on it.
949 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100950 def __init__(self, addr, handler, poll_interval=0.5,
951 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100952 class DelegatingUDPRequestHandler(DatagramRequestHandler):
953
954 def handle(self):
955 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100956
957 def finish(self):
958 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100959 if data:
960 try:
961 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200962 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100963 if not self.server._closed:
964 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100965
Vinay Sajip3ef12292011-05-23 23:00:42 +0100966 ThreadingUDPServer.__init__(self, addr,
967 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100968 bind_and_activate)
969 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100970 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100971
972 def server_bind(self):
973 super(TestUDPServer, self).server_bind()
974 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100975
Vinay Sajipba980db2011-05-23 21:37:54 +0100976 def server_close(self):
977 super(TestUDPServer, self).server_close()
978 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100979
Victor Stinnerec5a8602014-06-02 14:41:51 +0200980 if hasattr(socket, "AF_UNIX"):
981 class TestUnixStreamServer(TestTCPServer):
982 address_family = socket.AF_UNIX
983
984 class TestUnixDatagramServer(TestUDPServer):
985 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100986
Vinay Sajip7367d082011-05-02 13:17:27 +0100987# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100988
Vinay Sajipce7c9782011-05-17 07:15:53 +0100989@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100990class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000991 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200992
Vinay Sajipa463d252011-04-30 21:52:48 +0100993 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100994 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800995 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100996 sockmap)
997 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800998 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000999 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
1000 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001001 self.assertEqual(h.toaddrs, ['you'])
1002 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001003 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001004 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001005 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001006 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +01001007 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001008 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001009 self.assertEqual(len(self.messages), 1)
1010 peer, mailfrom, rcpttos, data = self.messages[0]
1011 self.assertEqual(mailfrom, 'me')
1012 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001013 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001014 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001015 h.close()
1016
1017 def process_message(self, *args):
1018 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001019 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001020
Christian Heimes180510d2008-03-03 19:15:45 +00001021class MemoryHandlerTest(BaseTest):
1022
1023 """Tests for the MemoryHandler."""
1024
1025 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001026 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001027
1028 def setUp(self):
1029 BaseTest.setUp(self)
1030 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001031 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001032 self.mem_logger = logging.getLogger('mem')
1033 self.mem_logger.propagate = 0
1034 self.mem_logger.addHandler(self.mem_hdlr)
1035
1036 def tearDown(self):
1037 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001038 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001039
1040 def test_flush(self):
1041 # The memory handler flushes to its target handler based on specific
1042 # criteria (message count and message level).
1043 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001044 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001045 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001046 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001047 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001048 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001049 lines = [
1050 ('DEBUG', '1'),
1051 ('INFO', '2'),
1052 ('WARNING', '3'),
1053 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001054 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001055 for n in (4, 14):
1056 for i in range(9):
1057 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001058 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001059 # This will flush because it's the 10th message since the last
1060 # flush.
1061 self.mem_logger.debug(self.next_message())
1062 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001063 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001064
1065 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001066 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001067
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001068 def test_flush_on_close(self):
1069 """
1070 Test that the flush-on-close configuration works as expected.
1071 """
1072 self.mem_logger.debug(self.next_message())
1073 self.assert_log_lines([])
1074 self.mem_logger.info(self.next_message())
1075 self.assert_log_lines([])
1076 self.mem_logger.removeHandler(self.mem_hdlr)
1077 # Default behaviour is to flush on close. Check that it happens.
1078 self.mem_hdlr.close()
1079 lines = [
1080 ('DEBUG', '1'),
1081 ('INFO', '2'),
1082 ]
1083 self.assert_log_lines(lines)
1084 # Now configure for flushing not to be done on close.
1085 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1086 self.root_hdlr,
1087 False)
1088 self.mem_logger.addHandler(self.mem_hdlr)
1089 self.mem_logger.debug(self.next_message())
1090 self.assert_log_lines(lines) # no change
1091 self.mem_logger.info(self.next_message())
1092 self.assert_log_lines(lines) # no change
1093 self.mem_logger.removeHandler(self.mem_hdlr)
1094 self.mem_hdlr.close()
1095 # assert that no new lines have been added
1096 self.assert_log_lines(lines) # no change
1097
Christian Heimes180510d2008-03-03 19:15:45 +00001098
1099class ExceptionFormatter(logging.Formatter):
1100 """A special exception formatter."""
1101 def formatException(self, ei):
1102 return "Got a [%s]" % ei[0].__name__
1103
1104
1105class ConfigFileTest(BaseTest):
1106
1107 """Reading logging config from a .ini-style config file."""
1108
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001109 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001110
1111 # config0 is a standard configuration.
1112 config0 = """
1113 [loggers]
1114 keys=root
1115
1116 [handlers]
1117 keys=hand1
1118
1119 [formatters]
1120 keys=form1
1121
1122 [logger_root]
1123 level=WARNING
1124 handlers=hand1
1125
1126 [handler_hand1]
1127 class=StreamHandler
1128 level=NOTSET
1129 formatter=form1
1130 args=(sys.stdout,)
1131
1132 [formatter_form1]
1133 format=%(levelname)s ++ %(message)s
1134 datefmt=
1135 """
1136
1137 # config1 adds a little to the standard configuration.
1138 config1 = """
1139 [loggers]
1140 keys=root,parser
1141
1142 [handlers]
1143 keys=hand1
1144
1145 [formatters]
1146 keys=form1
1147
1148 [logger_root]
1149 level=WARNING
1150 handlers=
1151
1152 [logger_parser]
1153 level=DEBUG
1154 handlers=hand1
1155 propagate=1
1156 qualname=compiler.parser
1157
1158 [handler_hand1]
1159 class=StreamHandler
1160 level=NOTSET
1161 formatter=form1
1162 args=(sys.stdout,)
1163
1164 [formatter_form1]
1165 format=%(levelname)s ++ %(message)s
1166 datefmt=
1167 """
1168
Vinay Sajip3f84b072011-03-07 17:49:33 +00001169 # config1a moves the handler to the root.
1170 config1a = """
1171 [loggers]
1172 keys=root,parser
1173
1174 [handlers]
1175 keys=hand1
1176
1177 [formatters]
1178 keys=form1
1179
1180 [logger_root]
1181 level=WARNING
1182 handlers=hand1
1183
1184 [logger_parser]
1185 level=DEBUG
1186 handlers=
1187 propagate=1
1188 qualname=compiler.parser
1189
1190 [handler_hand1]
1191 class=StreamHandler
1192 level=NOTSET
1193 formatter=form1
1194 args=(sys.stdout,)
1195
1196 [formatter_form1]
1197 format=%(levelname)s ++ %(message)s
1198 datefmt=
1199 """
1200
Christian Heimes180510d2008-03-03 19:15:45 +00001201 # config2 has a subtle configuration error that should be reported
1202 config2 = config1.replace("sys.stdout", "sys.stbout")
1203
1204 # config3 has a less subtle configuration error
1205 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1206
1207 # config4 specifies a custom formatter class to be loaded
1208 config4 = """
1209 [loggers]
1210 keys=root
1211
1212 [handlers]
1213 keys=hand1
1214
1215 [formatters]
1216 keys=form1
1217
1218 [logger_root]
1219 level=NOTSET
1220 handlers=hand1
1221
1222 [handler_hand1]
1223 class=StreamHandler
1224 level=NOTSET
1225 formatter=form1
1226 args=(sys.stdout,)
1227
1228 [formatter_form1]
1229 class=""" + __name__ + """.ExceptionFormatter
1230 format=%(levelname)s:%(name)s:%(message)s
1231 datefmt=
1232 """
1233
Georg Brandl3dbca812008-07-23 16:10:53 +00001234 # config5 specifies a custom handler class to be loaded
1235 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1236
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001237 # config6 uses ', ' delimiters in the handlers and formatters sections
1238 config6 = """
1239 [loggers]
1240 keys=root,parser
1241
1242 [handlers]
1243 keys=hand1, hand2
1244
1245 [formatters]
1246 keys=form1, form2
1247
1248 [logger_root]
1249 level=WARNING
1250 handlers=
1251
1252 [logger_parser]
1253 level=DEBUG
1254 handlers=hand1
1255 propagate=1
1256 qualname=compiler.parser
1257
1258 [handler_hand1]
1259 class=StreamHandler
1260 level=NOTSET
1261 formatter=form1
1262 args=(sys.stdout,)
1263
1264 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001265 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001266 level=NOTSET
1267 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001268 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001269
1270 [formatter_form1]
1271 format=%(levelname)s ++ %(message)s
1272 datefmt=
1273
1274 [formatter_form2]
1275 format=%(message)s
1276 datefmt=
1277 """
1278
Preston Landers6ea56d22017-08-02 15:44:28 -05001279 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001280 config7 = """
1281 [loggers]
1282 keys=root,parser,compiler
1283
1284 [handlers]
1285 keys=hand1
1286
1287 [formatters]
1288 keys=form1
1289
1290 [logger_root]
1291 level=WARNING
1292 handlers=hand1
1293
1294 [logger_compiler]
1295 level=DEBUG
1296 handlers=
1297 propagate=1
1298 qualname=compiler
1299
1300 [logger_parser]
1301 level=DEBUG
1302 handlers=
1303 propagate=1
1304 qualname=compiler.parser
1305
1306 [handler_hand1]
1307 class=StreamHandler
1308 level=NOTSET
1309 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001310 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001311
1312 [formatter_form1]
1313 format=%(levelname)s ++ %(message)s
1314 datefmt=
1315 """
1316
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001317 disable_test = """
1318 [loggers]
1319 keys=root
1320
1321 [handlers]
1322 keys=screen
1323
1324 [formatters]
1325 keys=
1326
1327 [logger_root]
1328 level=DEBUG
1329 handlers=screen
1330
1331 [handler_screen]
1332 level=DEBUG
1333 class=StreamHandler
1334 args=(sys.stdout,)
1335 formatter=
1336 """
1337
1338 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001339 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001340 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001341
1342 def test_config0_ok(self):
1343 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001344 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001345 self.apply_config(self.config0)
1346 logger = logging.getLogger()
1347 # Won't output anything
1348 logger.info(self.next_message())
1349 # Outputs a message
1350 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001351 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001352 ('ERROR', '2'),
1353 ], stream=output)
1354 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001355 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001356
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001357 def test_config0_using_cp_ok(self):
1358 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001359 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001360 file = io.StringIO(textwrap.dedent(self.config0))
1361 cp = configparser.ConfigParser()
1362 cp.read_file(file)
1363 logging.config.fileConfig(cp)
1364 logger = logging.getLogger()
1365 # Won't output anything
1366 logger.info(self.next_message())
1367 # Outputs a message
1368 logger.error(self.next_message())
1369 self.assert_log_lines([
1370 ('ERROR', '2'),
1371 ], stream=output)
1372 # Original logger output is empty.
1373 self.assert_log_lines([])
1374
Georg Brandl3dbca812008-07-23 16:10:53 +00001375 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001376 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001377 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001378 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001379 logger = logging.getLogger("compiler.parser")
1380 # Both will output a message
1381 logger.info(self.next_message())
1382 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001383 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001384 ('INFO', '1'),
1385 ('ERROR', '2'),
1386 ], stream=output)
1387 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001388 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001389
1390 def test_config2_failure(self):
1391 # A simple config file which overrides the default settings.
1392 self.assertRaises(Exception, self.apply_config, self.config2)
1393
1394 def test_config3_failure(self):
1395 # A simple config file which overrides the default settings.
1396 self.assertRaises(Exception, self.apply_config, self.config3)
1397
1398 def test_config4_ok(self):
1399 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001400 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001401 self.apply_config(self.config4)
1402 logger = logging.getLogger()
1403 try:
1404 raise RuntimeError()
1405 except RuntimeError:
1406 logging.exception("just testing")
1407 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001408 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001409 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1410 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001411 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001412
Georg Brandl3dbca812008-07-23 16:10:53 +00001413 def test_config5_ok(self):
1414 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001415
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001416 def test_config6_ok(self):
1417 self.test_config1_ok(config=self.config6)
1418
Vinay Sajip3f84b072011-03-07 17:49:33 +00001419 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001420 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001421 self.apply_config(self.config1a)
1422 logger = logging.getLogger("compiler.parser")
1423 # See issue #11424. compiler-hyphenated sorts
1424 # between compiler and compiler.xyz and this
1425 # was preventing compiler.xyz from being included
1426 # in the child loggers of compiler because of an
1427 # overzealous loop termination condition.
1428 hyphenated = logging.getLogger('compiler-hyphenated')
1429 # All will output a message
1430 logger.info(self.next_message())
1431 logger.error(self.next_message())
1432 hyphenated.critical(self.next_message())
1433 self.assert_log_lines([
1434 ('INFO', '1'),
1435 ('ERROR', '2'),
1436 ('CRITICAL', '3'),
1437 ], stream=output)
1438 # Original logger output is empty.
1439 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001440 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001441 self.apply_config(self.config7)
1442 logger = logging.getLogger("compiler.parser")
1443 self.assertFalse(logger.disabled)
1444 # Both will output a message
1445 logger.info(self.next_message())
1446 logger.error(self.next_message())
1447 logger = logging.getLogger("compiler.lexer")
1448 # Both will output a message
1449 logger.info(self.next_message())
1450 logger.error(self.next_message())
1451 # Will not appear
1452 hyphenated.critical(self.next_message())
1453 self.assert_log_lines([
1454 ('INFO', '4'),
1455 ('ERROR', '5'),
1456 ('INFO', '6'),
1457 ('ERROR', '7'),
1458 ], stream=output)
1459 # Original logger output is empty.
1460 self.assert_log_lines([])
1461
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001462 def test_logger_disabling(self):
1463 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001464 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001465 self.assertFalse(logger.disabled)
1466 self.apply_config(self.disable_test)
1467 self.assertTrue(logger.disabled)
1468 self.apply_config(self.disable_test, disable_existing_loggers=False)
1469 self.assertFalse(logger.disabled)
1470
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001471
Victor Stinner69669602017-08-18 23:47:54 +02001472@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinner45df8202010-04-28 22:31:17 +00001473@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001474class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001475
Christian Heimes180510d2008-03-03 19:15:45 +00001476 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001477
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001478 if threading:
1479 server_class = TestTCPServer
1480 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001481
Christian Heimes180510d2008-03-03 19:15:45 +00001482 def setUp(self):
1483 """Set up a TCP server to receive log messages, and a SocketHandler
1484 pointing to that server's address and port."""
1485 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001486 # Issue #29177: deal with errors that happen during setup
1487 self.server = self.sock_hdlr = self.server_exception = None
1488 try:
1489 self.server = server = self.server_class(self.address,
1490 self.handle_socket, 0.01)
1491 server.start()
1492 # Uncomment next line to test error recovery in setUp()
1493 # raise OSError('dummy error raised')
1494 except OSError as e:
1495 self.server_exception = e
1496 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001497 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001498 hcls = logging.handlers.SocketHandler
1499 if isinstance(server.server_address, tuple):
1500 self.sock_hdlr = hcls('localhost', server.port)
1501 else:
1502 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001503 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001504 self.root_logger.removeHandler(self.root_logger.handlers[0])
1505 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001506 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001507
Christian Heimes180510d2008-03-03 19:15:45 +00001508 def tearDown(self):
1509 """Shutdown the TCP server."""
1510 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001511 if self.server:
1512 self.server.stop(2.0)
1513 if self.sock_hdlr:
1514 self.root_logger.removeHandler(self.sock_hdlr)
1515 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001516 finally:
1517 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001518
Vinay Sajip7367d082011-05-02 13:17:27 +01001519 def handle_socket(self, request):
1520 conn = request.connection
1521 while True:
1522 chunk = conn.recv(4)
1523 if len(chunk) < 4:
1524 break
1525 slen = struct.unpack(">L", chunk)[0]
1526 chunk = conn.recv(slen)
1527 while len(chunk) < slen:
1528 chunk = chunk + conn.recv(slen - len(chunk))
1529 obj = pickle.loads(chunk)
1530 record = logging.makeLogRecord(obj)
1531 self.log_output += record.msg + '\n'
1532 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001533
Christian Heimes180510d2008-03-03 19:15:45 +00001534 def test_output(self):
1535 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001536 if self.server_exception:
1537 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001538 logger = logging.getLogger("tcp")
1539 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001540 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001541 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001542 self.handled.acquire()
1543 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001544
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001545 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001546 if self.server_exception:
1547 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001548 # Avoid timing-related failures due to SocketHandler's own hard-wired
1549 # one-second timeout on socket.create_connection() (issue #16264).
1550 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001551 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001552 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001553 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001554 try:
1555 raise RuntimeError('Deliberate mistake')
1556 except RuntimeError:
1557 self.root_logger.exception('Never sent')
1558 self.root_logger.error('Never sent, either')
1559 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001560 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001561 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1562 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001563
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001564def _get_temp_domain_socket():
1565 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1566 os.close(fd)
1567 # just need a name - file can't be present, or we'll get an
1568 # 'address already in use' error.
1569 os.remove(fn)
1570 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001571
Victor Stinner69669602017-08-18 23:47:54 +02001572@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001573@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001574@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001575class UnixSocketHandlerTest(SocketHandlerTest):
1576
1577 """Test for SocketHandler with unix sockets."""
1578
Victor Stinnerec5a8602014-06-02 14:41:51 +02001579 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001580 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001581
1582 def setUp(self):
1583 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001584 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001585 SocketHandlerTest.setUp(self)
1586
1587 def tearDown(self):
1588 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001589 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001590
Victor Stinner69669602017-08-18 23:47:54 +02001591@unittest.skipIf(True, "FIXME: bpo-30830")
Vinay Sajip5421f352013-09-27 18:18:28 +01001592@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001593class DatagramHandlerTest(BaseTest):
1594
1595 """Test for DatagramHandler."""
1596
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001597 if threading:
1598 server_class = TestUDPServer
1599 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001600
Vinay Sajip7367d082011-05-02 13:17:27 +01001601 def setUp(self):
1602 """Set up a UDP server to receive log messages, and a DatagramHandler
1603 pointing to that server's address and port."""
1604 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001605 # Issue #29177: deal with errors that happen during setup
1606 self.server = self.sock_hdlr = self.server_exception = None
1607 try:
1608 self.server = server = self.server_class(self.address,
1609 self.handle_datagram, 0.01)
1610 server.start()
1611 # Uncomment next line to test error recovery in setUp()
1612 # raise OSError('dummy error raised')
1613 except OSError as e:
1614 self.server_exception = e
1615 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001616 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001617 hcls = logging.handlers.DatagramHandler
1618 if isinstance(server.server_address, tuple):
1619 self.sock_hdlr = hcls('localhost', server.port)
1620 else:
1621 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001622 self.log_output = ''
1623 self.root_logger.removeHandler(self.root_logger.handlers[0])
1624 self.root_logger.addHandler(self.sock_hdlr)
1625 self.handled = threading.Event()
1626
1627 def tearDown(self):
1628 """Shutdown the UDP server."""
1629 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001630 if self.server:
1631 self.server.stop(2.0)
1632 if self.sock_hdlr:
1633 self.root_logger.removeHandler(self.sock_hdlr)
1634 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001635 finally:
1636 BaseTest.tearDown(self)
1637
1638 def handle_datagram(self, request):
1639 slen = struct.pack('>L', 0) # length of prefix
1640 packet = request.packet[len(slen):]
1641 obj = pickle.loads(packet)
1642 record = logging.makeLogRecord(obj)
1643 self.log_output += record.msg + '\n'
1644 self.handled.set()
1645
1646 def test_output(self):
1647 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001648 if self.server_exception:
1649 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001650 logger = logging.getLogger("udp")
1651 logger.error("spam")
1652 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001653 self.handled.clear()
1654 logger.error("eggs")
1655 self.handled.wait()
1656 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001657
Victor Stinner69669602017-08-18 23:47:54 +02001658@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001659@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001660@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001661class UnixDatagramHandlerTest(DatagramHandlerTest):
1662
1663 """Test for DatagramHandler using Unix sockets."""
1664
Victor Stinnerec5a8602014-06-02 14:41:51 +02001665 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001666 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001667
1668 def setUp(self):
1669 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001670 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001671 DatagramHandlerTest.setUp(self)
1672
1673 def tearDown(self):
1674 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001675 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001676
1677@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001678class SysLogHandlerTest(BaseTest):
1679
1680 """Test for SysLogHandler using UDP."""
1681
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001682 if threading:
1683 server_class = TestUDPServer
1684 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001685
Vinay Sajip7367d082011-05-02 13:17:27 +01001686 def setUp(self):
1687 """Set up a UDP server to receive log messages, and a SysLogHandler
1688 pointing to that server's address and port."""
1689 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001690 # Issue #29177: deal with errors that happen during setup
1691 self.server = self.sl_hdlr = self.server_exception = None
1692 try:
1693 self.server = server = self.server_class(self.address,
1694 self.handle_datagram, 0.01)
1695 server.start()
1696 # Uncomment next line to test error recovery in setUp()
1697 # raise OSError('dummy error raised')
1698 except OSError as e:
1699 self.server_exception = e
1700 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001701 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001702 hcls = logging.handlers.SysLogHandler
1703 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001704 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001705 else:
1706 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001707 self.log_output = ''
1708 self.root_logger.removeHandler(self.root_logger.handlers[0])
1709 self.root_logger.addHandler(self.sl_hdlr)
1710 self.handled = threading.Event()
1711
1712 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001713 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001714 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001715 if self.server:
1716 self.server.stop(2.0)
1717 if self.sl_hdlr:
1718 self.root_logger.removeHandler(self.sl_hdlr)
1719 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001720 finally:
1721 BaseTest.tearDown(self)
1722
1723 def handle_datagram(self, request):
1724 self.log_output = request.packet
1725 self.handled.set()
1726
1727 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001728 if self.server_exception:
1729 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001730 # The log message sent to the SysLogHandler is properly received.
1731 logger = logging.getLogger("slh")
1732 logger.error("sp\xe4m")
1733 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001734 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001735 self.handled.clear()
1736 self.sl_hdlr.append_nul = False
1737 logger.error("sp\xe4m")
1738 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001739 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001740 self.handled.clear()
1741 self.sl_hdlr.ident = "h\xe4m-"
1742 logger.error("sp\xe4m")
1743 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001744 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001745
Victor Stinner69669602017-08-18 23:47:54 +02001746@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001747@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001748@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001749class UnixSysLogHandlerTest(SysLogHandlerTest):
1750
1751 """Test for SysLogHandler with Unix sockets."""
1752
Victor Stinnerec5a8602014-06-02 14:41:51 +02001753 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001754 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001755
1756 def setUp(self):
1757 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001758 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001759 SysLogHandlerTest.setUp(self)
1760
1761 def tearDown(self):
1762 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001763 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001764
Victor Stinner69669602017-08-18 23:47:54 +02001765@unittest.skipIf(True, "FIXME: bpo-30830")
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001766@unittest.skipUnless(support.IPV6_ENABLED,
1767 'IPv6 support required for this test.')
1768@unittest.skipUnless(threading, 'Threading required for this test.')
1769class IPv6SysLogHandlerTest(SysLogHandlerTest):
1770
1771 """Test for SysLogHandler with IPv6 host."""
1772
1773 server_class = TestUDPServer
1774 address = ('::1', 0)
1775
1776 def setUp(self):
1777 self.server_class.address_family = socket.AF_INET6
1778 super(IPv6SysLogHandlerTest, self).setUp()
1779
1780 def tearDown(self):
1781 self.server_class.address_family = socket.AF_INET
1782 super(IPv6SysLogHandlerTest, self).tearDown()
1783
Vinay Sajip5421f352013-09-27 18:18:28 +01001784@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001785class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001786 """Test for HTTPHandler."""
1787
1788 def setUp(self):
1789 """Set up an HTTP server to receive log messages, and a HTTPHandler
1790 pointing to that server's address and port."""
1791 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001792 self.handled = threading.Event()
1793
Vinay Sajip7367d082011-05-02 13:17:27 +01001794 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001795 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001796 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001797 if self.command == 'POST':
1798 try:
1799 rlen = int(request.headers['Content-Length'])
1800 self.post_data = request.rfile.read(rlen)
1801 except:
1802 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001803 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001804 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001805 self.handled.set()
1806
1807 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001808 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001809 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001810 root_logger = self.root_logger
1811 root_logger.removeHandler(self.root_logger.handlers[0])
1812 for secure in (False, True):
1813 addr = ('localhost', 0)
1814 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001815 try:
1816 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001817 except ImportError:
1818 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001819 else:
1820 here = os.path.dirname(__file__)
1821 localhost_cert = os.path.join(here, "keycert.pem")
1822 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1823 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001824
1825 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001826 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001827 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001828 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001829 self.server = server = TestHTTPServer(addr, self.handle_request,
1830 0.01, sslctx=sslctx)
1831 server.start()
1832 server.ready.wait()
1833 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001834 secure_client = secure and sslctx
1835 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001836 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001837 context=context,
1838 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001839 self.log_data = None
1840 root_logger.addHandler(self.h_hdlr)
1841
1842 for method in ('GET', 'POST'):
1843 self.h_hdlr.method = method
1844 self.handled.clear()
1845 msg = "sp\xe4m"
1846 logger.error(msg)
1847 self.handled.wait()
1848 self.assertEqual(self.log_data.path, '/frob')
1849 self.assertEqual(self.command, method)
1850 if method == 'GET':
1851 d = parse_qs(self.log_data.query)
1852 else:
1853 d = parse_qs(self.post_data.decode('utf-8'))
1854 self.assertEqual(d['name'], ['http'])
1855 self.assertEqual(d['funcName'], ['test_output'])
1856 self.assertEqual(d['msg'], [msg])
1857
1858 self.server.stop(2.0)
1859 self.root_logger.removeHandler(self.h_hdlr)
1860 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001861
Christian Heimes180510d2008-03-03 19:15:45 +00001862class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001863
Christian Heimes180510d2008-03-03 19:15:45 +00001864 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001865
Christian Heimes180510d2008-03-03 19:15:45 +00001866 def setUp(self):
1867 """Create a dict to remember potentially destroyed objects."""
1868 BaseTest.setUp(self)
1869 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001870
Christian Heimes180510d2008-03-03 19:15:45 +00001871 def _watch_for_survival(self, *args):
1872 """Watch the given objects for survival, by creating weakrefs to
1873 them."""
1874 for obj in args:
1875 key = id(obj), repr(obj)
1876 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001877
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001878 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001879 """Assert that all objects watched for survival have survived."""
1880 # Trigger cycle breaking.
1881 gc.collect()
1882 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001883 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001884 if ref() is None:
1885 dead.append(repr_)
1886 if dead:
1887 self.fail("%d objects should have survived "
1888 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001889
Christian Heimes180510d2008-03-03 19:15:45 +00001890 def test_persistent_loggers(self):
1891 # Logger objects are persistent and retain their configuration, even
1892 # if visible references are destroyed.
1893 self.root_logger.setLevel(logging.INFO)
1894 foo = logging.getLogger("foo")
1895 self._watch_for_survival(foo)
1896 foo.setLevel(logging.DEBUG)
1897 self.root_logger.debug(self.next_message())
1898 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001899 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001900 ('foo', 'DEBUG', '2'),
1901 ])
1902 del foo
1903 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001904 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001905 # foo has retained its settings.
1906 bar = logging.getLogger("foo")
1907 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001908 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001909 ('foo', 'DEBUG', '2'),
1910 ('foo', 'DEBUG', '3'),
1911 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001912
Benjamin Petersonf91df042009-02-13 02:50:59 +00001913
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001914class EncodingTest(BaseTest):
1915 def test_encoding_plain_file(self):
1916 # In Python 2.x, a plain file object is treated as having no encoding.
1917 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001918 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1919 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001920 # the non-ascii data we write to the log.
1921 data = "foo\x80"
1922 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001923 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001924 log.addHandler(handler)
1925 try:
1926 # write non-ascii data to the log.
1927 log.warning(data)
1928 finally:
1929 log.removeHandler(handler)
1930 handler.close()
1931 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001932 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001933 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001934 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001935 finally:
1936 f.close()
1937 finally:
1938 if os.path.isfile(fn):
1939 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001940
Benjamin Petersonf91df042009-02-13 02:50:59 +00001941 def test_encoding_cyrillic_unicode(self):
1942 log = logging.getLogger("test")
1943 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1944 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1945 #Ensure it's written in a Cyrillic encoding
1946 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001947 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001948 stream = io.BytesIO()
1949 writer = writer_class(stream, 'strict')
1950 handler = logging.StreamHandler(writer)
1951 log.addHandler(handler)
1952 try:
1953 log.warning(message)
1954 finally:
1955 log.removeHandler(handler)
1956 handler.close()
1957 # check we wrote exactly those bytes, ignoring trailing \n etc
1958 s = stream.getvalue()
1959 #Compare against what the data should be when encoded in CP-1251
1960 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1961
1962
Georg Brandlf9734072008-12-07 15:30:06 +00001963class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001964
Georg Brandlf9734072008-12-07 15:30:06 +00001965 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001966 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001967 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001968 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001969 warnings.filterwarnings("always", category=UserWarning)
1970 stream = io.StringIO()
1971 h = logging.StreamHandler(stream)
1972 logger = logging.getLogger("py.warnings")
1973 logger.addHandler(h)
1974 warnings.warn("I'm warning you...")
1975 logger.removeHandler(h)
1976 s = stream.getvalue()
1977 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001978 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001979
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001980 #See if an explicit file uses the original implementation
1981 a_file = io.StringIO()
1982 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1983 a_file, "Dummy line")
1984 s = a_file.getvalue()
1985 a_file.close()
1986 self.assertEqual(s,
1987 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1988
1989 def test_warnings_no_handlers(self):
1990 with warnings.catch_warnings():
1991 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001992 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001993
1994 # confirm our assumption: no loggers are set
1995 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001996 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001997
1998 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001999 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002000 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002001
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002002
2003def formatFunc(format, datefmt=None):
2004 return logging.Formatter(format, datefmt)
2005
2006def handlerFunc():
2007 return logging.StreamHandler()
2008
2009class CustomHandler(logging.StreamHandler):
2010 pass
2011
2012class ConfigDictTest(BaseTest):
2013
2014 """Reading logging config from a dictionary."""
2015
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002016 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002017
2018 # config0 is a standard configuration.
2019 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002020 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002021 'formatters': {
2022 'form1' : {
2023 'format' : '%(levelname)s ++ %(message)s',
2024 },
2025 },
2026 'handlers' : {
2027 'hand1' : {
2028 'class' : 'logging.StreamHandler',
2029 'formatter' : 'form1',
2030 'level' : 'NOTSET',
2031 'stream' : 'ext://sys.stdout',
2032 },
2033 },
2034 'root' : {
2035 'level' : 'WARNING',
2036 'handlers' : ['hand1'],
2037 },
2038 }
2039
2040 # config1 adds a little to the standard configuration.
2041 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002042 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002043 'formatters': {
2044 'form1' : {
2045 'format' : '%(levelname)s ++ %(message)s',
2046 },
2047 },
2048 'handlers' : {
2049 'hand1' : {
2050 'class' : 'logging.StreamHandler',
2051 'formatter' : 'form1',
2052 'level' : 'NOTSET',
2053 'stream' : 'ext://sys.stdout',
2054 },
2055 },
2056 'loggers' : {
2057 'compiler.parser' : {
2058 'level' : 'DEBUG',
2059 'handlers' : ['hand1'],
2060 },
2061 },
2062 'root' : {
2063 'level' : 'WARNING',
2064 },
2065 }
2066
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002067 # config1a moves the handler to the root. Used with config8a
2068 config1a = {
2069 'version': 1,
2070 'formatters': {
2071 'form1' : {
2072 'format' : '%(levelname)s ++ %(message)s',
2073 },
2074 },
2075 'handlers' : {
2076 'hand1' : {
2077 'class' : 'logging.StreamHandler',
2078 'formatter' : 'form1',
2079 'level' : 'NOTSET',
2080 'stream' : 'ext://sys.stdout',
2081 },
2082 },
2083 'loggers' : {
2084 'compiler.parser' : {
2085 'level' : 'DEBUG',
2086 },
2087 },
2088 'root' : {
2089 'level' : 'WARNING',
2090 'handlers' : ['hand1'],
2091 },
2092 }
2093
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002094 # config2 has a subtle configuration error that should be reported
2095 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002097 'formatters': {
2098 'form1' : {
2099 'format' : '%(levelname)s ++ %(message)s',
2100 },
2101 },
2102 'handlers' : {
2103 'hand1' : {
2104 'class' : 'logging.StreamHandler',
2105 'formatter' : 'form1',
2106 'level' : 'NOTSET',
2107 'stream' : 'ext://sys.stdbout',
2108 },
2109 },
2110 'loggers' : {
2111 'compiler.parser' : {
2112 'level' : 'DEBUG',
2113 'handlers' : ['hand1'],
2114 },
2115 },
2116 'root' : {
2117 'level' : 'WARNING',
2118 },
2119 }
2120
2121 #As config1 but with a misspelt level on a handler
2122 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002123 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002124 'formatters': {
2125 'form1' : {
2126 'format' : '%(levelname)s ++ %(message)s',
2127 },
2128 },
2129 'handlers' : {
2130 'hand1' : {
2131 'class' : 'logging.StreamHandler',
2132 'formatter' : 'form1',
2133 'level' : 'NTOSET',
2134 'stream' : 'ext://sys.stdout',
2135 },
2136 },
2137 'loggers' : {
2138 'compiler.parser' : {
2139 'level' : 'DEBUG',
2140 'handlers' : ['hand1'],
2141 },
2142 },
2143 'root' : {
2144 'level' : 'WARNING',
2145 },
2146 }
2147
2148
2149 #As config1 but with a misspelt level on a logger
2150 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002151 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002152 'formatters': {
2153 'form1' : {
2154 'format' : '%(levelname)s ++ %(message)s',
2155 },
2156 },
2157 'handlers' : {
2158 'hand1' : {
2159 'class' : 'logging.StreamHandler',
2160 'formatter' : 'form1',
2161 'level' : 'NOTSET',
2162 'stream' : 'ext://sys.stdout',
2163 },
2164 },
2165 'loggers' : {
2166 'compiler.parser' : {
2167 'level' : 'DEBUG',
2168 'handlers' : ['hand1'],
2169 },
2170 },
2171 'root' : {
2172 'level' : 'WRANING',
2173 },
2174 }
2175
2176 # config3 has a less subtle configuration error
2177 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002178 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002179 'formatters': {
2180 'form1' : {
2181 'format' : '%(levelname)s ++ %(message)s',
2182 },
2183 },
2184 'handlers' : {
2185 'hand1' : {
2186 'class' : 'logging.StreamHandler',
2187 'formatter' : 'misspelled_name',
2188 'level' : 'NOTSET',
2189 'stream' : 'ext://sys.stdout',
2190 },
2191 },
2192 'loggers' : {
2193 'compiler.parser' : {
2194 'level' : 'DEBUG',
2195 'handlers' : ['hand1'],
2196 },
2197 },
2198 'root' : {
2199 'level' : 'WARNING',
2200 },
2201 }
2202
2203 # config4 specifies a custom formatter class to be loaded
2204 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002205 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002206 'formatters': {
2207 'form1' : {
2208 '()' : __name__ + '.ExceptionFormatter',
2209 'format' : '%(levelname)s:%(name)s:%(message)s',
2210 },
2211 },
2212 'handlers' : {
2213 'hand1' : {
2214 'class' : 'logging.StreamHandler',
2215 'formatter' : 'form1',
2216 'level' : 'NOTSET',
2217 'stream' : 'ext://sys.stdout',
2218 },
2219 },
2220 'root' : {
2221 'level' : 'NOTSET',
2222 'handlers' : ['hand1'],
2223 },
2224 }
2225
2226 # As config4 but using an actual callable rather than a string
2227 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002228 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002229 'formatters': {
2230 'form1' : {
2231 '()' : ExceptionFormatter,
2232 'format' : '%(levelname)s:%(name)s:%(message)s',
2233 },
2234 'form2' : {
2235 '()' : __name__ + '.formatFunc',
2236 'format' : '%(levelname)s:%(name)s:%(message)s',
2237 },
2238 'form3' : {
2239 '()' : formatFunc,
2240 'format' : '%(levelname)s:%(name)s:%(message)s',
2241 },
2242 },
2243 'handlers' : {
2244 'hand1' : {
2245 'class' : 'logging.StreamHandler',
2246 'formatter' : 'form1',
2247 'level' : 'NOTSET',
2248 'stream' : 'ext://sys.stdout',
2249 },
2250 'hand2' : {
2251 '()' : handlerFunc,
2252 },
2253 },
2254 'root' : {
2255 'level' : 'NOTSET',
2256 'handlers' : ['hand1'],
2257 },
2258 }
2259
2260 # config5 specifies a custom handler class to be loaded
2261 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002262 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002263 'formatters': {
2264 'form1' : {
2265 'format' : '%(levelname)s ++ %(message)s',
2266 },
2267 },
2268 'handlers' : {
2269 'hand1' : {
2270 'class' : __name__ + '.CustomHandler',
2271 'formatter' : 'form1',
2272 'level' : 'NOTSET',
2273 'stream' : 'ext://sys.stdout',
2274 },
2275 },
2276 'loggers' : {
2277 'compiler.parser' : {
2278 'level' : 'DEBUG',
2279 'handlers' : ['hand1'],
2280 },
2281 },
2282 'root' : {
2283 'level' : 'WARNING',
2284 },
2285 }
2286
2287 # config6 specifies a custom handler class to be loaded
2288 # but has bad arguments
2289 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002290 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002291 'formatters': {
2292 'form1' : {
2293 'format' : '%(levelname)s ++ %(message)s',
2294 },
2295 },
2296 'handlers' : {
2297 'hand1' : {
2298 'class' : __name__ + '.CustomHandler',
2299 'formatter' : 'form1',
2300 'level' : 'NOTSET',
2301 'stream' : 'ext://sys.stdout',
2302 '9' : 'invalid parameter name',
2303 },
2304 },
2305 'loggers' : {
2306 'compiler.parser' : {
2307 'level' : 'DEBUG',
2308 'handlers' : ['hand1'],
2309 },
2310 },
2311 'root' : {
2312 'level' : 'WARNING',
2313 },
2314 }
2315
2316 #config 7 does not define compiler.parser but defines compiler.lexer
2317 #so compiler.parser should be disabled after applying it
2318 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002319 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002320 'formatters': {
2321 'form1' : {
2322 'format' : '%(levelname)s ++ %(message)s',
2323 },
2324 },
2325 'handlers' : {
2326 'hand1' : {
2327 'class' : 'logging.StreamHandler',
2328 'formatter' : 'form1',
2329 'level' : 'NOTSET',
2330 'stream' : 'ext://sys.stdout',
2331 },
2332 },
2333 'loggers' : {
2334 'compiler.lexer' : {
2335 'level' : 'DEBUG',
2336 'handlers' : ['hand1'],
2337 },
2338 },
2339 'root' : {
2340 'level' : 'WARNING',
2341 },
2342 }
2343
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002344 # config8 defines both compiler and compiler.lexer
2345 # so compiler.parser should not be disabled (since
2346 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002347 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002348 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002349 'disable_existing_loggers' : False,
2350 'formatters': {
2351 'form1' : {
2352 'format' : '%(levelname)s ++ %(message)s',
2353 },
2354 },
2355 'handlers' : {
2356 'hand1' : {
2357 'class' : 'logging.StreamHandler',
2358 'formatter' : 'form1',
2359 'level' : 'NOTSET',
2360 'stream' : 'ext://sys.stdout',
2361 },
2362 },
2363 'loggers' : {
2364 'compiler' : {
2365 'level' : 'DEBUG',
2366 'handlers' : ['hand1'],
2367 },
2368 'compiler.lexer' : {
2369 },
2370 },
2371 'root' : {
2372 'level' : 'WARNING',
2373 },
2374 }
2375
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002376 # config8a disables existing loggers
2377 config8a = {
2378 'version': 1,
2379 'disable_existing_loggers' : True,
2380 'formatters': {
2381 'form1' : {
2382 'format' : '%(levelname)s ++ %(message)s',
2383 },
2384 },
2385 'handlers' : {
2386 'hand1' : {
2387 'class' : 'logging.StreamHandler',
2388 'formatter' : 'form1',
2389 'level' : 'NOTSET',
2390 'stream' : 'ext://sys.stdout',
2391 },
2392 },
2393 'loggers' : {
2394 'compiler' : {
2395 'level' : 'DEBUG',
2396 'handlers' : ['hand1'],
2397 },
2398 'compiler.lexer' : {
2399 },
2400 },
2401 'root' : {
2402 'level' : 'WARNING',
2403 },
2404 }
2405
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002406 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002407 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002408 'formatters': {
2409 'form1' : {
2410 'format' : '%(levelname)s ++ %(message)s',
2411 },
2412 },
2413 'handlers' : {
2414 'hand1' : {
2415 'class' : 'logging.StreamHandler',
2416 'formatter' : 'form1',
2417 'level' : 'WARNING',
2418 'stream' : 'ext://sys.stdout',
2419 },
2420 },
2421 'loggers' : {
2422 'compiler.parser' : {
2423 'level' : 'WARNING',
2424 'handlers' : ['hand1'],
2425 },
2426 },
2427 'root' : {
2428 'level' : 'NOTSET',
2429 },
2430 }
2431
2432 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002433 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002434 'incremental' : True,
2435 'handlers' : {
2436 'hand1' : {
2437 'level' : 'WARNING',
2438 },
2439 },
2440 'loggers' : {
2441 'compiler.parser' : {
2442 'level' : 'INFO',
2443 },
2444 },
2445 }
2446
2447 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002448 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002449 'incremental' : True,
2450 'handlers' : {
2451 'hand1' : {
2452 'level' : 'INFO',
2453 },
2454 },
2455 'loggers' : {
2456 'compiler.parser' : {
2457 'level' : 'INFO',
2458 },
2459 },
2460 }
2461
2462 #As config1 but with a filter added
2463 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002464 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002465 'formatters': {
2466 'form1' : {
2467 'format' : '%(levelname)s ++ %(message)s',
2468 },
2469 },
2470 'filters' : {
2471 'filt1' : {
2472 'name' : 'compiler.parser',
2473 },
2474 },
2475 'handlers' : {
2476 'hand1' : {
2477 'class' : 'logging.StreamHandler',
2478 'formatter' : 'form1',
2479 'level' : 'NOTSET',
2480 'stream' : 'ext://sys.stdout',
2481 'filters' : ['filt1'],
2482 },
2483 },
2484 'loggers' : {
2485 'compiler.parser' : {
2486 'level' : 'DEBUG',
2487 'filters' : ['filt1'],
2488 },
2489 },
2490 'root' : {
2491 'level' : 'WARNING',
2492 'handlers' : ['hand1'],
2493 },
2494 }
2495
2496 #As config1 but using cfg:// references
2497 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002498 'version': 1,
2499 'true_formatters': {
2500 'form1' : {
2501 'format' : '%(levelname)s ++ %(message)s',
2502 },
2503 },
2504 'handler_configs': {
2505 'hand1' : {
2506 'class' : 'logging.StreamHandler',
2507 'formatter' : 'form1',
2508 'level' : 'NOTSET',
2509 'stream' : 'ext://sys.stdout',
2510 },
2511 },
2512 'formatters' : 'cfg://true_formatters',
2513 'handlers' : {
2514 'hand1' : 'cfg://handler_configs[hand1]',
2515 },
2516 'loggers' : {
2517 'compiler.parser' : {
2518 'level' : 'DEBUG',
2519 'handlers' : ['hand1'],
2520 },
2521 },
2522 'root' : {
2523 'level' : 'WARNING',
2524 },
2525 }
2526
2527 #As config11 but missing the version key
2528 config12 = {
2529 'true_formatters': {
2530 'form1' : {
2531 'format' : '%(levelname)s ++ %(message)s',
2532 },
2533 },
2534 'handler_configs': {
2535 'hand1' : {
2536 'class' : 'logging.StreamHandler',
2537 'formatter' : 'form1',
2538 'level' : 'NOTSET',
2539 'stream' : 'ext://sys.stdout',
2540 },
2541 },
2542 'formatters' : 'cfg://true_formatters',
2543 'handlers' : {
2544 'hand1' : 'cfg://handler_configs[hand1]',
2545 },
2546 'loggers' : {
2547 'compiler.parser' : {
2548 'level' : 'DEBUG',
2549 'handlers' : ['hand1'],
2550 },
2551 },
2552 'root' : {
2553 'level' : 'WARNING',
2554 },
2555 }
2556
2557 #As config11 but using an unsupported version
2558 config13 = {
2559 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002560 'true_formatters': {
2561 'form1' : {
2562 'format' : '%(levelname)s ++ %(message)s',
2563 },
2564 },
2565 'handler_configs': {
2566 'hand1' : {
2567 'class' : 'logging.StreamHandler',
2568 'formatter' : 'form1',
2569 'level' : 'NOTSET',
2570 'stream' : 'ext://sys.stdout',
2571 },
2572 },
2573 'formatters' : 'cfg://true_formatters',
2574 'handlers' : {
2575 'hand1' : 'cfg://handler_configs[hand1]',
2576 },
2577 'loggers' : {
2578 'compiler.parser' : {
2579 'level' : 'DEBUG',
2580 'handlers' : ['hand1'],
2581 },
2582 },
2583 'root' : {
2584 'level' : 'WARNING',
2585 },
2586 }
2587
Vinay Sajip8d270232012-11-15 14:20:18 +00002588 # As config0, but with properties
2589 config14 = {
2590 'version': 1,
2591 'formatters': {
2592 'form1' : {
2593 'format' : '%(levelname)s ++ %(message)s',
2594 },
2595 },
2596 'handlers' : {
2597 'hand1' : {
2598 'class' : 'logging.StreamHandler',
2599 'formatter' : 'form1',
2600 'level' : 'NOTSET',
2601 'stream' : 'ext://sys.stdout',
2602 '.': {
2603 'foo': 'bar',
2604 'terminator': '!\n',
2605 }
2606 },
2607 },
2608 'root' : {
2609 'level' : 'WARNING',
2610 'handlers' : ['hand1'],
2611 },
2612 }
2613
Vinay Sajip3f885b52013-03-22 15:19:54 +00002614 out_of_order = {
2615 "version": 1,
2616 "formatters": {
2617 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002618 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2619 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002620 }
2621 },
2622 "handlers": {
2623 "fileGlobal": {
2624 "class": "logging.StreamHandler",
2625 "level": "DEBUG",
2626 "formatter": "mySimpleFormatter"
2627 },
2628 "bufferGlobal": {
2629 "class": "logging.handlers.MemoryHandler",
2630 "capacity": 5,
2631 "formatter": "mySimpleFormatter",
2632 "target": "fileGlobal",
2633 "level": "DEBUG"
2634 }
2635 },
2636 "loggers": {
2637 "mymodule": {
2638 "level": "DEBUG",
2639 "handlers": ["bufferGlobal"],
2640 "propagate": "true"
2641 }
2642 }
2643 }
2644
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002645 def apply_config(self, conf):
2646 logging.config.dictConfig(conf)
2647
2648 def test_config0_ok(self):
2649 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002650 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002651 self.apply_config(self.config0)
2652 logger = logging.getLogger()
2653 # Won't output anything
2654 logger.info(self.next_message())
2655 # Outputs a message
2656 logger.error(self.next_message())
2657 self.assert_log_lines([
2658 ('ERROR', '2'),
2659 ], stream=output)
2660 # Original logger output is empty.
2661 self.assert_log_lines([])
2662
2663 def test_config1_ok(self, config=config1):
2664 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002665 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002666 self.apply_config(config)
2667 logger = logging.getLogger("compiler.parser")
2668 # Both will output a message
2669 logger.info(self.next_message())
2670 logger.error(self.next_message())
2671 self.assert_log_lines([
2672 ('INFO', '1'),
2673 ('ERROR', '2'),
2674 ], stream=output)
2675 # Original logger output is empty.
2676 self.assert_log_lines([])
2677
2678 def test_config2_failure(self):
2679 # A simple config which overrides the default settings.
2680 self.assertRaises(Exception, self.apply_config, self.config2)
2681
2682 def test_config2a_failure(self):
2683 # A simple config which overrides the default settings.
2684 self.assertRaises(Exception, self.apply_config, self.config2a)
2685
2686 def test_config2b_failure(self):
2687 # A simple config which overrides the default settings.
2688 self.assertRaises(Exception, self.apply_config, self.config2b)
2689
2690 def test_config3_failure(self):
2691 # A simple config which overrides the default settings.
2692 self.assertRaises(Exception, self.apply_config, self.config3)
2693
2694 def test_config4_ok(self):
2695 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002696 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002697 self.apply_config(self.config4)
2698 #logger = logging.getLogger()
2699 try:
2700 raise RuntimeError()
2701 except RuntimeError:
2702 logging.exception("just testing")
2703 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002704 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002705 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2706 # Original logger output is empty
2707 self.assert_log_lines([])
2708
2709 def test_config4a_ok(self):
2710 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002711 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002712 self.apply_config(self.config4a)
2713 #logger = logging.getLogger()
2714 try:
2715 raise RuntimeError()
2716 except RuntimeError:
2717 logging.exception("just testing")
2718 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002719 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002720 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2721 # Original logger output is empty
2722 self.assert_log_lines([])
2723
2724 def test_config5_ok(self):
2725 self.test_config1_ok(config=self.config5)
2726
2727 def test_config6_failure(self):
2728 self.assertRaises(Exception, self.apply_config, self.config6)
2729
2730 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002731 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002732 self.apply_config(self.config1)
2733 logger = logging.getLogger("compiler.parser")
2734 # Both will output a message
2735 logger.info(self.next_message())
2736 logger.error(self.next_message())
2737 self.assert_log_lines([
2738 ('INFO', '1'),
2739 ('ERROR', '2'),
2740 ], stream=output)
2741 # Original logger output is empty.
2742 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002743 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002744 self.apply_config(self.config7)
2745 logger = logging.getLogger("compiler.parser")
2746 self.assertTrue(logger.disabled)
2747 logger = logging.getLogger("compiler.lexer")
2748 # Both will output a message
2749 logger.info(self.next_message())
2750 logger.error(self.next_message())
2751 self.assert_log_lines([
2752 ('INFO', '3'),
2753 ('ERROR', '4'),
2754 ], stream=output)
2755 # Original logger output is empty.
2756 self.assert_log_lines([])
2757
2758 #Same as test_config_7_ok but don't disable old loggers.
2759 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002760 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002761 self.apply_config(self.config1)
2762 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002763 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002764 logger.info(self.next_message())
2765 logger.error(self.next_message())
2766 self.assert_log_lines([
2767 ('INFO', '1'),
2768 ('ERROR', '2'),
2769 ], stream=output)
2770 # Original logger output is empty.
2771 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002772 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002773 self.apply_config(self.config8)
2774 logger = logging.getLogger("compiler.parser")
2775 self.assertFalse(logger.disabled)
2776 # Both will output a message
2777 logger.info(self.next_message())
2778 logger.error(self.next_message())
2779 logger = logging.getLogger("compiler.lexer")
2780 # Both will output a message
2781 logger.info(self.next_message())
2782 logger.error(self.next_message())
2783 self.assert_log_lines([
2784 ('INFO', '3'),
2785 ('ERROR', '4'),
2786 ('INFO', '5'),
2787 ('ERROR', '6'),
2788 ], stream=output)
2789 # Original logger output is empty.
2790 self.assert_log_lines([])
2791
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002792 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002793 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002794 self.apply_config(self.config1a)
2795 logger = logging.getLogger("compiler.parser")
2796 # See issue #11424. compiler-hyphenated sorts
2797 # between compiler and compiler.xyz and this
2798 # was preventing compiler.xyz from being included
2799 # in the child loggers of compiler because of an
2800 # overzealous loop termination condition.
2801 hyphenated = logging.getLogger('compiler-hyphenated')
2802 # All will output a message
2803 logger.info(self.next_message())
2804 logger.error(self.next_message())
2805 hyphenated.critical(self.next_message())
2806 self.assert_log_lines([
2807 ('INFO', '1'),
2808 ('ERROR', '2'),
2809 ('CRITICAL', '3'),
2810 ], stream=output)
2811 # Original logger output is empty.
2812 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002813 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002814 self.apply_config(self.config8a)
2815 logger = logging.getLogger("compiler.parser")
2816 self.assertFalse(logger.disabled)
2817 # Both will output a message
2818 logger.info(self.next_message())
2819 logger.error(self.next_message())
2820 logger = logging.getLogger("compiler.lexer")
2821 # Both will output a message
2822 logger.info(self.next_message())
2823 logger.error(self.next_message())
2824 # Will not appear
2825 hyphenated.critical(self.next_message())
2826 self.assert_log_lines([
2827 ('INFO', '4'),
2828 ('ERROR', '5'),
2829 ('INFO', '6'),
2830 ('ERROR', '7'),
2831 ], stream=output)
2832 # Original logger output is empty.
2833 self.assert_log_lines([])
2834
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002835 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002836 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002837 self.apply_config(self.config9)
2838 logger = logging.getLogger("compiler.parser")
2839 #Nothing will be output since both handler and logger are set to WARNING
2840 logger.info(self.next_message())
2841 self.assert_log_lines([], stream=output)
2842 self.apply_config(self.config9a)
2843 #Nothing will be output since both handler is still set to WARNING
2844 logger.info(self.next_message())
2845 self.assert_log_lines([], stream=output)
2846 self.apply_config(self.config9b)
2847 #Message should now be output
2848 logger.info(self.next_message())
2849 self.assert_log_lines([
2850 ('INFO', '3'),
2851 ], stream=output)
2852
2853 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002854 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002855 self.apply_config(self.config10)
2856 logger = logging.getLogger("compiler.parser")
2857 logger.warning(self.next_message())
2858 logger = logging.getLogger('compiler')
2859 #Not output, because filtered
2860 logger.warning(self.next_message())
2861 logger = logging.getLogger('compiler.lexer')
2862 #Not output, because filtered
2863 logger.warning(self.next_message())
2864 logger = logging.getLogger("compiler.parser.codegen")
2865 #Output, as not filtered
2866 logger.error(self.next_message())
2867 self.assert_log_lines([
2868 ('WARNING', '1'),
2869 ('ERROR', '4'),
2870 ], stream=output)
2871
2872 def test_config11_ok(self):
2873 self.test_config1_ok(self.config11)
2874
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002875 def test_config12_failure(self):
2876 self.assertRaises(Exception, self.apply_config, self.config12)
2877
2878 def test_config13_failure(self):
2879 self.assertRaises(Exception, self.apply_config, self.config13)
2880
Vinay Sajip8d270232012-11-15 14:20:18 +00002881 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002882 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002883 self.apply_config(self.config14)
2884 h = logging._handlers['hand1']
2885 self.assertEqual(h.foo, 'bar')
2886 self.assertEqual(h.terminator, '!\n')
2887 logging.warning('Exclamation')
2888 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2889
Victor Stinner69669602017-08-18 23:47:54 +02002890 # listen() uses ConfigSocketReceiver which is based
2891 # on socketserver.ThreadingTCPServer
2892 @unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinner45df8202010-04-28 22:31:17 +00002893 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002894 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002895 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002896 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002897 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002898 t.start()
2899 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002900 # Now get the port allocated
2901 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002902 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002903 try:
2904 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2905 sock.settimeout(2.0)
2906 sock.connect(('localhost', port))
2907
2908 slen = struct.pack('>L', len(text))
2909 s = slen + text
2910 sentsofar = 0
2911 left = len(s)
2912 while left > 0:
2913 sent = sock.send(s[sentsofar:])
2914 sentsofar += sent
2915 left -= sent
2916 sock.close()
2917 finally:
2918 t.ready.wait(2.0)
2919 logging.config.stopListening()
2920 t.join(2.0)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002921 if t.is_alive():
2922 self.fail("join() timed out")
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002923
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002924 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002925 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002926 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002927 self.setup_via_listener(json.dumps(self.config10))
2928 logger = logging.getLogger("compiler.parser")
2929 logger.warning(self.next_message())
2930 logger = logging.getLogger('compiler')
2931 #Not output, because filtered
2932 logger.warning(self.next_message())
2933 logger = logging.getLogger('compiler.lexer')
2934 #Not output, because filtered
2935 logger.warning(self.next_message())
2936 logger = logging.getLogger("compiler.parser.codegen")
2937 #Output, as not filtered
2938 logger.error(self.next_message())
2939 self.assert_log_lines([
2940 ('WARNING', '1'),
2941 ('ERROR', '4'),
2942 ], stream=output)
2943
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002944 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002945 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002946 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002947 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
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', '1'),
2954 ('ERROR', '2'),
2955 ], stream=output)
2956 # Original logger output is empty.
2957 self.assert_log_lines([])
2958
Vinay Sajip4ded5512012-10-02 15:56:16 +01002959 @unittest.skipUnless(threading, 'Threading required for this test.')
2960 def test_listen_verify(self):
2961
2962 def verify_fail(stuff):
2963 return None
2964
2965 def verify_reverse(stuff):
2966 return stuff[::-1]
2967
2968 logger = logging.getLogger("compiler.parser")
2969 to_send = textwrap.dedent(ConfigFileTest.config1)
2970 # First, specify a verification function that will fail.
2971 # We expect to see no output, since our configuration
2972 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002973 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002974 self.setup_via_listener(to_send, verify_fail)
2975 # Both will output a message
2976 logger.info(self.next_message())
2977 logger.error(self.next_message())
2978 self.assert_log_lines([], stream=output)
2979 # Original logger output has the stuff we logged.
2980 self.assert_log_lines([
2981 ('INFO', '1'),
2982 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002983 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002984
2985 # Now, perform no verification. Our configuration
2986 # should take effect.
2987
Vinay Sajip1feedb42014-05-31 08:19:12 +01002988 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002989 self.setup_via_listener(to_send) # no verify callable specified
2990 logger = logging.getLogger("compiler.parser")
2991 # Both will output a message
2992 logger.info(self.next_message())
2993 logger.error(self.next_message())
2994 self.assert_log_lines([
2995 ('INFO', '3'),
2996 ('ERROR', '4'),
2997 ], stream=output)
2998 # Original logger output still has the stuff we logged before.
2999 self.assert_log_lines([
3000 ('INFO', '1'),
3001 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003002 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003003
3004 # Now, perform verification which transforms the bytes.
3005
Vinay Sajip1feedb42014-05-31 08:19:12 +01003006 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003007 self.setup_via_listener(to_send[::-1], verify_reverse)
3008 logger = logging.getLogger("compiler.parser")
3009 # Both will output a message
3010 logger.info(self.next_message())
3011 logger.error(self.next_message())
3012 self.assert_log_lines([
3013 ('INFO', '5'),
3014 ('ERROR', '6'),
3015 ], stream=output)
3016 # Original logger output still has the stuff we logged before.
3017 self.assert_log_lines([
3018 ('INFO', '1'),
3019 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003020 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003021
Vinay Sajip3f885b52013-03-22 15:19:54 +00003022 def test_out_of_order(self):
3023 self.apply_config(self.out_of_order)
3024 handler = logging.getLogger('mymodule').handlers[0]
3025 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003026 self.assertIsInstance(handler.formatter._style,
3027 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003028
Vinay Sajip373baef2011-04-26 20:05:24 +01003029 def test_baseconfig(self):
3030 d = {
3031 'atuple': (1, 2, 3),
3032 'alist': ['a', 'b', 'c'],
3033 'adict': {'d': 'e', 'f': 3 },
3034 'nest1': ('g', ('h', 'i'), 'j'),
3035 'nest2': ['k', ['l', 'm'], 'n'],
3036 'nest3': ['o', 'cfg://alist', 'p'],
3037 }
3038 bc = logging.config.BaseConfigurator(d)
3039 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3040 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3041 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3042 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3043 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3044 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3045 v = bc.convert('cfg://nest3')
3046 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3047 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3048 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3049 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003050
3051class ManagerTest(BaseTest):
3052 def test_manager_loggerclass(self):
3053 logged = []
3054
3055 class MyLogger(logging.Logger):
3056 def _log(self, level, msg, args, exc_info=None, extra=None):
3057 logged.append(msg)
3058
3059 man = logging.Manager(None)
3060 self.assertRaises(TypeError, man.setLoggerClass, int)
3061 man.setLoggerClass(MyLogger)
3062 logger = man.getLogger('test')
3063 logger.warning('should appear in logged')
3064 logging.warning('should not appear in logged')
3065
3066 self.assertEqual(logged, ['should appear in logged'])
3067
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003068 def test_set_log_record_factory(self):
3069 man = logging.Manager(None)
3070 expected = object()
3071 man.setLogRecordFactory(expected)
3072 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003073
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003074class ChildLoggerTest(BaseTest):
3075 def test_child_loggers(self):
3076 r = logging.getLogger()
3077 l1 = logging.getLogger('abc')
3078 l2 = logging.getLogger('def.ghi')
3079 c1 = r.getChild('xyz')
3080 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003081 self.assertIs(c1, logging.getLogger('xyz'))
3082 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003083 c1 = l1.getChild('def')
3084 c2 = c1.getChild('ghi')
3085 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003086 self.assertIs(c1, logging.getLogger('abc.def'))
3087 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3088 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003089
3090
Vinay Sajip6fac8172010-10-19 20:44:14 +00003091class DerivedLogRecord(logging.LogRecord):
3092 pass
3093
Vinay Sajip61561522010-12-03 11:50:38 +00003094class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003095
3096 def setUp(self):
3097 class CheckingFilter(logging.Filter):
3098 def __init__(self, cls):
3099 self.cls = cls
3100
3101 def filter(self, record):
3102 t = type(record)
3103 if t is not self.cls:
3104 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3105 self.cls)
3106 raise TypeError(msg)
3107 return True
3108
3109 BaseTest.setUp(self)
3110 self.filter = CheckingFilter(DerivedLogRecord)
3111 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003112 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003113
3114 def tearDown(self):
3115 self.root_logger.removeFilter(self.filter)
3116 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003117 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003118
3119 def test_logrecord_class(self):
3120 self.assertRaises(TypeError, self.root_logger.warning,
3121 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003122 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003123 self.root_logger.error(self.next_message())
3124 self.assert_log_lines([
3125 ('root', 'ERROR', '2'),
3126 ])
3127
3128
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003129class QueueHandlerTest(BaseTest):
3130 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003131 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003132
3133 def setUp(self):
3134 BaseTest.setUp(self)
3135 self.queue = queue.Queue(-1)
3136 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003137 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003138 self.que_logger = logging.getLogger('que')
3139 self.que_logger.propagate = False
3140 self.que_logger.setLevel(logging.WARNING)
3141 self.que_logger.addHandler(self.que_hdlr)
3142
3143 def tearDown(self):
3144 self.que_hdlr.close()
3145 BaseTest.tearDown(self)
3146
3147 def test_queue_handler(self):
3148 self.que_logger.debug(self.next_message())
3149 self.assertRaises(queue.Empty, self.queue.get_nowait)
3150 self.que_logger.info(self.next_message())
3151 self.assertRaises(queue.Empty, self.queue.get_nowait)
3152 msg = self.next_message()
3153 self.que_logger.warning(msg)
3154 data = self.queue.get_nowait()
3155 self.assertTrue(isinstance(data, logging.LogRecord))
3156 self.assertEqual(data.name, self.que_logger.name)
3157 self.assertEqual((data.msg, data.args), (msg, None))
3158
favlladfe3442017-08-01 20:12:26 +02003159 def test_formatting(self):
3160 msg = self.next_message()
3161 levelname = logging.getLevelName(logging.WARNING)
3162 log_format_str = '{name} -> {levelname}: {message}'
3163 formatted_msg = log_format_str.format(name=self.name,
3164 levelname=levelname, message=msg)
3165 formatter = logging.Formatter(self.log_format)
3166 self.que_hdlr.setFormatter(formatter)
3167 self.que_logger.warning(msg)
3168 log_record = self.queue.get_nowait()
3169 self.assertEqual(formatted_msg, log_record.msg)
3170 self.assertEqual(formatted_msg, log_record.message)
3171
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003172 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3173 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003174 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003175 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003176 listener = logging.handlers.QueueListener(self.queue, handler)
3177 listener.start()
3178 try:
3179 self.que_logger.warning(self.next_message())
3180 self.que_logger.error(self.next_message())
3181 self.que_logger.critical(self.next_message())
3182 finally:
3183 listener.stop()
3184 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3185 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3186 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003187 handler.close()
3188
3189 # Now test with respect_handler_level set
3190
3191 handler = support.TestHandler(support.Matcher())
3192 handler.setLevel(logging.CRITICAL)
3193 listener = logging.handlers.QueueListener(self.queue, handler,
3194 respect_handler_level=True)
3195 listener.start()
3196 try:
3197 self.que_logger.warning(self.next_message())
3198 self.que_logger.error(self.next_message())
3199 self.que_logger.critical(self.next_message())
3200 finally:
3201 listener.stop()
3202 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3203 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3204 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3205
Vinay Sajipd61910c2016-09-08 01:13:39 +01003206if hasattr(logging.handlers, 'QueueListener'):
3207 import multiprocessing
3208 from unittest.mock import patch
3209
3210 class QueueListenerTest(BaseTest):
3211 """
3212 Tests based on patch submitted for issue #27930. Ensure that
3213 QueueListener handles all log messages.
3214 """
3215
3216 repeat = 20
3217
3218 @staticmethod
3219 def setup_and_log(log_queue, ident):
3220 """
3221 Creates a logger with a QueueHandler that logs to a queue read by a
3222 QueueListener. Starts the listener, logs five messages, and stops
3223 the listener.
3224 """
3225 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3226 logger.setLevel(logging.DEBUG)
3227 handler = logging.handlers.QueueHandler(log_queue)
3228 logger.addHandler(handler)
3229 listener = logging.handlers.QueueListener(log_queue)
3230 listener.start()
3231
3232 logger.info('one')
3233 logger.info('two')
3234 logger.info('three')
3235 logger.info('four')
3236 logger.info('five')
3237
3238 listener.stop()
3239 logger.removeHandler(handler)
3240 handler.close()
3241
3242 @patch.object(logging.handlers.QueueListener, 'handle')
3243 def test_handle_called_with_queue_queue(self, mock_handle):
3244 for i in range(self.repeat):
3245 log_queue = queue.Queue()
3246 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3247 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3248 'correct number of handled log messages')
3249
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003250 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003251 @patch.object(logging.handlers.QueueListener, 'handle')
3252 def test_handle_called_with_mp_queue(self, mock_handle):
3253 for i in range(self.repeat):
3254 log_queue = multiprocessing.Queue()
3255 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003256 log_queue.close()
3257 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003258 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3259 'correct number of handled log messages')
3260
3261 @staticmethod
3262 def get_all_from_queue(log_queue):
3263 try:
3264 while True:
3265 yield log_queue.get_nowait()
3266 except queue.Empty:
3267 return []
3268
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003269 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003270 def test_no_messages_in_queue_after_stop(self):
3271 """
3272 Five messages are logged then the QueueListener is stopped. This
3273 test then gets everything off the queue. Failure of this test
3274 indicates that messages were not registered on the queue until
3275 _after_ the QueueListener stopped.
3276 """
3277 for i in range(self.repeat):
3278 queue = multiprocessing.Queue()
3279 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3280 # time.sleep(1)
3281 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003282 queue.close()
3283 queue.join_thread()
3284
Vinay Sajipd61910c2016-09-08 01:13:39 +01003285 expected = [[], [logging.handlers.QueueListener._sentinel]]
3286 self.assertIn(items, expected,
3287 'Found unexpected messages in queue: %s' % (
3288 [m.msg if isinstance(m, logging.LogRecord)
3289 else m for m in items]))
3290
Vinay Sajipe723e962011-04-15 22:27:17 +01003291
Vinay Sajip37eb3382011-04-26 20:26:41 +01003292ZERO = datetime.timedelta(0)
3293
3294class UTC(datetime.tzinfo):
3295 def utcoffset(self, dt):
3296 return ZERO
3297
3298 dst = utcoffset
3299
3300 def tzname(self, dt):
3301 return 'UTC'
3302
3303utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003304
Vinay Sajipa39c5712010-10-25 13:57:39 +00003305class FormatterTest(unittest.TestCase):
3306 def setUp(self):
3307 self.common = {
3308 'name': 'formatter.test',
3309 'level': logging.DEBUG,
3310 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3311 'lineno': 42,
3312 'exc_info': None,
3313 'func': None,
3314 'msg': 'Message with %d %s',
3315 'args': (2, 'placeholders'),
3316 }
3317 self.variants = {
3318 }
3319
3320 def get_record(self, name=None):
3321 result = dict(self.common)
3322 if name is not None:
3323 result.update(self.variants[name])
3324 return logging.makeLogRecord(result)
3325
3326 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003327 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003328 r = self.get_record()
3329 f = logging.Formatter('${%(message)s}')
3330 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3331 f = logging.Formatter('%(random)s')
3332 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003333 self.assertFalse(f.usesTime())
3334 f = logging.Formatter('%(asctime)s')
3335 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003336 f = logging.Formatter('%(asctime)-15s')
3337 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003338 f = logging.Formatter('asctime')
3339 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003340
3341 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003342 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003343 r = self.get_record()
3344 f = logging.Formatter('$%{message}%$', style='{')
3345 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3346 f = logging.Formatter('{random}', style='{')
3347 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003348 self.assertFalse(f.usesTime())
3349 f = logging.Formatter('{asctime}', style='{')
3350 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003351 f = logging.Formatter('{asctime!s:15}', style='{')
3352 self.assertTrue(f.usesTime())
3353 f = logging.Formatter('{asctime:15}', style='{')
3354 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003355 f = logging.Formatter('asctime', style='{')
3356 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003357
3358 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003359 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003360 r = self.get_record()
3361 f = logging.Formatter('$message', style='$')
3362 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3363 f = logging.Formatter('$$%${message}%$$', style='$')
3364 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3365 f = logging.Formatter('${random}', style='$')
3366 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003367 self.assertFalse(f.usesTime())
3368 f = logging.Formatter('${asctime}', style='$')
3369 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003370 f = logging.Formatter('${asctime', style='$')
3371 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003372 f = logging.Formatter('$asctime', style='$')
3373 self.assertTrue(f.usesTime())
3374 f = logging.Formatter('asctime', style='$')
3375 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003376
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003377 def test_invalid_style(self):
3378 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3379
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003380 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003381 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003382 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3383 # We use None to indicate we want the local timezone
3384 # We're essentially converting a UTC time to local time
3385 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003386 r.msecs = 123
3387 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003388 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003389 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3390 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003391 f.format(r)
3392 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3393
3394class TestBufferingFormatter(logging.BufferingFormatter):
3395 def formatHeader(self, records):
3396 return '[(%d)' % len(records)
3397
3398 def formatFooter(self, records):
3399 return '(%d)]' % len(records)
3400
3401class BufferingFormatterTest(unittest.TestCase):
3402 def setUp(self):
3403 self.records = [
3404 logging.makeLogRecord({'msg': 'one'}),
3405 logging.makeLogRecord({'msg': 'two'}),
3406 ]
3407
3408 def test_default(self):
3409 f = logging.BufferingFormatter()
3410 self.assertEqual('', f.format([]))
3411 self.assertEqual('onetwo', f.format(self.records))
3412
3413 def test_custom(self):
3414 f = TestBufferingFormatter()
3415 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3416 lf = logging.Formatter('<%(message)s>')
3417 f = TestBufferingFormatter(lf)
3418 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003419
3420class ExceptionTest(BaseTest):
3421 def test_formatting(self):
3422 r = self.root_logger
3423 h = RecordingHandler()
3424 r.addHandler(h)
3425 try:
3426 raise RuntimeError('deliberate mistake')
3427 except:
3428 logging.exception('failed', stack_info=True)
3429 r.removeHandler(h)
3430 h.close()
3431 r = h.records[0]
3432 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3433 'call last):\n'))
3434 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3435 'deliberate mistake'))
3436 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3437 'call last):\n'))
3438 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3439 'stack_info=True)'))
3440
3441
Vinay Sajip5a27d402010-12-10 11:42:57 +00003442class LastResortTest(BaseTest):
3443 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003444 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003445 root = self.root_logger
3446 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003447 old_lastresort = logging.lastResort
3448 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003449
Vinay Sajip5a27d402010-12-10 11:42:57 +00003450 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003451 with support.captured_stderr() as stderr:
3452 root.debug('This should not appear')
3453 self.assertEqual(stderr.getvalue(), '')
3454 root.warning('Final chance!')
3455 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3456
3457 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003458 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003459 with support.captured_stderr() as stderr:
3460 root.warning('Final chance!')
3461 msg = 'No handlers could be found for logger "root"\n'
3462 self.assertEqual(stderr.getvalue(), msg)
3463
Vinay Sajip5a27d402010-12-10 11:42:57 +00003464 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003465 with support.captured_stderr() as stderr:
3466 root.warning('Final chance!')
3467 self.assertEqual(stderr.getvalue(), '')
3468
3469 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003470 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003471 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003472 with support.captured_stderr() as stderr:
3473 root.warning('Final chance!')
3474 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003475 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003476 root.addHandler(self.root_hdlr)
3477 logging.lastResort = old_lastresort
3478 logging.raiseExceptions = old_raise_exceptions
3479
3480
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003481class FakeHandler:
3482
3483 def __init__(self, identifier, called):
3484 for method in ('acquire', 'flush', 'close', 'release'):
3485 setattr(self, method, self.record_call(identifier, method, called))
3486
3487 def record_call(self, identifier, method_name, called):
3488 def inner():
3489 called.append('{} - {}'.format(identifier, method_name))
3490 return inner
3491
3492
3493class RecordingHandler(logging.NullHandler):
3494
3495 def __init__(self, *args, **kwargs):
3496 super(RecordingHandler, self).__init__(*args, **kwargs)
3497 self.records = []
3498
3499 def handle(self, record):
3500 """Keep track of all the emitted records."""
3501 self.records.append(record)
3502
3503
3504class ShutdownTest(BaseTest):
3505
Vinay Sajip5e66b162011-04-20 15:41:14 +01003506 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003507
3508 def setUp(self):
3509 super(ShutdownTest, self).setUp()
3510 self.called = []
3511
3512 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003513 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003514
3515 def raise_error(self, error):
3516 def inner():
3517 raise error()
3518 return inner
3519
3520 def test_no_failure(self):
3521 # create some fake handlers
3522 handler0 = FakeHandler(0, self.called)
3523 handler1 = FakeHandler(1, self.called)
3524 handler2 = FakeHandler(2, self.called)
3525
3526 # create live weakref to those handlers
3527 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3528
3529 logging.shutdown(handlerList=list(handlers))
3530
3531 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3532 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3533 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3534 self.assertEqual(expected, self.called)
3535
3536 def _test_with_failure_in_method(self, method, error):
3537 handler = FakeHandler(0, self.called)
3538 setattr(handler, method, self.raise_error(error))
3539 handlers = [logging.weakref.ref(handler)]
3540
3541 logging.shutdown(handlerList=list(handlers))
3542
3543 self.assertEqual('0 - release', self.called[-1])
3544
3545 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003546 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547
3548 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003549 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003550
3551 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003552 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003553
3554 def test_with_valueerror_in_acquire(self):
3555 self._test_with_failure_in_method('acquire', ValueError)
3556
3557 def test_with_valueerror_in_flush(self):
3558 self._test_with_failure_in_method('flush', ValueError)
3559
3560 def test_with_valueerror_in_close(self):
3561 self._test_with_failure_in_method('close', ValueError)
3562
3563 def test_with_other_error_in_acquire_without_raise(self):
3564 logging.raiseExceptions = False
3565 self._test_with_failure_in_method('acquire', IndexError)
3566
3567 def test_with_other_error_in_flush_without_raise(self):
3568 logging.raiseExceptions = False
3569 self._test_with_failure_in_method('flush', IndexError)
3570
3571 def test_with_other_error_in_close_without_raise(self):
3572 logging.raiseExceptions = False
3573 self._test_with_failure_in_method('close', IndexError)
3574
3575 def test_with_other_error_in_acquire_with_raise(self):
3576 logging.raiseExceptions = True
3577 self.assertRaises(IndexError, self._test_with_failure_in_method,
3578 'acquire', IndexError)
3579
3580 def test_with_other_error_in_flush_with_raise(self):
3581 logging.raiseExceptions = True
3582 self.assertRaises(IndexError, self._test_with_failure_in_method,
3583 'flush', IndexError)
3584
3585 def test_with_other_error_in_close_with_raise(self):
3586 logging.raiseExceptions = True
3587 self.assertRaises(IndexError, self._test_with_failure_in_method,
3588 'close', IndexError)
3589
3590
3591class ModuleLevelMiscTest(BaseTest):
3592
Vinay Sajip5e66b162011-04-20 15:41:14 +01003593 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003594
3595 def test_disable(self):
3596 old_disable = logging.root.manager.disable
3597 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003598 self.assertEqual(old_disable, 0)
3599 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003600
3601 logging.disable(83)
3602 self.assertEqual(logging.root.manager.disable, 83)
3603
Vinay Sajipd489ac92016-12-31 11:40:11 +00003604 # test the default value introduced in 3.7
3605 # (Issue #28524)
3606 logging.disable()
3607 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3608
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003609 def _test_log(self, method, level=None):
3610 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003611 support.patch(self, logging, 'basicConfig',
3612 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003613
3614 recording = RecordingHandler()
3615 logging.root.addHandler(recording)
3616
3617 log_method = getattr(logging, method)
3618 if level is not None:
3619 log_method(level, "test me: %r", recording)
3620 else:
3621 log_method("test me: %r", recording)
3622
3623 self.assertEqual(len(recording.records), 1)
3624 record = recording.records[0]
3625 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3626
3627 expected_level = level if level is not None else getattr(logging, method.upper())
3628 self.assertEqual(record.levelno, expected_level)
3629
3630 # basicConfig was not called!
3631 self.assertEqual(called, [])
3632
3633 def test_log(self):
3634 self._test_log('log', logging.ERROR)
3635
3636 def test_debug(self):
3637 self._test_log('debug')
3638
3639 def test_info(self):
3640 self._test_log('info')
3641
3642 def test_warning(self):
3643 self._test_log('warning')
3644
3645 def test_error(self):
3646 self._test_log('error')
3647
3648 def test_critical(self):
3649 self._test_log('critical')
3650
3651 def test_set_logger_class(self):
3652 self.assertRaises(TypeError, logging.setLoggerClass, object)
3653
3654 class MyLogger(logging.Logger):
3655 pass
3656
3657 logging.setLoggerClass(MyLogger)
3658 self.assertEqual(logging.getLoggerClass(), MyLogger)
3659
3660 logging.setLoggerClass(logging.Logger)
3661 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3662
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003663 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003664 def test_logging_at_shutdown(self):
3665 # Issue #20037
3666 code = """if 1:
3667 import logging
3668
3669 class A:
3670 def __del__(self):
3671 try:
3672 raise ValueError("some error")
3673 except Exception:
3674 logging.exception("exception in __del__")
3675
3676 a = A()"""
3677 rc, out, err = assert_python_ok("-c", code)
3678 err = err.decode()
3679 self.assertIn("exception in __del__", err)
3680 self.assertIn("ValueError: some error", err)
3681
3682
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003683class LogRecordTest(BaseTest):
3684 def test_str_rep(self):
3685 r = logging.makeLogRecord({})
3686 s = str(r)
3687 self.assertTrue(s.startswith('<LogRecord: '))
3688 self.assertTrue(s.endswith('>'))
3689
3690 def test_dict_arg(self):
3691 h = RecordingHandler()
3692 r = logging.getLogger()
3693 r.addHandler(h)
3694 d = {'less' : 'more' }
3695 logging.warning('less is %(less)s', d)
3696 self.assertIs(h.records[0].args, d)
3697 self.assertEqual(h.records[0].message, 'less is more')
3698 r.removeHandler(h)
3699 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003700
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003701 def test_multiprocessing(self):
3702 r = logging.makeLogRecord({})
3703 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003704 try:
3705 import multiprocessing as mp
3706 r = logging.makeLogRecord({})
3707 self.assertEqual(r.processName, mp.current_process().name)
3708 except ImportError:
3709 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003710
3711 def test_optional(self):
3712 r = logging.makeLogRecord({})
3713 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003714 if threading:
3715 NOT_NONE(r.thread)
3716 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003717 NOT_NONE(r.process)
3718 NOT_NONE(r.processName)
3719 log_threads = logging.logThreads
3720 log_processes = logging.logProcesses
3721 log_multiprocessing = logging.logMultiprocessing
3722 try:
3723 logging.logThreads = False
3724 logging.logProcesses = False
3725 logging.logMultiprocessing = False
3726 r = logging.makeLogRecord({})
3727 NONE = self.assertIsNone
3728 NONE(r.thread)
3729 NONE(r.threadName)
3730 NONE(r.process)
3731 NONE(r.processName)
3732 finally:
3733 logging.logThreads = log_threads
3734 logging.logProcesses = log_processes
3735 logging.logMultiprocessing = log_multiprocessing
3736
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003737class BasicConfigTest(unittest.TestCase):
3738
Vinay Sajip95bf5042011-04-20 11:50:56 +01003739 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003740
3741 def setUp(self):
3742 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003743 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003744 self.saved_handlers = logging._handlers.copy()
3745 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003746 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003747 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003748 logging.root.handlers = []
3749
3750 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003751 for h in logging.root.handlers[:]:
3752 logging.root.removeHandler(h)
3753 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003754 super(BasicConfigTest, self).tearDown()
3755
Vinay Sajip3def7e02011-04-20 10:58:06 +01003756 def cleanup(self):
3757 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003758 logging._handlers.clear()
3759 logging._handlers.update(self.saved_handlers)
3760 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003761 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003762
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003763 def test_no_kwargs(self):
3764 logging.basicConfig()
3765
3766 # handler defaults to a StreamHandler to sys.stderr
3767 self.assertEqual(len(logging.root.handlers), 1)
3768 handler = logging.root.handlers[0]
3769 self.assertIsInstance(handler, logging.StreamHandler)
3770 self.assertEqual(handler.stream, sys.stderr)
3771
3772 formatter = handler.formatter
3773 # format defaults to logging.BASIC_FORMAT
3774 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3775 # datefmt defaults to None
3776 self.assertIsNone(formatter.datefmt)
3777 # style defaults to %
3778 self.assertIsInstance(formatter._style, logging.PercentStyle)
3779
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003780 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003781 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003782
Vinay Sajip1fd12022014-01-13 21:59:56 +00003783 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003784 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003785 logging.basicConfig(stream=sys.stdout, style="{")
3786 logging.error("Log an error")
3787 sys.stdout.seek(0)
3788 self.assertEqual(output.getvalue().strip(),
3789 "ERROR:root:Log an error")
3790
3791 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003792 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003793 logging.basicConfig(stream=sys.stdout, style="$")
3794 logging.error("Log an error")
3795 sys.stdout.seek(0)
3796 self.assertEqual(output.getvalue().strip(),
3797 "ERROR:root:Log an error")
3798
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003799 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003800
3801 def cleanup(h1, h2, fn):
3802 h1.close()
3803 h2.close()
3804 os.remove(fn)
3805
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003806 logging.basicConfig(filename='test.log')
3807
3808 self.assertEqual(len(logging.root.handlers), 1)
3809 handler = logging.root.handlers[0]
3810 self.assertIsInstance(handler, logging.FileHandler)
3811
3812 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003813 self.assertEqual(handler.stream.mode, expected.stream.mode)
3814 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003815 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003816
3817 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003818
3819 def cleanup(h1, h2, fn):
3820 h1.close()
3821 h2.close()
3822 os.remove(fn)
3823
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003824 logging.basicConfig(filename='test.log', filemode='wb')
3825
3826 handler = logging.root.handlers[0]
3827 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003828 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003829 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003830
3831 def test_stream(self):
3832 stream = io.StringIO()
3833 self.addCleanup(stream.close)
3834 logging.basicConfig(stream=stream)
3835
3836 self.assertEqual(len(logging.root.handlers), 1)
3837 handler = logging.root.handlers[0]
3838 self.assertIsInstance(handler, logging.StreamHandler)
3839 self.assertEqual(handler.stream, stream)
3840
3841 def test_format(self):
3842 logging.basicConfig(format='foo')
3843
3844 formatter = logging.root.handlers[0].formatter
3845 self.assertEqual(formatter._style._fmt, 'foo')
3846
3847 def test_datefmt(self):
3848 logging.basicConfig(datefmt='bar')
3849
3850 formatter = logging.root.handlers[0].formatter
3851 self.assertEqual(formatter.datefmt, 'bar')
3852
3853 def test_style(self):
3854 logging.basicConfig(style='$')
3855
3856 formatter = logging.root.handlers[0].formatter
3857 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3858
3859 def test_level(self):
3860 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003861 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003862
3863 logging.basicConfig(level=57)
3864 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003865 # Test that second call has no effect
3866 logging.basicConfig(level=58)
3867 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003868
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003869 def test_incompatible(self):
3870 assertRaises = self.assertRaises
3871 handlers = [logging.StreamHandler()]
3872 stream = sys.stderr
3873 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3874 stream=stream)
3875 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3876 handlers=handlers)
3877 assertRaises(ValueError, logging.basicConfig, stream=stream,
3878 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003879 # Issue 23207: test for invalid kwargs
3880 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3881 # Should pop both filename and filemode even if filename is None
3882 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003883
3884 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003885 handlers = [
3886 logging.StreamHandler(),
3887 logging.StreamHandler(sys.stdout),
3888 logging.StreamHandler(),
3889 ]
3890 f = logging.Formatter()
3891 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003892 logging.basicConfig(handlers=handlers)
3893 self.assertIs(handlers[0], logging.root.handlers[0])
3894 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003895 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003896 self.assertIsNotNone(handlers[0].formatter)
3897 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003898 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003899 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3900
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003901 def _test_log(self, method, level=None):
3902 # logging.root has no handlers so basicConfig should be called
3903 called = []
3904
3905 old_basic_config = logging.basicConfig
3906 def my_basic_config(*a, **kw):
3907 old_basic_config()
3908 old_level = logging.root.level
3909 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003910 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003911 called.append((a, kw))
3912
Vinay Sajip1feedb42014-05-31 08:19:12 +01003913 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003914
3915 log_method = getattr(logging, method)
3916 if level is not None:
3917 log_method(level, "test me")
3918 else:
3919 log_method("test me")
3920
3921 # basicConfig was called with no arguments
3922 self.assertEqual(called, [((), {})])
3923
3924 def test_log(self):
3925 self._test_log('log', logging.WARNING)
3926
3927 def test_debug(self):
3928 self._test_log('debug')
3929
3930 def test_info(self):
3931 self._test_log('info')
3932
3933 def test_warning(self):
3934 self._test_log('warning')
3935
3936 def test_error(self):
3937 self._test_log('error')
3938
3939 def test_critical(self):
3940 self._test_log('critical')
3941
3942
3943class LoggerAdapterTest(unittest.TestCase):
3944
3945 def setUp(self):
3946 super(LoggerAdapterTest, self).setUp()
3947 old_handler_list = logging._handlerList[:]
3948
3949 self.recording = RecordingHandler()
3950 self.logger = logging.root
3951 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003952 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003953 self.addCleanup(self.recording.close)
3954
3955 def cleanup():
3956 logging._handlerList[:] = old_handler_list
3957
3958 self.addCleanup(cleanup)
3959 self.addCleanup(logging.shutdown)
3960 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3961
3962 def test_exception(self):
3963 msg = 'testing exception: %r'
3964 exc = None
3965 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003966 1 / 0
3967 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003968 exc = e
3969 self.adapter.exception(msg, self.recording)
3970
3971 self.assertEqual(len(self.recording.records), 1)
3972 record = self.recording.records[0]
3973 self.assertEqual(record.levelno, logging.ERROR)
3974 self.assertEqual(record.msg, msg)
3975 self.assertEqual(record.args, (self.recording,))
3976 self.assertEqual(record.exc_info,
3977 (exc.__class__, exc, exc.__traceback__))
3978
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003979 def test_exception_excinfo(self):
3980 try:
3981 1 / 0
3982 except ZeroDivisionError as e:
3983 exc = e
3984
3985 self.adapter.exception('exc_info test', exc_info=exc)
3986
3987 self.assertEqual(len(self.recording.records), 1)
3988 record = self.recording.records[0]
3989 self.assertEqual(record.exc_info,
3990 (exc.__class__, exc, exc.__traceback__))
3991
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003992 def test_critical(self):
3993 msg = 'critical test! %r'
3994 self.adapter.critical(msg, self.recording)
3995
3996 self.assertEqual(len(self.recording.records), 1)
3997 record = self.recording.records[0]
3998 self.assertEqual(record.levelno, logging.CRITICAL)
3999 self.assertEqual(record.msg, msg)
4000 self.assertEqual(record.args, (self.recording,))
4001
4002 def test_is_enabled_for(self):
4003 old_disable = self.adapter.logger.manager.disable
4004 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004005 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4006 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004007 self.assertFalse(self.adapter.isEnabledFor(32))
4008
4009 def test_has_handlers(self):
4010 self.assertTrue(self.adapter.hasHandlers())
4011
4012 for handler in self.logger.handlers:
4013 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004014
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004015 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004016 self.assertFalse(self.adapter.hasHandlers())
4017
4018
4019class LoggerTest(BaseTest):
4020
4021 def setUp(self):
4022 super(LoggerTest, self).setUp()
4023 self.recording = RecordingHandler()
4024 self.logger = logging.Logger(name='blah')
4025 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004026 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004027 self.addCleanup(self.recording.close)
4028 self.addCleanup(logging.shutdown)
4029
4030 def test_set_invalid_level(self):
4031 self.assertRaises(TypeError, self.logger.setLevel, object())
4032
4033 def test_exception(self):
4034 msg = 'testing exception: %r'
4035 exc = None
4036 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004037 1 / 0
4038 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004039 exc = e
4040 self.logger.exception(msg, self.recording)
4041
4042 self.assertEqual(len(self.recording.records), 1)
4043 record = self.recording.records[0]
4044 self.assertEqual(record.levelno, logging.ERROR)
4045 self.assertEqual(record.msg, msg)
4046 self.assertEqual(record.args, (self.recording,))
4047 self.assertEqual(record.exc_info,
4048 (exc.__class__, exc, exc.__traceback__))
4049
4050 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004051 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004052 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004053
4054 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004055 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004056 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004057
4058 def test_find_caller_with_stack_info(self):
4059 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004060 support.patch(self, logging.traceback, 'print_stack',
4061 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004062
4063 self.logger.findCaller(stack_info=True)
4064
4065 self.assertEqual(len(called), 1)
4066 self.assertEqual('Stack (most recent call last):\n', called[0])
4067
4068 def test_make_record_with_extra_overwrite(self):
4069 name = 'my record'
4070 level = 13
4071 fn = lno = msg = args = exc_info = func = sinfo = None
4072 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4073 exc_info, func, sinfo)
4074
4075 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4076 extra = {key: 'some value'}
4077 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4078 fn, lno, msg, args, exc_info,
4079 extra=extra, sinfo=sinfo)
4080
4081 def test_make_record_with_extra_no_overwrite(self):
4082 name = 'my record'
4083 level = 13
4084 fn = lno = msg = args = exc_info = func = sinfo = None
4085 extra = {'valid_key': 'some value'}
4086 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4087 exc_info, extra=extra, sinfo=sinfo)
4088 self.assertIn('valid_key', result.__dict__)
4089
4090 def test_has_handlers(self):
4091 self.assertTrue(self.logger.hasHandlers())
4092
4093 for handler in self.logger.handlers:
4094 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004095 self.assertFalse(self.logger.hasHandlers())
4096
4097 def test_has_handlers_no_propagate(self):
4098 child_logger = logging.getLogger('blah.child')
4099 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004100 self.assertFalse(child_logger.hasHandlers())
4101
4102 def test_is_enabled_for(self):
4103 old_disable = self.logger.manager.disable
4104 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004105 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004106 self.assertFalse(self.logger.isEnabledFor(22))
4107
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004108 def test_root_logger_aliases(self):
4109 root = logging.getLogger()
4110 self.assertIs(root, logging.root)
4111 self.assertIs(root, logging.getLogger(None))
4112 self.assertIs(root, logging.getLogger(''))
4113 self.assertIs(root, logging.getLogger('foo').root)
4114 self.assertIs(root, logging.getLogger('foo.bar').root)
4115 self.assertIs(root, logging.getLogger('foo').parent)
4116
4117 self.assertIsNot(root, logging.getLogger('\0'))
4118 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4119
4120 def test_invalid_names(self):
4121 self.assertRaises(TypeError, logging.getLogger, any)
4122 self.assertRaises(TypeError, logging.getLogger, b'foo')
4123
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004124 def test_pickling(self):
4125 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4126 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4127 logger = logging.getLogger(name)
4128 s = pickle.dumps(logger, proto)
4129 unpickled = pickle.loads(s)
4130 self.assertIs(unpickled, logger)
4131
Avram Lubkin78c18a92017-07-30 05:36:33 -04004132 def test_caching(self):
4133 root = self.root_logger
4134 logger1 = logging.getLogger("abc")
4135 logger2 = logging.getLogger("abc.def")
4136
4137 # Set root logger level and ensure cache is empty
4138 root.setLevel(logging.ERROR)
4139 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4140 self.assertEqual(logger2._cache, {})
4141
4142 # Ensure cache is populated and calls are consistent
4143 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4144 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4145 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4146 self.assertEqual(root._cache, {})
4147 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4148
4149 # Ensure root cache gets populated
4150 self.assertEqual(root._cache, {})
4151 self.assertTrue(root.isEnabledFor(logging.ERROR))
4152 self.assertEqual(root._cache, {logging.ERROR: True})
4153
4154 # Set parent logger level and ensure caches are emptied
4155 logger1.setLevel(logging.CRITICAL)
4156 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4157 self.assertEqual(logger2._cache, {})
4158
4159 # Ensure logger2 uses parent logger's effective level
4160 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4161
4162 # Set level to NOTSET and ensure caches are empty
4163 logger2.setLevel(logging.NOTSET)
4164 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4165 self.assertEqual(logger2._cache, {})
4166 self.assertEqual(logger1._cache, {})
4167 self.assertEqual(root._cache, {})
4168
4169 # Verify logger2 follows parent and not root
4170 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4171 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4172 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4173 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4174 self.assertTrue(root.isEnabledFor(logging.ERROR))
4175
4176 # Disable logging in manager and ensure caches are clear
4177 logging.disable()
4178 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4179 self.assertEqual(logger2._cache, {})
4180 self.assertEqual(logger1._cache, {})
4181 self.assertEqual(root._cache, {})
4182
4183 # Ensure no loggers are enabled
4184 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4185 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4186 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4187
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004188
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004189class BaseFileTest(BaseTest):
4190 "Base class for handler tests that write log files"
4191
4192 def setUp(self):
4193 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004194 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4195 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004196 self.rmfiles = []
4197
4198 def tearDown(self):
4199 for fn in self.rmfiles:
4200 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004201 if os.path.exists(self.fn):
4202 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004203 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004204
4205 def assertLogFile(self, filename):
4206 "Assert a log file is there and register it for deletion"
4207 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004208 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004209 self.rmfiles.append(filename)
4210
4211
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004212class FileHandlerTest(BaseFileTest):
4213 def test_delay(self):
4214 os.unlink(self.fn)
4215 fh = logging.FileHandler(self.fn, delay=True)
4216 self.assertIsNone(fh.stream)
4217 self.assertFalse(os.path.exists(self.fn))
4218 fh.handle(logging.makeLogRecord({}))
4219 self.assertIsNotNone(fh.stream)
4220 self.assertTrue(os.path.exists(self.fn))
4221 fh.close()
4222
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004223class RotatingFileHandlerTest(BaseFileTest):
4224 def next_rec(self):
4225 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4226 self.next_message(), None, None, None)
4227
4228 def test_should_not_rollover(self):
4229 # If maxbytes is zero rollover never occurs
4230 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4231 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004232 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004233
4234 def test_should_rollover(self):
4235 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4236 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004237 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004238
4239 def test_file_created(self):
4240 # checks that the file is created and assumes it was created
4241 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004242 rh = logging.handlers.RotatingFileHandler(self.fn)
4243 rh.emit(self.next_rec())
4244 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004245 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004246
4247 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004248 def namer(name):
4249 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004250 rh = logging.handlers.RotatingFileHandler(
4251 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004252 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004253 rh.emit(self.next_rec())
4254 self.assertLogFile(self.fn)
4255 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004256 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004257 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004258 self.assertLogFile(namer(self.fn + ".2"))
4259 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4260 rh.close()
4261
Vinay Sajip1feedb42014-05-31 08:19:12 +01004262 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004263 def test_rotator(self):
4264 def namer(name):
4265 return name + ".gz"
4266
4267 def rotator(source, dest):
4268 with open(source, "rb") as sf:
4269 data = sf.read()
4270 compressed = zlib.compress(data, 9)
4271 with open(dest, "wb") as df:
4272 df.write(compressed)
4273 os.remove(source)
4274
4275 rh = logging.handlers.RotatingFileHandler(
4276 self.fn, backupCount=2, maxBytes=1)
4277 rh.rotator = rotator
4278 rh.namer = namer
4279 m1 = self.next_rec()
4280 rh.emit(m1)
4281 self.assertLogFile(self.fn)
4282 m2 = self.next_rec()
4283 rh.emit(m2)
4284 fn = namer(self.fn + ".1")
4285 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004286 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004287 with open(fn, "rb") as f:
4288 compressed = f.read()
4289 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004290 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004291 rh.emit(self.next_rec())
4292 fn = namer(self.fn + ".2")
4293 self.assertLogFile(fn)
4294 with open(fn, "rb") as f:
4295 compressed = f.read()
4296 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004297 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004298 rh.emit(self.next_rec())
4299 fn = namer(self.fn + ".2")
4300 with open(fn, "rb") as f:
4301 compressed = f.read()
4302 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004303 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004304 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004305 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004306
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004307class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004308 # other test methods added below
4309 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004310 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4311 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004312 fmt = logging.Formatter('%(asctime)s %(message)s')
4313 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004314 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004315 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004316 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004317 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004318 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004319 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004320 fh.close()
4321 # At this point, we should have a recent rotated file which we
4322 # can test for the existence of. However, in practice, on some
4323 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004324 # in time to go to look for the log file. So, we go back a fair
4325 # bit, and stop as soon as we see a rotated file. In theory this
4326 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004327 found = False
4328 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004329 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004330 for secs in range(GO_BACK):
4331 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004332 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4333 found = os.path.exists(fn)
4334 if found:
4335 self.rmfiles.append(fn)
4336 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004337 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4338 if not found:
4339 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004340 dn, fn = os.path.split(self.fn)
4341 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004342 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4343 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004344 for f in files:
4345 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004346 path = os.path.join(dn, f)
4347 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004348 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004349 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004350
Vinay Sajip0372e102011-05-05 12:59:14 +01004351 def test_invalid(self):
4352 assertRaises = self.assertRaises
4353 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004354 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004355 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004356 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004357 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004358 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004359
Vinay Sajipa7130792013-04-12 17:04:23 +01004360 def test_compute_rollover_daily_attime(self):
4361 currentTime = 0
4362 atTime = datetime.time(12, 0, 0)
4363 rh = logging.handlers.TimedRotatingFileHandler(
4364 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4365 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004366 try:
4367 actual = rh.computeRollover(currentTime)
4368 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004369
Vinay Sajipd86ac962013-04-14 12:20:46 +01004370 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4371 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4372 finally:
4373 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004374
Vinay Sajip10e8c492013-05-18 10:19:54 -07004375 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004376 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004377 currentTime = int(time.time())
4378 today = currentTime - currentTime % 86400
4379
Vinay Sajipa7130792013-04-12 17:04:23 +01004380 atTime = datetime.time(12, 0, 0)
4381
Vinay Sajip10e8c492013-05-18 10:19:54 -07004382 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004383 for day in range(7):
4384 rh = logging.handlers.TimedRotatingFileHandler(
4385 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4386 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004387 try:
4388 if wday > day:
4389 # The rollover day has already passed this week, so we
4390 # go over into next week
4391 expected = (7 - wday + day)
4392 else:
4393 expected = (day - wday)
4394 # At this point expected is in days from now, convert to seconds
4395 expected *= 24 * 60 * 60
4396 # Add in the rollover time
4397 expected += 12 * 60 * 60
4398 # Add in adjustment for today
4399 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004400 actual = rh.computeRollover(today)
4401 if actual != expected:
4402 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004403 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004404 self.assertEqual(actual, expected)
4405 if day == wday:
4406 # goes into following week
4407 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004408 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004409 if actual != expected:
4410 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004411 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004412 self.assertEqual(actual, expected)
4413 finally:
4414 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004415
4416
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004417def secs(**kw):
4418 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4419
4420for when, exp in (('S', 1),
4421 ('M', 60),
4422 ('H', 60 * 60),
4423 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004424 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004425 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004426 ('W0', secs(days=4, hours=24)),
4427 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004428 def test_compute_rollover(self, when=when, exp=exp):
4429 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004430 self.fn, when=when, interval=1, backupCount=0, utc=True)
4431 currentTime = 0.0
4432 actual = rh.computeRollover(currentTime)
4433 if exp != actual:
4434 # Failures occur on some systems for MIDNIGHT and W0.
4435 # Print detailed calculation for MIDNIGHT so we can try to see
4436 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004437 if when == 'MIDNIGHT':
4438 try:
4439 if rh.utc:
4440 t = time.gmtime(currentTime)
4441 else:
4442 t = time.localtime(currentTime)
4443 currentHour = t[3]
4444 currentMinute = t[4]
4445 currentSecond = t[5]
4446 # r is the number of seconds left between now and midnight
4447 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4448 currentMinute) * 60 +
4449 currentSecond)
4450 result = currentTime + r
4451 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4452 print('currentHour: %s' % currentHour, file=sys.stderr)
4453 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4454 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4455 print('r: %s' % r, file=sys.stderr)
4456 print('result: %s' % result, file=sys.stderr)
4457 except Exception:
4458 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4459 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004460 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004461 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4462
Vinay Sajip60ccd822011-05-09 17:32:09 +01004463
Vinay Sajip223349c2015-10-01 20:37:54 +01004464@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004465class NTEventLogHandlerTest(BaseTest):
4466 def test_basic(self):
4467 logtype = 'Application'
4468 elh = win32evtlog.OpenEventLog(None, logtype)
4469 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004470
4471 try:
4472 h = logging.handlers.NTEventLogHandler('test_logging')
4473 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004474 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004475 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004476 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004477
Vinay Sajip60ccd822011-05-09 17:32:09 +01004478 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4479 h.handle(r)
4480 h.close()
4481 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004482 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004483 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4484 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4485 found = False
4486 GO_BACK = 100
4487 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4488 for e in events:
4489 if e.SourceName != 'test_logging':
4490 continue
4491 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4492 if msg != 'Test Log Message\r\n':
4493 continue
4494 found = True
4495 break
4496 msg = 'Record not found in event log, went back %d records' % GO_BACK
4497 self.assertTrue(found, msg=msg)
4498
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004499
4500class MiscTestCase(unittest.TestCase):
4501 def test__all__(self):
4502 blacklist = {'logThreads', 'logMultiprocessing',
4503 'logProcesses', 'currentframe',
4504 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4505 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004506 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004507 support.check__all__(self, logging, blacklist=blacklist)
4508
4509
Christian Heimes180510d2008-03-03 19:15:45 +00004510# Set the locale to the platform-dependent default. I have no idea
4511# why the test does this, but in any case we save the current locale
4512# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004513@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004514def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004515 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004516 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4517 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4518 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4519 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4520 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4521 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4522 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4523 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004524 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004525 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004526 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004527 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004528 ]
4529 if hasattr(logging.handlers, 'QueueListener'):
4530 tests.append(QueueListenerTest)
4531 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004532
Christian Heimes180510d2008-03-03 19:15:45 +00004533if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004534 test_main()