blob: f4aef9f8962f0399083d093275ef4de6ccbfc3ec [file] [log] [blame]
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001# Copyright 2001-2017 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip1e6499c2017-01-09 16:54:12 +000019Copyright (C) 2001-2017 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 from http.server import HTTPServer, BaseHTTPRequestHandler
55 import smtpd
56 from urllib.parse import urlparse, parse_qs
57 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010058 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000059except ImportError:
60 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010061try:
Vinay Sajip223349c2015-10-01 20:37:54 +010062 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010063except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010064 win32evtlog = win32evtlogutil = pywintypes = None
65
Eric V. Smith851cad72012-03-11 22:46:04 -070066try:
67 import zlib
68except ImportError:
69 pass
Christian Heimes18c66892008-02-17 13:31:39 +000070
Christian Heimes180510d2008-03-03 19:15:45 +000071class BaseTest(unittest.TestCase):
72
73 """Base class for logging tests."""
74
75 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030076 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000077 message_num = 0
78
79 def setUp(self):
80 """Setup the default logging stream to an internal StringIO instance,
81 so that we can examine log output as we want."""
Victor Stinner69669602017-08-18 23:47:54 +020082 self._threading_key = support.threading_setup()
83
Christian Heimes180510d2008-03-03 19:15:45 +000084 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000085 logging._acquireLock()
86 try:
Christian Heimes180510d2008-03-03 19:15:45 +000087 self.saved_handlers = logging._handlers.copy()
88 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070090 self.saved_name_to_level = logging._nameToLevel.copy()
91 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000092 self.logger_states = logger_states = {}
93 for name in saved_loggers:
94 logger_states[name] = getattr(saved_loggers[name],
95 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000096 finally:
97 logging._releaseLock()
98
Florent Xicluna5252f9f2011-11-07 19:43:05 +010099 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000100 self.logger1 = logging.getLogger("\xab\xd7\xbb")
101 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000102
Christian Heimes180510d2008-03-03 19:15:45 +0000103 self.root_logger = logging.getLogger("")
104 self.original_logging_level = self.root_logger.getEffectiveLevel()
105
106 self.stream = io.StringIO()
107 self.root_logger.setLevel(logging.DEBUG)
108 self.root_hdlr = logging.StreamHandler(self.stream)
109 self.root_formatter = logging.Formatter(self.log_format)
110 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000111 if self.logger1.hasHandlers():
112 hlist = self.logger1.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
114 if self.logger2.hasHandlers():
115 hlist = self.logger2.handlers + self.root_logger.handlers
116 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000117 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000118 self.assertTrue(self.logger1.hasHandlers())
119 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000120
121 def tearDown(self):
122 """Remove our logging stream, and restore the original logging
123 level."""
124 self.stream.close()
125 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000126 while self.root_logger.handlers:
127 h = self.root_logger.handlers[0]
128 self.root_logger.removeHandler(h)
129 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000130 self.root_logger.setLevel(self.original_logging_level)
131 logging._acquireLock()
132 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700133 logging._levelToName.clear()
134 logging._levelToName.update(self.saved_level_to_name)
135 logging._nameToLevel.clear()
136 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000137 logging._handlers.clear()
138 logging._handlers.update(self.saved_handlers)
139 logging._handlerList[:] = self.saved_handler_list
Avram Lubkin78c18a92017-07-30 05:36:33 -0400140 manager = logging.getLogger().manager
141 manager.disable = 0
142 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000143 loggerDict.clear()
144 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000145 logger_states = self.logger_states
146 for name in self.logger_states:
147 if logger_states[name] is not None:
148 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000149 finally:
150 logging._releaseLock()
151
Victor Stinner69669602017-08-18 23:47:54 +0200152 self.doCleanups()
153 support.threading_cleanup(*self._threading_key)
154
Vinay Sajip4ded5512012-10-02 15:56:16 +0100155 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000156 """Match the collected log lines against the regular expression
157 self.expected_log_pat, and compare the extracted group values to
158 the expected_values list of tuples."""
159 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100160 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300161 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100162 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000163 for actual, expected in zip(actual_lines, expected_values):
164 match = pat.search(actual)
165 if not match:
166 self.fail("Log line does not match expected pattern:\n" +
167 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000168 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000169 s = stream.read()
170 if s:
171 self.fail("Remaining output at end of log stream:\n" + s)
172
173 def next_message(self):
174 """Generate a message consisting solely of an auto-incrementing
175 integer."""
176 self.message_num += 1
177 return "%d" % self.message_num
178
179
180class BuiltinLevelsTest(BaseTest):
181 """Test builtin levels and their inheritance."""
182
183 def test_flat(self):
184 #Logging levels in a flat logger namespace.
185 m = self.next_message
186
187 ERR = logging.getLogger("ERR")
188 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000189 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000190 INF.setLevel(logging.INFO)
191 DEB = logging.getLogger("DEB")
192 DEB.setLevel(logging.DEBUG)
193
194 # These should log.
195 ERR.log(logging.CRITICAL, m())
196 ERR.error(m())
197
198 INF.log(logging.CRITICAL, m())
199 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100200 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000201 INF.info(m())
202
203 DEB.log(logging.CRITICAL, m())
204 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100205 DEB.warning(m())
206 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000207 DEB.debug(m())
208
209 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100210 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000211 ERR.info(m())
212 ERR.debug(m())
213
214 INF.debug(m())
215
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000216 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000217 ('ERR', 'CRITICAL', '1'),
218 ('ERR', 'ERROR', '2'),
219 ('INF', 'CRITICAL', '3'),
220 ('INF', 'ERROR', '4'),
221 ('INF', 'WARNING', '5'),
222 ('INF', 'INFO', '6'),
223 ('DEB', 'CRITICAL', '7'),
224 ('DEB', 'ERROR', '8'),
225 ('DEB', 'WARNING', '9'),
226 ('DEB', 'INFO', '10'),
227 ('DEB', 'DEBUG', '11'),
228 ])
229
230 def test_nested_explicit(self):
231 # Logging levels in a nested namespace, all explicitly set.
232 m = self.next_message
233
234 INF = logging.getLogger("INF")
235 INF.setLevel(logging.INFO)
236 INF_ERR = logging.getLogger("INF.ERR")
237 INF_ERR.setLevel(logging.ERROR)
238
239 # These should log.
240 INF_ERR.log(logging.CRITICAL, m())
241 INF_ERR.error(m())
242
243 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100244 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000245 INF_ERR.info(m())
246 INF_ERR.debug(m())
247
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000248 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000249 ('INF.ERR', 'CRITICAL', '1'),
250 ('INF.ERR', 'ERROR', '2'),
251 ])
252
253 def test_nested_inherited(self):
254 #Logging levels in a nested namespace, inherited from parent loggers.
255 m = self.next_message
256
257 INF = logging.getLogger("INF")
258 INF.setLevel(logging.INFO)
259 INF_ERR = logging.getLogger("INF.ERR")
260 INF_ERR.setLevel(logging.ERROR)
261 INF_UNDEF = logging.getLogger("INF.UNDEF")
262 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
263 UNDEF = logging.getLogger("UNDEF")
264
265 # These should log.
266 INF_UNDEF.log(logging.CRITICAL, m())
267 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100268 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000269 INF_UNDEF.info(m())
270 INF_ERR_UNDEF.log(logging.CRITICAL, m())
271 INF_ERR_UNDEF.error(m())
272
273 # These should not log.
274 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100275 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000276 INF_ERR_UNDEF.info(m())
277 INF_ERR_UNDEF.debug(m())
278
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000279 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000280 ('INF.UNDEF', 'CRITICAL', '1'),
281 ('INF.UNDEF', 'ERROR', '2'),
282 ('INF.UNDEF', 'WARNING', '3'),
283 ('INF.UNDEF', 'INFO', '4'),
284 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
285 ('INF.ERR.UNDEF', 'ERROR', '6'),
286 ])
287
288 def test_nested_with_virtual_parent(self):
289 # Logging levels when some parent does not exist yet.
290 m = self.next_message
291
292 INF = logging.getLogger("INF")
293 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
294 CHILD = logging.getLogger("INF.BADPARENT")
295 INF.setLevel(logging.INFO)
296
297 # These should log.
298 GRANDCHILD.log(logging.FATAL, m())
299 GRANDCHILD.info(m())
300 CHILD.log(logging.FATAL, m())
301 CHILD.info(m())
302
303 # These should not log.
304 GRANDCHILD.debug(m())
305 CHILD.debug(m())
306
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000307 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000308 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
309 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
310 ('INF.BADPARENT', 'CRITICAL', '3'),
311 ('INF.BADPARENT', 'INFO', '4'),
312 ])
313
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100314 def test_regression_22386(self):
315 """See issue #22386 for more information."""
316 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
317 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000318
Vinay Sajip8b866d52017-01-11 06:57:55 +0000319 def test_regression_29220(self):
320 """See issue #29220 for more information."""
321 logging.addLevelName(logging.INFO, '')
322 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
323 self.assertEqual(logging.getLevelName(logging.INFO), '')
324
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100325 def test_issue27935(self):
326 fatal = logging.getLevelName('FATAL')
327 self.assertEqual(fatal, logging.FATAL)
328
Vinay Sajip924aaae2017-01-11 17:35:36 +0000329 def test_regression_29220(self):
330 """See issue #29220 for more information."""
331 logging.addLevelName(logging.INFO, '')
332 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
333 self.assertEqual(logging.getLevelName(logging.INFO), '')
334 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
335 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
336
Christian Heimes180510d2008-03-03 19:15:45 +0000337class BasicFilterTest(BaseTest):
338
339 """Test the bundled Filter class."""
340
341 def test_filter(self):
342 # Only messages satisfying the specified criteria pass through the
343 # filter.
344 filter_ = logging.Filter("spam.eggs")
345 handler = self.root_logger.handlers[0]
346 try:
347 handler.addFilter(filter_)
348 spam = logging.getLogger("spam")
349 spam_eggs = logging.getLogger("spam.eggs")
350 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
351 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
352
353 spam.info(self.next_message())
354 spam_eggs.info(self.next_message()) # Good.
355 spam_eggs_fish.info(self.next_message()) # Good.
356 spam_bakedbeans.info(self.next_message())
357
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000358 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000359 ('spam.eggs', 'INFO', '2'),
360 ('spam.eggs.fish', 'INFO', '3'),
361 ])
362 finally:
363 handler.removeFilter(filter_)
364
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000365 def test_callable_filter(self):
366 # Only messages satisfying the specified criteria pass through the
367 # filter.
368
369 def filterfunc(record):
370 parts = record.name.split('.')
371 prefix = '.'.join(parts[:2])
372 return prefix == 'spam.eggs'
373
374 handler = self.root_logger.handlers[0]
375 try:
376 handler.addFilter(filterfunc)
377 spam = logging.getLogger("spam")
378 spam_eggs = logging.getLogger("spam.eggs")
379 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
380 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
381
382 spam.info(self.next_message())
383 spam_eggs.info(self.next_message()) # Good.
384 spam_eggs_fish.info(self.next_message()) # Good.
385 spam_bakedbeans.info(self.next_message())
386
387 self.assert_log_lines([
388 ('spam.eggs', 'INFO', '2'),
389 ('spam.eggs.fish', 'INFO', '3'),
390 ])
391 finally:
392 handler.removeFilter(filterfunc)
393
Vinay Sajip985ef872011-04-26 19:34:04 +0100394 def test_empty_filter(self):
395 f = logging.Filter()
396 r = logging.makeLogRecord({'name': 'spam.eggs'})
397 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000398
399#
400# First, we define our levels. There can be as many as you want - the only
401# limitations are that they should be integers, the lowest should be > 0 and
402# larger values mean less information being logged. If you need specific
403# level values which do not fit into these limitations, you can use a
404# mapping dictionary to convert between your application levels and the
405# logging system.
406#
407SILENT = 120
408TACITURN = 119
409TERSE = 118
410EFFUSIVE = 117
411SOCIABLE = 116
412VERBOSE = 115
413TALKATIVE = 114
414GARRULOUS = 113
415CHATTERBOX = 112
416BORING = 111
417
418LEVEL_RANGE = range(BORING, SILENT + 1)
419
420#
421# Next, we define names for our levels. You don't need to do this - in which
422# case the system will use "Level n" to denote the text for the level.
423#
424my_logging_levels = {
425 SILENT : 'Silent',
426 TACITURN : 'Taciturn',
427 TERSE : 'Terse',
428 EFFUSIVE : 'Effusive',
429 SOCIABLE : 'Sociable',
430 VERBOSE : 'Verbose',
431 TALKATIVE : 'Talkative',
432 GARRULOUS : 'Garrulous',
433 CHATTERBOX : 'Chatterbox',
434 BORING : 'Boring',
435}
436
437class GarrulousFilter(logging.Filter):
438
439 """A filter which blocks garrulous messages."""
440
441 def filter(self, record):
442 return record.levelno != GARRULOUS
443
444class VerySpecificFilter(logging.Filter):
445
446 """A filter which blocks sociable and taciturn messages."""
447
448 def filter(self, record):
449 return record.levelno not in [SOCIABLE, TACITURN]
450
451
452class CustomLevelsAndFiltersTest(BaseTest):
453
454 """Test various filtering possibilities with custom logging levels."""
455
456 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300457 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000458
459 def setUp(self):
460 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000461 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000462 logging.addLevelName(k, v)
463
464 def log_at_all_levels(self, logger):
465 for lvl in LEVEL_RANGE:
466 logger.log(lvl, self.next_message())
467
468 def test_logger_filter(self):
469 # Filter at logger level.
470 self.root_logger.setLevel(VERBOSE)
471 # Levels >= 'Verbose' are good.
472 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000473 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000474 ('Verbose', '5'),
475 ('Sociable', '6'),
476 ('Effusive', '7'),
477 ('Terse', '8'),
478 ('Taciturn', '9'),
479 ('Silent', '10'),
480 ])
481
482 def test_handler_filter(self):
483 # Filter at handler level.
484 self.root_logger.handlers[0].setLevel(SOCIABLE)
485 try:
486 # Levels >= 'Sociable' are good.
487 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000488 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000489 ('Sociable', '6'),
490 ('Effusive', '7'),
491 ('Terse', '8'),
492 ('Taciturn', '9'),
493 ('Silent', '10'),
494 ])
495 finally:
496 self.root_logger.handlers[0].setLevel(logging.NOTSET)
497
498 def test_specific_filters(self):
499 # Set a specific filter object on the handler, and then add another
500 # filter object on the logger itself.
501 handler = self.root_logger.handlers[0]
502 specific_filter = None
503 garr = GarrulousFilter()
504 handler.addFilter(garr)
505 try:
506 self.log_at_all_levels(self.root_logger)
507 first_lines = [
508 # Notice how 'Garrulous' is missing
509 ('Boring', '1'),
510 ('Chatterbox', '2'),
511 ('Talkative', '4'),
512 ('Verbose', '5'),
513 ('Sociable', '6'),
514 ('Effusive', '7'),
515 ('Terse', '8'),
516 ('Taciturn', '9'),
517 ('Silent', '10'),
518 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000519 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000520
521 specific_filter = VerySpecificFilter()
522 self.root_logger.addFilter(specific_filter)
523 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000524 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000525 # Not only 'Garrulous' is still missing, but also 'Sociable'
526 # and 'Taciturn'
527 ('Boring', '11'),
528 ('Chatterbox', '12'),
529 ('Talkative', '14'),
530 ('Verbose', '15'),
531 ('Effusive', '17'),
532 ('Terse', '18'),
533 ('Silent', '20'),
534 ])
535 finally:
536 if specific_filter:
537 self.root_logger.removeFilter(specific_filter)
538 handler.removeFilter(garr)
539
540
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100541class HandlerTest(BaseTest):
542 def test_name(self):
543 h = logging.Handler()
544 h.name = 'generic'
545 self.assertEqual(h.name, 'generic')
546 h.name = 'anothergeneric'
547 self.assertEqual(h.name, 'anothergeneric')
548 self.assertRaises(NotImplementedError, h.emit, None)
549
Vinay Sajip5a35b062011-04-27 11:31:14 +0100550 def test_builtin_handlers(self):
551 # We can't actually *use* too many handlers in the tests,
552 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200553 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100554 for existing in (True, False):
555 fd, fn = tempfile.mkstemp()
556 os.close(fd)
557 if not existing:
558 os.unlink(fn)
559 h = logging.handlers.WatchedFileHandler(fn, delay=True)
560 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100561 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100562 self.assertEqual(dev, -1)
563 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100564 r = logging.makeLogRecord({'msg': 'Test'})
565 h.handle(r)
566 # Now remove the file.
567 os.unlink(fn)
568 self.assertFalse(os.path.exists(fn))
569 # The next call should recreate the file.
570 h.handle(r)
571 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100572 else:
573 self.assertEqual(h.dev, -1)
574 self.assertEqual(h.ino, -1)
575 h.close()
576 if existing:
577 os.unlink(fn)
578 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100579 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100580 else:
581 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100582 try:
583 h = logging.handlers.SysLogHandler(sockname)
584 self.assertEqual(h.facility, h.LOG_USER)
585 self.assertTrue(h.unixsocket)
586 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200587 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100588 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100589 for method in ('GET', 'POST', 'PUT'):
590 if method == 'PUT':
591 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
592 'localhost', '/log', method)
593 else:
594 h = logging.handlers.HTTPHandler('localhost', '/log', method)
595 h.close()
596 h = logging.handlers.BufferingHandler(0)
597 r = logging.makeLogRecord({})
598 self.assertTrue(h.shouldFlush(r))
599 h.close()
600 h = logging.handlers.BufferingHandler(1)
601 self.assertFalse(h.shouldFlush(r))
602 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100603
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100604 def test_path_objects(self):
605 """
606 Test that Path objects are accepted as filename arguments to handlers.
607
608 See Issue #27493.
609 """
610 fd, fn = tempfile.mkstemp()
611 os.close(fd)
612 os.unlink(fn)
613 pfn = pathlib.Path(fn)
614 cases = (
615 (logging.FileHandler, (pfn, 'w')),
616 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
617 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
618 )
619 if sys.platform in ('linux', 'darwin'):
620 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
621 for cls, args in cases:
622 h = cls(*args)
623 self.assertTrue(os.path.exists(fn))
624 h.close()
625 os.unlink(fn)
626
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100627 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100628 @unittest.skipUnless(threading, 'Threading required for this test.')
629 def test_race(self):
630 # Issue #14632 refers.
631 def remove_loop(fname, tries):
632 for _ in range(tries):
633 try:
634 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000635 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100636 except OSError:
637 pass
638 time.sleep(0.004 * random.randint(0, 4))
639
Vinay Sajipc94871a2012-04-25 10:51:35 +0100640 del_count = 500
641 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100642
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000643 self.handle_time = None
644 self.deletion_time = None
645
Vinay Sajipa5798de2012-04-24 23:33:33 +0100646 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100647 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
648 os.close(fd)
649 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
650 remover.daemon = True
651 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100652 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100653 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
654 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100655 try:
656 for _ in range(log_count):
657 time.sleep(0.005)
658 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000659 try:
660 self.handle_time = time.time()
661 h.handle(r)
662 except Exception:
663 print('Deleted at %s, '
664 'opened at %s' % (self.deletion_time,
665 self.handle_time))
666 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100667 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100668 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100669 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100670 if os.path.exists(fn):
671 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100672
673
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100674class BadStream(object):
675 def write(self, data):
676 raise RuntimeError('deliberate mistake')
677
678class TestStreamHandler(logging.StreamHandler):
679 def handleError(self, record):
680 self.error_record = record
681
682class StreamHandlerTest(BaseTest):
683 def test_error_handling(self):
684 h = TestStreamHandler(BadStream())
685 r = logging.makeLogRecord({})
686 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100688 try:
689 h.handle(r)
690 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100691
Vinay Sajip985ef872011-04-26 19:34:04 +0100692 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100693 with support.captured_stderr() as stderr:
694 h.handle(r)
695 msg = '\nRuntimeError: deliberate mistake\n'
696 self.assertIn(msg, stderr.getvalue())
697
Vinay Sajip985ef872011-04-26 19:34:04 +0100698 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100699 with support.captured_stderr() as stderr:
700 h.handle(r)
701 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100702 finally:
703 logging.raiseExceptions = old_raise
704
Vinay Sajip2543f502017-07-30 10:41:45 +0100705 def test_stream_setting(self):
706 """
707 Test setting the handler's stream
708 """
709 h = logging.StreamHandler()
710 stream = io.StringIO()
711 old = h.setStream(stream)
712 self.assertIs(old, sys.stderr)
713 actual = h.setStream(old)
714 self.assertIs(actual, stream)
715 # test that setting to existing value returns None
716 actual = h.setStream(old)
717 self.assertIsNone(actual)
718
Vinay Sajip7367d082011-05-02 13:17:27 +0100719# -- The following section could be moved into a server_helper.py module
720# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100721
Vinay Sajipce7c9782011-05-17 07:15:53 +0100722if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100723 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100724 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100726
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 :param addr: A (host, port) tuple which the server listens on.
728 You can specify a port value of zero: the server's
729 *port* attribute will hold the actual port number
730 used, which can be used in client connections.
731 :param handler: A callable which will be called to process
732 incoming messages. The handler will be passed
733 the client address tuple, who the message is from,
734 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100735 :param poll_interval: The interval, in seconds, used in the underlying
736 :func:`select` or :func:`poll` call by
737 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 :param sockmap: A dictionary which will be used to hold
739 :class:`asyncore.dispatcher` instances used by
740 :func:`asyncore.loop`. This avoids changing the
741 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100742 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743
744 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400745 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
746 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100747 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 self._handler = handler
749 self._thread = None
750 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100751
Vinay Sajipce7c9782011-05-17 07:15:53 +0100752 def process_message(self, peer, mailfrom, rcpttos, data):
753 """
754 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100755
Vinay Sajipce7c9782011-05-17 07:15:53 +0100756 Typically, this will be a test case method.
757 :param peer: The client (host, port) tuple.
758 :param mailfrom: The address of the sender.
759 :param rcpttos: The addresses of the recipients.
760 :param data: The message.
761 """
762 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100763
Vinay Sajipce7c9782011-05-17 07:15:53 +0100764 def start(self):
765 """
766 Start the server running on a separate daemon thread.
767 """
768 self._thread = t = threading.Thread(target=self.serve_forever,
769 args=(self.poll_interval,))
770 t.setDaemon(True)
771 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100772
Vinay Sajipce7c9782011-05-17 07:15:53 +0100773 def serve_forever(self, poll_interval):
774 """
775 Run the :mod:`asyncore` loop until normal termination
776 conditions arise.
777 :param poll_interval: The interval, in seconds, used in the underlying
778 :func:`select` or :func:`poll` call by
779 :func:`asyncore.loop`.
780 """
781 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100782 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200783 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100784 # On FreeBSD 8, closing the server repeatably
785 # raises this error. We swallow it if the
786 # server has been closed.
787 if self.connected or self.accepting:
788 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100789
Vinay Sajipce7c9782011-05-17 07:15:53 +0100790 def stop(self, timeout=None):
791 """
792 Stop the thread by closing the server instance.
793 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100794
Vinay Sajipce7c9782011-05-17 07:15:53 +0100795 :param timeout: How long to wait for the server thread
796 to terminate.
797 """
798 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100799 self._thread.join(timeout)
Victor Stinnera7719e22017-08-19 00:34:00 +0200800 asyncore.close_all(map=self._map, ignore_all=True)
801
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200802 alive = self._thread.is_alive()
Vinay Sajip7367d082011-05-02 13:17:27 +0100803 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200804 if alive:
805 self.fail("join() timed out")
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Vinay Sajipce7c9782011-05-17 07:15:53 +0100807 class ControlMixin(object):
808 """
809 This mixin is used to start a server on a separate thread, and
810 shut it down programmatically. Request handling is simplified - instead
811 of needing to derive a suitable RequestHandler subclass, you just
812 provide a callable which will be passed each received request to be
813 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100814
Vinay Sajipce7c9782011-05-17 07:15:53 +0100815 :param handler: A handler callable which will be called with a
816 single parameter - the request - in order to
817 process the request. This handler is called on the
818 server thread, effectively meaning that requests are
819 processed serially. While not quite Web scale ;-),
820 this should be fine for testing applications.
821 :param poll_interval: The polling interval in seconds.
822 """
823 def __init__(self, handler, poll_interval):
824 self._thread = None
825 self.poll_interval = poll_interval
826 self._handler = handler
827 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100828
Vinay Sajipce7c9782011-05-17 07:15:53 +0100829 def start(self):
830 """
831 Create a daemon thread to run the server, and start it.
832 """
833 self._thread = t = threading.Thread(target=self.serve_forever,
834 args=(self.poll_interval,))
835 t.setDaemon(True)
836 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100837
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 def serve_forever(self, poll_interval):
839 """
840 Run the server. Set the ready flag before entering the
841 service loop.
842 """
843 self.ready.set()
844 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100845
Vinay Sajipce7c9782011-05-17 07:15:53 +0100846 def stop(self, timeout=None):
847 """
848 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100849
Vinay Sajipce7c9782011-05-17 07:15:53 +0100850 :param timeout: How long to wait for the server thread
851 to terminate.
852 """
853 self.shutdown()
854 if self._thread is not None:
855 self._thread.join(timeout)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200856 alive = self._thread.is_alive()
Vinay Sajipce7c9782011-05-17 07:15:53 +0100857 self._thread = None
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200858 if alive:
859 self.fail("join() timed out")
Vinay Sajipce7c9782011-05-17 07:15:53 +0100860 self.server_close()
861 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100862
Vinay Sajipce7c9782011-05-17 07:15:53 +0100863 class TestHTTPServer(ControlMixin, HTTPServer):
864 """
865 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100866
Vinay Sajipce7c9782011-05-17 07:15:53 +0100867 :param addr: A tuple with the IP address and port to listen on.
868 :param handler: A handler callable which will be called with a
869 single parameter - the request - in order to
870 process the request.
871 :param poll_interval: The polling interval in seconds.
872 :param log: Pass ``True`` to enable log messages.
873 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100874 def __init__(self, addr, handler, poll_interval=0.5,
875 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100876 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
877 def __getattr__(self, name, default=None):
878 if name.startswith('do_'):
879 return self.process_request
880 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100881
Vinay Sajipce7c9782011-05-17 07:15:53 +0100882 def process_request(self):
883 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100884
Vinay Sajipce7c9782011-05-17 07:15:53 +0100885 def log_message(self, format, *args):
886 if log:
887 super(DelegatingHTTPRequestHandler,
888 self).log_message(format, *args)
889 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
890 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100891 self.sslctx = sslctx
892
893 def get_request(self):
894 try:
895 sock, addr = self.socket.accept()
896 if self.sslctx:
897 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200898 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100899 # socket errors are silenced by the caller, print them here
900 sys.stderr.write("Got an error:\n%s\n" % e)
901 raise
902 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100903
Vinay Sajipce7c9782011-05-17 07:15:53 +0100904 class TestTCPServer(ControlMixin, ThreadingTCPServer):
905 """
906 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Vinay Sajipce7c9782011-05-17 07:15:53 +0100908 :param addr: A tuple with the IP address and port to listen on.
909 :param handler: A handler callable which will be called with a single
910 parameter - the request - in order to process the request.
911 :param poll_interval: The polling interval in seconds.
912 :bind_and_activate: If True (the default), binds the server and starts it
913 listening. If False, you need to call
914 :meth:`server_bind` and :meth:`server_activate` at
915 some later time before calling :meth:`start`, so that
916 the server will set up the socket and listen on it.
917 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100918
Vinay Sajipce7c9782011-05-17 07:15:53 +0100919 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100920
Vinay Sajipce7c9782011-05-17 07:15:53 +0100921 def __init__(self, addr, handler, poll_interval=0.5,
922 bind_and_activate=True):
923 class DelegatingTCPRequestHandler(StreamRequestHandler):
924
925 def handle(self):
926 self.server._handler(self)
927 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
928 bind_and_activate)
929 ControlMixin.__init__(self, handler, poll_interval)
930
931 def server_bind(self):
932 super(TestTCPServer, self).server_bind()
933 self.port = self.socket.getsockname()[1]
934
935 class TestUDPServer(ControlMixin, ThreadingUDPServer):
936 """
937 A UDP server which is controllable using :class:`ControlMixin`.
938
939 :param addr: A tuple with the IP address and port to listen on.
940 :param handler: A handler callable which will be called with a
941 single parameter - the request - in order to
942 process the request.
943 :param poll_interval: The polling interval for shutdown requests,
944 in seconds.
945 :bind_and_activate: If True (the default), binds the server and
946 starts it listening. If False, you need to
947 call :meth:`server_bind` and
948 :meth:`server_activate` at some later time
949 before calling :meth:`start`, so that the server will
950 set up the socket and listen on it.
951 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100952 def __init__(self, addr, handler, poll_interval=0.5,
953 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100954 class DelegatingUDPRequestHandler(DatagramRequestHandler):
955
956 def handle(self):
957 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100958
959 def finish(self):
960 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100961 if data:
962 try:
963 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200964 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100965 if not self.server._closed:
966 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100967
Vinay Sajip3ef12292011-05-23 23:00:42 +0100968 ThreadingUDPServer.__init__(self, addr,
969 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100970 bind_and_activate)
971 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100972 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100973
974 def server_bind(self):
975 super(TestUDPServer, self).server_bind()
976 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100977
Vinay Sajipba980db2011-05-23 21:37:54 +0100978 def server_close(self):
979 super(TestUDPServer, self).server_close()
980 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100981
Victor Stinnerec5a8602014-06-02 14:41:51 +0200982 if hasattr(socket, "AF_UNIX"):
983 class TestUnixStreamServer(TestTCPServer):
984 address_family = socket.AF_UNIX
985
986 class TestUnixDatagramServer(TestUDPServer):
987 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100988
Vinay Sajip7367d082011-05-02 13:17:27 +0100989# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100990
Vinay Sajipce7c9782011-05-17 07:15:53 +0100991@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100992class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000993 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200994
Vinay Sajipa463d252011-04-30 21:52:48 +0100995 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100996 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800997 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100998 sockmap)
999 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -08001000 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001001 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
1002 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +01001003 self.assertEqual(h.toaddrs, ['you'])
1004 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +01001005 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +01001006 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +01001007 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +00001008 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +01001009 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +00001010 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +01001011 self.assertEqual(len(self.messages), 1)
1012 peer, mailfrom, rcpttos, data = self.messages[0]
1013 self.assertEqual(mailfrom, 'me')
1014 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001015 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001016 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001017 h.close()
1018
1019 def process_message(self, *args):
1020 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001021 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001022
Christian Heimes180510d2008-03-03 19:15:45 +00001023class MemoryHandlerTest(BaseTest):
1024
1025 """Tests for the MemoryHandler."""
1026
1027 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001028 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001029
1030 def setUp(self):
1031 BaseTest.setUp(self)
1032 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001033 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001034 self.mem_logger = logging.getLogger('mem')
1035 self.mem_logger.propagate = 0
1036 self.mem_logger.addHandler(self.mem_hdlr)
1037
1038 def tearDown(self):
1039 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001040 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001041
1042 def test_flush(self):
1043 # The memory handler flushes to its target handler based on specific
1044 # criteria (message count and message level).
1045 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001046 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001047 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001048 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001049 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001050 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001051 lines = [
1052 ('DEBUG', '1'),
1053 ('INFO', '2'),
1054 ('WARNING', '3'),
1055 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001056 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001057 for n in (4, 14):
1058 for i in range(9):
1059 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001060 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001061 # This will flush because it's the 10th message since the last
1062 # flush.
1063 self.mem_logger.debug(self.next_message())
1064 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001065 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001066
1067 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001068 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001069
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001070 def test_flush_on_close(self):
1071 """
1072 Test that the flush-on-close configuration works as expected.
1073 """
1074 self.mem_logger.debug(self.next_message())
1075 self.assert_log_lines([])
1076 self.mem_logger.info(self.next_message())
1077 self.assert_log_lines([])
1078 self.mem_logger.removeHandler(self.mem_hdlr)
1079 # Default behaviour is to flush on close. Check that it happens.
1080 self.mem_hdlr.close()
1081 lines = [
1082 ('DEBUG', '1'),
1083 ('INFO', '2'),
1084 ]
1085 self.assert_log_lines(lines)
1086 # Now configure for flushing not to be done on close.
1087 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1088 self.root_hdlr,
1089 False)
1090 self.mem_logger.addHandler(self.mem_hdlr)
1091 self.mem_logger.debug(self.next_message())
1092 self.assert_log_lines(lines) # no change
1093 self.mem_logger.info(self.next_message())
1094 self.assert_log_lines(lines) # no change
1095 self.mem_logger.removeHandler(self.mem_hdlr)
1096 self.mem_hdlr.close()
1097 # assert that no new lines have been added
1098 self.assert_log_lines(lines) # no change
1099
Christian Heimes180510d2008-03-03 19:15:45 +00001100
1101class ExceptionFormatter(logging.Formatter):
1102 """A special exception formatter."""
1103 def formatException(self, ei):
1104 return "Got a [%s]" % ei[0].__name__
1105
1106
1107class ConfigFileTest(BaseTest):
1108
1109 """Reading logging config from a .ini-style config file."""
1110
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001111 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001112
1113 # config0 is a standard configuration.
1114 config0 = """
1115 [loggers]
1116 keys=root
1117
1118 [handlers]
1119 keys=hand1
1120
1121 [formatters]
1122 keys=form1
1123
1124 [logger_root]
1125 level=WARNING
1126 handlers=hand1
1127
1128 [handler_hand1]
1129 class=StreamHandler
1130 level=NOTSET
1131 formatter=form1
1132 args=(sys.stdout,)
1133
1134 [formatter_form1]
1135 format=%(levelname)s ++ %(message)s
1136 datefmt=
1137 """
1138
1139 # config1 adds a little to the standard configuration.
1140 config1 = """
1141 [loggers]
1142 keys=root,parser
1143
1144 [handlers]
1145 keys=hand1
1146
1147 [formatters]
1148 keys=form1
1149
1150 [logger_root]
1151 level=WARNING
1152 handlers=
1153
1154 [logger_parser]
1155 level=DEBUG
1156 handlers=hand1
1157 propagate=1
1158 qualname=compiler.parser
1159
1160 [handler_hand1]
1161 class=StreamHandler
1162 level=NOTSET
1163 formatter=form1
1164 args=(sys.stdout,)
1165
1166 [formatter_form1]
1167 format=%(levelname)s ++ %(message)s
1168 datefmt=
1169 """
1170
Vinay Sajip3f84b072011-03-07 17:49:33 +00001171 # config1a moves the handler to the root.
1172 config1a = """
1173 [loggers]
1174 keys=root,parser
1175
1176 [handlers]
1177 keys=hand1
1178
1179 [formatters]
1180 keys=form1
1181
1182 [logger_root]
1183 level=WARNING
1184 handlers=hand1
1185
1186 [logger_parser]
1187 level=DEBUG
1188 handlers=
1189 propagate=1
1190 qualname=compiler.parser
1191
1192 [handler_hand1]
1193 class=StreamHandler
1194 level=NOTSET
1195 formatter=form1
1196 args=(sys.stdout,)
1197
1198 [formatter_form1]
1199 format=%(levelname)s ++ %(message)s
1200 datefmt=
1201 """
1202
Christian Heimes180510d2008-03-03 19:15:45 +00001203 # config2 has a subtle configuration error that should be reported
1204 config2 = config1.replace("sys.stdout", "sys.stbout")
1205
1206 # config3 has a less subtle configuration error
1207 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1208
1209 # config4 specifies a custom formatter class to be loaded
1210 config4 = """
1211 [loggers]
1212 keys=root
1213
1214 [handlers]
1215 keys=hand1
1216
1217 [formatters]
1218 keys=form1
1219
1220 [logger_root]
1221 level=NOTSET
1222 handlers=hand1
1223
1224 [handler_hand1]
1225 class=StreamHandler
1226 level=NOTSET
1227 formatter=form1
1228 args=(sys.stdout,)
1229
1230 [formatter_form1]
1231 class=""" + __name__ + """.ExceptionFormatter
1232 format=%(levelname)s:%(name)s:%(message)s
1233 datefmt=
1234 """
1235
Georg Brandl3dbca812008-07-23 16:10:53 +00001236 # config5 specifies a custom handler class to be loaded
1237 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1238
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001239 # config6 uses ', ' delimiters in the handlers and formatters sections
1240 config6 = """
1241 [loggers]
1242 keys=root,parser
1243
1244 [handlers]
1245 keys=hand1, hand2
1246
1247 [formatters]
1248 keys=form1, form2
1249
1250 [logger_root]
1251 level=WARNING
1252 handlers=
1253
1254 [logger_parser]
1255 level=DEBUG
1256 handlers=hand1
1257 propagate=1
1258 qualname=compiler.parser
1259
1260 [handler_hand1]
1261 class=StreamHandler
1262 level=NOTSET
1263 formatter=form1
1264 args=(sys.stdout,)
1265
1266 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001267 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001268 level=NOTSET
1269 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001270 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001271
1272 [formatter_form1]
1273 format=%(levelname)s ++ %(message)s
1274 datefmt=
1275
1276 [formatter_form2]
1277 format=%(message)s
1278 datefmt=
1279 """
1280
Preston Landers6ea56d22017-08-02 15:44:28 -05001281 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001282 config7 = """
1283 [loggers]
1284 keys=root,parser,compiler
1285
1286 [handlers]
1287 keys=hand1
1288
1289 [formatters]
1290 keys=form1
1291
1292 [logger_root]
1293 level=WARNING
1294 handlers=hand1
1295
1296 [logger_compiler]
1297 level=DEBUG
1298 handlers=
1299 propagate=1
1300 qualname=compiler
1301
1302 [logger_parser]
1303 level=DEBUG
1304 handlers=
1305 propagate=1
1306 qualname=compiler.parser
1307
1308 [handler_hand1]
1309 class=StreamHandler
1310 level=NOTSET
1311 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001312 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001313
1314 [formatter_form1]
1315 format=%(levelname)s ++ %(message)s
1316 datefmt=
1317 """
1318
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001319 disable_test = """
1320 [loggers]
1321 keys=root
1322
1323 [handlers]
1324 keys=screen
1325
1326 [formatters]
1327 keys=
1328
1329 [logger_root]
1330 level=DEBUG
1331 handlers=screen
1332
1333 [handler_screen]
1334 level=DEBUG
1335 class=StreamHandler
1336 args=(sys.stdout,)
1337 formatter=
1338 """
1339
1340 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001341 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001342 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001343
1344 def test_config0_ok(self):
1345 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001346 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001347 self.apply_config(self.config0)
1348 logger = logging.getLogger()
1349 # Won't output anything
1350 logger.info(self.next_message())
1351 # Outputs a message
1352 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001353 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001354 ('ERROR', '2'),
1355 ], stream=output)
1356 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001357 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001358
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001359 def test_config0_using_cp_ok(self):
1360 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001361 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001362 file = io.StringIO(textwrap.dedent(self.config0))
1363 cp = configparser.ConfigParser()
1364 cp.read_file(file)
1365 logging.config.fileConfig(cp)
1366 logger = logging.getLogger()
1367 # Won't output anything
1368 logger.info(self.next_message())
1369 # Outputs a message
1370 logger.error(self.next_message())
1371 self.assert_log_lines([
1372 ('ERROR', '2'),
1373 ], stream=output)
1374 # Original logger output is empty.
1375 self.assert_log_lines([])
1376
Georg Brandl3dbca812008-07-23 16:10:53 +00001377 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001378 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001379 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001380 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001381 logger = logging.getLogger("compiler.parser")
1382 # Both will output a message
1383 logger.info(self.next_message())
1384 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001385 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001386 ('INFO', '1'),
1387 ('ERROR', '2'),
1388 ], stream=output)
1389 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001390 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001391
1392 def test_config2_failure(self):
1393 # A simple config file which overrides the default settings.
1394 self.assertRaises(Exception, self.apply_config, self.config2)
1395
1396 def test_config3_failure(self):
1397 # A simple config file which overrides the default settings.
1398 self.assertRaises(Exception, self.apply_config, self.config3)
1399
1400 def test_config4_ok(self):
1401 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001402 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001403 self.apply_config(self.config4)
1404 logger = logging.getLogger()
1405 try:
1406 raise RuntimeError()
1407 except RuntimeError:
1408 logging.exception("just testing")
1409 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001410 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001411 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1412 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001413 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001414
Georg Brandl3dbca812008-07-23 16:10:53 +00001415 def test_config5_ok(self):
1416 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001417
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001418 def test_config6_ok(self):
1419 self.test_config1_ok(config=self.config6)
1420
Vinay Sajip3f84b072011-03-07 17:49:33 +00001421 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001422 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001423 self.apply_config(self.config1a)
1424 logger = logging.getLogger("compiler.parser")
1425 # See issue #11424. compiler-hyphenated sorts
1426 # between compiler and compiler.xyz and this
1427 # was preventing compiler.xyz from being included
1428 # in the child loggers of compiler because of an
1429 # overzealous loop termination condition.
1430 hyphenated = logging.getLogger('compiler-hyphenated')
1431 # All will output a message
1432 logger.info(self.next_message())
1433 logger.error(self.next_message())
1434 hyphenated.critical(self.next_message())
1435 self.assert_log_lines([
1436 ('INFO', '1'),
1437 ('ERROR', '2'),
1438 ('CRITICAL', '3'),
1439 ], stream=output)
1440 # Original logger output is empty.
1441 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001442 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001443 self.apply_config(self.config7)
1444 logger = logging.getLogger("compiler.parser")
1445 self.assertFalse(logger.disabled)
1446 # Both will output a message
1447 logger.info(self.next_message())
1448 logger.error(self.next_message())
1449 logger = logging.getLogger("compiler.lexer")
1450 # Both will output a message
1451 logger.info(self.next_message())
1452 logger.error(self.next_message())
1453 # Will not appear
1454 hyphenated.critical(self.next_message())
1455 self.assert_log_lines([
1456 ('INFO', '4'),
1457 ('ERROR', '5'),
1458 ('INFO', '6'),
1459 ('ERROR', '7'),
1460 ], stream=output)
1461 # Original logger output is empty.
1462 self.assert_log_lines([])
1463
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001464 def test_logger_disabling(self):
1465 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001466 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001467 self.assertFalse(logger.disabled)
1468 self.apply_config(self.disable_test)
1469 self.assertTrue(logger.disabled)
1470 self.apply_config(self.disable_test, disable_existing_loggers=False)
1471 self.assertFalse(logger.disabled)
1472
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001473
Victor Stinner69669602017-08-18 23:47:54 +02001474@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinner45df8202010-04-28 22:31:17 +00001475@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001476class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001477
Christian Heimes180510d2008-03-03 19:15:45 +00001478 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001479
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001480 if threading:
1481 server_class = TestTCPServer
1482 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001483
Christian Heimes180510d2008-03-03 19:15:45 +00001484 def setUp(self):
1485 """Set up a TCP server to receive log messages, and a SocketHandler
1486 pointing to that server's address and port."""
1487 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001488 # Issue #29177: deal with errors that happen during setup
1489 self.server = self.sock_hdlr = self.server_exception = None
1490 try:
1491 self.server = server = self.server_class(self.address,
1492 self.handle_socket, 0.01)
1493 server.start()
1494 # Uncomment next line to test error recovery in setUp()
1495 # raise OSError('dummy error raised')
1496 except OSError as e:
1497 self.server_exception = e
1498 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001500 hcls = logging.handlers.SocketHandler
1501 if isinstance(server.server_address, tuple):
1502 self.sock_hdlr = hcls('localhost', server.port)
1503 else:
1504 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001505 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001506 self.root_logger.removeHandler(self.root_logger.handlers[0])
1507 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001508 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001509
Christian Heimes180510d2008-03-03 19:15:45 +00001510 def tearDown(self):
1511 """Shutdown the TCP server."""
1512 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001513 if self.server:
1514 self.server.stop(2.0)
1515 if self.sock_hdlr:
1516 self.root_logger.removeHandler(self.sock_hdlr)
1517 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001518 finally:
1519 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001520
Vinay Sajip7367d082011-05-02 13:17:27 +01001521 def handle_socket(self, request):
1522 conn = request.connection
1523 while True:
1524 chunk = conn.recv(4)
1525 if len(chunk) < 4:
1526 break
1527 slen = struct.unpack(">L", chunk)[0]
1528 chunk = conn.recv(slen)
1529 while len(chunk) < slen:
1530 chunk = chunk + conn.recv(slen - len(chunk))
1531 obj = pickle.loads(chunk)
1532 record = logging.makeLogRecord(obj)
1533 self.log_output += record.msg + '\n'
1534 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001535
Christian Heimes180510d2008-03-03 19:15:45 +00001536 def test_output(self):
1537 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001538 if self.server_exception:
1539 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001540 logger = logging.getLogger("tcp")
1541 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001542 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001543 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001544 self.handled.acquire()
1545 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001546
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001547 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001548 if self.server_exception:
1549 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001550 # Avoid timing-related failures due to SocketHandler's own hard-wired
1551 # one-second timeout on socket.create_connection() (issue #16264).
1552 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001553 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001554 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001555 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001556 try:
1557 raise RuntimeError('Deliberate mistake')
1558 except RuntimeError:
1559 self.root_logger.exception('Never sent')
1560 self.root_logger.error('Never sent, either')
1561 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001562 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001563 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1564 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001565
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001566def _get_temp_domain_socket():
1567 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1568 os.close(fd)
1569 # just need a name - file can't be present, or we'll get an
1570 # 'address already in use' error.
1571 os.remove(fn)
1572 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001573
Victor Stinner69669602017-08-18 23:47:54 +02001574@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001575@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001576@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001577class UnixSocketHandlerTest(SocketHandlerTest):
1578
1579 """Test for SocketHandler with unix sockets."""
1580
Victor Stinnerec5a8602014-06-02 14:41:51 +02001581 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001582 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001583
1584 def setUp(self):
1585 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001586 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001587 SocketHandlerTest.setUp(self)
1588
1589 def tearDown(self):
1590 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001591 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001592
Victor Stinner69669602017-08-18 23:47:54 +02001593@unittest.skipIf(True, "FIXME: bpo-30830")
Vinay Sajip5421f352013-09-27 18:18:28 +01001594@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001595class DatagramHandlerTest(BaseTest):
1596
1597 """Test for DatagramHandler."""
1598
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001599 if threading:
1600 server_class = TestUDPServer
1601 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001602
Vinay Sajip7367d082011-05-02 13:17:27 +01001603 def setUp(self):
1604 """Set up a UDP server to receive log messages, and a DatagramHandler
1605 pointing to that server's address and port."""
1606 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001607 # Issue #29177: deal with errors that happen during setup
1608 self.server = self.sock_hdlr = self.server_exception = None
1609 try:
1610 self.server = server = self.server_class(self.address,
1611 self.handle_datagram, 0.01)
1612 server.start()
1613 # Uncomment next line to test error recovery in setUp()
1614 # raise OSError('dummy error raised')
1615 except OSError as e:
1616 self.server_exception = e
1617 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001618 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001619 hcls = logging.handlers.DatagramHandler
1620 if isinstance(server.server_address, tuple):
1621 self.sock_hdlr = hcls('localhost', server.port)
1622 else:
1623 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001624 self.log_output = ''
1625 self.root_logger.removeHandler(self.root_logger.handlers[0])
1626 self.root_logger.addHandler(self.sock_hdlr)
1627 self.handled = threading.Event()
1628
1629 def tearDown(self):
1630 """Shutdown the UDP server."""
1631 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001632 if self.server:
1633 self.server.stop(2.0)
1634 if self.sock_hdlr:
1635 self.root_logger.removeHandler(self.sock_hdlr)
1636 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001637 finally:
1638 BaseTest.tearDown(self)
1639
1640 def handle_datagram(self, request):
1641 slen = struct.pack('>L', 0) # length of prefix
1642 packet = request.packet[len(slen):]
1643 obj = pickle.loads(packet)
1644 record = logging.makeLogRecord(obj)
1645 self.log_output += record.msg + '\n'
1646 self.handled.set()
1647
1648 def test_output(self):
1649 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001650 if self.server_exception:
1651 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001652 logger = logging.getLogger("udp")
1653 logger.error("spam")
1654 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001655 self.handled.clear()
1656 logger.error("eggs")
1657 self.handled.wait()
1658 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001659
Victor Stinner69669602017-08-18 23:47:54 +02001660@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001661@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001662@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001663class UnixDatagramHandlerTest(DatagramHandlerTest):
1664
1665 """Test for DatagramHandler using Unix sockets."""
1666
Victor Stinnerec5a8602014-06-02 14:41:51 +02001667 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001668 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001669
1670 def setUp(self):
1671 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001672 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001673 DatagramHandlerTest.setUp(self)
1674
1675 def tearDown(self):
1676 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001677 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001678
1679@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001680class SysLogHandlerTest(BaseTest):
1681
1682 """Test for SysLogHandler using UDP."""
1683
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001684 if threading:
1685 server_class = TestUDPServer
1686 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001687
Vinay Sajip7367d082011-05-02 13:17:27 +01001688 def setUp(self):
1689 """Set up a UDP server to receive log messages, and a SysLogHandler
1690 pointing to that server's address and port."""
1691 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001692 # Issue #29177: deal with errors that happen during setup
1693 self.server = self.sl_hdlr = self.server_exception = None
1694 try:
1695 self.server = server = self.server_class(self.address,
1696 self.handle_datagram, 0.01)
1697 server.start()
1698 # Uncomment next line to test error recovery in setUp()
1699 # raise OSError('dummy error raised')
1700 except OSError as e:
1701 self.server_exception = e
1702 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001703 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001704 hcls = logging.handlers.SysLogHandler
1705 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001706 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001707 else:
1708 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001709 self.log_output = ''
1710 self.root_logger.removeHandler(self.root_logger.handlers[0])
1711 self.root_logger.addHandler(self.sl_hdlr)
1712 self.handled = threading.Event()
1713
1714 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001715 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001716 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001717 if self.server:
1718 self.server.stop(2.0)
1719 if self.sl_hdlr:
1720 self.root_logger.removeHandler(self.sl_hdlr)
1721 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001722 finally:
1723 BaseTest.tearDown(self)
1724
1725 def handle_datagram(self, request):
1726 self.log_output = request.packet
1727 self.handled.set()
1728
1729 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001730 if self.server_exception:
1731 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001732 # The log message sent to the SysLogHandler is properly received.
1733 logger = logging.getLogger("slh")
1734 logger.error("sp\xe4m")
1735 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001736 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001737 self.handled.clear()
1738 self.sl_hdlr.append_nul = False
1739 logger.error("sp\xe4m")
1740 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001741 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001742 self.handled.clear()
1743 self.sl_hdlr.ident = "h\xe4m-"
1744 logger.error("sp\xe4m")
1745 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001746 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001747
Victor Stinner69669602017-08-18 23:47:54 +02001748@unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinnerec5a8602014-06-02 14:41:51 +02001749@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001750@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001751class UnixSysLogHandlerTest(SysLogHandlerTest):
1752
1753 """Test for SysLogHandler with Unix sockets."""
1754
Victor Stinnerec5a8602014-06-02 14:41:51 +02001755 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001756 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001757
1758 def setUp(self):
1759 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001760 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001761 SysLogHandlerTest.setUp(self)
1762
1763 def tearDown(self):
1764 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001765 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001766
Victor Stinner69669602017-08-18 23:47:54 +02001767@unittest.skipIf(True, "FIXME: bpo-30830")
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001768@unittest.skipUnless(support.IPV6_ENABLED,
1769 'IPv6 support required for this test.')
1770@unittest.skipUnless(threading, 'Threading required for this test.')
1771class IPv6SysLogHandlerTest(SysLogHandlerTest):
1772
1773 """Test for SysLogHandler with IPv6 host."""
1774
1775 server_class = TestUDPServer
1776 address = ('::1', 0)
1777
1778 def setUp(self):
1779 self.server_class.address_family = socket.AF_INET6
1780 super(IPv6SysLogHandlerTest, self).setUp()
1781
1782 def tearDown(self):
1783 self.server_class.address_family = socket.AF_INET
1784 super(IPv6SysLogHandlerTest, self).tearDown()
1785
Vinay Sajip5421f352013-09-27 18:18:28 +01001786@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001787class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001788 """Test for HTTPHandler."""
1789
1790 def setUp(self):
1791 """Set up an HTTP server to receive log messages, and a HTTPHandler
1792 pointing to that server's address and port."""
1793 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001794 self.handled = threading.Event()
1795
Vinay Sajip7367d082011-05-02 13:17:27 +01001796 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001797 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001798 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001799 if self.command == 'POST':
1800 try:
1801 rlen = int(request.headers['Content-Length'])
1802 self.post_data = request.rfile.read(rlen)
1803 except:
1804 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001805 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001806 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001807 self.handled.set()
1808
1809 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001810 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001811 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001812 root_logger = self.root_logger
1813 root_logger.removeHandler(self.root_logger.handlers[0])
1814 for secure in (False, True):
1815 addr = ('localhost', 0)
1816 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001817 try:
1818 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001819 except ImportError:
1820 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001821 else:
1822 here = os.path.dirname(__file__)
1823 localhost_cert = os.path.join(here, "keycert.pem")
1824 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1825 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001826
1827 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001828 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001829 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001830 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001831 self.server = server = TestHTTPServer(addr, self.handle_request,
1832 0.01, sslctx=sslctx)
1833 server.start()
1834 server.ready.wait()
1835 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001836 secure_client = secure and sslctx
1837 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001838 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001839 context=context,
1840 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001841 self.log_data = None
1842 root_logger.addHandler(self.h_hdlr)
1843
1844 for method in ('GET', 'POST'):
1845 self.h_hdlr.method = method
1846 self.handled.clear()
1847 msg = "sp\xe4m"
1848 logger.error(msg)
1849 self.handled.wait()
1850 self.assertEqual(self.log_data.path, '/frob')
1851 self.assertEqual(self.command, method)
1852 if method == 'GET':
1853 d = parse_qs(self.log_data.query)
1854 else:
1855 d = parse_qs(self.post_data.decode('utf-8'))
1856 self.assertEqual(d['name'], ['http'])
1857 self.assertEqual(d['funcName'], ['test_output'])
1858 self.assertEqual(d['msg'], [msg])
1859
1860 self.server.stop(2.0)
1861 self.root_logger.removeHandler(self.h_hdlr)
1862 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001863
Christian Heimes180510d2008-03-03 19:15:45 +00001864class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001865
Christian Heimes180510d2008-03-03 19:15:45 +00001866 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001867
Christian Heimes180510d2008-03-03 19:15:45 +00001868 def setUp(self):
1869 """Create a dict to remember potentially destroyed objects."""
1870 BaseTest.setUp(self)
1871 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001872
Christian Heimes180510d2008-03-03 19:15:45 +00001873 def _watch_for_survival(self, *args):
1874 """Watch the given objects for survival, by creating weakrefs to
1875 them."""
1876 for obj in args:
1877 key = id(obj), repr(obj)
1878 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001879
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001880 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001881 """Assert that all objects watched for survival have survived."""
1882 # Trigger cycle breaking.
1883 gc.collect()
1884 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001885 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001886 if ref() is None:
1887 dead.append(repr_)
1888 if dead:
1889 self.fail("%d objects should have survived "
1890 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001891
Christian Heimes180510d2008-03-03 19:15:45 +00001892 def test_persistent_loggers(self):
1893 # Logger objects are persistent and retain their configuration, even
1894 # if visible references are destroyed.
1895 self.root_logger.setLevel(logging.INFO)
1896 foo = logging.getLogger("foo")
1897 self._watch_for_survival(foo)
1898 foo.setLevel(logging.DEBUG)
1899 self.root_logger.debug(self.next_message())
1900 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001901 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001902 ('foo', 'DEBUG', '2'),
1903 ])
1904 del foo
1905 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001906 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001907 # foo has retained its settings.
1908 bar = logging.getLogger("foo")
1909 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001910 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001911 ('foo', 'DEBUG', '2'),
1912 ('foo', 'DEBUG', '3'),
1913 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001914
Benjamin Petersonf91df042009-02-13 02:50:59 +00001915
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001916class EncodingTest(BaseTest):
1917 def test_encoding_plain_file(self):
1918 # In Python 2.x, a plain file object is treated as having no encoding.
1919 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001920 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1921 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001922 # the non-ascii data we write to the log.
1923 data = "foo\x80"
1924 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001925 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001926 log.addHandler(handler)
1927 try:
1928 # write non-ascii data to the log.
1929 log.warning(data)
1930 finally:
1931 log.removeHandler(handler)
1932 handler.close()
1933 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001934 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001935 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001936 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001937 finally:
1938 f.close()
1939 finally:
1940 if os.path.isfile(fn):
1941 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001942
Benjamin Petersonf91df042009-02-13 02:50:59 +00001943 def test_encoding_cyrillic_unicode(self):
1944 log = logging.getLogger("test")
1945 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1946 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1947 #Ensure it's written in a Cyrillic encoding
1948 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001949 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001950 stream = io.BytesIO()
1951 writer = writer_class(stream, 'strict')
1952 handler = logging.StreamHandler(writer)
1953 log.addHandler(handler)
1954 try:
1955 log.warning(message)
1956 finally:
1957 log.removeHandler(handler)
1958 handler.close()
1959 # check we wrote exactly those bytes, ignoring trailing \n etc
1960 s = stream.getvalue()
1961 #Compare against what the data should be when encoded in CP-1251
1962 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1963
1964
Georg Brandlf9734072008-12-07 15:30:06 +00001965class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001966
Georg Brandlf9734072008-12-07 15:30:06 +00001967 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001968 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001969 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001970 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001971 warnings.filterwarnings("always", category=UserWarning)
1972 stream = io.StringIO()
1973 h = logging.StreamHandler(stream)
1974 logger = logging.getLogger("py.warnings")
1975 logger.addHandler(h)
1976 warnings.warn("I'm warning you...")
1977 logger.removeHandler(h)
1978 s = stream.getvalue()
1979 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001980 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001981
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001982 #See if an explicit file uses the original implementation
1983 a_file = io.StringIO()
1984 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1985 a_file, "Dummy line")
1986 s = a_file.getvalue()
1987 a_file.close()
1988 self.assertEqual(s,
1989 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1990
1991 def test_warnings_no_handlers(self):
1992 with warnings.catch_warnings():
1993 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001994 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001995
1996 # confirm our assumption: no loggers are set
1997 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001998 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001999
2000 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002001 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002002 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002003
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002004
2005def formatFunc(format, datefmt=None):
2006 return logging.Formatter(format, datefmt)
2007
2008def handlerFunc():
2009 return logging.StreamHandler()
2010
2011class CustomHandler(logging.StreamHandler):
2012 pass
2013
2014class ConfigDictTest(BaseTest):
2015
2016 """Reading logging config from a dictionary."""
2017
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002018 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002019
2020 # config0 is a standard configuration.
2021 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002022 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002023 'formatters': {
2024 'form1' : {
2025 'format' : '%(levelname)s ++ %(message)s',
2026 },
2027 },
2028 'handlers' : {
2029 'hand1' : {
2030 'class' : 'logging.StreamHandler',
2031 'formatter' : 'form1',
2032 'level' : 'NOTSET',
2033 'stream' : 'ext://sys.stdout',
2034 },
2035 },
2036 'root' : {
2037 'level' : 'WARNING',
2038 'handlers' : ['hand1'],
2039 },
2040 }
2041
2042 # config1 adds a little to the standard configuration.
2043 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002044 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002045 'formatters': {
2046 'form1' : {
2047 'format' : '%(levelname)s ++ %(message)s',
2048 },
2049 },
2050 'handlers' : {
2051 'hand1' : {
2052 'class' : 'logging.StreamHandler',
2053 'formatter' : 'form1',
2054 'level' : 'NOTSET',
2055 'stream' : 'ext://sys.stdout',
2056 },
2057 },
2058 'loggers' : {
2059 'compiler.parser' : {
2060 'level' : 'DEBUG',
2061 'handlers' : ['hand1'],
2062 },
2063 },
2064 'root' : {
2065 'level' : 'WARNING',
2066 },
2067 }
2068
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002069 # config1a moves the handler to the root. Used with config8a
2070 config1a = {
2071 'version': 1,
2072 'formatters': {
2073 'form1' : {
2074 'format' : '%(levelname)s ++ %(message)s',
2075 },
2076 },
2077 'handlers' : {
2078 'hand1' : {
2079 'class' : 'logging.StreamHandler',
2080 'formatter' : 'form1',
2081 'level' : 'NOTSET',
2082 'stream' : 'ext://sys.stdout',
2083 },
2084 },
2085 'loggers' : {
2086 'compiler.parser' : {
2087 'level' : 'DEBUG',
2088 },
2089 },
2090 'root' : {
2091 'level' : 'WARNING',
2092 'handlers' : ['hand1'],
2093 },
2094 }
2095
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002096 # config2 has a subtle configuration error that should be reported
2097 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002098 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002099 'formatters': {
2100 'form1' : {
2101 'format' : '%(levelname)s ++ %(message)s',
2102 },
2103 },
2104 'handlers' : {
2105 'hand1' : {
2106 'class' : 'logging.StreamHandler',
2107 'formatter' : 'form1',
2108 'level' : 'NOTSET',
2109 'stream' : 'ext://sys.stdbout',
2110 },
2111 },
2112 'loggers' : {
2113 'compiler.parser' : {
2114 'level' : 'DEBUG',
2115 'handlers' : ['hand1'],
2116 },
2117 },
2118 'root' : {
2119 'level' : 'WARNING',
2120 },
2121 }
2122
2123 #As config1 but with a misspelt level on a handler
2124 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002125 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002126 'formatters': {
2127 'form1' : {
2128 'format' : '%(levelname)s ++ %(message)s',
2129 },
2130 },
2131 'handlers' : {
2132 'hand1' : {
2133 'class' : 'logging.StreamHandler',
2134 'formatter' : 'form1',
2135 'level' : 'NTOSET',
2136 'stream' : 'ext://sys.stdout',
2137 },
2138 },
2139 'loggers' : {
2140 'compiler.parser' : {
2141 'level' : 'DEBUG',
2142 'handlers' : ['hand1'],
2143 },
2144 },
2145 'root' : {
2146 'level' : 'WARNING',
2147 },
2148 }
2149
2150
2151 #As config1 but with a misspelt level on a logger
2152 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002153 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002154 'formatters': {
2155 'form1' : {
2156 'format' : '%(levelname)s ++ %(message)s',
2157 },
2158 },
2159 'handlers' : {
2160 'hand1' : {
2161 'class' : 'logging.StreamHandler',
2162 'formatter' : 'form1',
2163 'level' : 'NOTSET',
2164 'stream' : 'ext://sys.stdout',
2165 },
2166 },
2167 'loggers' : {
2168 'compiler.parser' : {
2169 'level' : 'DEBUG',
2170 'handlers' : ['hand1'],
2171 },
2172 },
2173 'root' : {
2174 'level' : 'WRANING',
2175 },
2176 }
2177
2178 # config3 has a less subtle configuration error
2179 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002180 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002181 'formatters': {
2182 'form1' : {
2183 'format' : '%(levelname)s ++ %(message)s',
2184 },
2185 },
2186 'handlers' : {
2187 'hand1' : {
2188 'class' : 'logging.StreamHandler',
2189 'formatter' : 'misspelled_name',
2190 'level' : 'NOTSET',
2191 'stream' : 'ext://sys.stdout',
2192 },
2193 },
2194 'loggers' : {
2195 'compiler.parser' : {
2196 'level' : 'DEBUG',
2197 'handlers' : ['hand1'],
2198 },
2199 },
2200 'root' : {
2201 'level' : 'WARNING',
2202 },
2203 }
2204
2205 # config4 specifies a custom formatter class to be loaded
2206 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002207 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002208 'formatters': {
2209 'form1' : {
2210 '()' : __name__ + '.ExceptionFormatter',
2211 'format' : '%(levelname)s:%(name)s:%(message)s',
2212 },
2213 },
2214 'handlers' : {
2215 'hand1' : {
2216 'class' : 'logging.StreamHandler',
2217 'formatter' : 'form1',
2218 'level' : 'NOTSET',
2219 'stream' : 'ext://sys.stdout',
2220 },
2221 },
2222 'root' : {
2223 'level' : 'NOTSET',
2224 'handlers' : ['hand1'],
2225 },
2226 }
2227
2228 # As config4 but using an actual callable rather than a string
2229 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002230 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002231 'formatters': {
2232 'form1' : {
2233 '()' : ExceptionFormatter,
2234 'format' : '%(levelname)s:%(name)s:%(message)s',
2235 },
2236 'form2' : {
2237 '()' : __name__ + '.formatFunc',
2238 'format' : '%(levelname)s:%(name)s:%(message)s',
2239 },
2240 'form3' : {
2241 '()' : formatFunc,
2242 'format' : '%(levelname)s:%(name)s:%(message)s',
2243 },
2244 },
2245 'handlers' : {
2246 'hand1' : {
2247 'class' : 'logging.StreamHandler',
2248 'formatter' : 'form1',
2249 'level' : 'NOTSET',
2250 'stream' : 'ext://sys.stdout',
2251 },
2252 'hand2' : {
2253 '()' : handlerFunc,
2254 },
2255 },
2256 'root' : {
2257 'level' : 'NOTSET',
2258 'handlers' : ['hand1'],
2259 },
2260 }
2261
2262 # config5 specifies a custom handler class to be loaded
2263 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002264 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002265 'formatters': {
2266 'form1' : {
2267 'format' : '%(levelname)s ++ %(message)s',
2268 },
2269 },
2270 'handlers' : {
2271 'hand1' : {
2272 'class' : __name__ + '.CustomHandler',
2273 'formatter' : 'form1',
2274 'level' : 'NOTSET',
2275 'stream' : 'ext://sys.stdout',
2276 },
2277 },
2278 'loggers' : {
2279 'compiler.parser' : {
2280 'level' : 'DEBUG',
2281 'handlers' : ['hand1'],
2282 },
2283 },
2284 'root' : {
2285 'level' : 'WARNING',
2286 },
2287 }
2288
2289 # config6 specifies a custom handler class to be loaded
2290 # but has bad arguments
2291 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002292 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002293 'formatters': {
2294 'form1' : {
2295 'format' : '%(levelname)s ++ %(message)s',
2296 },
2297 },
2298 'handlers' : {
2299 'hand1' : {
2300 'class' : __name__ + '.CustomHandler',
2301 'formatter' : 'form1',
2302 'level' : 'NOTSET',
2303 'stream' : 'ext://sys.stdout',
2304 '9' : 'invalid parameter name',
2305 },
2306 },
2307 'loggers' : {
2308 'compiler.parser' : {
2309 'level' : 'DEBUG',
2310 'handlers' : ['hand1'],
2311 },
2312 },
2313 'root' : {
2314 'level' : 'WARNING',
2315 },
2316 }
2317
2318 #config 7 does not define compiler.parser but defines compiler.lexer
2319 #so compiler.parser should be disabled after applying it
2320 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002321 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002322 'formatters': {
2323 'form1' : {
2324 'format' : '%(levelname)s ++ %(message)s',
2325 },
2326 },
2327 'handlers' : {
2328 'hand1' : {
2329 'class' : 'logging.StreamHandler',
2330 'formatter' : 'form1',
2331 'level' : 'NOTSET',
2332 'stream' : 'ext://sys.stdout',
2333 },
2334 },
2335 'loggers' : {
2336 'compiler.lexer' : {
2337 'level' : 'DEBUG',
2338 'handlers' : ['hand1'],
2339 },
2340 },
2341 'root' : {
2342 'level' : 'WARNING',
2343 },
2344 }
2345
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002346 # config8 defines both compiler and compiler.lexer
2347 # so compiler.parser should not be disabled (since
2348 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002349 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002350 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002351 'disable_existing_loggers' : False,
2352 'formatters': {
2353 'form1' : {
2354 'format' : '%(levelname)s ++ %(message)s',
2355 },
2356 },
2357 'handlers' : {
2358 'hand1' : {
2359 'class' : 'logging.StreamHandler',
2360 'formatter' : 'form1',
2361 'level' : 'NOTSET',
2362 'stream' : 'ext://sys.stdout',
2363 },
2364 },
2365 'loggers' : {
2366 'compiler' : {
2367 'level' : 'DEBUG',
2368 'handlers' : ['hand1'],
2369 },
2370 'compiler.lexer' : {
2371 },
2372 },
2373 'root' : {
2374 'level' : 'WARNING',
2375 },
2376 }
2377
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002378 # config8a disables existing loggers
2379 config8a = {
2380 'version': 1,
2381 'disable_existing_loggers' : True,
2382 'formatters': {
2383 'form1' : {
2384 'format' : '%(levelname)s ++ %(message)s',
2385 },
2386 },
2387 'handlers' : {
2388 'hand1' : {
2389 'class' : 'logging.StreamHandler',
2390 'formatter' : 'form1',
2391 'level' : 'NOTSET',
2392 'stream' : 'ext://sys.stdout',
2393 },
2394 },
2395 'loggers' : {
2396 'compiler' : {
2397 'level' : 'DEBUG',
2398 'handlers' : ['hand1'],
2399 },
2400 'compiler.lexer' : {
2401 },
2402 },
2403 'root' : {
2404 'level' : 'WARNING',
2405 },
2406 }
2407
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002408 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002409 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002410 'formatters': {
2411 'form1' : {
2412 'format' : '%(levelname)s ++ %(message)s',
2413 },
2414 },
2415 'handlers' : {
2416 'hand1' : {
2417 'class' : 'logging.StreamHandler',
2418 'formatter' : 'form1',
2419 'level' : 'WARNING',
2420 'stream' : 'ext://sys.stdout',
2421 },
2422 },
2423 'loggers' : {
2424 'compiler.parser' : {
2425 'level' : 'WARNING',
2426 'handlers' : ['hand1'],
2427 },
2428 },
2429 'root' : {
2430 'level' : 'NOTSET',
2431 },
2432 }
2433
2434 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002435 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002436 'incremental' : True,
2437 'handlers' : {
2438 'hand1' : {
2439 'level' : 'WARNING',
2440 },
2441 },
2442 'loggers' : {
2443 'compiler.parser' : {
2444 'level' : 'INFO',
2445 },
2446 },
2447 }
2448
2449 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002450 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002451 'incremental' : True,
2452 'handlers' : {
2453 'hand1' : {
2454 'level' : 'INFO',
2455 },
2456 },
2457 'loggers' : {
2458 'compiler.parser' : {
2459 'level' : 'INFO',
2460 },
2461 },
2462 }
2463
2464 #As config1 but with a filter added
2465 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002466 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002467 'formatters': {
2468 'form1' : {
2469 'format' : '%(levelname)s ++ %(message)s',
2470 },
2471 },
2472 'filters' : {
2473 'filt1' : {
2474 'name' : 'compiler.parser',
2475 },
2476 },
2477 'handlers' : {
2478 'hand1' : {
2479 'class' : 'logging.StreamHandler',
2480 'formatter' : 'form1',
2481 'level' : 'NOTSET',
2482 'stream' : 'ext://sys.stdout',
2483 'filters' : ['filt1'],
2484 },
2485 },
2486 'loggers' : {
2487 'compiler.parser' : {
2488 'level' : 'DEBUG',
2489 'filters' : ['filt1'],
2490 },
2491 },
2492 'root' : {
2493 'level' : 'WARNING',
2494 'handlers' : ['hand1'],
2495 },
2496 }
2497
2498 #As config1 but using cfg:// references
2499 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002500 'version': 1,
2501 'true_formatters': {
2502 'form1' : {
2503 'format' : '%(levelname)s ++ %(message)s',
2504 },
2505 },
2506 'handler_configs': {
2507 'hand1' : {
2508 'class' : 'logging.StreamHandler',
2509 'formatter' : 'form1',
2510 'level' : 'NOTSET',
2511 'stream' : 'ext://sys.stdout',
2512 },
2513 },
2514 'formatters' : 'cfg://true_formatters',
2515 'handlers' : {
2516 'hand1' : 'cfg://handler_configs[hand1]',
2517 },
2518 'loggers' : {
2519 'compiler.parser' : {
2520 'level' : 'DEBUG',
2521 'handlers' : ['hand1'],
2522 },
2523 },
2524 'root' : {
2525 'level' : 'WARNING',
2526 },
2527 }
2528
2529 #As config11 but missing the version key
2530 config12 = {
2531 'true_formatters': {
2532 'form1' : {
2533 'format' : '%(levelname)s ++ %(message)s',
2534 },
2535 },
2536 'handler_configs': {
2537 'hand1' : {
2538 'class' : 'logging.StreamHandler',
2539 'formatter' : 'form1',
2540 'level' : 'NOTSET',
2541 'stream' : 'ext://sys.stdout',
2542 },
2543 },
2544 'formatters' : 'cfg://true_formatters',
2545 'handlers' : {
2546 'hand1' : 'cfg://handler_configs[hand1]',
2547 },
2548 'loggers' : {
2549 'compiler.parser' : {
2550 'level' : 'DEBUG',
2551 'handlers' : ['hand1'],
2552 },
2553 },
2554 'root' : {
2555 'level' : 'WARNING',
2556 },
2557 }
2558
2559 #As config11 but using an unsupported version
2560 config13 = {
2561 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002562 'true_formatters': {
2563 'form1' : {
2564 'format' : '%(levelname)s ++ %(message)s',
2565 },
2566 },
2567 'handler_configs': {
2568 'hand1' : {
2569 'class' : 'logging.StreamHandler',
2570 'formatter' : 'form1',
2571 'level' : 'NOTSET',
2572 'stream' : 'ext://sys.stdout',
2573 },
2574 },
2575 'formatters' : 'cfg://true_formatters',
2576 'handlers' : {
2577 'hand1' : 'cfg://handler_configs[hand1]',
2578 },
2579 'loggers' : {
2580 'compiler.parser' : {
2581 'level' : 'DEBUG',
2582 'handlers' : ['hand1'],
2583 },
2584 },
2585 'root' : {
2586 'level' : 'WARNING',
2587 },
2588 }
2589
Vinay Sajip8d270232012-11-15 14:20:18 +00002590 # As config0, but with properties
2591 config14 = {
2592 'version': 1,
2593 'formatters': {
2594 'form1' : {
2595 'format' : '%(levelname)s ++ %(message)s',
2596 },
2597 },
2598 'handlers' : {
2599 'hand1' : {
2600 'class' : 'logging.StreamHandler',
2601 'formatter' : 'form1',
2602 'level' : 'NOTSET',
2603 'stream' : 'ext://sys.stdout',
2604 '.': {
2605 'foo': 'bar',
2606 'terminator': '!\n',
2607 }
2608 },
2609 },
2610 'root' : {
2611 'level' : 'WARNING',
2612 'handlers' : ['hand1'],
2613 },
2614 }
2615
Vinay Sajip3f885b52013-03-22 15:19:54 +00002616 out_of_order = {
2617 "version": 1,
2618 "formatters": {
2619 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002620 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2621 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002622 }
2623 },
2624 "handlers": {
2625 "fileGlobal": {
2626 "class": "logging.StreamHandler",
2627 "level": "DEBUG",
2628 "formatter": "mySimpleFormatter"
2629 },
2630 "bufferGlobal": {
2631 "class": "logging.handlers.MemoryHandler",
2632 "capacity": 5,
2633 "formatter": "mySimpleFormatter",
2634 "target": "fileGlobal",
2635 "level": "DEBUG"
2636 }
2637 },
2638 "loggers": {
2639 "mymodule": {
2640 "level": "DEBUG",
2641 "handlers": ["bufferGlobal"],
2642 "propagate": "true"
2643 }
2644 }
2645 }
2646
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002647 def apply_config(self, conf):
2648 logging.config.dictConfig(conf)
2649
2650 def test_config0_ok(self):
2651 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002652 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002653 self.apply_config(self.config0)
2654 logger = logging.getLogger()
2655 # Won't output anything
2656 logger.info(self.next_message())
2657 # Outputs a message
2658 logger.error(self.next_message())
2659 self.assert_log_lines([
2660 ('ERROR', '2'),
2661 ], stream=output)
2662 # Original logger output is empty.
2663 self.assert_log_lines([])
2664
2665 def test_config1_ok(self, config=config1):
2666 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002667 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002668 self.apply_config(config)
2669 logger = logging.getLogger("compiler.parser")
2670 # Both will output a message
2671 logger.info(self.next_message())
2672 logger.error(self.next_message())
2673 self.assert_log_lines([
2674 ('INFO', '1'),
2675 ('ERROR', '2'),
2676 ], stream=output)
2677 # Original logger output is empty.
2678 self.assert_log_lines([])
2679
2680 def test_config2_failure(self):
2681 # A simple config which overrides the default settings.
2682 self.assertRaises(Exception, self.apply_config, self.config2)
2683
2684 def test_config2a_failure(self):
2685 # A simple config which overrides the default settings.
2686 self.assertRaises(Exception, self.apply_config, self.config2a)
2687
2688 def test_config2b_failure(self):
2689 # A simple config which overrides the default settings.
2690 self.assertRaises(Exception, self.apply_config, self.config2b)
2691
2692 def test_config3_failure(self):
2693 # A simple config which overrides the default settings.
2694 self.assertRaises(Exception, self.apply_config, self.config3)
2695
2696 def test_config4_ok(self):
2697 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002698 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002699 self.apply_config(self.config4)
2700 #logger = logging.getLogger()
2701 try:
2702 raise RuntimeError()
2703 except RuntimeError:
2704 logging.exception("just testing")
2705 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002706 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002707 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2708 # Original logger output is empty
2709 self.assert_log_lines([])
2710
2711 def test_config4a_ok(self):
2712 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002713 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002714 self.apply_config(self.config4a)
2715 #logger = logging.getLogger()
2716 try:
2717 raise RuntimeError()
2718 except RuntimeError:
2719 logging.exception("just testing")
2720 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002721 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002722 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2723 # Original logger output is empty
2724 self.assert_log_lines([])
2725
2726 def test_config5_ok(self):
2727 self.test_config1_ok(config=self.config5)
2728
2729 def test_config6_failure(self):
2730 self.assertRaises(Exception, self.apply_config, self.config6)
2731
2732 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002733 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002734 self.apply_config(self.config1)
2735 logger = logging.getLogger("compiler.parser")
2736 # Both will output a message
2737 logger.info(self.next_message())
2738 logger.error(self.next_message())
2739 self.assert_log_lines([
2740 ('INFO', '1'),
2741 ('ERROR', '2'),
2742 ], stream=output)
2743 # Original logger output is empty.
2744 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002745 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002746 self.apply_config(self.config7)
2747 logger = logging.getLogger("compiler.parser")
2748 self.assertTrue(logger.disabled)
2749 logger = logging.getLogger("compiler.lexer")
2750 # Both will output a message
2751 logger.info(self.next_message())
2752 logger.error(self.next_message())
2753 self.assert_log_lines([
2754 ('INFO', '3'),
2755 ('ERROR', '4'),
2756 ], stream=output)
2757 # Original logger output is empty.
2758 self.assert_log_lines([])
2759
2760 #Same as test_config_7_ok but don't disable old loggers.
2761 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002762 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002763 self.apply_config(self.config1)
2764 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002765 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002766 logger.info(self.next_message())
2767 logger.error(self.next_message())
2768 self.assert_log_lines([
2769 ('INFO', '1'),
2770 ('ERROR', '2'),
2771 ], stream=output)
2772 # Original logger output is empty.
2773 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002774 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002775 self.apply_config(self.config8)
2776 logger = logging.getLogger("compiler.parser")
2777 self.assertFalse(logger.disabled)
2778 # Both will output a message
2779 logger.info(self.next_message())
2780 logger.error(self.next_message())
2781 logger = logging.getLogger("compiler.lexer")
2782 # Both will output a message
2783 logger.info(self.next_message())
2784 logger.error(self.next_message())
2785 self.assert_log_lines([
2786 ('INFO', '3'),
2787 ('ERROR', '4'),
2788 ('INFO', '5'),
2789 ('ERROR', '6'),
2790 ], stream=output)
2791 # Original logger output is empty.
2792 self.assert_log_lines([])
2793
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002794 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002795 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002796 self.apply_config(self.config1a)
2797 logger = logging.getLogger("compiler.parser")
2798 # See issue #11424. compiler-hyphenated sorts
2799 # between compiler and compiler.xyz and this
2800 # was preventing compiler.xyz from being included
2801 # in the child loggers of compiler because of an
2802 # overzealous loop termination condition.
2803 hyphenated = logging.getLogger('compiler-hyphenated')
2804 # All will output a message
2805 logger.info(self.next_message())
2806 logger.error(self.next_message())
2807 hyphenated.critical(self.next_message())
2808 self.assert_log_lines([
2809 ('INFO', '1'),
2810 ('ERROR', '2'),
2811 ('CRITICAL', '3'),
2812 ], stream=output)
2813 # Original logger output is empty.
2814 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002815 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002816 self.apply_config(self.config8a)
2817 logger = logging.getLogger("compiler.parser")
2818 self.assertFalse(logger.disabled)
2819 # Both will output a message
2820 logger.info(self.next_message())
2821 logger.error(self.next_message())
2822 logger = logging.getLogger("compiler.lexer")
2823 # Both will output a message
2824 logger.info(self.next_message())
2825 logger.error(self.next_message())
2826 # Will not appear
2827 hyphenated.critical(self.next_message())
2828 self.assert_log_lines([
2829 ('INFO', '4'),
2830 ('ERROR', '5'),
2831 ('INFO', '6'),
2832 ('ERROR', '7'),
2833 ], stream=output)
2834 # Original logger output is empty.
2835 self.assert_log_lines([])
2836
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002837 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002838 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002839 self.apply_config(self.config9)
2840 logger = logging.getLogger("compiler.parser")
2841 #Nothing will be output since both handler and logger are set to WARNING
2842 logger.info(self.next_message())
2843 self.assert_log_lines([], stream=output)
2844 self.apply_config(self.config9a)
2845 #Nothing will be output since both handler is still set to WARNING
2846 logger.info(self.next_message())
2847 self.assert_log_lines([], stream=output)
2848 self.apply_config(self.config9b)
2849 #Message should now be output
2850 logger.info(self.next_message())
2851 self.assert_log_lines([
2852 ('INFO', '3'),
2853 ], stream=output)
2854
2855 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002856 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002857 self.apply_config(self.config10)
2858 logger = logging.getLogger("compiler.parser")
2859 logger.warning(self.next_message())
2860 logger = logging.getLogger('compiler')
2861 #Not output, because filtered
2862 logger.warning(self.next_message())
2863 logger = logging.getLogger('compiler.lexer')
2864 #Not output, because filtered
2865 logger.warning(self.next_message())
2866 logger = logging.getLogger("compiler.parser.codegen")
2867 #Output, as not filtered
2868 logger.error(self.next_message())
2869 self.assert_log_lines([
2870 ('WARNING', '1'),
2871 ('ERROR', '4'),
2872 ], stream=output)
2873
2874 def test_config11_ok(self):
2875 self.test_config1_ok(self.config11)
2876
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002877 def test_config12_failure(self):
2878 self.assertRaises(Exception, self.apply_config, self.config12)
2879
2880 def test_config13_failure(self):
2881 self.assertRaises(Exception, self.apply_config, self.config13)
2882
Vinay Sajip8d270232012-11-15 14:20:18 +00002883 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002884 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002885 self.apply_config(self.config14)
2886 h = logging._handlers['hand1']
2887 self.assertEqual(h.foo, 'bar')
2888 self.assertEqual(h.terminator, '!\n')
2889 logging.warning('Exclamation')
2890 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2891
Victor Stinner69669602017-08-18 23:47:54 +02002892 # listen() uses ConfigSocketReceiver which is based
2893 # on socketserver.ThreadingTCPServer
2894 @unittest.skipIf(True, "FIXME: bpo-30830")
Victor Stinner45df8202010-04-28 22:31:17 +00002895 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002896 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002897 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002898 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002899 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002900 t.start()
2901 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002902 # Now get the port allocated
2903 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002904 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002905 try:
2906 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2907 sock.settimeout(2.0)
2908 sock.connect(('localhost', port))
2909
2910 slen = struct.pack('>L', len(text))
2911 s = slen + text
2912 sentsofar = 0
2913 left = len(s)
2914 while left > 0:
2915 sent = sock.send(s[sentsofar:])
2916 sentsofar += sent
2917 left -= sent
2918 sock.close()
2919 finally:
2920 t.ready.wait(2.0)
2921 logging.config.stopListening()
2922 t.join(2.0)
Victor Stinner4bcfa3a2017-04-25 00:41:36 +02002923 if t.is_alive():
2924 self.fail("join() timed out")
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002925
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002926 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002927 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002928 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002929 self.setup_via_listener(json.dumps(self.config10))
2930 logger = logging.getLogger("compiler.parser")
2931 logger.warning(self.next_message())
2932 logger = logging.getLogger('compiler')
2933 #Not output, because filtered
2934 logger.warning(self.next_message())
2935 logger = logging.getLogger('compiler.lexer')
2936 #Not output, because filtered
2937 logger.warning(self.next_message())
2938 logger = logging.getLogger("compiler.parser.codegen")
2939 #Output, as not filtered
2940 logger.error(self.next_message())
2941 self.assert_log_lines([
2942 ('WARNING', '1'),
2943 ('ERROR', '4'),
2944 ], stream=output)
2945
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002946 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002947 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002948 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002949 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2950 logger = logging.getLogger("compiler.parser")
2951 # Both will output a message
2952 logger.info(self.next_message())
2953 logger.error(self.next_message())
2954 self.assert_log_lines([
2955 ('INFO', '1'),
2956 ('ERROR', '2'),
2957 ], stream=output)
2958 # Original logger output is empty.
2959 self.assert_log_lines([])
2960
Vinay Sajip4ded5512012-10-02 15:56:16 +01002961 @unittest.skipUnless(threading, 'Threading required for this test.')
2962 def test_listen_verify(self):
2963
2964 def verify_fail(stuff):
2965 return None
2966
2967 def verify_reverse(stuff):
2968 return stuff[::-1]
2969
2970 logger = logging.getLogger("compiler.parser")
2971 to_send = textwrap.dedent(ConfigFileTest.config1)
2972 # First, specify a verification function that will fail.
2973 # We expect to see no output, since our configuration
2974 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002975 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002976 self.setup_via_listener(to_send, verify_fail)
2977 # Both will output a message
2978 logger.info(self.next_message())
2979 logger.error(self.next_message())
2980 self.assert_log_lines([], stream=output)
2981 # Original logger output has the stuff we logged.
2982 self.assert_log_lines([
2983 ('INFO', '1'),
2984 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002985 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002986
2987 # Now, perform no verification. Our configuration
2988 # should take effect.
2989
Vinay Sajip1feedb42014-05-31 08:19:12 +01002990 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002991 self.setup_via_listener(to_send) # no verify callable specified
2992 logger = logging.getLogger("compiler.parser")
2993 # Both will output a message
2994 logger.info(self.next_message())
2995 logger.error(self.next_message())
2996 self.assert_log_lines([
2997 ('INFO', '3'),
2998 ('ERROR', '4'),
2999 ], stream=output)
3000 # Original logger output still has the stuff we logged before.
3001 self.assert_log_lines([
3002 ('INFO', '1'),
3003 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003004 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003005
3006 # Now, perform verification which transforms the bytes.
3007
Vinay Sajip1feedb42014-05-31 08:19:12 +01003008 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003009 self.setup_via_listener(to_send[::-1], verify_reverse)
3010 logger = logging.getLogger("compiler.parser")
3011 # Both will output a message
3012 logger.info(self.next_message())
3013 logger.error(self.next_message())
3014 self.assert_log_lines([
3015 ('INFO', '5'),
3016 ('ERROR', '6'),
3017 ], stream=output)
3018 # Original logger output still has the stuff we logged before.
3019 self.assert_log_lines([
3020 ('INFO', '1'),
3021 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003022 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003023
Vinay Sajip3f885b52013-03-22 15:19:54 +00003024 def test_out_of_order(self):
3025 self.apply_config(self.out_of_order)
3026 handler = logging.getLogger('mymodule').handlers[0]
3027 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003028 self.assertIsInstance(handler.formatter._style,
3029 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003030
Vinay Sajip373baef2011-04-26 20:05:24 +01003031 def test_baseconfig(self):
3032 d = {
3033 'atuple': (1, 2, 3),
3034 'alist': ['a', 'b', 'c'],
3035 'adict': {'d': 'e', 'f': 3 },
3036 'nest1': ('g', ('h', 'i'), 'j'),
3037 'nest2': ['k', ['l', 'm'], 'n'],
3038 'nest3': ['o', 'cfg://alist', 'p'],
3039 }
3040 bc = logging.config.BaseConfigurator(d)
3041 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3042 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3043 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3044 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3045 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3046 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3047 v = bc.convert('cfg://nest3')
3048 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3049 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3050 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3051 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003052
3053class ManagerTest(BaseTest):
3054 def test_manager_loggerclass(self):
3055 logged = []
3056
3057 class MyLogger(logging.Logger):
3058 def _log(self, level, msg, args, exc_info=None, extra=None):
3059 logged.append(msg)
3060
3061 man = logging.Manager(None)
3062 self.assertRaises(TypeError, man.setLoggerClass, int)
3063 man.setLoggerClass(MyLogger)
3064 logger = man.getLogger('test')
3065 logger.warning('should appear in logged')
3066 logging.warning('should not appear in logged')
3067
3068 self.assertEqual(logged, ['should appear in logged'])
3069
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003070 def test_set_log_record_factory(self):
3071 man = logging.Manager(None)
3072 expected = object()
3073 man.setLogRecordFactory(expected)
3074 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003075
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003076class ChildLoggerTest(BaseTest):
3077 def test_child_loggers(self):
3078 r = logging.getLogger()
3079 l1 = logging.getLogger('abc')
3080 l2 = logging.getLogger('def.ghi')
3081 c1 = r.getChild('xyz')
3082 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003083 self.assertIs(c1, logging.getLogger('xyz'))
3084 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003085 c1 = l1.getChild('def')
3086 c2 = c1.getChild('ghi')
3087 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003088 self.assertIs(c1, logging.getLogger('abc.def'))
3089 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3090 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003091
3092
Vinay Sajip6fac8172010-10-19 20:44:14 +00003093class DerivedLogRecord(logging.LogRecord):
3094 pass
3095
Vinay Sajip61561522010-12-03 11:50:38 +00003096class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003097
3098 def setUp(self):
3099 class CheckingFilter(logging.Filter):
3100 def __init__(self, cls):
3101 self.cls = cls
3102
3103 def filter(self, record):
3104 t = type(record)
3105 if t is not self.cls:
3106 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3107 self.cls)
3108 raise TypeError(msg)
3109 return True
3110
3111 BaseTest.setUp(self)
3112 self.filter = CheckingFilter(DerivedLogRecord)
3113 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003114 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003115
3116 def tearDown(self):
3117 self.root_logger.removeFilter(self.filter)
3118 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003119 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003120
3121 def test_logrecord_class(self):
3122 self.assertRaises(TypeError, self.root_logger.warning,
3123 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003124 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003125 self.root_logger.error(self.next_message())
3126 self.assert_log_lines([
3127 ('root', 'ERROR', '2'),
3128 ])
3129
3130
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003131class QueueHandlerTest(BaseTest):
3132 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003133 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003134
3135 def setUp(self):
3136 BaseTest.setUp(self)
3137 self.queue = queue.Queue(-1)
3138 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003139 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003140 self.que_logger = logging.getLogger('que')
3141 self.que_logger.propagate = False
3142 self.que_logger.setLevel(logging.WARNING)
3143 self.que_logger.addHandler(self.que_hdlr)
3144
3145 def tearDown(self):
3146 self.que_hdlr.close()
3147 BaseTest.tearDown(self)
3148
3149 def test_queue_handler(self):
3150 self.que_logger.debug(self.next_message())
3151 self.assertRaises(queue.Empty, self.queue.get_nowait)
3152 self.que_logger.info(self.next_message())
3153 self.assertRaises(queue.Empty, self.queue.get_nowait)
3154 msg = self.next_message()
3155 self.que_logger.warning(msg)
3156 data = self.queue.get_nowait()
3157 self.assertTrue(isinstance(data, logging.LogRecord))
3158 self.assertEqual(data.name, self.que_logger.name)
3159 self.assertEqual((data.msg, data.args), (msg, None))
3160
favlladfe3442017-08-01 20:12:26 +02003161 def test_formatting(self):
3162 msg = self.next_message()
3163 levelname = logging.getLevelName(logging.WARNING)
3164 log_format_str = '{name} -> {levelname}: {message}'
3165 formatted_msg = log_format_str.format(name=self.name,
3166 levelname=levelname, message=msg)
3167 formatter = logging.Formatter(self.log_format)
3168 self.que_hdlr.setFormatter(formatter)
3169 self.que_logger.warning(msg)
3170 log_record = self.queue.get_nowait()
3171 self.assertEqual(formatted_msg, log_record.msg)
3172 self.assertEqual(formatted_msg, log_record.message)
3173
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003174 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3175 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003176 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003177 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003178 listener = logging.handlers.QueueListener(self.queue, handler)
3179 listener.start()
3180 try:
3181 self.que_logger.warning(self.next_message())
3182 self.que_logger.error(self.next_message())
3183 self.que_logger.critical(self.next_message())
3184 finally:
3185 listener.stop()
3186 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3187 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3188 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003189 handler.close()
3190
3191 # Now test with respect_handler_level set
3192
3193 handler = support.TestHandler(support.Matcher())
3194 handler.setLevel(logging.CRITICAL)
3195 listener = logging.handlers.QueueListener(self.queue, handler,
3196 respect_handler_level=True)
3197 listener.start()
3198 try:
3199 self.que_logger.warning(self.next_message())
3200 self.que_logger.error(self.next_message())
3201 self.que_logger.critical(self.next_message())
3202 finally:
3203 listener.stop()
3204 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3205 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3206 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3207
Vinay Sajipd61910c2016-09-08 01:13:39 +01003208if hasattr(logging.handlers, 'QueueListener'):
3209 import multiprocessing
3210 from unittest.mock import patch
3211
3212 class QueueListenerTest(BaseTest):
3213 """
3214 Tests based on patch submitted for issue #27930. Ensure that
3215 QueueListener handles all log messages.
3216 """
3217
3218 repeat = 20
3219
3220 @staticmethod
3221 def setup_and_log(log_queue, ident):
3222 """
3223 Creates a logger with a QueueHandler that logs to a queue read by a
3224 QueueListener. Starts the listener, logs five messages, and stops
3225 the listener.
3226 """
3227 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3228 logger.setLevel(logging.DEBUG)
3229 handler = logging.handlers.QueueHandler(log_queue)
3230 logger.addHandler(handler)
3231 listener = logging.handlers.QueueListener(log_queue)
3232 listener.start()
3233
3234 logger.info('one')
3235 logger.info('two')
3236 logger.info('three')
3237 logger.info('four')
3238 logger.info('five')
3239
3240 listener.stop()
3241 logger.removeHandler(handler)
3242 handler.close()
3243
3244 @patch.object(logging.handlers.QueueListener, 'handle')
3245 def test_handle_called_with_queue_queue(self, mock_handle):
3246 for i in range(self.repeat):
3247 log_queue = queue.Queue()
3248 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3249 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3250 'correct number of handled log messages')
3251
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003252 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003253 @patch.object(logging.handlers.QueueListener, 'handle')
3254 def test_handle_called_with_mp_queue(self, mock_handle):
3255 for i in range(self.repeat):
3256 log_queue = multiprocessing.Queue()
3257 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003258 log_queue.close()
3259 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003260 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3261 'correct number of handled log messages')
3262
3263 @staticmethod
3264 def get_all_from_queue(log_queue):
3265 try:
3266 while True:
3267 yield log_queue.get_nowait()
3268 except queue.Empty:
3269 return []
3270
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003271 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003272 def test_no_messages_in_queue_after_stop(self):
3273 """
3274 Five messages are logged then the QueueListener is stopped. This
3275 test then gets everything off the queue. Failure of this test
3276 indicates that messages were not registered on the queue until
3277 _after_ the QueueListener stopped.
3278 """
3279 for i in range(self.repeat):
3280 queue = multiprocessing.Queue()
3281 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3282 # time.sleep(1)
3283 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003284 queue.close()
3285 queue.join_thread()
3286
Vinay Sajipd61910c2016-09-08 01:13:39 +01003287 expected = [[], [logging.handlers.QueueListener._sentinel]]
3288 self.assertIn(items, expected,
3289 'Found unexpected messages in queue: %s' % (
3290 [m.msg if isinstance(m, logging.LogRecord)
3291 else m for m in items]))
3292
Vinay Sajipe723e962011-04-15 22:27:17 +01003293
Vinay Sajip37eb3382011-04-26 20:26:41 +01003294ZERO = datetime.timedelta(0)
3295
3296class UTC(datetime.tzinfo):
3297 def utcoffset(self, dt):
3298 return ZERO
3299
3300 dst = utcoffset
3301
3302 def tzname(self, dt):
3303 return 'UTC'
3304
3305utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003306
Vinay Sajipa39c5712010-10-25 13:57:39 +00003307class FormatterTest(unittest.TestCase):
3308 def setUp(self):
3309 self.common = {
3310 'name': 'formatter.test',
3311 'level': logging.DEBUG,
3312 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3313 'lineno': 42,
3314 'exc_info': None,
3315 'func': None,
3316 'msg': 'Message with %d %s',
3317 'args': (2, 'placeholders'),
3318 }
3319 self.variants = {
3320 }
3321
3322 def get_record(self, name=None):
3323 result = dict(self.common)
3324 if name is not None:
3325 result.update(self.variants[name])
3326 return logging.makeLogRecord(result)
3327
3328 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003329 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003330 r = self.get_record()
3331 f = logging.Formatter('${%(message)s}')
3332 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3333 f = logging.Formatter('%(random)s')
3334 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003335 self.assertFalse(f.usesTime())
3336 f = logging.Formatter('%(asctime)s')
3337 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003338 f = logging.Formatter('%(asctime)-15s')
3339 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003340 f = logging.Formatter('asctime')
3341 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003342
3343 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003344 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003345 r = self.get_record()
3346 f = logging.Formatter('$%{message}%$', style='{')
3347 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3348 f = logging.Formatter('{random}', style='{')
3349 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003350 self.assertFalse(f.usesTime())
3351 f = logging.Formatter('{asctime}', style='{')
3352 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003353 f = logging.Formatter('{asctime!s:15}', style='{')
3354 self.assertTrue(f.usesTime())
3355 f = logging.Formatter('{asctime:15}', style='{')
3356 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003357 f = logging.Formatter('asctime', style='{')
3358 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003359
3360 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003361 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003362 r = self.get_record()
3363 f = logging.Formatter('$message', style='$')
3364 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3365 f = logging.Formatter('$$%${message}%$$', style='$')
3366 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3367 f = logging.Formatter('${random}', style='$')
3368 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003369 self.assertFalse(f.usesTime())
3370 f = logging.Formatter('${asctime}', style='$')
3371 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003372 f = logging.Formatter('${asctime', style='$')
3373 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003374 f = logging.Formatter('$asctime', style='$')
3375 self.assertTrue(f.usesTime())
3376 f = logging.Formatter('asctime', style='$')
3377 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003378
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003379 def test_invalid_style(self):
3380 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3381
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003382 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003383 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003384 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3385 # We use None to indicate we want the local timezone
3386 # We're essentially converting a UTC time to local time
3387 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003388 r.msecs = 123
3389 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003390 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003391 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3392 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003393 f.format(r)
3394 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3395
3396class TestBufferingFormatter(logging.BufferingFormatter):
3397 def formatHeader(self, records):
3398 return '[(%d)' % len(records)
3399
3400 def formatFooter(self, records):
3401 return '(%d)]' % len(records)
3402
3403class BufferingFormatterTest(unittest.TestCase):
3404 def setUp(self):
3405 self.records = [
3406 logging.makeLogRecord({'msg': 'one'}),
3407 logging.makeLogRecord({'msg': 'two'}),
3408 ]
3409
3410 def test_default(self):
3411 f = logging.BufferingFormatter()
3412 self.assertEqual('', f.format([]))
3413 self.assertEqual('onetwo', f.format(self.records))
3414
3415 def test_custom(self):
3416 f = TestBufferingFormatter()
3417 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3418 lf = logging.Formatter('<%(message)s>')
3419 f = TestBufferingFormatter(lf)
3420 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003421
3422class ExceptionTest(BaseTest):
3423 def test_formatting(self):
3424 r = self.root_logger
3425 h = RecordingHandler()
3426 r.addHandler(h)
3427 try:
3428 raise RuntimeError('deliberate mistake')
3429 except:
3430 logging.exception('failed', stack_info=True)
3431 r.removeHandler(h)
3432 h.close()
3433 r = h.records[0]
3434 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3435 'call last):\n'))
3436 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3437 'deliberate mistake'))
3438 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3439 'call last):\n'))
3440 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3441 'stack_info=True)'))
3442
3443
Vinay Sajip5a27d402010-12-10 11:42:57 +00003444class LastResortTest(BaseTest):
3445 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003446 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003447 root = self.root_logger
3448 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003449 old_lastresort = logging.lastResort
3450 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003451
Vinay Sajip5a27d402010-12-10 11:42:57 +00003452 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003453 with support.captured_stderr() as stderr:
3454 root.debug('This should not appear')
3455 self.assertEqual(stderr.getvalue(), '')
3456 root.warning('Final chance!')
3457 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3458
3459 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003460 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003461 with support.captured_stderr() as stderr:
3462 root.warning('Final chance!')
3463 msg = 'No handlers could be found for logger "root"\n'
3464 self.assertEqual(stderr.getvalue(), msg)
3465
Vinay Sajip5a27d402010-12-10 11:42:57 +00003466 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003467 with support.captured_stderr() as stderr:
3468 root.warning('Final chance!')
3469 self.assertEqual(stderr.getvalue(), '')
3470
3471 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003472 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003473 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003474 with support.captured_stderr() as stderr:
3475 root.warning('Final chance!')
3476 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003477 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003478 root.addHandler(self.root_hdlr)
3479 logging.lastResort = old_lastresort
3480 logging.raiseExceptions = old_raise_exceptions
3481
3482
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003483class FakeHandler:
3484
3485 def __init__(self, identifier, called):
3486 for method in ('acquire', 'flush', 'close', 'release'):
3487 setattr(self, method, self.record_call(identifier, method, called))
3488
3489 def record_call(self, identifier, method_name, called):
3490 def inner():
3491 called.append('{} - {}'.format(identifier, method_name))
3492 return inner
3493
3494
3495class RecordingHandler(logging.NullHandler):
3496
3497 def __init__(self, *args, **kwargs):
3498 super(RecordingHandler, self).__init__(*args, **kwargs)
3499 self.records = []
3500
3501 def handle(self, record):
3502 """Keep track of all the emitted records."""
3503 self.records.append(record)
3504
3505
3506class ShutdownTest(BaseTest):
3507
Vinay Sajip5e66b162011-04-20 15:41:14 +01003508 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003509
3510 def setUp(self):
3511 super(ShutdownTest, self).setUp()
3512 self.called = []
3513
3514 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003515 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003516
3517 def raise_error(self, error):
3518 def inner():
3519 raise error()
3520 return inner
3521
3522 def test_no_failure(self):
3523 # create some fake handlers
3524 handler0 = FakeHandler(0, self.called)
3525 handler1 = FakeHandler(1, self.called)
3526 handler2 = FakeHandler(2, self.called)
3527
3528 # create live weakref to those handlers
3529 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3530
3531 logging.shutdown(handlerList=list(handlers))
3532
3533 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3534 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3535 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3536 self.assertEqual(expected, self.called)
3537
3538 def _test_with_failure_in_method(self, method, error):
3539 handler = FakeHandler(0, self.called)
3540 setattr(handler, method, self.raise_error(error))
3541 handlers = [logging.weakref.ref(handler)]
3542
3543 logging.shutdown(handlerList=list(handlers))
3544
3545 self.assertEqual('0 - release', self.called[-1])
3546
3547 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003548 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003549
3550 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003551 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003552
3553 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003554 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003555
3556 def test_with_valueerror_in_acquire(self):
3557 self._test_with_failure_in_method('acquire', ValueError)
3558
3559 def test_with_valueerror_in_flush(self):
3560 self._test_with_failure_in_method('flush', ValueError)
3561
3562 def test_with_valueerror_in_close(self):
3563 self._test_with_failure_in_method('close', ValueError)
3564
3565 def test_with_other_error_in_acquire_without_raise(self):
3566 logging.raiseExceptions = False
3567 self._test_with_failure_in_method('acquire', IndexError)
3568
3569 def test_with_other_error_in_flush_without_raise(self):
3570 logging.raiseExceptions = False
3571 self._test_with_failure_in_method('flush', IndexError)
3572
3573 def test_with_other_error_in_close_without_raise(self):
3574 logging.raiseExceptions = False
3575 self._test_with_failure_in_method('close', IndexError)
3576
3577 def test_with_other_error_in_acquire_with_raise(self):
3578 logging.raiseExceptions = True
3579 self.assertRaises(IndexError, self._test_with_failure_in_method,
3580 'acquire', IndexError)
3581
3582 def test_with_other_error_in_flush_with_raise(self):
3583 logging.raiseExceptions = True
3584 self.assertRaises(IndexError, self._test_with_failure_in_method,
3585 'flush', IndexError)
3586
3587 def test_with_other_error_in_close_with_raise(self):
3588 logging.raiseExceptions = True
3589 self.assertRaises(IndexError, self._test_with_failure_in_method,
3590 'close', IndexError)
3591
3592
3593class ModuleLevelMiscTest(BaseTest):
3594
Vinay Sajip5e66b162011-04-20 15:41:14 +01003595 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003596
3597 def test_disable(self):
3598 old_disable = logging.root.manager.disable
3599 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003600 self.assertEqual(old_disable, 0)
3601 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003602
3603 logging.disable(83)
3604 self.assertEqual(logging.root.manager.disable, 83)
3605
Vinay Sajipd489ac92016-12-31 11:40:11 +00003606 # test the default value introduced in 3.7
3607 # (Issue #28524)
3608 logging.disable()
3609 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3610
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003611 def _test_log(self, method, level=None):
3612 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003613 support.patch(self, logging, 'basicConfig',
3614 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003615
3616 recording = RecordingHandler()
3617 logging.root.addHandler(recording)
3618
3619 log_method = getattr(logging, method)
3620 if level is not None:
3621 log_method(level, "test me: %r", recording)
3622 else:
3623 log_method("test me: %r", recording)
3624
3625 self.assertEqual(len(recording.records), 1)
3626 record = recording.records[0]
3627 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3628
3629 expected_level = level if level is not None else getattr(logging, method.upper())
3630 self.assertEqual(record.levelno, expected_level)
3631
3632 # basicConfig was not called!
3633 self.assertEqual(called, [])
3634
3635 def test_log(self):
3636 self._test_log('log', logging.ERROR)
3637
3638 def test_debug(self):
3639 self._test_log('debug')
3640
3641 def test_info(self):
3642 self._test_log('info')
3643
3644 def test_warning(self):
3645 self._test_log('warning')
3646
3647 def test_error(self):
3648 self._test_log('error')
3649
3650 def test_critical(self):
3651 self._test_log('critical')
3652
3653 def test_set_logger_class(self):
3654 self.assertRaises(TypeError, logging.setLoggerClass, object)
3655
3656 class MyLogger(logging.Logger):
3657 pass
3658
3659 logging.setLoggerClass(MyLogger)
3660 self.assertEqual(logging.getLoggerClass(), MyLogger)
3661
3662 logging.setLoggerClass(logging.Logger)
3663 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3664
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003665 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003666 def test_logging_at_shutdown(self):
3667 # Issue #20037
3668 code = """if 1:
3669 import logging
3670
3671 class A:
3672 def __del__(self):
3673 try:
3674 raise ValueError("some error")
3675 except Exception:
3676 logging.exception("exception in __del__")
3677
3678 a = A()"""
3679 rc, out, err = assert_python_ok("-c", code)
3680 err = err.decode()
3681 self.assertIn("exception in __del__", err)
3682 self.assertIn("ValueError: some error", err)
3683
3684
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003685class LogRecordTest(BaseTest):
3686 def test_str_rep(self):
3687 r = logging.makeLogRecord({})
3688 s = str(r)
3689 self.assertTrue(s.startswith('<LogRecord: '))
3690 self.assertTrue(s.endswith('>'))
3691
3692 def test_dict_arg(self):
3693 h = RecordingHandler()
3694 r = logging.getLogger()
3695 r.addHandler(h)
3696 d = {'less' : 'more' }
3697 logging.warning('less is %(less)s', d)
3698 self.assertIs(h.records[0].args, d)
3699 self.assertEqual(h.records[0].message, 'less is more')
3700 r.removeHandler(h)
3701 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003702
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003703 def test_multiprocessing(self):
3704 r = logging.makeLogRecord({})
3705 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003706 try:
3707 import multiprocessing as mp
3708 r = logging.makeLogRecord({})
3709 self.assertEqual(r.processName, mp.current_process().name)
3710 except ImportError:
3711 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003712
3713 def test_optional(self):
3714 r = logging.makeLogRecord({})
3715 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003716 if threading:
3717 NOT_NONE(r.thread)
3718 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003719 NOT_NONE(r.process)
3720 NOT_NONE(r.processName)
3721 log_threads = logging.logThreads
3722 log_processes = logging.logProcesses
3723 log_multiprocessing = logging.logMultiprocessing
3724 try:
3725 logging.logThreads = False
3726 logging.logProcesses = False
3727 logging.logMultiprocessing = False
3728 r = logging.makeLogRecord({})
3729 NONE = self.assertIsNone
3730 NONE(r.thread)
3731 NONE(r.threadName)
3732 NONE(r.process)
3733 NONE(r.processName)
3734 finally:
3735 logging.logThreads = log_threads
3736 logging.logProcesses = log_processes
3737 logging.logMultiprocessing = log_multiprocessing
3738
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003739class BasicConfigTest(unittest.TestCase):
3740
Vinay Sajip95bf5042011-04-20 11:50:56 +01003741 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003742
3743 def setUp(self):
3744 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003745 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003746 self.saved_handlers = logging._handlers.copy()
3747 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003748 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003749 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003750 logging.root.handlers = []
3751
3752 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003753 for h in logging.root.handlers[:]:
3754 logging.root.removeHandler(h)
3755 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003756 super(BasicConfigTest, self).tearDown()
3757
Vinay Sajip3def7e02011-04-20 10:58:06 +01003758 def cleanup(self):
3759 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003760 logging._handlers.clear()
3761 logging._handlers.update(self.saved_handlers)
3762 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003763 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003764
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003765 def test_no_kwargs(self):
3766 logging.basicConfig()
3767
3768 # handler defaults to a StreamHandler to sys.stderr
3769 self.assertEqual(len(logging.root.handlers), 1)
3770 handler = logging.root.handlers[0]
3771 self.assertIsInstance(handler, logging.StreamHandler)
3772 self.assertEqual(handler.stream, sys.stderr)
3773
3774 formatter = handler.formatter
3775 # format defaults to logging.BASIC_FORMAT
3776 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3777 # datefmt defaults to None
3778 self.assertIsNone(formatter.datefmt)
3779 # style defaults to %
3780 self.assertIsInstance(formatter._style, logging.PercentStyle)
3781
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003782 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003783 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003784
Vinay Sajip1fd12022014-01-13 21:59:56 +00003785 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003786 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003787 logging.basicConfig(stream=sys.stdout, style="{")
3788 logging.error("Log an error")
3789 sys.stdout.seek(0)
3790 self.assertEqual(output.getvalue().strip(),
3791 "ERROR:root:Log an error")
3792
3793 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003794 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003795 logging.basicConfig(stream=sys.stdout, style="$")
3796 logging.error("Log an error")
3797 sys.stdout.seek(0)
3798 self.assertEqual(output.getvalue().strip(),
3799 "ERROR:root:Log an error")
3800
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003801 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003802
3803 def cleanup(h1, h2, fn):
3804 h1.close()
3805 h2.close()
3806 os.remove(fn)
3807
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003808 logging.basicConfig(filename='test.log')
3809
3810 self.assertEqual(len(logging.root.handlers), 1)
3811 handler = logging.root.handlers[0]
3812 self.assertIsInstance(handler, logging.FileHandler)
3813
3814 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003815 self.assertEqual(handler.stream.mode, expected.stream.mode)
3816 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003817 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003818
3819 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003820
3821 def cleanup(h1, h2, fn):
3822 h1.close()
3823 h2.close()
3824 os.remove(fn)
3825
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003826 logging.basicConfig(filename='test.log', filemode='wb')
3827
3828 handler = logging.root.handlers[0]
3829 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003830 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003831 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003832
3833 def test_stream(self):
3834 stream = io.StringIO()
3835 self.addCleanup(stream.close)
3836 logging.basicConfig(stream=stream)
3837
3838 self.assertEqual(len(logging.root.handlers), 1)
3839 handler = logging.root.handlers[0]
3840 self.assertIsInstance(handler, logging.StreamHandler)
3841 self.assertEqual(handler.stream, stream)
3842
3843 def test_format(self):
3844 logging.basicConfig(format='foo')
3845
3846 formatter = logging.root.handlers[0].formatter
3847 self.assertEqual(formatter._style._fmt, 'foo')
3848
3849 def test_datefmt(self):
3850 logging.basicConfig(datefmt='bar')
3851
3852 formatter = logging.root.handlers[0].formatter
3853 self.assertEqual(formatter.datefmt, 'bar')
3854
3855 def test_style(self):
3856 logging.basicConfig(style='$')
3857
3858 formatter = logging.root.handlers[0].formatter
3859 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3860
3861 def test_level(self):
3862 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003863 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003864
3865 logging.basicConfig(level=57)
3866 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003867 # Test that second call has no effect
3868 logging.basicConfig(level=58)
3869 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003870
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003871 def test_incompatible(self):
3872 assertRaises = self.assertRaises
3873 handlers = [logging.StreamHandler()]
3874 stream = sys.stderr
3875 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3876 stream=stream)
3877 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3878 handlers=handlers)
3879 assertRaises(ValueError, logging.basicConfig, stream=stream,
3880 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003881 # Issue 23207: test for invalid kwargs
3882 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3883 # Should pop both filename and filemode even if filename is None
3884 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003885
3886 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003887 handlers = [
3888 logging.StreamHandler(),
3889 logging.StreamHandler(sys.stdout),
3890 logging.StreamHandler(),
3891 ]
3892 f = logging.Formatter()
3893 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003894 logging.basicConfig(handlers=handlers)
3895 self.assertIs(handlers[0], logging.root.handlers[0])
3896 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003897 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003898 self.assertIsNotNone(handlers[0].formatter)
3899 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003900 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003901 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3902
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003903 def _test_log(self, method, level=None):
3904 # logging.root has no handlers so basicConfig should be called
3905 called = []
3906
3907 old_basic_config = logging.basicConfig
3908 def my_basic_config(*a, **kw):
3909 old_basic_config()
3910 old_level = logging.root.level
3911 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003912 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003913 called.append((a, kw))
3914
Vinay Sajip1feedb42014-05-31 08:19:12 +01003915 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003916
3917 log_method = getattr(logging, method)
3918 if level is not None:
3919 log_method(level, "test me")
3920 else:
3921 log_method("test me")
3922
3923 # basicConfig was called with no arguments
3924 self.assertEqual(called, [((), {})])
3925
3926 def test_log(self):
3927 self._test_log('log', logging.WARNING)
3928
3929 def test_debug(self):
3930 self._test_log('debug')
3931
3932 def test_info(self):
3933 self._test_log('info')
3934
3935 def test_warning(self):
3936 self._test_log('warning')
3937
3938 def test_error(self):
3939 self._test_log('error')
3940
3941 def test_critical(self):
3942 self._test_log('critical')
3943
3944
3945class LoggerAdapterTest(unittest.TestCase):
3946
3947 def setUp(self):
3948 super(LoggerAdapterTest, self).setUp()
3949 old_handler_list = logging._handlerList[:]
3950
3951 self.recording = RecordingHandler()
3952 self.logger = logging.root
3953 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003954 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003955 self.addCleanup(self.recording.close)
3956
3957 def cleanup():
3958 logging._handlerList[:] = old_handler_list
3959
3960 self.addCleanup(cleanup)
3961 self.addCleanup(logging.shutdown)
3962 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3963
3964 def test_exception(self):
3965 msg = 'testing exception: %r'
3966 exc = None
3967 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003968 1 / 0
3969 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003970 exc = e
3971 self.adapter.exception(msg, self.recording)
3972
3973 self.assertEqual(len(self.recording.records), 1)
3974 record = self.recording.records[0]
3975 self.assertEqual(record.levelno, logging.ERROR)
3976 self.assertEqual(record.msg, msg)
3977 self.assertEqual(record.args, (self.recording,))
3978 self.assertEqual(record.exc_info,
3979 (exc.__class__, exc, exc.__traceback__))
3980
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003981 def test_exception_excinfo(self):
3982 try:
3983 1 / 0
3984 except ZeroDivisionError as e:
3985 exc = e
3986
3987 self.adapter.exception('exc_info test', exc_info=exc)
3988
3989 self.assertEqual(len(self.recording.records), 1)
3990 record = self.recording.records[0]
3991 self.assertEqual(record.exc_info,
3992 (exc.__class__, exc, exc.__traceback__))
3993
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003994 def test_critical(self):
3995 msg = 'critical test! %r'
3996 self.adapter.critical(msg, self.recording)
3997
3998 self.assertEqual(len(self.recording.records), 1)
3999 record = self.recording.records[0]
4000 self.assertEqual(record.levelno, logging.CRITICAL)
4001 self.assertEqual(record.msg, msg)
4002 self.assertEqual(record.args, (self.recording,))
4003
4004 def test_is_enabled_for(self):
4005 old_disable = self.adapter.logger.manager.disable
4006 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004007 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4008 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004009 self.assertFalse(self.adapter.isEnabledFor(32))
4010
4011 def test_has_handlers(self):
4012 self.assertTrue(self.adapter.hasHandlers())
4013
4014 for handler in self.logger.handlers:
4015 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004016
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004017 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004018 self.assertFalse(self.adapter.hasHandlers())
4019
4020
4021class LoggerTest(BaseTest):
4022
4023 def setUp(self):
4024 super(LoggerTest, self).setUp()
4025 self.recording = RecordingHandler()
4026 self.logger = logging.Logger(name='blah')
4027 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004028 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004029 self.addCleanup(self.recording.close)
4030 self.addCleanup(logging.shutdown)
4031
4032 def test_set_invalid_level(self):
4033 self.assertRaises(TypeError, self.logger.setLevel, object())
4034
4035 def test_exception(self):
4036 msg = 'testing exception: %r'
4037 exc = None
4038 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004039 1 / 0
4040 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004041 exc = e
4042 self.logger.exception(msg, self.recording)
4043
4044 self.assertEqual(len(self.recording.records), 1)
4045 record = self.recording.records[0]
4046 self.assertEqual(record.levelno, logging.ERROR)
4047 self.assertEqual(record.msg, msg)
4048 self.assertEqual(record.args, (self.recording,))
4049 self.assertEqual(record.exc_info,
4050 (exc.__class__, exc, exc.__traceback__))
4051
4052 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004053 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004054 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004055
4056 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004057 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004058 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004059
4060 def test_find_caller_with_stack_info(self):
4061 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004062 support.patch(self, logging.traceback, 'print_stack',
4063 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004064
4065 self.logger.findCaller(stack_info=True)
4066
4067 self.assertEqual(len(called), 1)
4068 self.assertEqual('Stack (most recent call last):\n', called[0])
4069
4070 def test_make_record_with_extra_overwrite(self):
4071 name = 'my record'
4072 level = 13
4073 fn = lno = msg = args = exc_info = func = sinfo = None
4074 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4075 exc_info, func, sinfo)
4076
4077 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4078 extra = {key: 'some value'}
4079 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4080 fn, lno, msg, args, exc_info,
4081 extra=extra, sinfo=sinfo)
4082
4083 def test_make_record_with_extra_no_overwrite(self):
4084 name = 'my record'
4085 level = 13
4086 fn = lno = msg = args = exc_info = func = sinfo = None
4087 extra = {'valid_key': 'some value'}
4088 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4089 exc_info, extra=extra, sinfo=sinfo)
4090 self.assertIn('valid_key', result.__dict__)
4091
4092 def test_has_handlers(self):
4093 self.assertTrue(self.logger.hasHandlers())
4094
4095 for handler in self.logger.handlers:
4096 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004097 self.assertFalse(self.logger.hasHandlers())
4098
4099 def test_has_handlers_no_propagate(self):
4100 child_logger = logging.getLogger('blah.child')
4101 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004102 self.assertFalse(child_logger.hasHandlers())
4103
4104 def test_is_enabled_for(self):
4105 old_disable = self.logger.manager.disable
4106 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004107 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004108 self.assertFalse(self.logger.isEnabledFor(22))
4109
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004110 def test_root_logger_aliases(self):
4111 root = logging.getLogger()
4112 self.assertIs(root, logging.root)
4113 self.assertIs(root, logging.getLogger(None))
4114 self.assertIs(root, logging.getLogger(''))
4115 self.assertIs(root, logging.getLogger('foo').root)
4116 self.assertIs(root, logging.getLogger('foo.bar').root)
4117 self.assertIs(root, logging.getLogger('foo').parent)
4118
4119 self.assertIsNot(root, logging.getLogger('\0'))
4120 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4121
4122 def test_invalid_names(self):
4123 self.assertRaises(TypeError, logging.getLogger, any)
4124 self.assertRaises(TypeError, logging.getLogger, b'foo')
4125
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004126 def test_pickling(self):
4127 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4128 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4129 logger = logging.getLogger(name)
4130 s = pickle.dumps(logger, proto)
4131 unpickled = pickle.loads(s)
4132 self.assertIs(unpickled, logger)
4133
Avram Lubkin78c18a92017-07-30 05:36:33 -04004134 def test_caching(self):
4135 root = self.root_logger
4136 logger1 = logging.getLogger("abc")
4137 logger2 = logging.getLogger("abc.def")
4138
4139 # Set root logger level and ensure cache is empty
4140 root.setLevel(logging.ERROR)
4141 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4142 self.assertEqual(logger2._cache, {})
4143
4144 # Ensure cache is populated and calls are consistent
4145 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4146 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4147 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4148 self.assertEqual(root._cache, {})
4149 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4150
4151 # Ensure root cache gets populated
4152 self.assertEqual(root._cache, {})
4153 self.assertTrue(root.isEnabledFor(logging.ERROR))
4154 self.assertEqual(root._cache, {logging.ERROR: True})
4155
4156 # Set parent logger level and ensure caches are emptied
4157 logger1.setLevel(logging.CRITICAL)
4158 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4159 self.assertEqual(logger2._cache, {})
4160
4161 # Ensure logger2 uses parent logger's effective level
4162 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4163
4164 # Set level to NOTSET and ensure caches are empty
4165 logger2.setLevel(logging.NOTSET)
4166 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4167 self.assertEqual(logger2._cache, {})
4168 self.assertEqual(logger1._cache, {})
4169 self.assertEqual(root._cache, {})
4170
4171 # Verify logger2 follows parent and not root
4172 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4173 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4174 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4175 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4176 self.assertTrue(root.isEnabledFor(logging.ERROR))
4177
4178 # Disable logging in manager and ensure caches are clear
4179 logging.disable()
4180 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4181 self.assertEqual(logger2._cache, {})
4182 self.assertEqual(logger1._cache, {})
4183 self.assertEqual(root._cache, {})
4184
4185 # Ensure no loggers are enabled
4186 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4187 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4188 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4189
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004190
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004191class BaseFileTest(BaseTest):
4192 "Base class for handler tests that write log files"
4193
4194 def setUp(self):
4195 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004196 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4197 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004198 self.rmfiles = []
4199
4200 def tearDown(self):
4201 for fn in self.rmfiles:
4202 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004203 if os.path.exists(self.fn):
4204 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004205 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004206
4207 def assertLogFile(self, filename):
4208 "Assert a log file is there and register it for deletion"
4209 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004210 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004211 self.rmfiles.append(filename)
4212
4213
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004214class FileHandlerTest(BaseFileTest):
4215 def test_delay(self):
4216 os.unlink(self.fn)
4217 fh = logging.FileHandler(self.fn, delay=True)
4218 self.assertIsNone(fh.stream)
4219 self.assertFalse(os.path.exists(self.fn))
4220 fh.handle(logging.makeLogRecord({}))
4221 self.assertIsNotNone(fh.stream)
4222 self.assertTrue(os.path.exists(self.fn))
4223 fh.close()
4224
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004225class RotatingFileHandlerTest(BaseFileTest):
4226 def next_rec(self):
4227 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4228 self.next_message(), None, None, None)
4229
4230 def test_should_not_rollover(self):
4231 # If maxbytes is zero rollover never occurs
4232 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4233 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004234 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004235
4236 def test_should_rollover(self):
4237 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4238 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004239 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004240
4241 def test_file_created(self):
4242 # checks that the file is created and assumes it was created
4243 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004244 rh = logging.handlers.RotatingFileHandler(self.fn)
4245 rh.emit(self.next_rec())
4246 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004247 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004248
4249 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004250 def namer(name):
4251 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004252 rh = logging.handlers.RotatingFileHandler(
4253 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004254 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004255 rh.emit(self.next_rec())
4256 self.assertLogFile(self.fn)
4257 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004258 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004259 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004260 self.assertLogFile(namer(self.fn + ".2"))
4261 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4262 rh.close()
4263
Vinay Sajip1feedb42014-05-31 08:19:12 +01004264 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004265 def test_rotator(self):
4266 def namer(name):
4267 return name + ".gz"
4268
4269 def rotator(source, dest):
4270 with open(source, "rb") as sf:
4271 data = sf.read()
4272 compressed = zlib.compress(data, 9)
4273 with open(dest, "wb") as df:
4274 df.write(compressed)
4275 os.remove(source)
4276
4277 rh = logging.handlers.RotatingFileHandler(
4278 self.fn, backupCount=2, maxBytes=1)
4279 rh.rotator = rotator
4280 rh.namer = namer
4281 m1 = self.next_rec()
4282 rh.emit(m1)
4283 self.assertLogFile(self.fn)
4284 m2 = self.next_rec()
4285 rh.emit(m2)
4286 fn = namer(self.fn + ".1")
4287 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004288 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004289 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 self.assertLogFile(fn)
4296 with open(fn, "rb") as f:
4297 compressed = f.read()
4298 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004299 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004300 rh.emit(self.next_rec())
4301 fn = namer(self.fn + ".2")
4302 with open(fn, "rb") as f:
4303 compressed = f.read()
4304 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004305 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004306 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004307 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004308
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004309class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004310 # other test methods added below
4311 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004312 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4313 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004314 fmt = logging.Formatter('%(asctime)s %(message)s')
4315 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004316 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004317 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004318 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004319 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004320 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004321 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004322 fh.close()
4323 # At this point, we should have a recent rotated file which we
4324 # can test for the existence of. However, in practice, on some
4325 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004326 # in time to go to look for the log file. So, we go back a fair
4327 # bit, and stop as soon as we see a rotated file. In theory this
4328 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004329 found = False
4330 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004331 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004332 for secs in range(GO_BACK):
4333 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004334 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4335 found = os.path.exists(fn)
4336 if found:
4337 self.rmfiles.append(fn)
4338 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004339 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4340 if not found:
4341 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004342 dn, fn = os.path.split(self.fn)
4343 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004344 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4345 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004346 for f in files:
4347 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004348 path = os.path.join(dn, f)
4349 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004350 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004351 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004352
Vinay Sajip0372e102011-05-05 12:59:14 +01004353 def test_invalid(self):
4354 assertRaises = self.assertRaises
4355 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004356 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004357 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004358 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004359 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004360 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004361
Vinay Sajipa7130792013-04-12 17:04:23 +01004362 def test_compute_rollover_daily_attime(self):
4363 currentTime = 0
4364 atTime = datetime.time(12, 0, 0)
4365 rh = logging.handlers.TimedRotatingFileHandler(
4366 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4367 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004368 try:
4369 actual = rh.computeRollover(currentTime)
4370 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004371
Vinay Sajipd86ac962013-04-14 12:20:46 +01004372 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4373 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4374 finally:
4375 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004376
Vinay Sajip10e8c492013-05-18 10:19:54 -07004377 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004378 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004379 currentTime = int(time.time())
4380 today = currentTime - currentTime % 86400
4381
Vinay Sajipa7130792013-04-12 17:04:23 +01004382 atTime = datetime.time(12, 0, 0)
4383
Vinay Sajip10e8c492013-05-18 10:19:54 -07004384 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004385 for day in range(7):
4386 rh = logging.handlers.TimedRotatingFileHandler(
4387 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4388 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004389 try:
4390 if wday > day:
4391 # The rollover day has already passed this week, so we
4392 # go over into next week
4393 expected = (7 - wday + day)
4394 else:
4395 expected = (day - wday)
4396 # At this point expected is in days from now, convert to seconds
4397 expected *= 24 * 60 * 60
4398 # Add in the rollover time
4399 expected += 12 * 60 * 60
4400 # Add in adjustment for today
4401 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004402 actual = rh.computeRollover(today)
4403 if actual != expected:
4404 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004405 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004406 self.assertEqual(actual, expected)
4407 if day == wday:
4408 # goes into following week
4409 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004410 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004411 if actual != expected:
4412 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004413 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004414 self.assertEqual(actual, expected)
4415 finally:
4416 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004417
4418
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004419def secs(**kw):
4420 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4421
4422for when, exp in (('S', 1),
4423 ('M', 60),
4424 ('H', 60 * 60),
4425 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004426 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004427 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004428 ('W0', secs(days=4, hours=24)),
4429 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004430 def test_compute_rollover(self, when=when, exp=exp):
4431 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004432 self.fn, when=when, interval=1, backupCount=0, utc=True)
4433 currentTime = 0.0
4434 actual = rh.computeRollover(currentTime)
4435 if exp != actual:
4436 # Failures occur on some systems for MIDNIGHT and W0.
4437 # Print detailed calculation for MIDNIGHT so we can try to see
4438 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004439 if when == 'MIDNIGHT':
4440 try:
4441 if rh.utc:
4442 t = time.gmtime(currentTime)
4443 else:
4444 t = time.localtime(currentTime)
4445 currentHour = t[3]
4446 currentMinute = t[4]
4447 currentSecond = t[5]
4448 # r is the number of seconds left between now and midnight
4449 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4450 currentMinute) * 60 +
4451 currentSecond)
4452 result = currentTime + r
4453 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4454 print('currentHour: %s' % currentHour, file=sys.stderr)
4455 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4456 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4457 print('r: %s' % r, file=sys.stderr)
4458 print('result: %s' % result, file=sys.stderr)
4459 except Exception:
4460 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4461 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004462 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004463 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4464
Vinay Sajip60ccd822011-05-09 17:32:09 +01004465
Vinay Sajip223349c2015-10-01 20:37:54 +01004466@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004467class NTEventLogHandlerTest(BaseTest):
4468 def test_basic(self):
4469 logtype = 'Application'
4470 elh = win32evtlog.OpenEventLog(None, logtype)
4471 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004472
4473 try:
4474 h = logging.handlers.NTEventLogHandler('test_logging')
4475 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004476 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004477 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004478 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004479
Vinay Sajip60ccd822011-05-09 17:32:09 +01004480 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4481 h.handle(r)
4482 h.close()
4483 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004484 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004485 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4486 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4487 found = False
4488 GO_BACK = 100
4489 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4490 for e in events:
4491 if e.SourceName != 'test_logging':
4492 continue
4493 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4494 if msg != 'Test Log Message\r\n':
4495 continue
4496 found = True
4497 break
4498 msg = 'Record not found in event log, went back %d records' % GO_BACK
4499 self.assertTrue(found, msg=msg)
4500
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004501
4502class MiscTestCase(unittest.TestCase):
4503 def test__all__(self):
4504 blacklist = {'logThreads', 'logMultiprocessing',
4505 'logProcesses', 'currentframe',
4506 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4507 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004508 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004509 support.check__all__(self, logging, blacklist=blacklist)
4510
4511
Christian Heimes180510d2008-03-03 19:15:45 +00004512# Set the locale to the platform-dependent default. I have no idea
4513# why the test does this, but in any case we save the current locale
4514# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004515@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004516def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004517 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004518 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4519 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4520 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4521 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4522 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4523 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4524 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4525 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004526 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004527 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004528 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004529 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004530 ]
4531 if hasattr(logging.handlers, 'QueueListener'):
4532 tests.append(QueueListenerTest)
4533 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004534
Christian Heimes180510d2008-03-03 19:15:45 +00004535if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004536 test_main()