blob: 36ea07251536edef47663483e467c567e8856b4f [file] [log] [blame]
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001# Copyright 2001-2017 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip1e6499c2017-01-09 16:54:12 +000019Copyright (C) 2001-2017 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 from http.server import HTTPServer, BaseHTTPRequestHandler
55 import smtpd
56 from urllib.parse import urlparse, parse_qs
57 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010058 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000059except ImportError:
60 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010061try:
Vinay Sajip223349c2015-10-01 20:37:54 +010062 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010063except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010064 win32evtlog = win32evtlogutil = pywintypes = None
65
Eric V. Smith851cad72012-03-11 22:46:04 -070066try:
67 import zlib
68except ImportError:
69 pass
Christian Heimes18c66892008-02-17 13:31:39 +000070
Christian Heimes180510d2008-03-03 19:15:45 +000071class BaseTest(unittest.TestCase):
72
73 """Base class for logging tests."""
74
75 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030076 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000077 message_num = 0
78
79 def setUp(self):
80 """Setup the default logging stream to an internal StringIO instance,
81 so that we can examine log output as we want."""
82 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000083 logging._acquireLock()
84 try:
Christian Heimes180510d2008-03-03 19:15:45 +000085 self.saved_handlers = logging._handlers.copy()
86 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000087 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070088 self.saved_name_to_level = logging._nameToLevel.copy()
89 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.logger_states = logger_states = {}
91 for name in saved_loggers:
92 logger_states[name] = getattr(saved_loggers[name],
93 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000094 finally:
95 logging._releaseLock()
96
Florent Xicluna5252f9f2011-11-07 19:43:05 +010097 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000098 self.logger1 = logging.getLogger("\xab\xd7\xbb")
99 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000100
Christian Heimes180510d2008-03-03 19:15:45 +0000101 self.root_logger = logging.getLogger("")
102 self.original_logging_level = self.root_logger.getEffectiveLevel()
103
104 self.stream = io.StringIO()
105 self.root_logger.setLevel(logging.DEBUG)
106 self.root_hdlr = logging.StreamHandler(self.stream)
107 self.root_formatter = logging.Formatter(self.log_format)
108 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000109 if self.logger1.hasHandlers():
110 hlist = self.logger1.handlers + self.root_logger.handlers
111 raise AssertionError('Unexpected handlers: %s' % hlist)
112 if self.logger2.hasHandlers():
113 hlist = self.logger2.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000115 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000116 self.assertTrue(self.logger1.hasHandlers())
117 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000118
119 def tearDown(self):
120 """Remove our logging stream, and restore the original logging
121 level."""
122 self.stream.close()
123 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000124 while self.root_logger.handlers:
125 h = self.root_logger.handlers[0]
126 self.root_logger.removeHandler(h)
127 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000128 self.root_logger.setLevel(self.original_logging_level)
129 logging._acquireLock()
130 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700131 logging._levelToName.clear()
132 logging._levelToName.update(self.saved_level_to_name)
133 logging._nameToLevel.clear()
134 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000135 logging._handlers.clear()
136 logging._handlers.update(self.saved_handlers)
137 logging._handlerList[:] = self.saved_handler_list
Avram Lubkin78c18a92017-07-30 05:36:33 -0400138 manager = logging.getLogger().manager
139 manager.disable = 0
140 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000141 loggerDict.clear()
142 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000143 logger_states = self.logger_states
144 for name in self.logger_states:
145 if logger_states[name] is not None:
146 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000147 finally:
148 logging._releaseLock()
149
Vinay Sajip4ded5512012-10-02 15:56:16 +0100150 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000151 """Match the collected log lines against the regular expression
152 self.expected_log_pat, and compare the extracted group values to
153 the expected_values list of tuples."""
154 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100155 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300156 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100157 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000158 for actual, expected in zip(actual_lines, expected_values):
159 match = pat.search(actual)
160 if not match:
161 self.fail("Log line does not match expected pattern:\n" +
162 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000163 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000164 s = stream.read()
165 if s:
166 self.fail("Remaining output at end of log stream:\n" + s)
167
168 def next_message(self):
169 """Generate a message consisting solely of an auto-incrementing
170 integer."""
171 self.message_num += 1
172 return "%d" % self.message_num
173
174
175class BuiltinLevelsTest(BaseTest):
176 """Test builtin levels and their inheritance."""
177
178 def test_flat(self):
179 #Logging levels in a flat logger namespace.
180 m = self.next_message
181
182 ERR = logging.getLogger("ERR")
183 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000184 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000185 INF.setLevel(logging.INFO)
186 DEB = logging.getLogger("DEB")
187 DEB.setLevel(logging.DEBUG)
188
189 # These should log.
190 ERR.log(logging.CRITICAL, m())
191 ERR.error(m())
192
193 INF.log(logging.CRITICAL, m())
194 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100195 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000196 INF.info(m())
197
198 DEB.log(logging.CRITICAL, m())
199 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100200 DEB.warning(m())
201 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000202 DEB.debug(m())
203
204 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100205 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000206 ERR.info(m())
207 ERR.debug(m())
208
209 INF.debug(m())
210
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000211 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000212 ('ERR', 'CRITICAL', '1'),
213 ('ERR', 'ERROR', '2'),
214 ('INF', 'CRITICAL', '3'),
215 ('INF', 'ERROR', '4'),
216 ('INF', 'WARNING', '5'),
217 ('INF', 'INFO', '6'),
218 ('DEB', 'CRITICAL', '7'),
219 ('DEB', 'ERROR', '8'),
220 ('DEB', 'WARNING', '9'),
221 ('DEB', 'INFO', '10'),
222 ('DEB', 'DEBUG', '11'),
223 ])
224
225 def test_nested_explicit(self):
226 # Logging levels in a nested namespace, all explicitly set.
227 m = self.next_message
228
229 INF = logging.getLogger("INF")
230 INF.setLevel(logging.INFO)
231 INF_ERR = logging.getLogger("INF.ERR")
232 INF_ERR.setLevel(logging.ERROR)
233
234 # These should log.
235 INF_ERR.log(logging.CRITICAL, m())
236 INF_ERR.error(m())
237
238 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100239 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000240 INF_ERR.info(m())
241 INF_ERR.debug(m())
242
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000243 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000244 ('INF.ERR', 'CRITICAL', '1'),
245 ('INF.ERR', 'ERROR', '2'),
246 ])
247
248 def test_nested_inherited(self):
249 #Logging levels in a nested namespace, inherited from parent loggers.
250 m = self.next_message
251
252 INF = logging.getLogger("INF")
253 INF.setLevel(logging.INFO)
254 INF_ERR = logging.getLogger("INF.ERR")
255 INF_ERR.setLevel(logging.ERROR)
256 INF_UNDEF = logging.getLogger("INF.UNDEF")
257 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
258 UNDEF = logging.getLogger("UNDEF")
259
260 # These should log.
261 INF_UNDEF.log(logging.CRITICAL, m())
262 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100263 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000264 INF_UNDEF.info(m())
265 INF_ERR_UNDEF.log(logging.CRITICAL, m())
266 INF_ERR_UNDEF.error(m())
267
268 # These should not log.
269 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100270 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000271 INF_ERR_UNDEF.info(m())
272 INF_ERR_UNDEF.debug(m())
273
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000274 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000275 ('INF.UNDEF', 'CRITICAL', '1'),
276 ('INF.UNDEF', 'ERROR', '2'),
277 ('INF.UNDEF', 'WARNING', '3'),
278 ('INF.UNDEF', 'INFO', '4'),
279 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
280 ('INF.ERR.UNDEF', 'ERROR', '6'),
281 ])
282
283 def test_nested_with_virtual_parent(self):
284 # Logging levels when some parent does not exist yet.
285 m = self.next_message
286
287 INF = logging.getLogger("INF")
288 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
289 CHILD = logging.getLogger("INF.BADPARENT")
290 INF.setLevel(logging.INFO)
291
292 # These should log.
293 GRANDCHILD.log(logging.FATAL, m())
294 GRANDCHILD.info(m())
295 CHILD.log(logging.FATAL, m())
296 CHILD.info(m())
297
298 # These should not log.
299 GRANDCHILD.debug(m())
300 CHILD.debug(m())
301
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000302 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000303 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
304 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
305 ('INF.BADPARENT', 'CRITICAL', '3'),
306 ('INF.BADPARENT', 'INFO', '4'),
307 ])
308
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100309 def test_regression_22386(self):
310 """See issue #22386 for more information."""
311 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
312 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000313
Vinay Sajip8b866d52017-01-11 06:57:55 +0000314 def test_regression_29220(self):
315 """See issue #29220 for more information."""
316 logging.addLevelName(logging.INFO, '')
317 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
318 self.assertEqual(logging.getLevelName(logging.INFO), '')
319
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100320 def test_issue27935(self):
321 fatal = logging.getLevelName('FATAL')
322 self.assertEqual(fatal, logging.FATAL)
323
Vinay Sajip924aaae2017-01-11 17:35:36 +0000324 def test_regression_29220(self):
325 """See issue #29220 for more information."""
326 logging.addLevelName(logging.INFO, '')
327 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
328 self.assertEqual(logging.getLevelName(logging.INFO), '')
329 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
330 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
331
Christian Heimes180510d2008-03-03 19:15:45 +0000332class BasicFilterTest(BaseTest):
333
334 """Test the bundled Filter class."""
335
336 def test_filter(self):
337 # Only messages satisfying the specified criteria pass through the
338 # filter.
339 filter_ = logging.Filter("spam.eggs")
340 handler = self.root_logger.handlers[0]
341 try:
342 handler.addFilter(filter_)
343 spam = logging.getLogger("spam")
344 spam_eggs = logging.getLogger("spam.eggs")
345 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
346 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
347
348 spam.info(self.next_message())
349 spam_eggs.info(self.next_message()) # Good.
350 spam_eggs_fish.info(self.next_message()) # Good.
351 spam_bakedbeans.info(self.next_message())
352
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000353 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000354 ('spam.eggs', 'INFO', '2'),
355 ('spam.eggs.fish', 'INFO', '3'),
356 ])
357 finally:
358 handler.removeFilter(filter_)
359
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000360 def test_callable_filter(self):
361 # Only messages satisfying the specified criteria pass through the
362 # filter.
363
364 def filterfunc(record):
365 parts = record.name.split('.')
366 prefix = '.'.join(parts[:2])
367 return prefix == 'spam.eggs'
368
369 handler = self.root_logger.handlers[0]
370 try:
371 handler.addFilter(filterfunc)
372 spam = logging.getLogger("spam")
373 spam_eggs = logging.getLogger("spam.eggs")
374 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
375 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
376
377 spam.info(self.next_message())
378 spam_eggs.info(self.next_message()) # Good.
379 spam_eggs_fish.info(self.next_message()) # Good.
380 spam_bakedbeans.info(self.next_message())
381
382 self.assert_log_lines([
383 ('spam.eggs', 'INFO', '2'),
384 ('spam.eggs.fish', 'INFO', '3'),
385 ])
386 finally:
387 handler.removeFilter(filterfunc)
388
Vinay Sajip985ef872011-04-26 19:34:04 +0100389 def test_empty_filter(self):
390 f = logging.Filter()
391 r = logging.makeLogRecord({'name': 'spam.eggs'})
392 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000393
394#
395# First, we define our levels. There can be as many as you want - the only
396# limitations are that they should be integers, the lowest should be > 0 and
397# larger values mean less information being logged. If you need specific
398# level values which do not fit into these limitations, you can use a
399# mapping dictionary to convert between your application levels and the
400# logging system.
401#
402SILENT = 120
403TACITURN = 119
404TERSE = 118
405EFFUSIVE = 117
406SOCIABLE = 116
407VERBOSE = 115
408TALKATIVE = 114
409GARRULOUS = 113
410CHATTERBOX = 112
411BORING = 111
412
413LEVEL_RANGE = range(BORING, SILENT + 1)
414
415#
416# Next, we define names for our levels. You don't need to do this - in which
417# case the system will use "Level n" to denote the text for the level.
418#
419my_logging_levels = {
420 SILENT : 'Silent',
421 TACITURN : 'Taciturn',
422 TERSE : 'Terse',
423 EFFUSIVE : 'Effusive',
424 SOCIABLE : 'Sociable',
425 VERBOSE : 'Verbose',
426 TALKATIVE : 'Talkative',
427 GARRULOUS : 'Garrulous',
428 CHATTERBOX : 'Chatterbox',
429 BORING : 'Boring',
430}
431
432class GarrulousFilter(logging.Filter):
433
434 """A filter which blocks garrulous messages."""
435
436 def filter(self, record):
437 return record.levelno != GARRULOUS
438
439class VerySpecificFilter(logging.Filter):
440
441 """A filter which blocks sociable and taciturn messages."""
442
443 def filter(self, record):
444 return record.levelno not in [SOCIABLE, TACITURN]
445
446
447class CustomLevelsAndFiltersTest(BaseTest):
448
449 """Test various filtering possibilities with custom logging levels."""
450
451 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300452 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000453
454 def setUp(self):
455 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000456 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000457 logging.addLevelName(k, v)
458
459 def log_at_all_levels(self, logger):
460 for lvl in LEVEL_RANGE:
461 logger.log(lvl, self.next_message())
462
463 def test_logger_filter(self):
464 # Filter at logger level.
465 self.root_logger.setLevel(VERBOSE)
466 # Levels >= 'Verbose' are good.
467 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000468 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000469 ('Verbose', '5'),
470 ('Sociable', '6'),
471 ('Effusive', '7'),
472 ('Terse', '8'),
473 ('Taciturn', '9'),
474 ('Silent', '10'),
475 ])
476
477 def test_handler_filter(self):
478 # Filter at handler level.
479 self.root_logger.handlers[0].setLevel(SOCIABLE)
480 try:
481 # Levels >= 'Sociable' are good.
482 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000483 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000484 ('Sociable', '6'),
485 ('Effusive', '7'),
486 ('Terse', '8'),
487 ('Taciturn', '9'),
488 ('Silent', '10'),
489 ])
490 finally:
491 self.root_logger.handlers[0].setLevel(logging.NOTSET)
492
493 def test_specific_filters(self):
494 # Set a specific filter object on the handler, and then add another
495 # filter object on the logger itself.
496 handler = self.root_logger.handlers[0]
497 specific_filter = None
498 garr = GarrulousFilter()
499 handler.addFilter(garr)
500 try:
501 self.log_at_all_levels(self.root_logger)
502 first_lines = [
503 # Notice how 'Garrulous' is missing
504 ('Boring', '1'),
505 ('Chatterbox', '2'),
506 ('Talkative', '4'),
507 ('Verbose', '5'),
508 ('Sociable', '6'),
509 ('Effusive', '7'),
510 ('Terse', '8'),
511 ('Taciturn', '9'),
512 ('Silent', '10'),
513 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000514 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000515
516 specific_filter = VerySpecificFilter()
517 self.root_logger.addFilter(specific_filter)
518 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000519 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000520 # Not only 'Garrulous' is still missing, but also 'Sociable'
521 # and 'Taciturn'
522 ('Boring', '11'),
523 ('Chatterbox', '12'),
524 ('Talkative', '14'),
525 ('Verbose', '15'),
526 ('Effusive', '17'),
527 ('Terse', '18'),
528 ('Silent', '20'),
529 ])
530 finally:
531 if specific_filter:
532 self.root_logger.removeFilter(specific_filter)
533 handler.removeFilter(garr)
534
535
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100536class HandlerTest(BaseTest):
537 def test_name(self):
538 h = logging.Handler()
539 h.name = 'generic'
540 self.assertEqual(h.name, 'generic')
541 h.name = 'anothergeneric'
542 self.assertEqual(h.name, 'anothergeneric')
543 self.assertRaises(NotImplementedError, h.emit, None)
544
Vinay Sajip5a35b062011-04-27 11:31:14 +0100545 def test_builtin_handlers(self):
546 # We can't actually *use* too many handlers in the tests,
547 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200548 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100549 for existing in (True, False):
550 fd, fn = tempfile.mkstemp()
551 os.close(fd)
552 if not existing:
553 os.unlink(fn)
554 h = logging.handlers.WatchedFileHandler(fn, delay=True)
555 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100556 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100557 self.assertEqual(dev, -1)
558 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100559 r = logging.makeLogRecord({'msg': 'Test'})
560 h.handle(r)
561 # Now remove the file.
562 os.unlink(fn)
563 self.assertFalse(os.path.exists(fn))
564 # The next call should recreate the file.
565 h.handle(r)
566 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100567 else:
568 self.assertEqual(h.dev, -1)
569 self.assertEqual(h.ino, -1)
570 h.close()
571 if existing:
572 os.unlink(fn)
573 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100574 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100575 else:
576 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100577 try:
578 h = logging.handlers.SysLogHandler(sockname)
579 self.assertEqual(h.facility, h.LOG_USER)
580 self.assertTrue(h.unixsocket)
581 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200582 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100583 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100584 for method in ('GET', 'POST', 'PUT'):
585 if method == 'PUT':
586 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
587 'localhost', '/log', method)
588 else:
589 h = logging.handlers.HTTPHandler('localhost', '/log', method)
590 h.close()
591 h = logging.handlers.BufferingHandler(0)
592 r = logging.makeLogRecord({})
593 self.assertTrue(h.shouldFlush(r))
594 h.close()
595 h = logging.handlers.BufferingHandler(1)
596 self.assertFalse(h.shouldFlush(r))
597 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100598
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100599 def test_path_objects(self):
600 """
601 Test that Path objects are accepted as filename arguments to handlers.
602
603 See Issue #27493.
604 """
605 fd, fn = tempfile.mkstemp()
606 os.close(fd)
607 os.unlink(fn)
608 pfn = pathlib.Path(fn)
609 cases = (
610 (logging.FileHandler, (pfn, 'w')),
611 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
612 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
613 )
614 if sys.platform in ('linux', 'darwin'):
615 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
616 for cls, args in cases:
617 h = cls(*args)
618 self.assertTrue(os.path.exists(fn))
619 h.close()
620 os.unlink(fn)
621
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100622 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200624 @support.reap_threads
Vinay Sajipa5798de2012-04-24 23:33:33 +0100625 def test_race(self):
626 # Issue #14632 refers.
627 def remove_loop(fname, tries):
628 for _ in range(tries):
629 try:
630 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000631 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100632 except OSError:
633 pass
634 time.sleep(0.004 * random.randint(0, 4))
635
Vinay Sajipc94871a2012-04-25 10:51:35 +0100636 del_count = 500
637 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100638
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000639 self.handle_time = None
640 self.deletion_time = None
641
Vinay Sajipa5798de2012-04-24 23:33:33 +0100642 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100643 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
644 os.close(fd)
645 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
646 remover.daemon = True
647 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100648 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100649 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
650 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100651 try:
652 for _ in range(log_count):
653 time.sleep(0.005)
654 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000655 try:
656 self.handle_time = time.time()
657 h.handle(r)
658 except Exception:
659 print('Deleted at %s, '
660 'opened at %s' % (self.deletion_time,
661 self.handle_time))
662 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100663 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100664 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100665 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100666 if os.path.exists(fn):
667 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100668
669
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100670class BadStream(object):
671 def write(self, data):
672 raise RuntimeError('deliberate mistake')
673
674class TestStreamHandler(logging.StreamHandler):
675 def handleError(self, record):
676 self.error_record = record
677
678class StreamHandlerTest(BaseTest):
679 def test_error_handling(self):
680 h = TestStreamHandler(BadStream())
681 r = logging.makeLogRecord({})
682 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100683
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100684 try:
685 h.handle(r)
686 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687
Vinay Sajip985ef872011-04-26 19:34:04 +0100688 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100689 with support.captured_stderr() as stderr:
690 h.handle(r)
691 msg = '\nRuntimeError: deliberate mistake\n'
692 self.assertIn(msg, stderr.getvalue())
693
Vinay Sajip985ef872011-04-26 19:34:04 +0100694 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100695 with support.captured_stderr() as stderr:
696 h.handle(r)
697 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100698 finally:
699 logging.raiseExceptions = old_raise
700
Vinay Sajip2543f502017-07-30 10:41:45 +0100701 def test_stream_setting(self):
702 """
703 Test setting the handler's stream
704 """
705 h = logging.StreamHandler()
706 stream = io.StringIO()
707 old = h.setStream(stream)
708 self.assertIs(old, sys.stderr)
709 actual = h.setStream(old)
710 self.assertIs(actual, stream)
711 # test that setting to existing value returns None
712 actual = h.setStream(old)
713 self.assertIsNone(actual)
714
Vinay Sajip7367d082011-05-02 13:17:27 +0100715# -- The following section could be moved into a server_helper.py module
716# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100717
Vinay Sajipce7c9782011-05-17 07:15:53 +0100718if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100719 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100720 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100722
Vinay Sajipce7c9782011-05-17 07:15:53 +0100723 :param addr: A (host, port) tuple which the server listens on.
724 You can specify a port value of zero: the server's
725 *port* attribute will hold the actual port number
726 used, which can be used in client connections.
727 :param handler: A callable which will be called to process
728 incoming messages. The handler will be passed
729 the client address tuple, who the message is from,
730 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100731 :param poll_interval: The interval, in seconds, used in the underlying
732 :func:`select` or :func:`poll` call by
733 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100734 :param sockmap: A dictionary which will be used to hold
735 :class:`asyncore.dispatcher` instances used by
736 :func:`asyncore.loop`. This avoids changing the
737 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100738 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100739
740 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400741 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
742 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100743 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100744 self._handler = handler
745 self._thread = None
746 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100747
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 def process_message(self, peer, mailfrom, rcpttos, data):
749 """
750 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100751
Vinay Sajipce7c9782011-05-17 07:15:53 +0100752 Typically, this will be a test case method.
753 :param peer: The client (host, port) tuple.
754 :param mailfrom: The address of the sender.
755 :param rcpttos: The addresses of the recipients.
756 :param data: The message.
757 """
758 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100759
Vinay Sajipce7c9782011-05-17 07:15:53 +0100760 def start(self):
761 """
762 Start the server running on a separate daemon thread.
763 """
764 self._thread = t = threading.Thread(target=self.serve_forever,
765 args=(self.poll_interval,))
766 t.setDaemon(True)
767 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100768
Vinay Sajipce7c9782011-05-17 07:15:53 +0100769 def serve_forever(self, poll_interval):
770 """
771 Run the :mod:`asyncore` loop until normal termination
772 conditions arise.
773 :param poll_interval: The interval, in seconds, used in the underlying
774 :func:`select` or :func:`poll` call by
775 :func:`asyncore.loop`.
776 """
777 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100778 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200779 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100780 # On FreeBSD 8, closing the server repeatably
781 # raises this error. We swallow it if the
782 # server has been closed.
783 if self.connected or self.accepting:
784 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 def stop(self, timeout=None):
787 """
788 Stop the thread by closing the server instance.
789 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100790
Vinay Sajipce7c9782011-05-17 07:15:53 +0100791 :param timeout: How long to wait for the server thread
792 to terminate.
793 """
794 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100795 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200796 alive = self._thread.is_alive()
Vinay Sajip7367d082011-05-02 13:17:27 +0100797 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200798 if alive:
799 self.fail("join() timed out")
Vinay Sajip7367d082011-05-02 13:17:27 +0100800
Vinay Sajipce7c9782011-05-17 07:15:53 +0100801 class ControlMixin(object):
802 """
803 This mixin is used to start a server on a separate thread, and
804 shut it down programmatically. Request handling is simplified - instead
805 of needing to derive a suitable RequestHandler subclass, you just
806 provide a callable which will be passed each received request to be
807 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100808
Vinay Sajipce7c9782011-05-17 07:15:53 +0100809 :param handler: A handler callable which will be called with a
810 single parameter - the request - in order to
811 process the request. This handler is called on the
812 server thread, effectively meaning that requests are
813 processed serially. While not quite Web scale ;-),
814 this should be fine for testing applications.
815 :param poll_interval: The polling interval in seconds.
816 """
817 def __init__(self, handler, poll_interval):
818 self._thread = None
819 self.poll_interval = poll_interval
820 self._handler = handler
821 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100822
Vinay Sajipce7c9782011-05-17 07:15:53 +0100823 def start(self):
824 """
825 Create a daemon thread to run the server, and start it.
826 """
827 self._thread = t = threading.Thread(target=self.serve_forever,
828 args=(self.poll_interval,))
829 t.setDaemon(True)
830 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100831
Vinay Sajipce7c9782011-05-17 07:15:53 +0100832 def serve_forever(self, poll_interval):
833 """
834 Run the server. Set the ready flag before entering the
835 service loop.
836 """
837 self.ready.set()
838 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100839
Vinay Sajipce7c9782011-05-17 07:15:53 +0100840 def stop(self, timeout=None):
841 """
842 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100843
Vinay Sajipce7c9782011-05-17 07:15:53 +0100844 :param timeout: How long to wait for the server thread
845 to terminate.
846 """
847 self.shutdown()
848 if self._thread is not None:
849 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200850 alive = self._thread.is_alive()
Vinay Sajipce7c9782011-05-17 07:15:53 +0100851 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200852 if alive:
853 self.fail("join() timed out")
Vinay Sajipce7c9782011-05-17 07:15:53 +0100854 self.server_close()
855 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100856
Vinay Sajipce7c9782011-05-17 07:15:53 +0100857 class TestHTTPServer(ControlMixin, HTTPServer):
858 """
859 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 :param addr: A tuple with the IP address and port to listen on.
862 :param handler: A handler callable which will be called with a
863 single parameter - the request - in order to
864 process the request.
865 :param poll_interval: The polling interval in seconds.
866 :param log: Pass ``True`` to enable log messages.
867 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100868 def __init__(self, addr, handler, poll_interval=0.5,
869 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100870 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
871 def __getattr__(self, name, default=None):
872 if name.startswith('do_'):
873 return self.process_request
874 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100875
Vinay Sajipce7c9782011-05-17 07:15:53 +0100876 def process_request(self):
877 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100878
Vinay Sajipce7c9782011-05-17 07:15:53 +0100879 def log_message(self, format, *args):
880 if log:
881 super(DelegatingHTTPRequestHandler,
882 self).log_message(format, *args)
883 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
884 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100885 self.sslctx = sslctx
886
887 def get_request(self):
888 try:
889 sock, addr = self.socket.accept()
890 if self.sslctx:
891 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200892 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100893 # socket errors are silenced by the caller, print them here
894 sys.stderr.write("Got an error:\n%s\n" % e)
895 raise
896 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100897
Vinay Sajipce7c9782011-05-17 07:15:53 +0100898 class TestTCPServer(ControlMixin, ThreadingTCPServer):
899 """
900 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100901
Vinay Sajipce7c9782011-05-17 07:15:53 +0100902 :param addr: A tuple with the IP address and port to listen on.
903 :param handler: A handler callable which will be called with a single
904 parameter - the request - in order to process the request.
905 :param poll_interval: The polling interval in seconds.
906 :bind_and_activate: If True (the default), binds the server and starts it
907 listening. If False, you need to call
908 :meth:`server_bind` and :meth:`server_activate` at
909 some later time before calling :meth:`start`, so that
910 the server will set up the socket and listen on it.
911 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100912
Vinay Sajipce7c9782011-05-17 07:15:53 +0100913 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Vinay Sajipce7c9782011-05-17 07:15:53 +0100915 def __init__(self, addr, handler, poll_interval=0.5,
916 bind_and_activate=True):
917 class DelegatingTCPRequestHandler(StreamRequestHandler):
918
919 def handle(self):
920 self.server._handler(self)
921 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
922 bind_and_activate)
923 ControlMixin.__init__(self, handler, poll_interval)
924
925 def server_bind(self):
926 super(TestTCPServer, self).server_bind()
927 self.port = self.socket.getsockname()[1]
928
929 class TestUDPServer(ControlMixin, ThreadingUDPServer):
930 """
931 A UDP server which is controllable using :class:`ControlMixin`.
932
933 :param addr: A tuple with the IP address and port to listen on.
934 :param handler: A handler callable which will be called with a
935 single parameter - the request - in order to
936 process the request.
937 :param poll_interval: The polling interval for shutdown requests,
938 in seconds.
939 :bind_and_activate: If True (the default), binds the server and
940 starts it listening. If False, you need to
941 call :meth:`server_bind` and
942 :meth:`server_activate` at some later time
943 before calling :meth:`start`, so that the server will
944 set up the socket and listen on it.
945 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100946 def __init__(self, addr, handler, poll_interval=0.5,
947 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100948 class DelegatingUDPRequestHandler(DatagramRequestHandler):
949
950 def handle(self):
951 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100952
953 def finish(self):
954 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100955 if data:
956 try:
957 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200958 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100959 if not self.server._closed:
960 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100961
Vinay Sajip3ef12292011-05-23 23:00:42 +0100962 ThreadingUDPServer.__init__(self, addr,
963 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100964 bind_and_activate)
965 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100966 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100967
968 def server_bind(self):
969 super(TestUDPServer, self).server_bind()
970 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100971
Vinay Sajipba980db2011-05-23 21:37:54 +0100972 def server_close(self):
973 super(TestUDPServer, self).server_close()
974 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100975
Victor Stinnerec5a8602014-06-02 14:41:51 +0200976 if hasattr(socket, "AF_UNIX"):
977 class TestUnixStreamServer(TestTCPServer):
978 address_family = socket.AF_UNIX
979
980 class TestUnixDatagramServer(TestUDPServer):
981 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100982
Vinay Sajip7367d082011-05-02 13:17:27 +0100983# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100984
Vinay Sajipce7c9782011-05-17 07:15:53 +0100985@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100986class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000987 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200988
989 @support.reap_threads
Vinay Sajipa463d252011-04-30 21:52:48 +0100990 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100991 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800992 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100993 sockmap)
994 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800995 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000996 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
997 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100998 self.assertEqual(h.toaddrs, ['you'])
999 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001000 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001001 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001002 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001003 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +01001004 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001005 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001006 self.assertEqual(len(self.messages), 1)
1007 peer, mailfrom, rcpttos, data = self.messages[0]
1008 self.assertEqual(mailfrom, 'me')
1009 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001010 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001011 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001012 h.close()
1013
1014 def process_message(self, *args):
1015 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001016 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001017
Christian Heimes180510d2008-03-03 19:15:45 +00001018class MemoryHandlerTest(BaseTest):
1019
1020 """Tests for the MemoryHandler."""
1021
1022 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001023 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001024
1025 def setUp(self):
1026 BaseTest.setUp(self)
1027 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001028 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001029 self.mem_logger = logging.getLogger('mem')
1030 self.mem_logger.propagate = 0
1031 self.mem_logger.addHandler(self.mem_hdlr)
1032
1033 def tearDown(self):
1034 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001035 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001036
1037 def test_flush(self):
1038 # The memory handler flushes to its target handler based on specific
1039 # criteria (message count and message level).
1040 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001041 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001042 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001043 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001044 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001045 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001046 lines = [
1047 ('DEBUG', '1'),
1048 ('INFO', '2'),
1049 ('WARNING', '3'),
1050 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001051 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001052 for n in (4, 14):
1053 for i in range(9):
1054 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001055 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001056 # This will flush because it's the 10th message since the last
1057 # flush.
1058 self.mem_logger.debug(self.next_message())
1059 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001060 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001061
1062 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001063 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001064
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001065 def test_flush_on_close(self):
1066 """
1067 Test that the flush-on-close configuration works as expected.
1068 """
1069 self.mem_logger.debug(self.next_message())
1070 self.assert_log_lines([])
1071 self.mem_logger.info(self.next_message())
1072 self.assert_log_lines([])
1073 self.mem_logger.removeHandler(self.mem_hdlr)
1074 # Default behaviour is to flush on close. Check that it happens.
1075 self.mem_hdlr.close()
1076 lines = [
1077 ('DEBUG', '1'),
1078 ('INFO', '2'),
1079 ]
1080 self.assert_log_lines(lines)
1081 # Now configure for flushing not to be done on close.
1082 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1083 self.root_hdlr,
1084 False)
1085 self.mem_logger.addHandler(self.mem_hdlr)
1086 self.mem_logger.debug(self.next_message())
1087 self.assert_log_lines(lines) # no change
1088 self.mem_logger.info(self.next_message())
1089 self.assert_log_lines(lines) # no change
1090 self.mem_logger.removeHandler(self.mem_hdlr)
1091 self.mem_hdlr.close()
1092 # assert that no new lines have been added
1093 self.assert_log_lines(lines) # no change
1094
Christian Heimes180510d2008-03-03 19:15:45 +00001095
1096class ExceptionFormatter(logging.Formatter):
1097 """A special exception formatter."""
1098 def formatException(self, ei):
1099 return "Got a [%s]" % ei[0].__name__
1100
1101
1102class ConfigFileTest(BaseTest):
1103
1104 """Reading logging config from a .ini-style config file."""
1105
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001106 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001107
1108 # config0 is a standard configuration.
1109 config0 = """
1110 [loggers]
1111 keys=root
1112
1113 [handlers]
1114 keys=hand1
1115
1116 [formatters]
1117 keys=form1
1118
1119 [logger_root]
1120 level=WARNING
1121 handlers=hand1
1122
1123 [handler_hand1]
1124 class=StreamHandler
1125 level=NOTSET
1126 formatter=form1
1127 args=(sys.stdout,)
1128
1129 [formatter_form1]
1130 format=%(levelname)s ++ %(message)s
1131 datefmt=
1132 """
1133
1134 # config1 adds a little to the standard configuration.
1135 config1 = """
1136 [loggers]
1137 keys=root,parser
1138
1139 [handlers]
1140 keys=hand1
1141
1142 [formatters]
1143 keys=form1
1144
1145 [logger_root]
1146 level=WARNING
1147 handlers=
1148
1149 [logger_parser]
1150 level=DEBUG
1151 handlers=hand1
1152 propagate=1
1153 qualname=compiler.parser
1154
1155 [handler_hand1]
1156 class=StreamHandler
1157 level=NOTSET
1158 formatter=form1
1159 args=(sys.stdout,)
1160
1161 [formatter_form1]
1162 format=%(levelname)s ++ %(message)s
1163 datefmt=
1164 """
1165
Vinay Sajip3f84b072011-03-07 17:49:33 +00001166 # config1a moves the handler to the root.
1167 config1a = """
1168 [loggers]
1169 keys=root,parser
1170
1171 [handlers]
1172 keys=hand1
1173
1174 [formatters]
1175 keys=form1
1176
1177 [logger_root]
1178 level=WARNING
1179 handlers=hand1
1180
1181 [logger_parser]
1182 level=DEBUG
1183 handlers=
1184 propagate=1
1185 qualname=compiler.parser
1186
1187 [handler_hand1]
1188 class=StreamHandler
1189 level=NOTSET
1190 formatter=form1
1191 args=(sys.stdout,)
1192
1193 [formatter_form1]
1194 format=%(levelname)s ++ %(message)s
1195 datefmt=
1196 """
1197
Christian Heimes180510d2008-03-03 19:15:45 +00001198 # config2 has a subtle configuration error that should be reported
1199 config2 = config1.replace("sys.stdout", "sys.stbout")
1200
1201 # config3 has a less subtle configuration error
1202 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1203
1204 # config4 specifies a custom formatter class to be loaded
1205 config4 = """
1206 [loggers]
1207 keys=root
1208
1209 [handlers]
1210 keys=hand1
1211
1212 [formatters]
1213 keys=form1
1214
1215 [logger_root]
1216 level=NOTSET
1217 handlers=hand1
1218
1219 [handler_hand1]
1220 class=StreamHandler
1221 level=NOTSET
1222 formatter=form1
1223 args=(sys.stdout,)
1224
1225 [formatter_form1]
1226 class=""" + __name__ + """.ExceptionFormatter
1227 format=%(levelname)s:%(name)s:%(message)s
1228 datefmt=
1229 """
1230
Georg Brandl3dbca812008-07-23 16:10:53 +00001231 # config5 specifies a custom handler class to be loaded
1232 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1233
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001234 # config6 uses ', ' delimiters in the handlers and formatters sections
1235 config6 = """
1236 [loggers]
1237 keys=root,parser
1238
1239 [handlers]
1240 keys=hand1, hand2
1241
1242 [formatters]
1243 keys=form1, form2
1244
1245 [logger_root]
1246 level=WARNING
1247 handlers=
1248
1249 [logger_parser]
1250 level=DEBUG
1251 handlers=hand1
1252 propagate=1
1253 qualname=compiler.parser
1254
1255 [handler_hand1]
1256 class=StreamHandler
1257 level=NOTSET
1258 formatter=form1
1259 args=(sys.stdout,)
1260
1261 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001262 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001263 level=NOTSET
1264 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001265 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001266
1267 [formatter_form1]
1268 format=%(levelname)s ++ %(message)s
1269 datefmt=
1270
1271 [formatter_form2]
1272 format=%(message)s
1273 datefmt=
1274 """
1275
Vinay Sajip3f84b072011-03-07 17:49:33 +00001276 # config7 adds a compiler logger.
1277 config7 = """
1278 [loggers]
1279 keys=root,parser,compiler
1280
1281 [handlers]
1282 keys=hand1
1283
1284 [formatters]
1285 keys=form1
1286
1287 [logger_root]
1288 level=WARNING
1289 handlers=hand1
1290
1291 [logger_compiler]
1292 level=DEBUG
1293 handlers=
1294 propagate=1
1295 qualname=compiler
1296
1297 [logger_parser]
1298 level=DEBUG
1299 handlers=
1300 propagate=1
1301 qualname=compiler.parser
1302
1303 [handler_hand1]
1304 class=StreamHandler
1305 level=NOTSET
1306 formatter=form1
1307 args=(sys.stdout,)
1308
1309 [formatter_form1]
1310 format=%(levelname)s ++ %(message)s
1311 datefmt=
1312 """
1313
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001314 disable_test = """
1315 [loggers]
1316 keys=root
1317
1318 [handlers]
1319 keys=screen
1320
1321 [formatters]
1322 keys=
1323
1324 [logger_root]
1325 level=DEBUG
1326 handlers=screen
1327
1328 [handler_screen]
1329 level=DEBUG
1330 class=StreamHandler
1331 args=(sys.stdout,)
1332 formatter=
1333 """
1334
1335 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001336 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001337 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001338
1339 def test_config0_ok(self):
1340 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001341 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001342 self.apply_config(self.config0)
1343 logger = logging.getLogger()
1344 # Won't output anything
1345 logger.info(self.next_message())
1346 # Outputs a message
1347 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001348 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001349 ('ERROR', '2'),
1350 ], stream=output)
1351 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001352 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001353
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001354 def test_config0_using_cp_ok(self):
1355 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001356 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001357 file = io.StringIO(textwrap.dedent(self.config0))
1358 cp = configparser.ConfigParser()
1359 cp.read_file(file)
1360 logging.config.fileConfig(cp)
1361 logger = logging.getLogger()
1362 # Won't output anything
1363 logger.info(self.next_message())
1364 # Outputs a message
1365 logger.error(self.next_message())
1366 self.assert_log_lines([
1367 ('ERROR', '2'),
1368 ], stream=output)
1369 # Original logger output is empty.
1370 self.assert_log_lines([])
1371
Georg Brandl3dbca812008-07-23 16:10:53 +00001372 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001373 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001374 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001375 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001376 logger = logging.getLogger("compiler.parser")
1377 # Both will output a message
1378 logger.info(self.next_message())
1379 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001380 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001381 ('INFO', '1'),
1382 ('ERROR', '2'),
1383 ], stream=output)
1384 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001385 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001386
1387 def test_config2_failure(self):
1388 # A simple config file which overrides the default settings.
1389 self.assertRaises(Exception, self.apply_config, self.config2)
1390
1391 def test_config3_failure(self):
1392 # A simple config file which overrides the default settings.
1393 self.assertRaises(Exception, self.apply_config, self.config3)
1394
1395 def test_config4_ok(self):
1396 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001397 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001398 self.apply_config(self.config4)
1399 logger = logging.getLogger()
1400 try:
1401 raise RuntimeError()
1402 except RuntimeError:
1403 logging.exception("just testing")
1404 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001405 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001406 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1407 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001408 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001409
Georg Brandl3dbca812008-07-23 16:10:53 +00001410 def test_config5_ok(self):
1411 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001412
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001413 def test_config6_ok(self):
1414 self.test_config1_ok(config=self.config6)
1415
Vinay Sajip3f84b072011-03-07 17:49:33 +00001416 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001417 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001418 self.apply_config(self.config1a)
1419 logger = logging.getLogger("compiler.parser")
1420 # See issue #11424. compiler-hyphenated sorts
1421 # between compiler and compiler.xyz and this
1422 # was preventing compiler.xyz from being included
1423 # in the child loggers of compiler because of an
1424 # overzealous loop termination condition.
1425 hyphenated = logging.getLogger('compiler-hyphenated')
1426 # All will output a message
1427 logger.info(self.next_message())
1428 logger.error(self.next_message())
1429 hyphenated.critical(self.next_message())
1430 self.assert_log_lines([
1431 ('INFO', '1'),
1432 ('ERROR', '2'),
1433 ('CRITICAL', '3'),
1434 ], stream=output)
1435 # Original logger output is empty.
1436 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001437 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001438 self.apply_config(self.config7)
1439 logger = logging.getLogger("compiler.parser")
1440 self.assertFalse(logger.disabled)
1441 # Both will output a message
1442 logger.info(self.next_message())
1443 logger.error(self.next_message())
1444 logger = logging.getLogger("compiler.lexer")
1445 # Both will output a message
1446 logger.info(self.next_message())
1447 logger.error(self.next_message())
1448 # Will not appear
1449 hyphenated.critical(self.next_message())
1450 self.assert_log_lines([
1451 ('INFO', '4'),
1452 ('ERROR', '5'),
1453 ('INFO', '6'),
1454 ('ERROR', '7'),
1455 ], stream=output)
1456 # Original logger output is empty.
1457 self.assert_log_lines([])
1458
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001459 def test_logger_disabling(self):
1460 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001461 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001462 self.assertFalse(logger.disabled)
1463 self.apply_config(self.disable_test)
1464 self.assertTrue(logger.disabled)
1465 self.apply_config(self.disable_test, disable_existing_loggers=False)
1466 self.assertFalse(logger.disabled)
1467
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001468
Victor Stinner45df8202010-04-28 22:31:17 +00001469@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001470class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001471
Christian Heimes180510d2008-03-03 19:15:45 +00001472 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001473
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001474 if threading:
1475 server_class = TestTCPServer
1476 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001477
Christian Heimes180510d2008-03-03 19:15:45 +00001478 def setUp(self):
1479 """Set up a TCP server to receive log messages, and a SocketHandler
1480 pointing to that server's address and port."""
1481 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001482 # Issue #29177: deal with errors that happen during setup
1483 self.server = self.sock_hdlr = self.server_exception = None
1484 try:
1485 self.server = server = self.server_class(self.address,
1486 self.handle_socket, 0.01)
1487 server.start()
1488 # Uncomment next line to test error recovery in setUp()
1489 # raise OSError('dummy error raised')
1490 except OSError as e:
1491 self.server_exception = e
1492 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001493 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001494 hcls = logging.handlers.SocketHandler
1495 if isinstance(server.server_address, tuple):
1496 self.sock_hdlr = hcls('localhost', server.port)
1497 else:
1498 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001500 self.root_logger.removeHandler(self.root_logger.handlers[0])
1501 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001502 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001503
Christian Heimes180510d2008-03-03 19:15:45 +00001504 def tearDown(self):
1505 """Shutdown the TCP server."""
1506 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001507 if self.server:
1508 self.server.stop(2.0)
1509 if self.sock_hdlr:
1510 self.root_logger.removeHandler(self.sock_hdlr)
1511 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001512 finally:
1513 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001514
Vinay Sajip7367d082011-05-02 13:17:27 +01001515 def handle_socket(self, request):
1516 conn = request.connection
1517 while True:
1518 chunk = conn.recv(4)
1519 if len(chunk) < 4:
1520 break
1521 slen = struct.unpack(">L", chunk)[0]
1522 chunk = conn.recv(slen)
1523 while len(chunk) < slen:
1524 chunk = chunk + conn.recv(slen - len(chunk))
1525 obj = pickle.loads(chunk)
1526 record = logging.makeLogRecord(obj)
1527 self.log_output += record.msg + '\n'
1528 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001529
Christian Heimes180510d2008-03-03 19:15:45 +00001530 def test_output(self):
1531 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001532 if self.server_exception:
1533 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001534 logger = logging.getLogger("tcp")
1535 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001536 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001537 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001538 self.handled.acquire()
1539 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001540
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001541 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001542 if self.server_exception:
1543 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001544 # Avoid timing-related failures due to SocketHandler's own hard-wired
1545 # one-second timeout on socket.create_connection() (issue #16264).
1546 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001547 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001548 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001549 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001550 try:
1551 raise RuntimeError('Deliberate mistake')
1552 except RuntimeError:
1553 self.root_logger.exception('Never sent')
1554 self.root_logger.error('Never sent, either')
1555 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001556 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001557 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1558 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001559
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001560def _get_temp_domain_socket():
1561 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1562 os.close(fd)
1563 # just need a name - file can't be present, or we'll get an
1564 # 'address already in use' error.
1565 os.remove(fn)
1566 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001567
Victor Stinnerec5a8602014-06-02 14:41:51 +02001568@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001569@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001570class UnixSocketHandlerTest(SocketHandlerTest):
1571
1572 """Test for SocketHandler with unix sockets."""
1573
Victor Stinnerec5a8602014-06-02 14:41:51 +02001574 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001575 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001576
1577 def setUp(self):
1578 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001579 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001580 SocketHandlerTest.setUp(self)
1581
1582 def tearDown(self):
1583 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001584 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001585
1586@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001587class DatagramHandlerTest(BaseTest):
1588
1589 """Test for DatagramHandler."""
1590
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001591 if threading:
1592 server_class = TestUDPServer
1593 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001594
Vinay Sajip7367d082011-05-02 13:17:27 +01001595 def setUp(self):
1596 """Set up a UDP server to receive log messages, and a DatagramHandler
1597 pointing to that server's address and port."""
1598 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001599 # Issue #29177: deal with errors that happen during setup
1600 self.server = self.sock_hdlr = self.server_exception = None
1601 try:
1602 self.server = server = self.server_class(self.address,
1603 self.handle_datagram, 0.01)
1604 server.start()
1605 # Uncomment next line to test error recovery in setUp()
1606 # raise OSError('dummy error raised')
1607 except OSError as e:
1608 self.server_exception = e
1609 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001610 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001611 hcls = logging.handlers.DatagramHandler
1612 if isinstance(server.server_address, tuple):
1613 self.sock_hdlr = hcls('localhost', server.port)
1614 else:
1615 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001616 self.log_output = ''
1617 self.root_logger.removeHandler(self.root_logger.handlers[0])
1618 self.root_logger.addHandler(self.sock_hdlr)
1619 self.handled = threading.Event()
1620
1621 def tearDown(self):
1622 """Shutdown the UDP server."""
1623 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001624 if self.server:
1625 self.server.stop(2.0)
1626 if self.sock_hdlr:
1627 self.root_logger.removeHandler(self.sock_hdlr)
1628 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001629 finally:
1630 BaseTest.tearDown(self)
1631
1632 def handle_datagram(self, request):
1633 slen = struct.pack('>L', 0) # length of prefix
1634 packet = request.packet[len(slen):]
1635 obj = pickle.loads(packet)
1636 record = logging.makeLogRecord(obj)
1637 self.log_output += record.msg + '\n'
1638 self.handled.set()
1639
1640 def test_output(self):
1641 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001642 if self.server_exception:
1643 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001644 logger = logging.getLogger("udp")
1645 logger.error("spam")
1646 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001647 self.handled.clear()
1648 logger.error("eggs")
1649 self.handled.wait()
1650 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001651
Victor Stinnerec5a8602014-06-02 14:41:51 +02001652@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001653@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001654class UnixDatagramHandlerTest(DatagramHandlerTest):
1655
1656 """Test for DatagramHandler using Unix sockets."""
1657
Victor Stinnerec5a8602014-06-02 14:41:51 +02001658 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001659 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001660
1661 def setUp(self):
1662 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001663 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001664 DatagramHandlerTest.setUp(self)
1665
1666 def tearDown(self):
1667 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001668 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001669
1670@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001671class SysLogHandlerTest(BaseTest):
1672
1673 """Test for SysLogHandler using UDP."""
1674
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001675 if threading:
1676 server_class = TestUDPServer
1677 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001678
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 def setUp(self):
1680 """Set up a UDP server to receive log messages, and a SysLogHandler
1681 pointing to that server's address and port."""
1682 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001683 # Issue #29177: deal with errors that happen during setup
1684 self.server = self.sl_hdlr = self.server_exception = None
1685 try:
1686 self.server = server = self.server_class(self.address,
1687 self.handle_datagram, 0.01)
1688 server.start()
1689 # Uncomment next line to test error recovery in setUp()
1690 # raise OSError('dummy error raised')
1691 except OSError as e:
1692 self.server_exception = e
1693 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001694 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001695 hcls = logging.handlers.SysLogHandler
1696 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001697 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001698 else:
1699 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001700 self.log_output = ''
1701 self.root_logger.removeHandler(self.root_logger.handlers[0])
1702 self.root_logger.addHandler(self.sl_hdlr)
1703 self.handled = threading.Event()
1704
1705 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001706 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001707 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001708 if self.server:
1709 self.server.stop(2.0)
1710 if self.sl_hdlr:
1711 self.root_logger.removeHandler(self.sl_hdlr)
1712 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001713 finally:
1714 BaseTest.tearDown(self)
1715
1716 def handle_datagram(self, request):
1717 self.log_output = request.packet
1718 self.handled.set()
1719
1720 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001721 if self.server_exception:
1722 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001723 # The log message sent to the SysLogHandler is properly received.
1724 logger = logging.getLogger("slh")
1725 logger.error("sp\xe4m")
1726 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001727 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001728 self.handled.clear()
1729 self.sl_hdlr.append_nul = False
1730 logger.error("sp\xe4m")
1731 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001732 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001733 self.handled.clear()
1734 self.sl_hdlr.ident = "h\xe4m-"
1735 logger.error("sp\xe4m")
1736 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001737 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001738
Victor Stinnerec5a8602014-06-02 14:41:51 +02001739@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001740@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001741class UnixSysLogHandlerTest(SysLogHandlerTest):
1742
1743 """Test for SysLogHandler with Unix sockets."""
1744
Victor Stinnerec5a8602014-06-02 14:41:51 +02001745 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001746 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001747
1748 def setUp(self):
1749 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001750 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001751 SysLogHandlerTest.setUp(self)
1752
1753 def tearDown(self):
1754 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001755 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001756
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001757@unittest.skipUnless(support.IPV6_ENABLED,
1758 'IPv6 support required for this test.')
1759@unittest.skipUnless(threading, 'Threading required for this test.')
1760class IPv6SysLogHandlerTest(SysLogHandlerTest):
1761
1762 """Test for SysLogHandler with IPv6 host."""
1763
1764 server_class = TestUDPServer
1765 address = ('::1', 0)
1766
1767 def setUp(self):
1768 self.server_class.address_family = socket.AF_INET6
1769 super(IPv6SysLogHandlerTest, self).setUp()
1770
1771 def tearDown(self):
1772 self.server_class.address_family = socket.AF_INET
1773 super(IPv6SysLogHandlerTest, self).tearDown()
1774
Vinay Sajip5421f352013-09-27 18:18:28 +01001775@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001776class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001777 """Test for HTTPHandler."""
1778
1779 def setUp(self):
1780 """Set up an HTTP server to receive log messages, and a HTTPHandler
1781 pointing to that server's address and port."""
1782 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001783 self.handled = threading.Event()
1784
Vinay Sajip7367d082011-05-02 13:17:27 +01001785 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001786 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001787 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001788 if self.command == 'POST':
1789 try:
1790 rlen = int(request.headers['Content-Length'])
1791 self.post_data = request.rfile.read(rlen)
1792 except:
1793 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001794 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001795 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001796 self.handled.set()
1797
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02001798 @support.reap_threads
Vinay Sajip7367d082011-05-02 13:17:27 +01001799 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001800 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001801 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001802 root_logger = self.root_logger
1803 root_logger.removeHandler(self.root_logger.handlers[0])
1804 for secure in (False, True):
1805 addr = ('localhost', 0)
1806 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001807 try:
1808 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001809 except ImportError:
1810 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001811 else:
1812 here = os.path.dirname(__file__)
1813 localhost_cert = os.path.join(here, "keycert.pem")
1814 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1815 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001816
1817 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001818 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001819 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001820 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001821 self.server = server = TestHTTPServer(addr, self.handle_request,
1822 0.01, sslctx=sslctx)
1823 server.start()
1824 server.ready.wait()
1825 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001826 secure_client = secure and sslctx
1827 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001828 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001829 context=context,
1830 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001831 self.log_data = None
1832 root_logger.addHandler(self.h_hdlr)
1833
1834 for method in ('GET', 'POST'):
1835 self.h_hdlr.method = method
1836 self.handled.clear()
1837 msg = "sp\xe4m"
1838 logger.error(msg)
1839 self.handled.wait()
1840 self.assertEqual(self.log_data.path, '/frob')
1841 self.assertEqual(self.command, method)
1842 if method == 'GET':
1843 d = parse_qs(self.log_data.query)
1844 else:
1845 d = parse_qs(self.post_data.decode('utf-8'))
1846 self.assertEqual(d['name'], ['http'])
1847 self.assertEqual(d['funcName'], ['test_output'])
1848 self.assertEqual(d['msg'], [msg])
1849
1850 self.server.stop(2.0)
1851 self.root_logger.removeHandler(self.h_hdlr)
1852 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001853
Christian Heimes180510d2008-03-03 19:15:45 +00001854class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001855
Christian Heimes180510d2008-03-03 19:15:45 +00001856 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001857
Christian Heimes180510d2008-03-03 19:15:45 +00001858 def setUp(self):
1859 """Create a dict to remember potentially destroyed objects."""
1860 BaseTest.setUp(self)
1861 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001862
Christian Heimes180510d2008-03-03 19:15:45 +00001863 def _watch_for_survival(self, *args):
1864 """Watch the given objects for survival, by creating weakrefs to
1865 them."""
1866 for obj in args:
1867 key = id(obj), repr(obj)
1868 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001869
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001870 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001871 """Assert that all objects watched for survival have survived."""
1872 # Trigger cycle breaking.
1873 gc.collect()
1874 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001875 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001876 if ref() is None:
1877 dead.append(repr_)
1878 if dead:
1879 self.fail("%d objects should have survived "
1880 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001881
Christian Heimes180510d2008-03-03 19:15:45 +00001882 def test_persistent_loggers(self):
1883 # Logger objects are persistent and retain their configuration, even
1884 # if visible references are destroyed.
1885 self.root_logger.setLevel(logging.INFO)
1886 foo = logging.getLogger("foo")
1887 self._watch_for_survival(foo)
1888 foo.setLevel(logging.DEBUG)
1889 self.root_logger.debug(self.next_message())
1890 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001891 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001892 ('foo', 'DEBUG', '2'),
1893 ])
1894 del foo
1895 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001896 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001897 # foo has retained its settings.
1898 bar = logging.getLogger("foo")
1899 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001900 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001901 ('foo', 'DEBUG', '2'),
1902 ('foo', 'DEBUG', '3'),
1903 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001904
Benjamin Petersonf91df042009-02-13 02:50:59 +00001905
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001906class EncodingTest(BaseTest):
1907 def test_encoding_plain_file(self):
1908 # In Python 2.x, a plain file object is treated as having no encoding.
1909 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001910 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1911 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001912 # the non-ascii data we write to the log.
1913 data = "foo\x80"
1914 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001915 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001916 log.addHandler(handler)
1917 try:
1918 # write non-ascii data to the log.
1919 log.warning(data)
1920 finally:
1921 log.removeHandler(handler)
1922 handler.close()
1923 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001924 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001925 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001926 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001927 finally:
1928 f.close()
1929 finally:
1930 if os.path.isfile(fn):
1931 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001932
Benjamin Petersonf91df042009-02-13 02:50:59 +00001933 def test_encoding_cyrillic_unicode(self):
1934 log = logging.getLogger("test")
1935 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1936 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1937 #Ensure it's written in a Cyrillic encoding
1938 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001939 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001940 stream = io.BytesIO()
1941 writer = writer_class(stream, 'strict')
1942 handler = logging.StreamHandler(writer)
1943 log.addHandler(handler)
1944 try:
1945 log.warning(message)
1946 finally:
1947 log.removeHandler(handler)
1948 handler.close()
1949 # check we wrote exactly those bytes, ignoring trailing \n etc
1950 s = stream.getvalue()
1951 #Compare against what the data should be when encoded in CP-1251
1952 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1953
1954
Georg Brandlf9734072008-12-07 15:30:06 +00001955class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001956
Georg Brandlf9734072008-12-07 15:30:06 +00001957 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001958 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001959 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001960 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001961 warnings.filterwarnings("always", category=UserWarning)
1962 stream = io.StringIO()
1963 h = logging.StreamHandler(stream)
1964 logger = logging.getLogger("py.warnings")
1965 logger.addHandler(h)
1966 warnings.warn("I'm warning you...")
1967 logger.removeHandler(h)
1968 s = stream.getvalue()
1969 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001970 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001971
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001972 #See if an explicit file uses the original implementation
1973 a_file = io.StringIO()
1974 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1975 a_file, "Dummy line")
1976 s = a_file.getvalue()
1977 a_file.close()
1978 self.assertEqual(s,
1979 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1980
1981 def test_warnings_no_handlers(self):
1982 with warnings.catch_warnings():
1983 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001984 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001985
1986 # confirm our assumption: no loggers are set
1987 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001988 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001989
1990 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001991 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001992 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001993
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001994
1995def formatFunc(format, datefmt=None):
1996 return logging.Formatter(format, datefmt)
1997
1998def handlerFunc():
1999 return logging.StreamHandler()
2000
2001class CustomHandler(logging.StreamHandler):
2002 pass
2003
2004class ConfigDictTest(BaseTest):
2005
2006 """Reading logging config from a dictionary."""
2007
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002008 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002009
2010 # config0 is a standard configuration.
2011 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002012 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002013 'formatters': {
2014 'form1' : {
2015 'format' : '%(levelname)s ++ %(message)s',
2016 },
2017 },
2018 'handlers' : {
2019 'hand1' : {
2020 'class' : 'logging.StreamHandler',
2021 'formatter' : 'form1',
2022 'level' : 'NOTSET',
2023 'stream' : 'ext://sys.stdout',
2024 },
2025 },
2026 'root' : {
2027 'level' : 'WARNING',
2028 'handlers' : ['hand1'],
2029 },
2030 }
2031
2032 # config1 adds a little to the standard configuration.
2033 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002034 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002035 'formatters': {
2036 'form1' : {
2037 'format' : '%(levelname)s ++ %(message)s',
2038 },
2039 },
2040 'handlers' : {
2041 'hand1' : {
2042 'class' : 'logging.StreamHandler',
2043 'formatter' : 'form1',
2044 'level' : 'NOTSET',
2045 'stream' : 'ext://sys.stdout',
2046 },
2047 },
2048 'loggers' : {
2049 'compiler.parser' : {
2050 'level' : 'DEBUG',
2051 'handlers' : ['hand1'],
2052 },
2053 },
2054 'root' : {
2055 'level' : 'WARNING',
2056 },
2057 }
2058
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002059 # config1a moves the handler to the root. Used with config8a
2060 config1a = {
2061 'version': 1,
2062 'formatters': {
2063 'form1' : {
2064 'format' : '%(levelname)s ++ %(message)s',
2065 },
2066 },
2067 'handlers' : {
2068 'hand1' : {
2069 'class' : 'logging.StreamHandler',
2070 'formatter' : 'form1',
2071 'level' : 'NOTSET',
2072 'stream' : 'ext://sys.stdout',
2073 },
2074 },
2075 'loggers' : {
2076 'compiler.parser' : {
2077 'level' : 'DEBUG',
2078 },
2079 },
2080 'root' : {
2081 'level' : 'WARNING',
2082 'handlers' : ['hand1'],
2083 },
2084 }
2085
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002086 # config2 has a subtle configuration error that should be reported
2087 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002088 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002089 'formatters': {
2090 'form1' : {
2091 'format' : '%(levelname)s ++ %(message)s',
2092 },
2093 },
2094 'handlers' : {
2095 'hand1' : {
2096 'class' : 'logging.StreamHandler',
2097 'formatter' : 'form1',
2098 'level' : 'NOTSET',
2099 'stream' : 'ext://sys.stdbout',
2100 },
2101 },
2102 'loggers' : {
2103 'compiler.parser' : {
2104 'level' : 'DEBUG',
2105 'handlers' : ['hand1'],
2106 },
2107 },
2108 'root' : {
2109 'level' : 'WARNING',
2110 },
2111 }
2112
2113 #As config1 but with a misspelt level on a handler
2114 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002115 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002116 'formatters': {
2117 'form1' : {
2118 'format' : '%(levelname)s ++ %(message)s',
2119 },
2120 },
2121 'handlers' : {
2122 'hand1' : {
2123 'class' : 'logging.StreamHandler',
2124 'formatter' : 'form1',
2125 'level' : 'NTOSET',
2126 'stream' : 'ext://sys.stdout',
2127 },
2128 },
2129 'loggers' : {
2130 'compiler.parser' : {
2131 'level' : 'DEBUG',
2132 'handlers' : ['hand1'],
2133 },
2134 },
2135 'root' : {
2136 'level' : 'WARNING',
2137 },
2138 }
2139
2140
2141 #As config1 but with a misspelt level on a logger
2142 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002143 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002144 'formatters': {
2145 'form1' : {
2146 'format' : '%(levelname)s ++ %(message)s',
2147 },
2148 },
2149 'handlers' : {
2150 'hand1' : {
2151 'class' : 'logging.StreamHandler',
2152 'formatter' : 'form1',
2153 'level' : 'NOTSET',
2154 'stream' : 'ext://sys.stdout',
2155 },
2156 },
2157 'loggers' : {
2158 'compiler.parser' : {
2159 'level' : 'DEBUG',
2160 'handlers' : ['hand1'],
2161 },
2162 },
2163 'root' : {
2164 'level' : 'WRANING',
2165 },
2166 }
2167
2168 # config3 has a less subtle configuration error
2169 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002170 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002171 'formatters': {
2172 'form1' : {
2173 'format' : '%(levelname)s ++ %(message)s',
2174 },
2175 },
2176 'handlers' : {
2177 'hand1' : {
2178 'class' : 'logging.StreamHandler',
2179 'formatter' : 'misspelled_name',
2180 'level' : 'NOTSET',
2181 'stream' : 'ext://sys.stdout',
2182 },
2183 },
2184 'loggers' : {
2185 'compiler.parser' : {
2186 'level' : 'DEBUG',
2187 'handlers' : ['hand1'],
2188 },
2189 },
2190 'root' : {
2191 'level' : 'WARNING',
2192 },
2193 }
2194
2195 # config4 specifies a custom formatter class to be loaded
2196 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002197 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002198 'formatters': {
2199 'form1' : {
2200 '()' : __name__ + '.ExceptionFormatter',
2201 'format' : '%(levelname)s:%(name)s:%(message)s',
2202 },
2203 },
2204 'handlers' : {
2205 'hand1' : {
2206 'class' : 'logging.StreamHandler',
2207 'formatter' : 'form1',
2208 'level' : 'NOTSET',
2209 'stream' : 'ext://sys.stdout',
2210 },
2211 },
2212 'root' : {
2213 'level' : 'NOTSET',
2214 'handlers' : ['hand1'],
2215 },
2216 }
2217
2218 # As config4 but using an actual callable rather than a string
2219 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002220 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002221 'formatters': {
2222 'form1' : {
2223 '()' : ExceptionFormatter,
2224 'format' : '%(levelname)s:%(name)s:%(message)s',
2225 },
2226 'form2' : {
2227 '()' : __name__ + '.formatFunc',
2228 'format' : '%(levelname)s:%(name)s:%(message)s',
2229 },
2230 'form3' : {
2231 '()' : formatFunc,
2232 'format' : '%(levelname)s:%(name)s:%(message)s',
2233 },
2234 },
2235 'handlers' : {
2236 'hand1' : {
2237 'class' : 'logging.StreamHandler',
2238 'formatter' : 'form1',
2239 'level' : 'NOTSET',
2240 'stream' : 'ext://sys.stdout',
2241 },
2242 'hand2' : {
2243 '()' : handlerFunc,
2244 },
2245 },
2246 'root' : {
2247 'level' : 'NOTSET',
2248 'handlers' : ['hand1'],
2249 },
2250 }
2251
2252 # config5 specifies a custom handler class to be loaded
2253 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002254 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002255 'formatters': {
2256 'form1' : {
2257 'format' : '%(levelname)s ++ %(message)s',
2258 },
2259 },
2260 'handlers' : {
2261 'hand1' : {
2262 'class' : __name__ + '.CustomHandler',
2263 'formatter' : 'form1',
2264 'level' : 'NOTSET',
2265 'stream' : 'ext://sys.stdout',
2266 },
2267 },
2268 'loggers' : {
2269 'compiler.parser' : {
2270 'level' : 'DEBUG',
2271 'handlers' : ['hand1'],
2272 },
2273 },
2274 'root' : {
2275 'level' : 'WARNING',
2276 },
2277 }
2278
2279 # config6 specifies a custom handler class to be loaded
2280 # but has bad arguments
2281 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002282 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002283 'formatters': {
2284 'form1' : {
2285 'format' : '%(levelname)s ++ %(message)s',
2286 },
2287 },
2288 'handlers' : {
2289 'hand1' : {
2290 'class' : __name__ + '.CustomHandler',
2291 'formatter' : 'form1',
2292 'level' : 'NOTSET',
2293 'stream' : 'ext://sys.stdout',
2294 '9' : 'invalid parameter name',
2295 },
2296 },
2297 'loggers' : {
2298 'compiler.parser' : {
2299 'level' : 'DEBUG',
2300 'handlers' : ['hand1'],
2301 },
2302 },
2303 'root' : {
2304 'level' : 'WARNING',
2305 },
2306 }
2307
2308 #config 7 does not define compiler.parser but defines compiler.lexer
2309 #so compiler.parser should be disabled after applying it
2310 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002311 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002312 'formatters': {
2313 'form1' : {
2314 'format' : '%(levelname)s ++ %(message)s',
2315 },
2316 },
2317 'handlers' : {
2318 'hand1' : {
2319 'class' : 'logging.StreamHandler',
2320 'formatter' : 'form1',
2321 'level' : 'NOTSET',
2322 'stream' : 'ext://sys.stdout',
2323 },
2324 },
2325 'loggers' : {
2326 'compiler.lexer' : {
2327 'level' : 'DEBUG',
2328 'handlers' : ['hand1'],
2329 },
2330 },
2331 'root' : {
2332 'level' : 'WARNING',
2333 },
2334 }
2335
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002336 # config8 defines both compiler and compiler.lexer
2337 # so compiler.parser should not be disabled (since
2338 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002339 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002340 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002341 'disable_existing_loggers' : False,
2342 'formatters': {
2343 'form1' : {
2344 'format' : '%(levelname)s ++ %(message)s',
2345 },
2346 },
2347 'handlers' : {
2348 'hand1' : {
2349 'class' : 'logging.StreamHandler',
2350 'formatter' : 'form1',
2351 'level' : 'NOTSET',
2352 'stream' : 'ext://sys.stdout',
2353 },
2354 },
2355 'loggers' : {
2356 'compiler' : {
2357 'level' : 'DEBUG',
2358 'handlers' : ['hand1'],
2359 },
2360 'compiler.lexer' : {
2361 },
2362 },
2363 'root' : {
2364 'level' : 'WARNING',
2365 },
2366 }
2367
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002368 # config8a disables existing loggers
2369 config8a = {
2370 'version': 1,
2371 'disable_existing_loggers' : True,
2372 'formatters': {
2373 'form1' : {
2374 'format' : '%(levelname)s ++ %(message)s',
2375 },
2376 },
2377 'handlers' : {
2378 'hand1' : {
2379 'class' : 'logging.StreamHandler',
2380 'formatter' : 'form1',
2381 'level' : 'NOTSET',
2382 'stream' : 'ext://sys.stdout',
2383 },
2384 },
2385 'loggers' : {
2386 'compiler' : {
2387 'level' : 'DEBUG',
2388 'handlers' : ['hand1'],
2389 },
2390 'compiler.lexer' : {
2391 },
2392 },
2393 'root' : {
2394 'level' : 'WARNING',
2395 },
2396 }
2397
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002398 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002399 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002400 'formatters': {
2401 'form1' : {
2402 'format' : '%(levelname)s ++ %(message)s',
2403 },
2404 },
2405 'handlers' : {
2406 'hand1' : {
2407 'class' : 'logging.StreamHandler',
2408 'formatter' : 'form1',
2409 'level' : 'WARNING',
2410 'stream' : 'ext://sys.stdout',
2411 },
2412 },
2413 'loggers' : {
2414 'compiler.parser' : {
2415 'level' : 'WARNING',
2416 'handlers' : ['hand1'],
2417 },
2418 },
2419 'root' : {
2420 'level' : 'NOTSET',
2421 },
2422 }
2423
2424 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002425 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002426 'incremental' : True,
2427 'handlers' : {
2428 'hand1' : {
2429 'level' : 'WARNING',
2430 },
2431 },
2432 'loggers' : {
2433 'compiler.parser' : {
2434 'level' : 'INFO',
2435 },
2436 },
2437 }
2438
2439 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002440 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002441 'incremental' : True,
2442 'handlers' : {
2443 'hand1' : {
2444 'level' : 'INFO',
2445 },
2446 },
2447 'loggers' : {
2448 'compiler.parser' : {
2449 'level' : 'INFO',
2450 },
2451 },
2452 }
2453
2454 #As config1 but with a filter added
2455 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002456 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002457 'formatters': {
2458 'form1' : {
2459 'format' : '%(levelname)s ++ %(message)s',
2460 },
2461 },
2462 'filters' : {
2463 'filt1' : {
2464 'name' : 'compiler.parser',
2465 },
2466 },
2467 'handlers' : {
2468 'hand1' : {
2469 'class' : 'logging.StreamHandler',
2470 'formatter' : 'form1',
2471 'level' : 'NOTSET',
2472 'stream' : 'ext://sys.stdout',
2473 'filters' : ['filt1'],
2474 },
2475 },
2476 'loggers' : {
2477 'compiler.parser' : {
2478 'level' : 'DEBUG',
2479 'filters' : ['filt1'],
2480 },
2481 },
2482 'root' : {
2483 'level' : 'WARNING',
2484 'handlers' : ['hand1'],
2485 },
2486 }
2487
2488 #As config1 but using cfg:// references
2489 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002490 'version': 1,
2491 'true_formatters': {
2492 'form1' : {
2493 'format' : '%(levelname)s ++ %(message)s',
2494 },
2495 },
2496 'handler_configs': {
2497 'hand1' : {
2498 'class' : 'logging.StreamHandler',
2499 'formatter' : 'form1',
2500 'level' : 'NOTSET',
2501 'stream' : 'ext://sys.stdout',
2502 },
2503 },
2504 'formatters' : 'cfg://true_formatters',
2505 'handlers' : {
2506 'hand1' : 'cfg://handler_configs[hand1]',
2507 },
2508 'loggers' : {
2509 'compiler.parser' : {
2510 'level' : 'DEBUG',
2511 'handlers' : ['hand1'],
2512 },
2513 },
2514 'root' : {
2515 'level' : 'WARNING',
2516 },
2517 }
2518
2519 #As config11 but missing the version key
2520 config12 = {
2521 'true_formatters': {
2522 'form1' : {
2523 'format' : '%(levelname)s ++ %(message)s',
2524 },
2525 },
2526 'handler_configs': {
2527 'hand1' : {
2528 'class' : 'logging.StreamHandler',
2529 'formatter' : 'form1',
2530 'level' : 'NOTSET',
2531 'stream' : 'ext://sys.stdout',
2532 },
2533 },
2534 'formatters' : 'cfg://true_formatters',
2535 'handlers' : {
2536 'hand1' : 'cfg://handler_configs[hand1]',
2537 },
2538 'loggers' : {
2539 'compiler.parser' : {
2540 'level' : 'DEBUG',
2541 'handlers' : ['hand1'],
2542 },
2543 },
2544 'root' : {
2545 'level' : 'WARNING',
2546 },
2547 }
2548
2549 #As config11 but using an unsupported version
2550 config13 = {
2551 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002552 'true_formatters': {
2553 'form1' : {
2554 'format' : '%(levelname)s ++ %(message)s',
2555 },
2556 },
2557 'handler_configs': {
2558 'hand1' : {
2559 'class' : 'logging.StreamHandler',
2560 'formatter' : 'form1',
2561 'level' : 'NOTSET',
2562 'stream' : 'ext://sys.stdout',
2563 },
2564 },
2565 'formatters' : 'cfg://true_formatters',
2566 'handlers' : {
2567 'hand1' : 'cfg://handler_configs[hand1]',
2568 },
2569 'loggers' : {
2570 'compiler.parser' : {
2571 'level' : 'DEBUG',
2572 'handlers' : ['hand1'],
2573 },
2574 },
2575 'root' : {
2576 'level' : 'WARNING',
2577 },
2578 }
2579
Vinay Sajip8d270232012-11-15 14:20:18 +00002580 # As config0, but with properties
2581 config14 = {
2582 'version': 1,
2583 'formatters': {
2584 'form1' : {
2585 'format' : '%(levelname)s ++ %(message)s',
2586 },
2587 },
2588 'handlers' : {
2589 'hand1' : {
2590 'class' : 'logging.StreamHandler',
2591 'formatter' : 'form1',
2592 'level' : 'NOTSET',
2593 'stream' : 'ext://sys.stdout',
2594 '.': {
2595 'foo': 'bar',
2596 'terminator': '!\n',
2597 }
2598 },
2599 },
2600 'root' : {
2601 'level' : 'WARNING',
2602 'handlers' : ['hand1'],
2603 },
2604 }
2605
Vinay Sajip3f885b52013-03-22 15:19:54 +00002606 out_of_order = {
2607 "version": 1,
2608 "formatters": {
2609 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002610 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2611 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002612 }
2613 },
2614 "handlers": {
2615 "fileGlobal": {
2616 "class": "logging.StreamHandler",
2617 "level": "DEBUG",
2618 "formatter": "mySimpleFormatter"
2619 },
2620 "bufferGlobal": {
2621 "class": "logging.handlers.MemoryHandler",
2622 "capacity": 5,
2623 "formatter": "mySimpleFormatter",
2624 "target": "fileGlobal",
2625 "level": "DEBUG"
2626 }
2627 },
2628 "loggers": {
2629 "mymodule": {
2630 "level": "DEBUG",
2631 "handlers": ["bufferGlobal"],
2632 "propagate": "true"
2633 }
2634 }
2635 }
2636
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002637 def apply_config(self, conf):
2638 logging.config.dictConfig(conf)
2639
2640 def test_config0_ok(self):
2641 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002642 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002643 self.apply_config(self.config0)
2644 logger = logging.getLogger()
2645 # Won't output anything
2646 logger.info(self.next_message())
2647 # Outputs a message
2648 logger.error(self.next_message())
2649 self.assert_log_lines([
2650 ('ERROR', '2'),
2651 ], stream=output)
2652 # Original logger output is empty.
2653 self.assert_log_lines([])
2654
2655 def test_config1_ok(self, config=config1):
2656 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002657 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002658 self.apply_config(config)
2659 logger = logging.getLogger("compiler.parser")
2660 # Both will output a message
2661 logger.info(self.next_message())
2662 logger.error(self.next_message())
2663 self.assert_log_lines([
2664 ('INFO', '1'),
2665 ('ERROR', '2'),
2666 ], stream=output)
2667 # Original logger output is empty.
2668 self.assert_log_lines([])
2669
2670 def test_config2_failure(self):
2671 # A simple config which overrides the default settings.
2672 self.assertRaises(Exception, self.apply_config, self.config2)
2673
2674 def test_config2a_failure(self):
2675 # A simple config which overrides the default settings.
2676 self.assertRaises(Exception, self.apply_config, self.config2a)
2677
2678 def test_config2b_failure(self):
2679 # A simple config which overrides the default settings.
2680 self.assertRaises(Exception, self.apply_config, self.config2b)
2681
2682 def test_config3_failure(self):
2683 # A simple config which overrides the default settings.
2684 self.assertRaises(Exception, self.apply_config, self.config3)
2685
2686 def test_config4_ok(self):
2687 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002688 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002689 self.apply_config(self.config4)
2690 #logger = logging.getLogger()
2691 try:
2692 raise RuntimeError()
2693 except RuntimeError:
2694 logging.exception("just testing")
2695 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002696 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002697 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2698 # Original logger output is empty
2699 self.assert_log_lines([])
2700
2701 def test_config4a_ok(self):
2702 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002703 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002704 self.apply_config(self.config4a)
2705 #logger = logging.getLogger()
2706 try:
2707 raise RuntimeError()
2708 except RuntimeError:
2709 logging.exception("just testing")
2710 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002711 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002712 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2713 # Original logger output is empty
2714 self.assert_log_lines([])
2715
2716 def test_config5_ok(self):
2717 self.test_config1_ok(config=self.config5)
2718
2719 def test_config6_failure(self):
2720 self.assertRaises(Exception, self.apply_config, self.config6)
2721
2722 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002723 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002724 self.apply_config(self.config1)
2725 logger = logging.getLogger("compiler.parser")
2726 # Both will output a message
2727 logger.info(self.next_message())
2728 logger.error(self.next_message())
2729 self.assert_log_lines([
2730 ('INFO', '1'),
2731 ('ERROR', '2'),
2732 ], stream=output)
2733 # Original logger output is empty.
2734 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002735 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002736 self.apply_config(self.config7)
2737 logger = logging.getLogger("compiler.parser")
2738 self.assertTrue(logger.disabled)
2739 logger = logging.getLogger("compiler.lexer")
2740 # Both will output a message
2741 logger.info(self.next_message())
2742 logger.error(self.next_message())
2743 self.assert_log_lines([
2744 ('INFO', '3'),
2745 ('ERROR', '4'),
2746 ], stream=output)
2747 # Original logger output is empty.
2748 self.assert_log_lines([])
2749
2750 #Same as test_config_7_ok but don't disable old loggers.
2751 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002752 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002753 self.apply_config(self.config1)
2754 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002755 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002756 logger.info(self.next_message())
2757 logger.error(self.next_message())
2758 self.assert_log_lines([
2759 ('INFO', '1'),
2760 ('ERROR', '2'),
2761 ], stream=output)
2762 # Original logger output is empty.
2763 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002764 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002765 self.apply_config(self.config8)
2766 logger = logging.getLogger("compiler.parser")
2767 self.assertFalse(logger.disabled)
2768 # Both will output a message
2769 logger.info(self.next_message())
2770 logger.error(self.next_message())
2771 logger = logging.getLogger("compiler.lexer")
2772 # Both will output a message
2773 logger.info(self.next_message())
2774 logger.error(self.next_message())
2775 self.assert_log_lines([
2776 ('INFO', '3'),
2777 ('ERROR', '4'),
2778 ('INFO', '5'),
2779 ('ERROR', '6'),
2780 ], stream=output)
2781 # Original logger output is empty.
2782 self.assert_log_lines([])
2783
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002784 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002785 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002786 self.apply_config(self.config1a)
2787 logger = logging.getLogger("compiler.parser")
2788 # See issue #11424. compiler-hyphenated sorts
2789 # between compiler and compiler.xyz and this
2790 # was preventing compiler.xyz from being included
2791 # in the child loggers of compiler because of an
2792 # overzealous loop termination condition.
2793 hyphenated = logging.getLogger('compiler-hyphenated')
2794 # All will output a message
2795 logger.info(self.next_message())
2796 logger.error(self.next_message())
2797 hyphenated.critical(self.next_message())
2798 self.assert_log_lines([
2799 ('INFO', '1'),
2800 ('ERROR', '2'),
2801 ('CRITICAL', '3'),
2802 ], stream=output)
2803 # Original logger output is empty.
2804 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002805 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002806 self.apply_config(self.config8a)
2807 logger = logging.getLogger("compiler.parser")
2808 self.assertFalse(logger.disabled)
2809 # Both will output a message
2810 logger.info(self.next_message())
2811 logger.error(self.next_message())
2812 logger = logging.getLogger("compiler.lexer")
2813 # Both will output a message
2814 logger.info(self.next_message())
2815 logger.error(self.next_message())
2816 # Will not appear
2817 hyphenated.critical(self.next_message())
2818 self.assert_log_lines([
2819 ('INFO', '4'),
2820 ('ERROR', '5'),
2821 ('INFO', '6'),
2822 ('ERROR', '7'),
2823 ], stream=output)
2824 # Original logger output is empty.
2825 self.assert_log_lines([])
2826
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002827 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002828 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002829 self.apply_config(self.config9)
2830 logger = logging.getLogger("compiler.parser")
2831 #Nothing will be output since both handler and logger are set to WARNING
2832 logger.info(self.next_message())
2833 self.assert_log_lines([], stream=output)
2834 self.apply_config(self.config9a)
2835 #Nothing will be output since both handler is still set to WARNING
2836 logger.info(self.next_message())
2837 self.assert_log_lines([], stream=output)
2838 self.apply_config(self.config9b)
2839 #Message should now be output
2840 logger.info(self.next_message())
2841 self.assert_log_lines([
2842 ('INFO', '3'),
2843 ], stream=output)
2844
2845 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002846 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002847 self.apply_config(self.config10)
2848 logger = logging.getLogger("compiler.parser")
2849 logger.warning(self.next_message())
2850 logger = logging.getLogger('compiler')
2851 #Not output, because filtered
2852 logger.warning(self.next_message())
2853 logger = logging.getLogger('compiler.lexer')
2854 #Not output, because filtered
2855 logger.warning(self.next_message())
2856 logger = logging.getLogger("compiler.parser.codegen")
2857 #Output, as not filtered
2858 logger.error(self.next_message())
2859 self.assert_log_lines([
2860 ('WARNING', '1'),
2861 ('ERROR', '4'),
2862 ], stream=output)
2863
2864 def test_config11_ok(self):
2865 self.test_config1_ok(self.config11)
2866
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002867 def test_config12_failure(self):
2868 self.assertRaises(Exception, self.apply_config, self.config12)
2869
2870 def test_config13_failure(self):
2871 self.assertRaises(Exception, self.apply_config, self.config13)
2872
Vinay Sajip8d270232012-11-15 14:20:18 +00002873 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002874 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002875 self.apply_config(self.config14)
2876 h = logging._handlers['hand1']
2877 self.assertEqual(h.foo, 'bar')
2878 self.assertEqual(h.terminator, '!\n')
2879 logging.warning('Exclamation')
2880 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2881
Victor Stinner45df8202010-04-28 22:31:17 +00002882 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002883 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002884 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002885 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002886 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002887 t.start()
2888 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002889 # Now get the port allocated
2890 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002891 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002892 try:
2893 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2894 sock.settimeout(2.0)
2895 sock.connect(('localhost', port))
2896
2897 slen = struct.pack('>L', len(text))
2898 s = slen + text
2899 sentsofar = 0
2900 left = len(s)
2901 while left > 0:
2902 sent = sock.send(s[sentsofar:])
2903 sentsofar += sent
2904 left -= sent
2905 sock.close()
2906 finally:
2907 t.ready.wait(2.0)
2908 logging.config.stopListening()
2909 t.join(2.0)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002910 if t.is_alive():
2911 self.fail("join() timed out")
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002912
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002913 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002914 @support.reap_threads
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002915 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002916 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002917 self.setup_via_listener(json.dumps(self.config10))
2918 logger = logging.getLogger("compiler.parser")
2919 logger.warning(self.next_message())
2920 logger = logging.getLogger('compiler')
2921 #Not output, because filtered
2922 logger.warning(self.next_message())
2923 logger = logging.getLogger('compiler.lexer')
2924 #Not output, because filtered
2925 logger.warning(self.next_message())
2926 logger = logging.getLogger("compiler.parser.codegen")
2927 #Output, as not filtered
2928 logger.error(self.next_message())
2929 self.assert_log_lines([
2930 ('WARNING', '1'),
2931 ('ERROR', '4'),
2932 ], stream=output)
2933
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002934 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002935 @support.reap_threads
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002936 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002937 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002938 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2939 logger = logging.getLogger("compiler.parser")
2940 # Both will output a message
2941 logger.info(self.next_message())
2942 logger.error(self.next_message())
2943 self.assert_log_lines([
2944 ('INFO', '1'),
2945 ('ERROR', '2'),
2946 ], stream=output)
2947 # Original logger output is empty.
2948 self.assert_log_lines([])
2949
Vinay Sajip4ded5512012-10-02 15:56:16 +01002950 @unittest.skipUnless(threading, 'Threading required for this test.')
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002951 @support.reap_threads
Vinay Sajip4ded5512012-10-02 15:56:16 +01002952 def test_listen_verify(self):
2953
2954 def verify_fail(stuff):
2955 return None
2956
2957 def verify_reverse(stuff):
2958 return stuff[::-1]
2959
2960 logger = logging.getLogger("compiler.parser")
2961 to_send = textwrap.dedent(ConfigFileTest.config1)
2962 # First, specify a verification function that will fail.
2963 # We expect to see no output, since our configuration
2964 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002965 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002966 self.setup_via_listener(to_send, verify_fail)
2967 # Both will output a message
2968 logger.info(self.next_message())
2969 logger.error(self.next_message())
2970 self.assert_log_lines([], stream=output)
2971 # Original logger output has the stuff we logged.
2972 self.assert_log_lines([
2973 ('INFO', '1'),
2974 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002975 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002976
2977 # Now, perform no verification. Our configuration
2978 # should take effect.
2979
Vinay Sajip1feedb42014-05-31 08:19:12 +01002980 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002981 self.setup_via_listener(to_send) # no verify callable specified
2982 logger = logging.getLogger("compiler.parser")
2983 # Both will output a message
2984 logger.info(self.next_message())
2985 logger.error(self.next_message())
2986 self.assert_log_lines([
2987 ('INFO', '3'),
2988 ('ERROR', '4'),
2989 ], stream=output)
2990 # Original logger output still has the stuff we logged before.
2991 self.assert_log_lines([
2992 ('INFO', '1'),
2993 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002994 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002995
2996 # Now, perform verification which transforms the bytes.
2997
Vinay Sajip1feedb42014-05-31 08:19:12 +01002998 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002999 self.setup_via_listener(to_send[::-1], verify_reverse)
3000 logger = logging.getLogger("compiler.parser")
3001 # Both will output a message
3002 logger.info(self.next_message())
3003 logger.error(self.next_message())
3004 self.assert_log_lines([
3005 ('INFO', '5'),
3006 ('ERROR', '6'),
3007 ], stream=output)
3008 # Original logger output still has the stuff we logged before.
3009 self.assert_log_lines([
3010 ('INFO', '1'),
3011 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003012 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003013
Vinay Sajip3f885b52013-03-22 15:19:54 +00003014 def test_out_of_order(self):
3015 self.apply_config(self.out_of_order)
3016 handler = logging.getLogger('mymodule').handlers[0]
3017 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003018 self.assertIsInstance(handler.formatter._style,
3019 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003020
Vinay Sajip373baef2011-04-26 20:05:24 +01003021 def test_baseconfig(self):
3022 d = {
3023 'atuple': (1, 2, 3),
3024 'alist': ['a', 'b', 'c'],
3025 'adict': {'d': 'e', 'f': 3 },
3026 'nest1': ('g', ('h', 'i'), 'j'),
3027 'nest2': ['k', ['l', 'm'], 'n'],
3028 'nest3': ['o', 'cfg://alist', 'p'],
3029 }
3030 bc = logging.config.BaseConfigurator(d)
3031 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3032 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3033 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3034 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3035 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3036 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3037 v = bc.convert('cfg://nest3')
3038 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3039 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3040 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3041 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003042
3043class ManagerTest(BaseTest):
3044 def test_manager_loggerclass(self):
3045 logged = []
3046
3047 class MyLogger(logging.Logger):
3048 def _log(self, level, msg, args, exc_info=None, extra=None):
3049 logged.append(msg)
3050
3051 man = logging.Manager(None)
3052 self.assertRaises(TypeError, man.setLoggerClass, int)
3053 man.setLoggerClass(MyLogger)
3054 logger = man.getLogger('test')
3055 logger.warning('should appear in logged')
3056 logging.warning('should not appear in logged')
3057
3058 self.assertEqual(logged, ['should appear in logged'])
3059
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003060 def test_set_log_record_factory(self):
3061 man = logging.Manager(None)
3062 expected = object()
3063 man.setLogRecordFactory(expected)
3064 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003065
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003066class ChildLoggerTest(BaseTest):
3067 def test_child_loggers(self):
3068 r = logging.getLogger()
3069 l1 = logging.getLogger('abc')
3070 l2 = logging.getLogger('def.ghi')
3071 c1 = r.getChild('xyz')
3072 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003073 self.assertIs(c1, logging.getLogger('xyz'))
3074 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003075 c1 = l1.getChild('def')
3076 c2 = c1.getChild('ghi')
3077 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003078 self.assertIs(c1, logging.getLogger('abc.def'))
3079 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3080 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003081
3082
Vinay Sajip6fac8172010-10-19 20:44:14 +00003083class DerivedLogRecord(logging.LogRecord):
3084 pass
3085
Vinay Sajip61561522010-12-03 11:50:38 +00003086class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003087
3088 def setUp(self):
3089 class CheckingFilter(logging.Filter):
3090 def __init__(self, cls):
3091 self.cls = cls
3092
3093 def filter(self, record):
3094 t = type(record)
3095 if t is not self.cls:
3096 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3097 self.cls)
3098 raise TypeError(msg)
3099 return True
3100
3101 BaseTest.setUp(self)
3102 self.filter = CheckingFilter(DerivedLogRecord)
3103 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003104 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003105
3106 def tearDown(self):
3107 self.root_logger.removeFilter(self.filter)
3108 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003109 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003110
3111 def test_logrecord_class(self):
3112 self.assertRaises(TypeError, self.root_logger.warning,
3113 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003114 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003115 self.root_logger.error(self.next_message())
3116 self.assert_log_lines([
3117 ('root', 'ERROR', '2'),
3118 ])
3119
3120
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003121class QueueHandlerTest(BaseTest):
3122 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003123 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003124
3125 def setUp(self):
3126 BaseTest.setUp(self)
3127 self.queue = queue.Queue(-1)
3128 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003129 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003130 self.que_logger = logging.getLogger('que')
3131 self.que_logger.propagate = False
3132 self.que_logger.setLevel(logging.WARNING)
3133 self.que_logger.addHandler(self.que_hdlr)
3134
3135 def tearDown(self):
3136 self.que_hdlr.close()
3137 BaseTest.tearDown(self)
3138
3139 def test_queue_handler(self):
3140 self.que_logger.debug(self.next_message())
3141 self.assertRaises(queue.Empty, self.queue.get_nowait)
3142 self.que_logger.info(self.next_message())
3143 self.assertRaises(queue.Empty, self.queue.get_nowait)
3144 msg = self.next_message()
3145 self.que_logger.warning(msg)
3146 data = self.queue.get_nowait()
3147 self.assertTrue(isinstance(data, logging.LogRecord))
3148 self.assertEqual(data.name, self.que_logger.name)
3149 self.assertEqual((data.msg, data.args), (msg, None))
3150
favlladfe3442017-08-01 20:12:26 +02003151 def test_formatting(self):
3152 msg = self.next_message()
3153 levelname = logging.getLevelName(logging.WARNING)
3154 log_format_str = '{name} -> {levelname}: {message}'
3155 formatted_msg = log_format_str.format(name=self.name,
3156 levelname=levelname, message=msg)
3157 formatter = logging.Formatter(self.log_format)
3158 self.que_hdlr.setFormatter(formatter)
3159 self.que_logger.warning(msg)
3160 log_record = self.queue.get_nowait()
3161 self.assertEqual(formatted_msg, log_record.msg)
3162 self.assertEqual(formatted_msg, log_record.message)
3163
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003164 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3165 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003166 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003167 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003168 listener = logging.handlers.QueueListener(self.queue, handler)
3169 listener.start()
3170 try:
3171 self.que_logger.warning(self.next_message())
3172 self.que_logger.error(self.next_message())
3173 self.que_logger.critical(self.next_message())
3174 finally:
3175 listener.stop()
3176 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3177 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3178 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003179 handler.close()
3180
3181 # Now test with respect_handler_level set
3182
3183 handler = support.TestHandler(support.Matcher())
3184 handler.setLevel(logging.CRITICAL)
3185 listener = logging.handlers.QueueListener(self.queue, handler,
3186 respect_handler_level=True)
3187 listener.start()
3188 try:
3189 self.que_logger.warning(self.next_message())
3190 self.que_logger.error(self.next_message())
3191 self.que_logger.critical(self.next_message())
3192 finally:
3193 listener.stop()
3194 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3195 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3196 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3197
Vinay Sajipd61910c2016-09-08 01:13:39 +01003198if hasattr(logging.handlers, 'QueueListener'):
3199 import multiprocessing
3200 from unittest.mock import patch
3201
3202 class QueueListenerTest(BaseTest):
3203 """
3204 Tests based on patch submitted for issue #27930. Ensure that
3205 QueueListener handles all log messages.
3206 """
3207
3208 repeat = 20
3209
3210 @staticmethod
3211 def setup_and_log(log_queue, ident):
3212 """
3213 Creates a logger with a QueueHandler that logs to a queue read by a
3214 QueueListener. Starts the listener, logs five messages, and stops
3215 the listener.
3216 """
3217 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3218 logger.setLevel(logging.DEBUG)
3219 handler = logging.handlers.QueueHandler(log_queue)
3220 logger.addHandler(handler)
3221 listener = logging.handlers.QueueListener(log_queue)
3222 listener.start()
3223
3224 logger.info('one')
3225 logger.info('two')
3226 logger.info('three')
3227 logger.info('four')
3228 logger.info('five')
3229
3230 listener.stop()
3231 logger.removeHandler(handler)
3232 handler.close()
3233
3234 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003235 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003236 def test_handle_called_with_queue_queue(self, mock_handle):
3237 for i in range(self.repeat):
3238 log_queue = queue.Queue()
3239 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3240 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3241 'correct number of handled log messages')
3242
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003243 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003244 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003245 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003246 def test_handle_called_with_mp_queue(self, mock_handle):
3247 for i in range(self.repeat):
3248 log_queue = multiprocessing.Queue()
3249 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003250 log_queue.close()
3251 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003252 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3253 'correct number of handled log messages')
3254
3255 @staticmethod
3256 def get_all_from_queue(log_queue):
3257 try:
3258 while True:
3259 yield log_queue.get_nowait()
3260 except queue.Empty:
3261 return []
3262
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003263 @support.requires_multiprocessing_queue
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003264 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003265 def test_no_messages_in_queue_after_stop(self):
3266 """
3267 Five messages are logged then the QueueListener is stopped. This
3268 test then gets everything off the queue. Failure of this test
3269 indicates that messages were not registered on the queue until
3270 _after_ the QueueListener stopped.
3271 """
3272 for i in range(self.repeat):
3273 queue = multiprocessing.Queue()
3274 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3275 # time.sleep(1)
3276 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003277 queue.close()
3278 queue.join_thread()
3279
Vinay Sajipd61910c2016-09-08 01:13:39 +01003280 expected = [[], [logging.handlers.QueueListener._sentinel]]
3281 self.assertIn(items, expected,
3282 'Found unexpected messages in queue: %s' % (
3283 [m.msg if isinstance(m, logging.LogRecord)
3284 else m for m in items]))
3285
Vinay Sajipe723e962011-04-15 22:27:17 +01003286
Vinay Sajip37eb3382011-04-26 20:26:41 +01003287ZERO = datetime.timedelta(0)
3288
3289class UTC(datetime.tzinfo):
3290 def utcoffset(self, dt):
3291 return ZERO
3292
3293 dst = utcoffset
3294
3295 def tzname(self, dt):
3296 return 'UTC'
3297
3298utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003299
Vinay Sajipa39c5712010-10-25 13:57:39 +00003300class FormatterTest(unittest.TestCase):
3301 def setUp(self):
3302 self.common = {
3303 'name': 'formatter.test',
3304 'level': logging.DEBUG,
3305 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3306 'lineno': 42,
3307 'exc_info': None,
3308 'func': None,
3309 'msg': 'Message with %d %s',
3310 'args': (2, 'placeholders'),
3311 }
3312 self.variants = {
3313 }
3314
3315 def get_record(self, name=None):
3316 result = dict(self.common)
3317 if name is not None:
3318 result.update(self.variants[name])
3319 return logging.makeLogRecord(result)
3320
3321 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003322 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003323 r = self.get_record()
3324 f = logging.Formatter('${%(message)s}')
3325 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3326 f = logging.Formatter('%(random)s')
3327 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003328 self.assertFalse(f.usesTime())
3329 f = logging.Formatter('%(asctime)s')
3330 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003331 f = logging.Formatter('%(asctime)-15s')
3332 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003333 f = logging.Formatter('asctime')
3334 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003335
3336 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003337 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003338 r = self.get_record()
3339 f = logging.Formatter('$%{message}%$', style='{')
3340 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3341 f = logging.Formatter('{random}', style='{')
3342 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003343 self.assertFalse(f.usesTime())
3344 f = logging.Formatter('{asctime}', style='{')
3345 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003346 f = logging.Formatter('{asctime!s:15}', style='{')
3347 self.assertTrue(f.usesTime())
3348 f = logging.Formatter('{asctime:15}', style='{')
3349 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003350 f = logging.Formatter('asctime', style='{')
3351 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003352
3353 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003354 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003355 r = self.get_record()
3356 f = logging.Formatter('$message', style='$')
3357 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3358 f = logging.Formatter('$$%${message}%$$', style='$')
3359 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3360 f = logging.Formatter('${random}', style='$')
3361 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003362 self.assertFalse(f.usesTime())
3363 f = logging.Formatter('${asctime}', style='$')
3364 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003365 f = logging.Formatter('${asctime', style='$')
3366 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003367 f = logging.Formatter('$asctime', style='$')
3368 self.assertTrue(f.usesTime())
3369 f = logging.Formatter('asctime', style='$')
3370 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003371
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003372 def test_invalid_style(self):
3373 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3374
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003375 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003376 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003377 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3378 # We use None to indicate we want the local timezone
3379 # We're essentially converting a UTC time to local time
3380 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003381 r.msecs = 123
3382 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003383 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003384 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3385 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003386 f.format(r)
3387 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3388
3389class TestBufferingFormatter(logging.BufferingFormatter):
3390 def formatHeader(self, records):
3391 return '[(%d)' % len(records)
3392
3393 def formatFooter(self, records):
3394 return '(%d)]' % len(records)
3395
3396class BufferingFormatterTest(unittest.TestCase):
3397 def setUp(self):
3398 self.records = [
3399 logging.makeLogRecord({'msg': 'one'}),
3400 logging.makeLogRecord({'msg': 'two'}),
3401 ]
3402
3403 def test_default(self):
3404 f = logging.BufferingFormatter()
3405 self.assertEqual('', f.format([]))
3406 self.assertEqual('onetwo', f.format(self.records))
3407
3408 def test_custom(self):
3409 f = TestBufferingFormatter()
3410 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3411 lf = logging.Formatter('<%(message)s>')
3412 f = TestBufferingFormatter(lf)
3413 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003414
3415class ExceptionTest(BaseTest):
3416 def test_formatting(self):
3417 r = self.root_logger
3418 h = RecordingHandler()
3419 r.addHandler(h)
3420 try:
3421 raise RuntimeError('deliberate mistake')
3422 except:
3423 logging.exception('failed', stack_info=True)
3424 r.removeHandler(h)
3425 h.close()
3426 r = h.records[0]
3427 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3428 'call last):\n'))
3429 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3430 'deliberate mistake'))
3431 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3432 'call last):\n'))
3433 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3434 'stack_info=True)'))
3435
3436
Vinay Sajip5a27d402010-12-10 11:42:57 +00003437class LastResortTest(BaseTest):
3438 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003439 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003440 root = self.root_logger
3441 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003442 old_lastresort = logging.lastResort
3443 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003444
Vinay Sajip5a27d402010-12-10 11:42:57 +00003445 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003446 with support.captured_stderr() as stderr:
3447 root.debug('This should not appear')
3448 self.assertEqual(stderr.getvalue(), '')
3449 root.warning('Final chance!')
3450 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3451
3452 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003453 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003454 with support.captured_stderr() as stderr:
3455 root.warning('Final chance!')
3456 msg = 'No handlers could be found for logger "root"\n'
3457 self.assertEqual(stderr.getvalue(), msg)
3458
Vinay Sajip5a27d402010-12-10 11:42:57 +00003459 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003460 with support.captured_stderr() as stderr:
3461 root.warning('Final chance!')
3462 self.assertEqual(stderr.getvalue(), '')
3463
3464 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003465 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003466 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003467 with support.captured_stderr() as stderr:
3468 root.warning('Final chance!')
3469 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003470 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003471 root.addHandler(self.root_hdlr)
3472 logging.lastResort = old_lastresort
3473 logging.raiseExceptions = old_raise_exceptions
3474
3475
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003476class FakeHandler:
3477
3478 def __init__(self, identifier, called):
3479 for method in ('acquire', 'flush', 'close', 'release'):
3480 setattr(self, method, self.record_call(identifier, method, called))
3481
3482 def record_call(self, identifier, method_name, called):
3483 def inner():
3484 called.append('{} - {}'.format(identifier, method_name))
3485 return inner
3486
3487
3488class RecordingHandler(logging.NullHandler):
3489
3490 def __init__(self, *args, **kwargs):
3491 super(RecordingHandler, self).__init__(*args, **kwargs)
3492 self.records = []
3493
3494 def handle(self, record):
3495 """Keep track of all the emitted records."""
3496 self.records.append(record)
3497
3498
3499class ShutdownTest(BaseTest):
3500
Vinay Sajip5e66b162011-04-20 15:41:14 +01003501 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003502
3503 def setUp(self):
3504 super(ShutdownTest, self).setUp()
3505 self.called = []
3506
3507 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003508 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003509
3510 def raise_error(self, error):
3511 def inner():
3512 raise error()
3513 return inner
3514
3515 def test_no_failure(self):
3516 # create some fake handlers
3517 handler0 = FakeHandler(0, self.called)
3518 handler1 = FakeHandler(1, self.called)
3519 handler2 = FakeHandler(2, self.called)
3520
3521 # create live weakref to those handlers
3522 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3523
3524 logging.shutdown(handlerList=list(handlers))
3525
3526 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3527 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3528 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3529 self.assertEqual(expected, self.called)
3530
3531 def _test_with_failure_in_method(self, method, error):
3532 handler = FakeHandler(0, self.called)
3533 setattr(handler, method, self.raise_error(error))
3534 handlers = [logging.weakref.ref(handler)]
3535
3536 logging.shutdown(handlerList=list(handlers))
3537
3538 self.assertEqual('0 - release', self.called[-1])
3539
3540 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003541 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003542
3543 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003544 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003545
3546 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003547 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003548
3549 def test_with_valueerror_in_acquire(self):
3550 self._test_with_failure_in_method('acquire', ValueError)
3551
3552 def test_with_valueerror_in_flush(self):
3553 self._test_with_failure_in_method('flush', ValueError)
3554
3555 def test_with_valueerror_in_close(self):
3556 self._test_with_failure_in_method('close', ValueError)
3557
3558 def test_with_other_error_in_acquire_without_raise(self):
3559 logging.raiseExceptions = False
3560 self._test_with_failure_in_method('acquire', IndexError)
3561
3562 def test_with_other_error_in_flush_without_raise(self):
3563 logging.raiseExceptions = False
3564 self._test_with_failure_in_method('flush', IndexError)
3565
3566 def test_with_other_error_in_close_without_raise(self):
3567 logging.raiseExceptions = False
3568 self._test_with_failure_in_method('close', IndexError)
3569
3570 def test_with_other_error_in_acquire_with_raise(self):
3571 logging.raiseExceptions = True
3572 self.assertRaises(IndexError, self._test_with_failure_in_method,
3573 'acquire', IndexError)
3574
3575 def test_with_other_error_in_flush_with_raise(self):
3576 logging.raiseExceptions = True
3577 self.assertRaises(IndexError, self._test_with_failure_in_method,
3578 'flush', IndexError)
3579
3580 def test_with_other_error_in_close_with_raise(self):
3581 logging.raiseExceptions = True
3582 self.assertRaises(IndexError, self._test_with_failure_in_method,
3583 'close', IndexError)
3584
3585
3586class ModuleLevelMiscTest(BaseTest):
3587
Vinay Sajip5e66b162011-04-20 15:41:14 +01003588 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003589
3590 def test_disable(self):
3591 old_disable = logging.root.manager.disable
3592 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003593 self.assertEqual(old_disable, 0)
3594 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003595
3596 logging.disable(83)
3597 self.assertEqual(logging.root.manager.disable, 83)
3598
Vinay Sajipd489ac92016-12-31 11:40:11 +00003599 # test the default value introduced in 3.7
3600 # (Issue #28524)
3601 logging.disable()
3602 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3603
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003604 def _test_log(self, method, level=None):
3605 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003606 support.patch(self, logging, 'basicConfig',
3607 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003608
3609 recording = RecordingHandler()
3610 logging.root.addHandler(recording)
3611
3612 log_method = getattr(logging, method)
3613 if level is not None:
3614 log_method(level, "test me: %r", recording)
3615 else:
3616 log_method("test me: %r", recording)
3617
3618 self.assertEqual(len(recording.records), 1)
3619 record = recording.records[0]
3620 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3621
3622 expected_level = level if level is not None else getattr(logging, method.upper())
3623 self.assertEqual(record.levelno, expected_level)
3624
3625 # basicConfig was not called!
3626 self.assertEqual(called, [])
3627
3628 def test_log(self):
3629 self._test_log('log', logging.ERROR)
3630
3631 def test_debug(self):
3632 self._test_log('debug')
3633
3634 def test_info(self):
3635 self._test_log('info')
3636
3637 def test_warning(self):
3638 self._test_log('warning')
3639
3640 def test_error(self):
3641 self._test_log('error')
3642
3643 def test_critical(self):
3644 self._test_log('critical')
3645
3646 def test_set_logger_class(self):
3647 self.assertRaises(TypeError, logging.setLoggerClass, object)
3648
3649 class MyLogger(logging.Logger):
3650 pass
3651
3652 logging.setLoggerClass(MyLogger)
3653 self.assertEqual(logging.getLoggerClass(), MyLogger)
3654
3655 logging.setLoggerClass(logging.Logger)
3656 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3657
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003658 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003659 def test_logging_at_shutdown(self):
3660 # Issue #20037
3661 code = """if 1:
3662 import logging
3663
3664 class A:
3665 def __del__(self):
3666 try:
3667 raise ValueError("some error")
3668 except Exception:
3669 logging.exception("exception in __del__")
3670
3671 a = A()"""
3672 rc, out, err = assert_python_ok("-c", code)
3673 err = err.decode()
3674 self.assertIn("exception in __del__", err)
3675 self.assertIn("ValueError: some error", err)
3676
3677
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003678class LogRecordTest(BaseTest):
3679 def test_str_rep(self):
3680 r = logging.makeLogRecord({})
3681 s = str(r)
3682 self.assertTrue(s.startswith('<LogRecord: '))
3683 self.assertTrue(s.endswith('>'))
3684
3685 def test_dict_arg(self):
3686 h = RecordingHandler()
3687 r = logging.getLogger()
3688 r.addHandler(h)
3689 d = {'less' : 'more' }
3690 logging.warning('less is %(less)s', d)
3691 self.assertIs(h.records[0].args, d)
3692 self.assertEqual(h.records[0].message, 'less is more')
3693 r.removeHandler(h)
3694 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003695
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003696 def test_multiprocessing(self):
3697 r = logging.makeLogRecord({})
3698 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003699 try:
3700 import multiprocessing as mp
3701 r = logging.makeLogRecord({})
3702 self.assertEqual(r.processName, mp.current_process().name)
3703 except ImportError:
3704 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003705
3706 def test_optional(self):
3707 r = logging.makeLogRecord({})
3708 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003709 if threading:
3710 NOT_NONE(r.thread)
3711 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003712 NOT_NONE(r.process)
3713 NOT_NONE(r.processName)
3714 log_threads = logging.logThreads
3715 log_processes = logging.logProcesses
3716 log_multiprocessing = logging.logMultiprocessing
3717 try:
3718 logging.logThreads = False
3719 logging.logProcesses = False
3720 logging.logMultiprocessing = False
3721 r = logging.makeLogRecord({})
3722 NONE = self.assertIsNone
3723 NONE(r.thread)
3724 NONE(r.threadName)
3725 NONE(r.process)
3726 NONE(r.processName)
3727 finally:
3728 logging.logThreads = log_threads
3729 logging.logProcesses = log_processes
3730 logging.logMultiprocessing = log_multiprocessing
3731
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003732class BasicConfigTest(unittest.TestCase):
3733
Vinay Sajip95bf5042011-04-20 11:50:56 +01003734 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003735
3736 def setUp(self):
3737 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003738 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003739 self.saved_handlers = logging._handlers.copy()
3740 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003741 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003742 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003743 logging.root.handlers = []
3744
3745 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003746 for h in logging.root.handlers[:]:
3747 logging.root.removeHandler(h)
3748 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003749 super(BasicConfigTest, self).tearDown()
3750
Vinay Sajip3def7e02011-04-20 10:58:06 +01003751 def cleanup(self):
3752 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003753 logging._handlers.clear()
3754 logging._handlers.update(self.saved_handlers)
3755 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003756 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003757
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003758 def test_no_kwargs(self):
3759 logging.basicConfig()
3760
3761 # handler defaults to a StreamHandler to sys.stderr
3762 self.assertEqual(len(logging.root.handlers), 1)
3763 handler = logging.root.handlers[0]
3764 self.assertIsInstance(handler, logging.StreamHandler)
3765 self.assertEqual(handler.stream, sys.stderr)
3766
3767 formatter = handler.formatter
3768 # format defaults to logging.BASIC_FORMAT
3769 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3770 # datefmt defaults to None
3771 self.assertIsNone(formatter.datefmt)
3772 # style defaults to %
3773 self.assertIsInstance(formatter._style, logging.PercentStyle)
3774
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003775 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003776 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003777
Vinay Sajip1fd12022014-01-13 21:59:56 +00003778 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003779 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003780 logging.basicConfig(stream=sys.stdout, style="{")
3781 logging.error("Log an error")
3782 sys.stdout.seek(0)
3783 self.assertEqual(output.getvalue().strip(),
3784 "ERROR:root:Log an error")
3785
3786 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003787 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003788 logging.basicConfig(stream=sys.stdout, style="$")
3789 logging.error("Log an error")
3790 sys.stdout.seek(0)
3791 self.assertEqual(output.getvalue().strip(),
3792 "ERROR:root:Log an error")
3793
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003794 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003795
3796 def cleanup(h1, h2, fn):
3797 h1.close()
3798 h2.close()
3799 os.remove(fn)
3800
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003801 logging.basicConfig(filename='test.log')
3802
3803 self.assertEqual(len(logging.root.handlers), 1)
3804 handler = logging.root.handlers[0]
3805 self.assertIsInstance(handler, logging.FileHandler)
3806
3807 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003808 self.assertEqual(handler.stream.mode, expected.stream.mode)
3809 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003810 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003811
3812 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003813
3814 def cleanup(h1, h2, fn):
3815 h1.close()
3816 h2.close()
3817 os.remove(fn)
3818
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003819 logging.basicConfig(filename='test.log', filemode='wb')
3820
3821 handler = logging.root.handlers[0]
3822 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003823 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003824 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825
3826 def test_stream(self):
3827 stream = io.StringIO()
3828 self.addCleanup(stream.close)
3829 logging.basicConfig(stream=stream)
3830
3831 self.assertEqual(len(logging.root.handlers), 1)
3832 handler = logging.root.handlers[0]
3833 self.assertIsInstance(handler, logging.StreamHandler)
3834 self.assertEqual(handler.stream, stream)
3835
3836 def test_format(self):
3837 logging.basicConfig(format='foo')
3838
3839 formatter = logging.root.handlers[0].formatter
3840 self.assertEqual(formatter._style._fmt, 'foo')
3841
3842 def test_datefmt(self):
3843 logging.basicConfig(datefmt='bar')
3844
3845 formatter = logging.root.handlers[0].formatter
3846 self.assertEqual(formatter.datefmt, 'bar')
3847
3848 def test_style(self):
3849 logging.basicConfig(style='$')
3850
3851 formatter = logging.root.handlers[0].formatter
3852 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3853
3854 def test_level(self):
3855 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003856 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003857
3858 logging.basicConfig(level=57)
3859 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003860 # Test that second call has no effect
3861 logging.basicConfig(level=58)
3862 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003863
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003864 def test_incompatible(self):
3865 assertRaises = self.assertRaises
3866 handlers = [logging.StreamHandler()]
3867 stream = sys.stderr
3868 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3869 stream=stream)
3870 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3871 handlers=handlers)
3872 assertRaises(ValueError, logging.basicConfig, stream=stream,
3873 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003874 # Issue 23207: test for invalid kwargs
3875 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3876 # Should pop both filename and filemode even if filename is None
3877 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003878
3879 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003880 handlers = [
3881 logging.StreamHandler(),
3882 logging.StreamHandler(sys.stdout),
3883 logging.StreamHandler(),
3884 ]
3885 f = logging.Formatter()
3886 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003887 logging.basicConfig(handlers=handlers)
3888 self.assertIs(handlers[0], logging.root.handlers[0])
3889 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003890 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003891 self.assertIsNotNone(handlers[0].formatter)
3892 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003893 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003894 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3895
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003896 def _test_log(self, method, level=None):
3897 # logging.root has no handlers so basicConfig should be called
3898 called = []
3899
3900 old_basic_config = logging.basicConfig
3901 def my_basic_config(*a, **kw):
3902 old_basic_config()
3903 old_level = logging.root.level
3904 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003905 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003906 called.append((a, kw))
3907
Vinay Sajip1feedb42014-05-31 08:19:12 +01003908 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003909
3910 log_method = getattr(logging, method)
3911 if level is not None:
3912 log_method(level, "test me")
3913 else:
3914 log_method("test me")
3915
3916 # basicConfig was called with no arguments
3917 self.assertEqual(called, [((), {})])
3918
3919 def test_log(self):
3920 self._test_log('log', logging.WARNING)
3921
3922 def test_debug(self):
3923 self._test_log('debug')
3924
3925 def test_info(self):
3926 self._test_log('info')
3927
3928 def test_warning(self):
3929 self._test_log('warning')
3930
3931 def test_error(self):
3932 self._test_log('error')
3933
3934 def test_critical(self):
3935 self._test_log('critical')
3936
3937
3938class LoggerAdapterTest(unittest.TestCase):
3939
3940 def setUp(self):
3941 super(LoggerAdapterTest, self).setUp()
3942 old_handler_list = logging._handlerList[:]
3943
3944 self.recording = RecordingHandler()
3945 self.logger = logging.root
3946 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003947 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003948 self.addCleanup(self.recording.close)
3949
3950 def cleanup():
3951 logging._handlerList[:] = old_handler_list
3952
3953 self.addCleanup(cleanup)
3954 self.addCleanup(logging.shutdown)
3955 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3956
3957 def test_exception(self):
3958 msg = 'testing exception: %r'
3959 exc = None
3960 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003961 1 / 0
3962 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003963 exc = e
3964 self.adapter.exception(msg, self.recording)
3965
3966 self.assertEqual(len(self.recording.records), 1)
3967 record = self.recording.records[0]
3968 self.assertEqual(record.levelno, logging.ERROR)
3969 self.assertEqual(record.msg, msg)
3970 self.assertEqual(record.args, (self.recording,))
3971 self.assertEqual(record.exc_info,
3972 (exc.__class__, exc, exc.__traceback__))
3973
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003974 def test_exception_excinfo(self):
3975 try:
3976 1 / 0
3977 except ZeroDivisionError as e:
3978 exc = e
3979
3980 self.adapter.exception('exc_info test', exc_info=exc)
3981
3982 self.assertEqual(len(self.recording.records), 1)
3983 record = self.recording.records[0]
3984 self.assertEqual(record.exc_info,
3985 (exc.__class__, exc, exc.__traceback__))
3986
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003987 def test_critical(self):
3988 msg = 'critical test! %r'
3989 self.adapter.critical(msg, self.recording)
3990
3991 self.assertEqual(len(self.recording.records), 1)
3992 record = self.recording.records[0]
3993 self.assertEqual(record.levelno, logging.CRITICAL)
3994 self.assertEqual(record.msg, msg)
3995 self.assertEqual(record.args, (self.recording,))
3996
3997 def test_is_enabled_for(self):
3998 old_disable = self.adapter.logger.manager.disable
3999 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004000 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4001 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004002 self.assertFalse(self.adapter.isEnabledFor(32))
4003
4004 def test_has_handlers(self):
4005 self.assertTrue(self.adapter.hasHandlers())
4006
4007 for handler in self.logger.handlers:
4008 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004009
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004010 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004011 self.assertFalse(self.adapter.hasHandlers())
4012
4013
4014class LoggerTest(BaseTest):
4015
4016 def setUp(self):
4017 super(LoggerTest, self).setUp()
4018 self.recording = RecordingHandler()
4019 self.logger = logging.Logger(name='blah')
4020 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004021 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004022 self.addCleanup(self.recording.close)
4023 self.addCleanup(logging.shutdown)
4024
4025 def test_set_invalid_level(self):
4026 self.assertRaises(TypeError, self.logger.setLevel, object())
4027
4028 def test_exception(self):
4029 msg = 'testing exception: %r'
4030 exc = None
4031 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004032 1 / 0
4033 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004034 exc = e
4035 self.logger.exception(msg, self.recording)
4036
4037 self.assertEqual(len(self.recording.records), 1)
4038 record = self.recording.records[0]
4039 self.assertEqual(record.levelno, logging.ERROR)
4040 self.assertEqual(record.msg, msg)
4041 self.assertEqual(record.args, (self.recording,))
4042 self.assertEqual(record.exc_info,
4043 (exc.__class__, exc, exc.__traceback__))
4044
4045 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004046 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004047 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004048
4049 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004050 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004051 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004052
4053 def test_find_caller_with_stack_info(self):
4054 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004055 support.patch(self, logging.traceback, 'print_stack',
4056 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004057
4058 self.logger.findCaller(stack_info=True)
4059
4060 self.assertEqual(len(called), 1)
4061 self.assertEqual('Stack (most recent call last):\n', called[0])
4062
4063 def test_make_record_with_extra_overwrite(self):
4064 name = 'my record'
4065 level = 13
4066 fn = lno = msg = args = exc_info = func = sinfo = None
4067 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4068 exc_info, func, sinfo)
4069
4070 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4071 extra = {key: 'some value'}
4072 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4073 fn, lno, msg, args, exc_info,
4074 extra=extra, sinfo=sinfo)
4075
4076 def test_make_record_with_extra_no_overwrite(self):
4077 name = 'my record'
4078 level = 13
4079 fn = lno = msg = args = exc_info = func = sinfo = None
4080 extra = {'valid_key': 'some value'}
4081 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4082 exc_info, extra=extra, sinfo=sinfo)
4083 self.assertIn('valid_key', result.__dict__)
4084
4085 def test_has_handlers(self):
4086 self.assertTrue(self.logger.hasHandlers())
4087
4088 for handler in self.logger.handlers:
4089 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004090 self.assertFalse(self.logger.hasHandlers())
4091
4092 def test_has_handlers_no_propagate(self):
4093 child_logger = logging.getLogger('blah.child')
4094 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004095 self.assertFalse(child_logger.hasHandlers())
4096
4097 def test_is_enabled_for(self):
4098 old_disable = self.logger.manager.disable
4099 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004100 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004101 self.assertFalse(self.logger.isEnabledFor(22))
4102
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004103 def test_root_logger_aliases(self):
4104 root = logging.getLogger()
4105 self.assertIs(root, logging.root)
4106 self.assertIs(root, logging.getLogger(None))
4107 self.assertIs(root, logging.getLogger(''))
4108 self.assertIs(root, logging.getLogger('foo').root)
4109 self.assertIs(root, logging.getLogger('foo.bar').root)
4110 self.assertIs(root, logging.getLogger('foo').parent)
4111
4112 self.assertIsNot(root, logging.getLogger('\0'))
4113 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4114
4115 def test_invalid_names(self):
4116 self.assertRaises(TypeError, logging.getLogger, any)
4117 self.assertRaises(TypeError, logging.getLogger, b'foo')
4118
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004119 def test_pickling(self):
4120 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4121 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4122 logger = logging.getLogger(name)
4123 s = pickle.dumps(logger, proto)
4124 unpickled = pickle.loads(s)
4125 self.assertIs(unpickled, logger)
4126
Avram Lubkin78c18a92017-07-30 05:36:33 -04004127 def test_caching(self):
4128 root = self.root_logger
4129 logger1 = logging.getLogger("abc")
4130 logger2 = logging.getLogger("abc.def")
4131
4132 # Set root logger level and ensure cache is empty
4133 root.setLevel(logging.ERROR)
4134 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4135 self.assertEqual(logger2._cache, {})
4136
4137 # Ensure cache is populated and calls are consistent
4138 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4139 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4140 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4141 self.assertEqual(root._cache, {})
4142 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4143
4144 # Ensure root cache gets populated
4145 self.assertEqual(root._cache, {})
4146 self.assertTrue(root.isEnabledFor(logging.ERROR))
4147 self.assertEqual(root._cache, {logging.ERROR: True})
4148
4149 # Set parent logger level and ensure caches are emptied
4150 logger1.setLevel(logging.CRITICAL)
4151 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4152 self.assertEqual(logger2._cache, {})
4153
4154 # Ensure logger2 uses parent logger's effective level
4155 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4156
4157 # Set level to NOTSET and ensure caches are empty
4158 logger2.setLevel(logging.NOTSET)
4159 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4160 self.assertEqual(logger2._cache, {})
4161 self.assertEqual(logger1._cache, {})
4162 self.assertEqual(root._cache, {})
4163
4164 # Verify logger2 follows parent and not root
4165 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4166 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4167 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4168 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4169 self.assertTrue(root.isEnabledFor(logging.ERROR))
4170
4171 # Disable logging in manager and ensure caches are clear
4172 logging.disable()
4173 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4174 self.assertEqual(logger2._cache, {})
4175 self.assertEqual(logger1._cache, {})
4176 self.assertEqual(root._cache, {})
4177
4178 # Ensure no loggers are enabled
4179 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4180 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4181 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4182
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004183
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004184class BaseFileTest(BaseTest):
4185 "Base class for handler tests that write log files"
4186
4187 def setUp(self):
4188 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004189 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4190 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004191 self.rmfiles = []
4192
4193 def tearDown(self):
4194 for fn in self.rmfiles:
4195 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004196 if os.path.exists(self.fn):
4197 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004198 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004199
4200 def assertLogFile(self, filename):
4201 "Assert a log file is there and register it for deletion"
4202 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004203 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004204 self.rmfiles.append(filename)
4205
4206
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004207class FileHandlerTest(BaseFileTest):
4208 def test_delay(self):
4209 os.unlink(self.fn)
4210 fh = logging.FileHandler(self.fn, delay=True)
4211 self.assertIsNone(fh.stream)
4212 self.assertFalse(os.path.exists(self.fn))
4213 fh.handle(logging.makeLogRecord({}))
4214 self.assertIsNotNone(fh.stream)
4215 self.assertTrue(os.path.exists(self.fn))
4216 fh.close()
4217
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004218class RotatingFileHandlerTest(BaseFileTest):
4219 def next_rec(self):
4220 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4221 self.next_message(), None, None, None)
4222
4223 def test_should_not_rollover(self):
4224 # If maxbytes is zero rollover never occurs
4225 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4226 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004227 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004228
4229 def test_should_rollover(self):
4230 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4231 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004232 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004233
4234 def test_file_created(self):
4235 # checks that the file is created and assumes it was created
4236 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004237 rh = logging.handlers.RotatingFileHandler(self.fn)
4238 rh.emit(self.next_rec())
4239 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004240 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004241
4242 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004243 def namer(name):
4244 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004245 rh = logging.handlers.RotatingFileHandler(
4246 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004247 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004248 rh.emit(self.next_rec())
4249 self.assertLogFile(self.fn)
4250 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004251 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004252 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004253 self.assertLogFile(namer(self.fn + ".2"))
4254 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4255 rh.close()
4256
Vinay Sajip1feedb42014-05-31 08:19:12 +01004257 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004258 def test_rotator(self):
4259 def namer(name):
4260 return name + ".gz"
4261
4262 def rotator(source, dest):
4263 with open(source, "rb") as sf:
4264 data = sf.read()
4265 compressed = zlib.compress(data, 9)
4266 with open(dest, "wb") as df:
4267 df.write(compressed)
4268 os.remove(source)
4269
4270 rh = logging.handlers.RotatingFileHandler(
4271 self.fn, backupCount=2, maxBytes=1)
4272 rh.rotator = rotator
4273 rh.namer = namer
4274 m1 = self.next_rec()
4275 rh.emit(m1)
4276 self.assertLogFile(self.fn)
4277 m2 = self.next_rec()
4278 rh.emit(m2)
4279 fn = namer(self.fn + ".1")
4280 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004281 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004282 with open(fn, "rb") as f:
4283 compressed = f.read()
4284 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004285 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004286 rh.emit(self.next_rec())
4287 fn = namer(self.fn + ".2")
4288 self.assertLogFile(fn)
4289 with open(fn, "rb") as f:
4290 compressed = f.read()
4291 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004292 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004293 rh.emit(self.next_rec())
4294 fn = namer(self.fn + ".2")
4295 with open(fn, "rb") as f:
4296 compressed = f.read()
4297 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004298 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004299 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004300 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004301
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004302class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004303 # other test methods added below
4304 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004305 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4306 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004307 fmt = logging.Formatter('%(asctime)s %(message)s')
4308 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004309 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004310 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004311 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004312 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004313 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004314 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004315 fh.close()
4316 # At this point, we should have a recent rotated file which we
4317 # can test for the existence of. However, in practice, on some
4318 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004319 # in time to go to look for the log file. So, we go back a fair
4320 # bit, and stop as soon as we see a rotated file. In theory this
4321 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004322 found = False
4323 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004324 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004325 for secs in range(GO_BACK):
4326 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004327 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4328 found = os.path.exists(fn)
4329 if found:
4330 self.rmfiles.append(fn)
4331 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004332 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4333 if not found:
4334 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004335 dn, fn = os.path.split(self.fn)
4336 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004337 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4338 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004339 for f in files:
4340 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004341 path = os.path.join(dn, f)
4342 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004343 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004344 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004345
Vinay Sajip0372e102011-05-05 12:59:14 +01004346 def test_invalid(self):
4347 assertRaises = self.assertRaises
4348 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004349 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004350 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004351 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004352 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004353 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004354
Vinay Sajipa7130792013-04-12 17:04:23 +01004355 def test_compute_rollover_daily_attime(self):
4356 currentTime = 0
4357 atTime = datetime.time(12, 0, 0)
4358 rh = logging.handlers.TimedRotatingFileHandler(
4359 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4360 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004361 try:
4362 actual = rh.computeRollover(currentTime)
4363 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004364
Vinay Sajipd86ac962013-04-14 12:20:46 +01004365 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4366 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4367 finally:
4368 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004369
Vinay Sajip10e8c492013-05-18 10:19:54 -07004370 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004371 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004372 currentTime = int(time.time())
4373 today = currentTime - currentTime % 86400
4374
Vinay Sajipa7130792013-04-12 17:04:23 +01004375 atTime = datetime.time(12, 0, 0)
4376
Vinay Sajip10e8c492013-05-18 10:19:54 -07004377 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004378 for day in range(7):
4379 rh = logging.handlers.TimedRotatingFileHandler(
4380 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4381 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004382 try:
4383 if wday > day:
4384 # The rollover day has already passed this week, so we
4385 # go over into next week
4386 expected = (7 - wday + day)
4387 else:
4388 expected = (day - wday)
4389 # At this point expected is in days from now, convert to seconds
4390 expected *= 24 * 60 * 60
4391 # Add in the rollover time
4392 expected += 12 * 60 * 60
4393 # Add in adjustment for today
4394 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004395 actual = rh.computeRollover(today)
4396 if actual != expected:
4397 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004398 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004399 self.assertEqual(actual, expected)
4400 if day == wday:
4401 # goes into following week
4402 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004403 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004404 if actual != expected:
4405 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004406 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004407 self.assertEqual(actual, expected)
4408 finally:
4409 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004410
4411
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004412def secs(**kw):
4413 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4414
4415for when, exp in (('S', 1),
4416 ('M', 60),
4417 ('H', 60 * 60),
4418 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004419 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004420 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004421 ('W0', secs(days=4, hours=24)),
4422 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004423 def test_compute_rollover(self, when=when, exp=exp):
4424 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004425 self.fn, when=when, interval=1, backupCount=0, utc=True)
4426 currentTime = 0.0
4427 actual = rh.computeRollover(currentTime)
4428 if exp != actual:
4429 # Failures occur on some systems for MIDNIGHT and W0.
4430 # Print detailed calculation for MIDNIGHT so we can try to see
4431 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004432 if when == 'MIDNIGHT':
4433 try:
4434 if rh.utc:
4435 t = time.gmtime(currentTime)
4436 else:
4437 t = time.localtime(currentTime)
4438 currentHour = t[3]
4439 currentMinute = t[4]
4440 currentSecond = t[5]
4441 # r is the number of seconds left between now and midnight
4442 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4443 currentMinute) * 60 +
4444 currentSecond)
4445 result = currentTime + r
4446 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4447 print('currentHour: %s' % currentHour, file=sys.stderr)
4448 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4449 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4450 print('r: %s' % r, file=sys.stderr)
4451 print('result: %s' % result, file=sys.stderr)
4452 except Exception:
4453 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4454 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004455 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004456 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4457
Vinay Sajip60ccd822011-05-09 17:32:09 +01004458
Vinay Sajip223349c2015-10-01 20:37:54 +01004459@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004460class NTEventLogHandlerTest(BaseTest):
4461 def test_basic(self):
4462 logtype = 'Application'
4463 elh = win32evtlog.OpenEventLog(None, logtype)
4464 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004465
4466 try:
4467 h = logging.handlers.NTEventLogHandler('test_logging')
4468 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004469 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004470 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004471 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004472
Vinay Sajip60ccd822011-05-09 17:32:09 +01004473 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4474 h.handle(r)
4475 h.close()
4476 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004477 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004478 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4479 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4480 found = False
4481 GO_BACK = 100
4482 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4483 for e in events:
4484 if e.SourceName != 'test_logging':
4485 continue
4486 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4487 if msg != 'Test Log Message\r\n':
4488 continue
4489 found = True
4490 break
4491 msg = 'Record not found in event log, went back %d records' % GO_BACK
4492 self.assertTrue(found, msg=msg)
4493
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004494
4495class MiscTestCase(unittest.TestCase):
4496 def test__all__(self):
4497 blacklist = {'logThreads', 'logMultiprocessing',
4498 'logProcesses', 'currentframe',
4499 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4500 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004501 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004502 support.check__all__(self, logging, blacklist=blacklist)
4503
4504
Christian Heimes180510d2008-03-03 19:15:45 +00004505# Set the locale to the platform-dependent default. I have no idea
4506# why the test does this, but in any case we save the current locale
4507# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004508@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004509def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004510 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004511 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4512 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4513 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4514 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4515 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4516 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4517 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4518 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004519 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004520 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004521 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004522 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004523 ]
4524 if hasattr(logging.handlers, 'QueueListener'):
4525 tests.append(QueueListenerTest)
4526 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004527
Christian Heimes180510d2008-03-03 19:15:45 +00004528if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004529 test_main()