blob: 474affdaebcd35bdd525f4a89e87d56b8349a569 [file] [log] [blame]
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001# Copyright 2001-2017 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip1e6499c2017-01-09 16:54:12 +000019Copyright (C) 2001-2017 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 from http.server import HTTPServer, BaseHTTPRequestHandler
55 import smtpd
56 from urllib.parse import urlparse, parse_qs
57 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010058 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000059except ImportError:
60 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010061try:
Vinay Sajip223349c2015-10-01 20:37:54 +010062 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010063except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010064 win32evtlog = win32evtlogutil = pywintypes = None
65
Eric V. Smith851cad72012-03-11 22:46:04 -070066try:
67 import zlib
68except ImportError:
69 pass
Christian Heimes18c66892008-02-17 13:31:39 +000070
Christian Heimes180510d2008-03-03 19:15:45 +000071class BaseTest(unittest.TestCase):
72
73 """Base class for logging tests."""
74
75 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030076 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000077 message_num = 0
78
79 def setUp(self):
80 """Setup the default logging stream to an internal StringIO instance,
81 so that we can examine log output as we want."""
82 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000083 logging._acquireLock()
84 try:
Christian Heimes180510d2008-03-03 19:15:45 +000085 self.saved_handlers = logging._handlers.copy()
86 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000087 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070088 self.saved_name_to_level = logging._nameToLevel.copy()
89 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.logger_states = logger_states = {}
91 for name in saved_loggers:
92 logger_states[name] = getattr(saved_loggers[name],
93 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000094 finally:
95 logging._releaseLock()
96
Florent Xicluna5252f9f2011-11-07 19:43:05 +010097 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000098 self.logger1 = logging.getLogger("\xab\xd7\xbb")
99 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000100
Christian Heimes180510d2008-03-03 19:15:45 +0000101 self.root_logger = logging.getLogger("")
102 self.original_logging_level = self.root_logger.getEffectiveLevel()
103
104 self.stream = io.StringIO()
105 self.root_logger.setLevel(logging.DEBUG)
106 self.root_hdlr = logging.StreamHandler(self.stream)
107 self.root_formatter = logging.Formatter(self.log_format)
108 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000109 if self.logger1.hasHandlers():
110 hlist = self.logger1.handlers + self.root_logger.handlers
111 raise AssertionError('Unexpected handlers: %s' % hlist)
112 if self.logger2.hasHandlers():
113 hlist = self.logger2.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000115 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000116 self.assertTrue(self.logger1.hasHandlers())
117 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000118
119 def tearDown(self):
120 """Remove our logging stream, and restore the original logging
121 level."""
122 self.stream.close()
123 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000124 while self.root_logger.handlers:
125 h = self.root_logger.handlers[0]
126 self.root_logger.removeHandler(h)
127 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000128 self.root_logger.setLevel(self.original_logging_level)
129 logging._acquireLock()
130 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700131 logging._levelToName.clear()
132 logging._levelToName.update(self.saved_level_to_name)
133 logging._nameToLevel.clear()
134 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000135 logging._handlers.clear()
136 logging._handlers.update(self.saved_handlers)
137 logging._handlerList[:] = self.saved_handler_list
138 loggerDict = logging.getLogger().manager.loggerDict
139 loggerDict.clear()
140 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000141 logger_states = self.logger_states
142 for name in self.logger_states:
143 if logger_states[name] is not None:
144 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000145 finally:
146 logging._releaseLock()
147
Vinay Sajip4ded5512012-10-02 15:56:16 +0100148 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000149 """Match the collected log lines against the regular expression
150 self.expected_log_pat, and compare the extracted group values to
151 the expected_values list of tuples."""
152 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100153 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300154 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100155 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000156 for actual, expected in zip(actual_lines, expected_values):
157 match = pat.search(actual)
158 if not match:
159 self.fail("Log line does not match expected pattern:\n" +
160 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000161 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000162 s = stream.read()
163 if s:
164 self.fail("Remaining output at end of log stream:\n" + s)
165
166 def next_message(self):
167 """Generate a message consisting solely of an auto-incrementing
168 integer."""
169 self.message_num += 1
170 return "%d" % self.message_num
171
172
173class BuiltinLevelsTest(BaseTest):
174 """Test builtin levels and their inheritance."""
175
176 def test_flat(self):
177 #Logging levels in a flat logger namespace.
178 m = self.next_message
179
180 ERR = logging.getLogger("ERR")
181 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000182 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000183 INF.setLevel(logging.INFO)
184 DEB = logging.getLogger("DEB")
185 DEB.setLevel(logging.DEBUG)
186
187 # These should log.
188 ERR.log(logging.CRITICAL, m())
189 ERR.error(m())
190
191 INF.log(logging.CRITICAL, m())
192 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100193 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000194 INF.info(m())
195
196 DEB.log(logging.CRITICAL, m())
197 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100198 DEB.warning(m())
199 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 DEB.debug(m())
201
202 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100203 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 ERR.info(m())
205 ERR.debug(m())
206
207 INF.debug(m())
208
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000209 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ('ERR', 'CRITICAL', '1'),
211 ('ERR', 'ERROR', '2'),
212 ('INF', 'CRITICAL', '3'),
213 ('INF', 'ERROR', '4'),
214 ('INF', 'WARNING', '5'),
215 ('INF', 'INFO', '6'),
216 ('DEB', 'CRITICAL', '7'),
217 ('DEB', 'ERROR', '8'),
218 ('DEB', 'WARNING', '9'),
219 ('DEB', 'INFO', '10'),
220 ('DEB', 'DEBUG', '11'),
221 ])
222
223 def test_nested_explicit(self):
224 # Logging levels in a nested namespace, all explicitly set.
225 m = self.next_message
226
227 INF = logging.getLogger("INF")
228 INF.setLevel(logging.INFO)
229 INF_ERR = logging.getLogger("INF.ERR")
230 INF_ERR.setLevel(logging.ERROR)
231
232 # These should log.
233 INF_ERR.log(logging.CRITICAL, m())
234 INF_ERR.error(m())
235
236 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100237 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000238 INF_ERR.info(m())
239 INF_ERR.debug(m())
240
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000241 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000242 ('INF.ERR', 'CRITICAL', '1'),
243 ('INF.ERR', 'ERROR', '2'),
244 ])
245
246 def test_nested_inherited(self):
247 #Logging levels in a nested namespace, inherited from parent loggers.
248 m = self.next_message
249
250 INF = logging.getLogger("INF")
251 INF.setLevel(logging.INFO)
252 INF_ERR = logging.getLogger("INF.ERR")
253 INF_ERR.setLevel(logging.ERROR)
254 INF_UNDEF = logging.getLogger("INF.UNDEF")
255 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
256 UNDEF = logging.getLogger("UNDEF")
257
258 # These should log.
259 INF_UNDEF.log(logging.CRITICAL, m())
260 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100261 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000262 INF_UNDEF.info(m())
263 INF_ERR_UNDEF.log(logging.CRITICAL, m())
264 INF_ERR_UNDEF.error(m())
265
266 # These should not log.
267 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100268 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000269 INF_ERR_UNDEF.info(m())
270 INF_ERR_UNDEF.debug(m())
271
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000272 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000273 ('INF.UNDEF', 'CRITICAL', '1'),
274 ('INF.UNDEF', 'ERROR', '2'),
275 ('INF.UNDEF', 'WARNING', '3'),
276 ('INF.UNDEF', 'INFO', '4'),
277 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
278 ('INF.ERR.UNDEF', 'ERROR', '6'),
279 ])
280
281 def test_nested_with_virtual_parent(self):
282 # Logging levels when some parent does not exist yet.
283 m = self.next_message
284
285 INF = logging.getLogger("INF")
286 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
287 CHILD = logging.getLogger("INF.BADPARENT")
288 INF.setLevel(logging.INFO)
289
290 # These should log.
291 GRANDCHILD.log(logging.FATAL, m())
292 GRANDCHILD.info(m())
293 CHILD.log(logging.FATAL, m())
294 CHILD.info(m())
295
296 # These should not log.
297 GRANDCHILD.debug(m())
298 CHILD.debug(m())
299
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000300 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000301 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
302 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
303 ('INF.BADPARENT', 'CRITICAL', '3'),
304 ('INF.BADPARENT', 'INFO', '4'),
305 ])
306
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100307 def test_regression_22386(self):
308 """See issue #22386 for more information."""
309 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
310 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000311
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100312 def test_issue27935(self):
313 fatal = logging.getLevelName('FATAL')
314 self.assertEqual(fatal, logging.FATAL)
315
Vinay Sajip924aaae2017-01-11 17:35:36 +0000316 def test_regression_29220(self):
317 """See issue #29220 for more information."""
318 logging.addLevelName(logging.INFO, '')
319 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
320 self.assertEqual(logging.getLevelName(logging.INFO), '')
321 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
322 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
323
Christian Heimes180510d2008-03-03 19:15:45 +0000324class BasicFilterTest(BaseTest):
325
326 """Test the bundled Filter class."""
327
328 def test_filter(self):
329 # Only messages satisfying the specified criteria pass through the
330 # filter.
331 filter_ = logging.Filter("spam.eggs")
332 handler = self.root_logger.handlers[0]
333 try:
334 handler.addFilter(filter_)
335 spam = logging.getLogger("spam")
336 spam_eggs = logging.getLogger("spam.eggs")
337 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
338 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
339
340 spam.info(self.next_message())
341 spam_eggs.info(self.next_message()) # Good.
342 spam_eggs_fish.info(self.next_message()) # Good.
343 spam_bakedbeans.info(self.next_message())
344
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000345 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000346 ('spam.eggs', 'INFO', '2'),
347 ('spam.eggs.fish', 'INFO', '3'),
348 ])
349 finally:
350 handler.removeFilter(filter_)
351
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000352 def test_callable_filter(self):
353 # Only messages satisfying the specified criteria pass through the
354 # filter.
355
356 def filterfunc(record):
357 parts = record.name.split('.')
358 prefix = '.'.join(parts[:2])
359 return prefix == 'spam.eggs'
360
361 handler = self.root_logger.handlers[0]
362 try:
363 handler.addFilter(filterfunc)
364 spam = logging.getLogger("spam")
365 spam_eggs = logging.getLogger("spam.eggs")
366 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
367 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
368
369 spam.info(self.next_message())
370 spam_eggs.info(self.next_message()) # Good.
371 spam_eggs_fish.info(self.next_message()) # Good.
372 spam_bakedbeans.info(self.next_message())
373
374 self.assert_log_lines([
375 ('spam.eggs', 'INFO', '2'),
376 ('spam.eggs.fish', 'INFO', '3'),
377 ])
378 finally:
379 handler.removeFilter(filterfunc)
380
Vinay Sajip985ef872011-04-26 19:34:04 +0100381 def test_empty_filter(self):
382 f = logging.Filter()
383 r = logging.makeLogRecord({'name': 'spam.eggs'})
384 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000385
386#
387# First, we define our levels. There can be as many as you want - the only
388# limitations are that they should be integers, the lowest should be > 0 and
389# larger values mean less information being logged. If you need specific
390# level values which do not fit into these limitations, you can use a
391# mapping dictionary to convert between your application levels and the
392# logging system.
393#
394SILENT = 120
395TACITURN = 119
396TERSE = 118
397EFFUSIVE = 117
398SOCIABLE = 116
399VERBOSE = 115
400TALKATIVE = 114
401GARRULOUS = 113
402CHATTERBOX = 112
403BORING = 111
404
405LEVEL_RANGE = range(BORING, SILENT + 1)
406
407#
408# Next, we define names for our levels. You don't need to do this - in which
409# case the system will use "Level n" to denote the text for the level.
410#
411my_logging_levels = {
412 SILENT : 'Silent',
413 TACITURN : 'Taciturn',
414 TERSE : 'Terse',
415 EFFUSIVE : 'Effusive',
416 SOCIABLE : 'Sociable',
417 VERBOSE : 'Verbose',
418 TALKATIVE : 'Talkative',
419 GARRULOUS : 'Garrulous',
420 CHATTERBOX : 'Chatterbox',
421 BORING : 'Boring',
422}
423
424class GarrulousFilter(logging.Filter):
425
426 """A filter which blocks garrulous messages."""
427
428 def filter(self, record):
429 return record.levelno != GARRULOUS
430
431class VerySpecificFilter(logging.Filter):
432
433 """A filter which blocks sociable and taciturn messages."""
434
435 def filter(self, record):
436 return record.levelno not in [SOCIABLE, TACITURN]
437
438
439class CustomLevelsAndFiltersTest(BaseTest):
440
441 """Test various filtering possibilities with custom logging levels."""
442
443 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300444 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000445
446 def setUp(self):
447 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000448 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000449 logging.addLevelName(k, v)
450
451 def log_at_all_levels(self, logger):
452 for lvl in LEVEL_RANGE:
453 logger.log(lvl, self.next_message())
454
455 def test_logger_filter(self):
456 # Filter at logger level.
457 self.root_logger.setLevel(VERBOSE)
458 # Levels >= 'Verbose' are good.
459 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000460 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000461 ('Verbose', '5'),
462 ('Sociable', '6'),
463 ('Effusive', '7'),
464 ('Terse', '8'),
465 ('Taciturn', '9'),
466 ('Silent', '10'),
467 ])
468
469 def test_handler_filter(self):
470 # Filter at handler level.
471 self.root_logger.handlers[0].setLevel(SOCIABLE)
472 try:
473 # Levels >= 'Sociable' are good.
474 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000475 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000476 ('Sociable', '6'),
477 ('Effusive', '7'),
478 ('Terse', '8'),
479 ('Taciturn', '9'),
480 ('Silent', '10'),
481 ])
482 finally:
483 self.root_logger.handlers[0].setLevel(logging.NOTSET)
484
485 def test_specific_filters(self):
486 # Set a specific filter object on the handler, and then add another
487 # filter object on the logger itself.
488 handler = self.root_logger.handlers[0]
489 specific_filter = None
490 garr = GarrulousFilter()
491 handler.addFilter(garr)
492 try:
493 self.log_at_all_levels(self.root_logger)
494 first_lines = [
495 # Notice how 'Garrulous' is missing
496 ('Boring', '1'),
497 ('Chatterbox', '2'),
498 ('Talkative', '4'),
499 ('Verbose', '5'),
500 ('Sociable', '6'),
501 ('Effusive', '7'),
502 ('Terse', '8'),
503 ('Taciturn', '9'),
504 ('Silent', '10'),
505 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000506 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000507
508 specific_filter = VerySpecificFilter()
509 self.root_logger.addFilter(specific_filter)
510 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000511 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000512 # Not only 'Garrulous' is still missing, but also 'Sociable'
513 # and 'Taciturn'
514 ('Boring', '11'),
515 ('Chatterbox', '12'),
516 ('Talkative', '14'),
517 ('Verbose', '15'),
518 ('Effusive', '17'),
519 ('Terse', '18'),
520 ('Silent', '20'),
521 ])
522 finally:
523 if specific_filter:
524 self.root_logger.removeFilter(specific_filter)
525 handler.removeFilter(garr)
526
527
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100528class HandlerTest(BaseTest):
529 def test_name(self):
530 h = logging.Handler()
531 h.name = 'generic'
532 self.assertEqual(h.name, 'generic')
533 h.name = 'anothergeneric'
534 self.assertEqual(h.name, 'anothergeneric')
535 self.assertRaises(NotImplementedError, h.emit, None)
536
Vinay Sajip5a35b062011-04-27 11:31:14 +0100537 def test_builtin_handlers(self):
538 # We can't actually *use* too many handlers in the tests,
539 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200540 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100541 for existing in (True, False):
542 fd, fn = tempfile.mkstemp()
543 os.close(fd)
544 if not existing:
545 os.unlink(fn)
546 h = logging.handlers.WatchedFileHandler(fn, delay=True)
547 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100548 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100549 self.assertEqual(dev, -1)
550 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100551 r = logging.makeLogRecord({'msg': 'Test'})
552 h.handle(r)
553 # Now remove the file.
554 os.unlink(fn)
555 self.assertFalse(os.path.exists(fn))
556 # The next call should recreate the file.
557 h.handle(r)
558 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100559 else:
560 self.assertEqual(h.dev, -1)
561 self.assertEqual(h.ino, -1)
562 h.close()
563 if existing:
564 os.unlink(fn)
565 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100566 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100567 else:
568 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100569 try:
570 h = logging.handlers.SysLogHandler(sockname)
571 self.assertEqual(h.facility, h.LOG_USER)
572 self.assertTrue(h.unixsocket)
573 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200574 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100575 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100576 for method in ('GET', 'POST', 'PUT'):
577 if method == 'PUT':
578 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
579 'localhost', '/log', method)
580 else:
581 h = logging.handlers.HTTPHandler('localhost', '/log', method)
582 h.close()
583 h = logging.handlers.BufferingHandler(0)
584 r = logging.makeLogRecord({})
585 self.assertTrue(h.shouldFlush(r))
586 h.close()
587 h = logging.handlers.BufferingHandler(1)
588 self.assertFalse(h.shouldFlush(r))
589 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100590
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100591 def test_path_objects(self):
592 """
593 Test that Path objects are accepted as filename arguments to handlers.
594
595 See Issue #27493.
596 """
597 fd, fn = tempfile.mkstemp()
598 os.close(fd)
599 os.unlink(fn)
600 pfn = pathlib.Path(fn)
601 cases = (
602 (logging.FileHandler, (pfn, 'w')),
603 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
604 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
605 )
606 if sys.platform in ('linux', 'darwin'):
607 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
608 for cls, args in cases:
609 h = cls(*args)
610 self.assertTrue(os.path.exists(fn))
611 h.close()
612 os.unlink(fn)
613
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100614 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100615 @unittest.skipUnless(threading, 'Threading required for this test.')
616 def test_race(self):
617 # Issue #14632 refers.
618 def remove_loop(fname, tries):
619 for _ in range(tries):
620 try:
621 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000622 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623 except OSError:
624 pass
625 time.sleep(0.004 * random.randint(0, 4))
626
Vinay Sajipc94871a2012-04-25 10:51:35 +0100627 del_count = 500
628 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100629
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000630 self.handle_time = None
631 self.deletion_time = None
632
Vinay Sajipa5798de2012-04-24 23:33:33 +0100633 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100634 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
635 os.close(fd)
636 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
637 remover.daemon = True
638 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100639 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100640 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
641 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100642 try:
643 for _ in range(log_count):
644 time.sleep(0.005)
645 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000646 try:
647 self.handle_time = time.time()
648 h.handle(r)
649 except Exception:
650 print('Deleted at %s, '
651 'opened at %s' % (self.deletion_time,
652 self.handle_time))
653 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100654 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100655 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100656 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100657 if os.path.exists(fn):
658 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100659
660
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100661class BadStream(object):
662 def write(self, data):
663 raise RuntimeError('deliberate mistake')
664
665class TestStreamHandler(logging.StreamHandler):
666 def handleError(self, record):
667 self.error_record = record
668
669class StreamHandlerTest(BaseTest):
670 def test_error_handling(self):
671 h = TestStreamHandler(BadStream())
672 r = logging.makeLogRecord({})
673 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100674
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100675 try:
676 h.handle(r)
677 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100678
Vinay Sajip985ef872011-04-26 19:34:04 +0100679 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100680 with support.captured_stderr() as stderr:
681 h.handle(r)
682 msg = '\nRuntimeError: deliberate mistake\n'
683 self.assertIn(msg, stderr.getvalue())
684
Vinay Sajip985ef872011-04-26 19:34:04 +0100685 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100686 with support.captured_stderr() as stderr:
687 h.handle(r)
688 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100689 finally:
690 logging.raiseExceptions = old_raise
691
Vinay Sajip7367d082011-05-02 13:17:27 +0100692# -- The following section could be moved into a server_helper.py module
693# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100694
Vinay Sajipce7c9782011-05-17 07:15:53 +0100695if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100696 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100697 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100698 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100699
Vinay Sajipce7c9782011-05-17 07:15:53 +0100700 :param addr: A (host, port) tuple which the server listens on.
701 You can specify a port value of zero: the server's
702 *port* attribute will hold the actual port number
703 used, which can be used in client connections.
704 :param handler: A callable which will be called to process
705 incoming messages. The handler will be passed
706 the client address tuple, who the message is from,
707 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100708 :param poll_interval: The interval, in seconds, used in the underlying
709 :func:`select` or :func:`poll` call by
710 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100711 :param sockmap: A dictionary which will be used to hold
712 :class:`asyncore.dispatcher` instances used by
713 :func:`asyncore.loop`. This avoids changing the
714 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100715 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100716
717 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400718 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
719 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100720 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 self._handler = handler
722 self._thread = None
723 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100724
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 def process_message(self, peer, mailfrom, rcpttos, data):
726 """
727 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100728
Vinay Sajipce7c9782011-05-17 07:15:53 +0100729 Typically, this will be a test case method.
730 :param peer: The client (host, port) tuple.
731 :param mailfrom: The address of the sender.
732 :param rcpttos: The addresses of the recipients.
733 :param data: The message.
734 """
735 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100736
Vinay Sajipce7c9782011-05-17 07:15:53 +0100737 def start(self):
738 """
739 Start the server running on a separate daemon thread.
740 """
741 self._thread = t = threading.Thread(target=self.serve_forever,
742 args=(self.poll_interval,))
743 t.setDaemon(True)
744 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100745
Vinay Sajipce7c9782011-05-17 07:15:53 +0100746 def serve_forever(self, poll_interval):
747 """
748 Run the :mod:`asyncore` loop until normal termination
749 conditions arise.
750 :param poll_interval: The interval, in seconds, used in the underlying
751 :func:`select` or :func:`poll` call by
752 :func:`asyncore.loop`.
753 """
754 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100755 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200756 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100757 # On FreeBSD 8, closing the server repeatably
758 # raises this error. We swallow it if the
759 # server has been closed.
760 if self.connected or self.accepting:
761 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100762
Vinay Sajipce7c9782011-05-17 07:15:53 +0100763 def stop(self, timeout=None):
764 """
765 Stop the thread by closing the server instance.
766 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100767
Vinay Sajipce7c9782011-05-17 07:15:53 +0100768 :param timeout: How long to wait for the server thread
769 to terminate.
770 """
771 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100772 self._thread.join(timeout)
773 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100774
Vinay Sajipce7c9782011-05-17 07:15:53 +0100775 class ControlMixin(object):
776 """
777 This mixin is used to start a server on a separate thread, and
778 shut it down programmatically. Request handling is simplified - instead
779 of needing to derive a suitable RequestHandler subclass, you just
780 provide a callable which will be passed each received request to be
781 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100782
Vinay Sajipce7c9782011-05-17 07:15:53 +0100783 :param handler: A handler callable which will be called with a
784 single parameter - the request - in order to
785 process the request. This handler is called on the
786 server thread, effectively meaning that requests are
787 processed serially. While not quite Web scale ;-),
788 this should be fine for testing applications.
789 :param poll_interval: The polling interval in seconds.
790 """
791 def __init__(self, handler, poll_interval):
792 self._thread = None
793 self.poll_interval = poll_interval
794 self._handler = handler
795 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100796
Vinay Sajipce7c9782011-05-17 07:15:53 +0100797 def start(self):
798 """
799 Create a daemon thread to run the server, and start it.
800 """
801 self._thread = t = threading.Thread(target=self.serve_forever,
802 args=(self.poll_interval,))
803 t.setDaemon(True)
804 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100805
Vinay Sajipce7c9782011-05-17 07:15:53 +0100806 def serve_forever(self, poll_interval):
807 """
808 Run the server. Set the ready flag before entering the
809 service loop.
810 """
811 self.ready.set()
812 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 def stop(self, timeout=None):
815 """
816 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100817
Vinay Sajipce7c9782011-05-17 07:15:53 +0100818 :param timeout: How long to wait for the server thread
819 to terminate.
820 """
821 self.shutdown()
822 if self._thread is not None:
823 self._thread.join(timeout)
824 self._thread = None
825 self.server_close()
826 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100827
Vinay Sajipce7c9782011-05-17 07:15:53 +0100828 class TestHTTPServer(ControlMixin, HTTPServer):
829 """
830 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100831
Vinay Sajipce7c9782011-05-17 07:15:53 +0100832 :param addr: A tuple with the IP address and port to listen on.
833 :param handler: A handler callable which will be called with a
834 single parameter - the request - in order to
835 process the request.
836 :param poll_interval: The polling interval in seconds.
837 :param log: Pass ``True`` to enable log messages.
838 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100839 def __init__(self, addr, handler, poll_interval=0.5,
840 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
842 def __getattr__(self, name, default=None):
843 if name.startswith('do_'):
844 return self.process_request
845 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100846
Vinay Sajipce7c9782011-05-17 07:15:53 +0100847 def process_request(self):
848 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100849
Vinay Sajipce7c9782011-05-17 07:15:53 +0100850 def log_message(self, format, *args):
851 if log:
852 super(DelegatingHTTPRequestHandler,
853 self).log_message(format, *args)
854 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
855 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100856 self.sslctx = sslctx
857
858 def get_request(self):
859 try:
860 sock, addr = self.socket.accept()
861 if self.sslctx:
862 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200863 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100864 # socket errors are silenced by the caller, print them here
865 sys.stderr.write("Got an error:\n%s\n" % e)
866 raise
867 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100868
Vinay Sajipce7c9782011-05-17 07:15:53 +0100869 class TestTCPServer(ControlMixin, ThreadingTCPServer):
870 """
871 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100872
Vinay Sajipce7c9782011-05-17 07:15:53 +0100873 :param addr: A tuple with the IP address and port to listen on.
874 :param handler: A handler callable which will be called with a single
875 parameter - the request - in order to process the request.
876 :param poll_interval: The polling interval in seconds.
877 :bind_and_activate: If True (the default), binds the server and starts it
878 listening. If False, you need to call
879 :meth:`server_bind` and :meth:`server_activate` at
880 some later time before calling :meth:`start`, so that
881 the server will set up the socket and listen on it.
882 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100883
Vinay Sajipce7c9782011-05-17 07:15:53 +0100884 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100885
Vinay Sajipce7c9782011-05-17 07:15:53 +0100886 def __init__(self, addr, handler, poll_interval=0.5,
887 bind_and_activate=True):
888 class DelegatingTCPRequestHandler(StreamRequestHandler):
889
890 def handle(self):
891 self.server._handler(self)
892 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
893 bind_and_activate)
894 ControlMixin.__init__(self, handler, poll_interval)
895
896 def server_bind(self):
897 super(TestTCPServer, self).server_bind()
898 self.port = self.socket.getsockname()[1]
899
900 class TestUDPServer(ControlMixin, ThreadingUDPServer):
901 """
902 A UDP server which is controllable using :class:`ControlMixin`.
903
904 :param addr: A tuple with the IP address and port to listen on.
905 :param handler: A handler callable which will be called with a
906 single parameter - the request - in order to
907 process the request.
908 :param poll_interval: The polling interval for shutdown requests,
909 in seconds.
910 :bind_and_activate: If True (the default), binds the server and
911 starts it listening. If False, you need to
912 call :meth:`server_bind` and
913 :meth:`server_activate` at some later time
914 before calling :meth:`start`, so that the server will
915 set up the socket and listen on it.
916 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100917 def __init__(self, addr, handler, poll_interval=0.5,
918 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100919 class DelegatingUDPRequestHandler(DatagramRequestHandler):
920
921 def handle(self):
922 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100923
924 def finish(self):
925 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100926 if data:
927 try:
928 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200929 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100930 if not self.server._closed:
931 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100932
Vinay Sajip3ef12292011-05-23 23:00:42 +0100933 ThreadingUDPServer.__init__(self, addr,
934 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100935 bind_and_activate)
936 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100937 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100938
939 def server_bind(self):
940 super(TestUDPServer, self).server_bind()
941 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100942
Vinay Sajipba980db2011-05-23 21:37:54 +0100943 def server_close(self):
944 super(TestUDPServer, self).server_close()
945 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100946
Victor Stinnerec5a8602014-06-02 14:41:51 +0200947 if hasattr(socket, "AF_UNIX"):
948 class TestUnixStreamServer(TestTCPServer):
949 address_family = socket.AF_UNIX
950
951 class TestUnixDatagramServer(TestUDPServer):
952 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100953
Vinay Sajip7367d082011-05-02 13:17:27 +0100954# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100955
Vinay Sajipce7c9782011-05-17 07:15:53 +0100956@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100957class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000958 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100959 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100960 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800961 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100962 sockmap)
963 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800964 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000965 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
966 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100967 self.assertEqual(h.toaddrs, ['you'])
968 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100969 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100970 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100971 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000972 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100973 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000974 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100975 self.assertEqual(len(self.messages), 1)
976 peer, mailfrom, rcpttos, data = self.messages[0]
977 self.assertEqual(mailfrom, 'me')
978 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100979 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100980 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100981 h.close()
982
983 def process_message(self, *args):
984 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100985 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100986
Christian Heimes180510d2008-03-03 19:15:45 +0000987class MemoryHandlerTest(BaseTest):
988
989 """Tests for the MemoryHandler."""
990
991 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300992 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000993
994 def setUp(self):
995 BaseTest.setUp(self)
996 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100997 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +0000998 self.mem_logger = logging.getLogger('mem')
999 self.mem_logger.propagate = 0
1000 self.mem_logger.addHandler(self.mem_hdlr)
1001
1002 def tearDown(self):
1003 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001004 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001005
1006 def test_flush(self):
1007 # The memory handler flushes to its target handler based on specific
1008 # criteria (message count and message level).
1009 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001010 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001011 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001012 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001013 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001014 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001015 lines = [
1016 ('DEBUG', '1'),
1017 ('INFO', '2'),
1018 ('WARNING', '3'),
1019 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001020 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001021 for n in (4, 14):
1022 for i in range(9):
1023 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001024 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001025 # This will flush because it's the 10th message since the last
1026 # flush.
1027 self.mem_logger.debug(self.next_message())
1028 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001029 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001030
1031 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001032 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001033
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001034 def test_flush_on_close(self):
1035 """
1036 Test that the flush-on-close configuration works as expected.
1037 """
1038 self.mem_logger.debug(self.next_message())
1039 self.assert_log_lines([])
1040 self.mem_logger.info(self.next_message())
1041 self.assert_log_lines([])
1042 self.mem_logger.removeHandler(self.mem_hdlr)
1043 # Default behaviour is to flush on close. Check that it happens.
1044 self.mem_hdlr.close()
1045 lines = [
1046 ('DEBUG', '1'),
1047 ('INFO', '2'),
1048 ]
1049 self.assert_log_lines(lines)
1050 # Now configure for flushing not to be done on close.
1051 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1052 self.root_hdlr,
1053 False)
1054 self.mem_logger.addHandler(self.mem_hdlr)
1055 self.mem_logger.debug(self.next_message())
1056 self.assert_log_lines(lines) # no change
1057 self.mem_logger.info(self.next_message())
1058 self.assert_log_lines(lines) # no change
1059 self.mem_logger.removeHandler(self.mem_hdlr)
1060 self.mem_hdlr.close()
1061 # assert that no new lines have been added
1062 self.assert_log_lines(lines) # no change
1063
Christian Heimes180510d2008-03-03 19:15:45 +00001064
1065class ExceptionFormatter(logging.Formatter):
1066 """A special exception formatter."""
1067 def formatException(self, ei):
1068 return "Got a [%s]" % ei[0].__name__
1069
1070
1071class ConfigFileTest(BaseTest):
1072
1073 """Reading logging config from a .ini-style config file."""
1074
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001075 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001076
1077 # config0 is a standard configuration.
1078 config0 = """
1079 [loggers]
1080 keys=root
1081
1082 [handlers]
1083 keys=hand1
1084
1085 [formatters]
1086 keys=form1
1087
1088 [logger_root]
1089 level=WARNING
1090 handlers=hand1
1091
1092 [handler_hand1]
1093 class=StreamHandler
1094 level=NOTSET
1095 formatter=form1
1096 args=(sys.stdout,)
1097
1098 [formatter_form1]
1099 format=%(levelname)s ++ %(message)s
1100 datefmt=
1101 """
1102
1103 # config1 adds a little to the standard configuration.
1104 config1 = """
1105 [loggers]
1106 keys=root,parser
1107
1108 [handlers]
1109 keys=hand1
1110
1111 [formatters]
1112 keys=form1
1113
1114 [logger_root]
1115 level=WARNING
1116 handlers=
1117
1118 [logger_parser]
1119 level=DEBUG
1120 handlers=hand1
1121 propagate=1
1122 qualname=compiler.parser
1123
1124 [handler_hand1]
1125 class=StreamHandler
1126 level=NOTSET
1127 formatter=form1
1128 args=(sys.stdout,)
1129
1130 [formatter_form1]
1131 format=%(levelname)s ++ %(message)s
1132 datefmt=
1133 """
1134
Vinay Sajip3f84b072011-03-07 17:49:33 +00001135 # config1a moves the handler to the root.
1136 config1a = """
1137 [loggers]
1138 keys=root,parser
1139
1140 [handlers]
1141 keys=hand1
1142
1143 [formatters]
1144 keys=form1
1145
1146 [logger_root]
1147 level=WARNING
1148 handlers=hand1
1149
1150 [logger_parser]
1151 level=DEBUG
1152 handlers=
1153 propagate=1
1154 qualname=compiler.parser
1155
1156 [handler_hand1]
1157 class=StreamHandler
1158 level=NOTSET
1159 formatter=form1
1160 args=(sys.stdout,)
1161
1162 [formatter_form1]
1163 format=%(levelname)s ++ %(message)s
1164 datefmt=
1165 """
1166
Christian Heimes180510d2008-03-03 19:15:45 +00001167 # config2 has a subtle configuration error that should be reported
1168 config2 = config1.replace("sys.stdout", "sys.stbout")
1169
1170 # config3 has a less subtle configuration error
1171 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1172
1173 # config4 specifies a custom formatter class to be loaded
1174 config4 = """
1175 [loggers]
1176 keys=root
1177
1178 [handlers]
1179 keys=hand1
1180
1181 [formatters]
1182 keys=form1
1183
1184 [logger_root]
1185 level=NOTSET
1186 handlers=hand1
1187
1188 [handler_hand1]
1189 class=StreamHandler
1190 level=NOTSET
1191 formatter=form1
1192 args=(sys.stdout,)
1193
1194 [formatter_form1]
1195 class=""" + __name__ + """.ExceptionFormatter
1196 format=%(levelname)s:%(name)s:%(message)s
1197 datefmt=
1198 """
1199
Georg Brandl3dbca812008-07-23 16:10:53 +00001200 # config5 specifies a custom handler class to be loaded
1201 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1202
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001203 # config6 uses ', ' delimiters in the handlers and formatters sections
1204 config6 = """
1205 [loggers]
1206 keys=root,parser
1207
1208 [handlers]
1209 keys=hand1, hand2
1210
1211 [formatters]
1212 keys=form1, form2
1213
1214 [logger_root]
1215 level=WARNING
1216 handlers=
1217
1218 [logger_parser]
1219 level=DEBUG
1220 handlers=hand1
1221 propagate=1
1222 qualname=compiler.parser
1223
1224 [handler_hand1]
1225 class=StreamHandler
1226 level=NOTSET
1227 formatter=form1
1228 args=(sys.stdout,)
1229
1230 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001231 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001232 level=NOTSET
1233 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001234 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001235
1236 [formatter_form1]
1237 format=%(levelname)s ++ %(message)s
1238 datefmt=
1239
1240 [formatter_form2]
1241 format=%(message)s
1242 datefmt=
1243 """
1244
Vinay Sajip3f84b072011-03-07 17:49:33 +00001245 # config7 adds a compiler logger.
1246 config7 = """
1247 [loggers]
1248 keys=root,parser,compiler
1249
1250 [handlers]
1251 keys=hand1
1252
1253 [formatters]
1254 keys=form1
1255
1256 [logger_root]
1257 level=WARNING
1258 handlers=hand1
1259
1260 [logger_compiler]
1261 level=DEBUG
1262 handlers=
1263 propagate=1
1264 qualname=compiler
1265
1266 [logger_parser]
1267 level=DEBUG
1268 handlers=
1269 propagate=1
1270 qualname=compiler.parser
1271
1272 [handler_hand1]
1273 class=StreamHandler
1274 level=NOTSET
1275 formatter=form1
1276 args=(sys.stdout,)
1277
1278 [formatter_form1]
1279 format=%(levelname)s ++ %(message)s
1280 datefmt=
1281 """
1282
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001283 disable_test = """
1284 [loggers]
1285 keys=root
1286
1287 [handlers]
1288 keys=screen
1289
1290 [formatters]
1291 keys=
1292
1293 [logger_root]
1294 level=DEBUG
1295 handlers=screen
1296
1297 [handler_screen]
1298 level=DEBUG
1299 class=StreamHandler
1300 args=(sys.stdout,)
1301 formatter=
1302 """
1303
1304 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001305 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001306 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001307
1308 def test_config0_ok(self):
1309 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001310 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001311 self.apply_config(self.config0)
1312 logger = logging.getLogger()
1313 # Won't output anything
1314 logger.info(self.next_message())
1315 # Outputs a message
1316 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001317 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001318 ('ERROR', '2'),
1319 ], stream=output)
1320 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001321 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001322
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001323 def test_config0_using_cp_ok(self):
1324 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001325 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001326 file = io.StringIO(textwrap.dedent(self.config0))
1327 cp = configparser.ConfigParser()
1328 cp.read_file(file)
1329 logging.config.fileConfig(cp)
1330 logger = logging.getLogger()
1331 # Won't output anything
1332 logger.info(self.next_message())
1333 # Outputs a message
1334 logger.error(self.next_message())
1335 self.assert_log_lines([
1336 ('ERROR', '2'),
1337 ], stream=output)
1338 # Original logger output is empty.
1339 self.assert_log_lines([])
1340
Georg Brandl3dbca812008-07-23 16:10:53 +00001341 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001342 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001343 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001344 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001345 logger = logging.getLogger("compiler.parser")
1346 # Both will output a message
1347 logger.info(self.next_message())
1348 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001349 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001350 ('INFO', '1'),
1351 ('ERROR', '2'),
1352 ], stream=output)
1353 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001354 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001355
1356 def test_config2_failure(self):
1357 # A simple config file which overrides the default settings.
1358 self.assertRaises(Exception, self.apply_config, self.config2)
1359
1360 def test_config3_failure(self):
1361 # A simple config file which overrides the default settings.
1362 self.assertRaises(Exception, self.apply_config, self.config3)
1363
1364 def test_config4_ok(self):
1365 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001366 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001367 self.apply_config(self.config4)
1368 logger = logging.getLogger()
1369 try:
1370 raise RuntimeError()
1371 except RuntimeError:
1372 logging.exception("just testing")
1373 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001374 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001375 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1376 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001377 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001378
Georg Brandl3dbca812008-07-23 16:10:53 +00001379 def test_config5_ok(self):
1380 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001381
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001382 def test_config6_ok(self):
1383 self.test_config1_ok(config=self.config6)
1384
Vinay Sajip3f84b072011-03-07 17:49:33 +00001385 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001386 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001387 self.apply_config(self.config1a)
1388 logger = logging.getLogger("compiler.parser")
1389 # See issue #11424. compiler-hyphenated sorts
1390 # between compiler and compiler.xyz and this
1391 # was preventing compiler.xyz from being included
1392 # in the child loggers of compiler because of an
1393 # overzealous loop termination condition.
1394 hyphenated = logging.getLogger('compiler-hyphenated')
1395 # All will output a message
1396 logger.info(self.next_message())
1397 logger.error(self.next_message())
1398 hyphenated.critical(self.next_message())
1399 self.assert_log_lines([
1400 ('INFO', '1'),
1401 ('ERROR', '2'),
1402 ('CRITICAL', '3'),
1403 ], stream=output)
1404 # Original logger output is empty.
1405 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001406 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001407 self.apply_config(self.config7)
1408 logger = logging.getLogger("compiler.parser")
1409 self.assertFalse(logger.disabled)
1410 # Both will output a message
1411 logger.info(self.next_message())
1412 logger.error(self.next_message())
1413 logger = logging.getLogger("compiler.lexer")
1414 # Both will output a message
1415 logger.info(self.next_message())
1416 logger.error(self.next_message())
1417 # Will not appear
1418 hyphenated.critical(self.next_message())
1419 self.assert_log_lines([
1420 ('INFO', '4'),
1421 ('ERROR', '5'),
1422 ('INFO', '6'),
1423 ('ERROR', '7'),
1424 ], stream=output)
1425 # Original logger output is empty.
1426 self.assert_log_lines([])
1427
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001428 def test_logger_disabling(self):
1429 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001430 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001431 self.assertFalse(logger.disabled)
1432 self.apply_config(self.disable_test)
1433 self.assertTrue(logger.disabled)
1434 self.apply_config(self.disable_test, disable_existing_loggers=False)
1435 self.assertFalse(logger.disabled)
1436
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001437
Victor Stinner45df8202010-04-28 22:31:17 +00001438@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001439class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001440
Christian Heimes180510d2008-03-03 19:15:45 +00001441 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001442
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001443 if threading:
1444 server_class = TestTCPServer
1445 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001446
Christian Heimes180510d2008-03-03 19:15:45 +00001447 def setUp(self):
1448 """Set up a TCP server to receive log messages, and a SocketHandler
1449 pointing to that server's address and port."""
1450 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001451 # Issue #29177: deal with errors that happen during setup
1452 self.server = self.sock_hdlr = self.server_exception = None
1453 try:
1454 self.server = server = self.server_class(self.address,
1455 self.handle_socket, 0.01)
1456 server.start()
1457 # Uncomment next line to test error recovery in setUp()
1458 # raise OSError('dummy error raised')
1459 except OSError as e:
1460 self.server_exception = e
1461 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001462 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001463 hcls = logging.handlers.SocketHandler
1464 if isinstance(server.server_address, tuple):
1465 self.sock_hdlr = hcls('localhost', server.port)
1466 else:
1467 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001468 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001469 self.root_logger.removeHandler(self.root_logger.handlers[0])
1470 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001471 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001472
Christian Heimes180510d2008-03-03 19:15:45 +00001473 def tearDown(self):
1474 """Shutdown the TCP server."""
1475 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001476 if self.server:
1477 self.server.stop(2.0)
1478 if self.sock_hdlr:
1479 self.root_logger.removeHandler(self.sock_hdlr)
1480 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001481 finally:
1482 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001483
Vinay Sajip7367d082011-05-02 13:17:27 +01001484 def handle_socket(self, request):
1485 conn = request.connection
1486 while True:
1487 chunk = conn.recv(4)
1488 if len(chunk) < 4:
1489 break
1490 slen = struct.unpack(">L", chunk)[0]
1491 chunk = conn.recv(slen)
1492 while len(chunk) < slen:
1493 chunk = chunk + conn.recv(slen - len(chunk))
1494 obj = pickle.loads(chunk)
1495 record = logging.makeLogRecord(obj)
1496 self.log_output += record.msg + '\n'
1497 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001498
Christian Heimes180510d2008-03-03 19:15:45 +00001499 def test_output(self):
1500 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001501 if self.server_exception:
1502 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001503 logger = logging.getLogger("tcp")
1504 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001505 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001506 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001507 self.handled.acquire()
1508 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001509
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001510 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001511 if self.server_exception:
1512 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001513 # Avoid timing-related failures due to SocketHandler's own hard-wired
1514 # one-second timeout on socket.create_connection() (issue #16264).
1515 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001516 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001517 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001518 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001519 try:
1520 raise RuntimeError('Deliberate mistake')
1521 except RuntimeError:
1522 self.root_logger.exception('Never sent')
1523 self.root_logger.error('Never sent, either')
1524 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001525 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001526 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1527 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001528
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001529def _get_temp_domain_socket():
1530 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1531 os.close(fd)
1532 # just need a name - file can't be present, or we'll get an
1533 # 'address already in use' error.
1534 os.remove(fn)
1535 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001536
Victor Stinnerec5a8602014-06-02 14:41:51 +02001537@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001538@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001539class UnixSocketHandlerTest(SocketHandlerTest):
1540
1541 """Test for SocketHandler with unix sockets."""
1542
Victor Stinnerec5a8602014-06-02 14:41:51 +02001543 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001544 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001545
1546 def setUp(self):
1547 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001548 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001549 SocketHandlerTest.setUp(self)
1550
1551 def tearDown(self):
1552 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001553 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001554
1555@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001556class DatagramHandlerTest(BaseTest):
1557
1558 """Test for DatagramHandler."""
1559
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001560 if threading:
1561 server_class = TestUDPServer
1562 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001563
Vinay Sajip7367d082011-05-02 13:17:27 +01001564 def setUp(self):
1565 """Set up a UDP server to receive log messages, and a DatagramHandler
1566 pointing to that server's address and port."""
1567 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001568 # Issue #29177: deal with errors that happen during setup
1569 self.server = self.sock_hdlr = self.server_exception = None
1570 try:
1571 self.server = server = self.server_class(self.address,
1572 self.handle_datagram, 0.01)
1573 server.start()
1574 # Uncomment next line to test error recovery in setUp()
1575 # raise OSError('dummy error raised')
1576 except OSError as e:
1577 self.server_exception = e
1578 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001579 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001580 hcls = logging.handlers.DatagramHandler
1581 if isinstance(server.server_address, tuple):
1582 self.sock_hdlr = hcls('localhost', server.port)
1583 else:
1584 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001585 self.log_output = ''
1586 self.root_logger.removeHandler(self.root_logger.handlers[0])
1587 self.root_logger.addHandler(self.sock_hdlr)
1588 self.handled = threading.Event()
1589
1590 def tearDown(self):
1591 """Shutdown the UDP server."""
1592 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001593 if self.server:
1594 self.server.stop(2.0)
1595 if self.sock_hdlr:
1596 self.root_logger.removeHandler(self.sock_hdlr)
1597 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001598 finally:
1599 BaseTest.tearDown(self)
1600
1601 def handle_datagram(self, request):
1602 slen = struct.pack('>L', 0) # length of prefix
1603 packet = request.packet[len(slen):]
1604 obj = pickle.loads(packet)
1605 record = logging.makeLogRecord(obj)
1606 self.log_output += record.msg + '\n'
1607 self.handled.set()
1608
1609 def test_output(self):
1610 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001611 if self.server_exception:
1612 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001613 logger = logging.getLogger("udp")
1614 logger.error("spam")
1615 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001616 self.handled.clear()
1617 logger.error("eggs")
1618 self.handled.wait()
1619 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001620
Victor Stinnerec5a8602014-06-02 14:41:51 +02001621@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001622@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001623class UnixDatagramHandlerTest(DatagramHandlerTest):
1624
1625 """Test for DatagramHandler using Unix sockets."""
1626
Victor Stinnerec5a8602014-06-02 14:41:51 +02001627 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001628 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001629
1630 def setUp(self):
1631 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001632 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001633 DatagramHandlerTest.setUp(self)
1634
1635 def tearDown(self):
1636 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001637 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001638
1639@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001640class SysLogHandlerTest(BaseTest):
1641
1642 """Test for SysLogHandler using UDP."""
1643
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001644 if threading:
1645 server_class = TestUDPServer
1646 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001647
Vinay Sajip7367d082011-05-02 13:17:27 +01001648 def setUp(self):
1649 """Set up a UDP server to receive log messages, and a SysLogHandler
1650 pointing to that server's address and port."""
1651 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001652 # Issue #29177: deal with errors that happen during setup
1653 self.server = self.sl_hdlr = self.server_exception = None
1654 try:
1655 self.server = server = self.server_class(self.address,
1656 self.handle_datagram, 0.01)
1657 server.start()
1658 # Uncomment next line to test error recovery in setUp()
1659 # raise OSError('dummy error raised')
1660 except OSError as e:
1661 self.server_exception = e
1662 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001663 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001664 hcls = logging.handlers.SysLogHandler
1665 if isinstance(server.server_address, tuple):
Xiang Zhang95b4da22017-06-01 22:20:27 +08001666 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001667 else:
1668 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001669 self.log_output = ''
1670 self.root_logger.removeHandler(self.root_logger.handlers[0])
1671 self.root_logger.addHandler(self.sl_hdlr)
1672 self.handled = threading.Event()
1673
1674 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001675 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001676 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001677 if self.server:
1678 self.server.stop(2.0)
1679 if self.sl_hdlr:
1680 self.root_logger.removeHandler(self.sl_hdlr)
1681 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001682 finally:
1683 BaseTest.tearDown(self)
1684
1685 def handle_datagram(self, request):
1686 self.log_output = request.packet
1687 self.handled.set()
1688
1689 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001690 if self.server_exception:
1691 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001692 # The log message sent to the SysLogHandler is properly received.
1693 logger = logging.getLogger("slh")
1694 logger.error("sp\xe4m")
1695 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001696 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001697 self.handled.clear()
1698 self.sl_hdlr.append_nul = False
1699 logger.error("sp\xe4m")
1700 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001701 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001702 self.handled.clear()
1703 self.sl_hdlr.ident = "h\xe4m-"
1704 logger.error("sp\xe4m")
1705 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001706 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001707
Victor Stinnerec5a8602014-06-02 14:41:51 +02001708@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001709@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001710class UnixSysLogHandlerTest(SysLogHandlerTest):
1711
1712 """Test for SysLogHandler with Unix sockets."""
1713
Victor Stinnerec5a8602014-06-02 14:41:51 +02001714 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001715 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001716
1717 def setUp(self):
1718 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001719 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001720 SysLogHandlerTest.setUp(self)
1721
1722 def tearDown(self):
1723 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001724 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001725
Xiang Zhang95b4da22017-06-01 22:20:27 +08001726@unittest.skipUnless(support.IPV6_ENABLED,
1727 'IPv6 support required for this test.')
1728@unittest.skipUnless(threading, 'Threading required for this test.')
1729class IPv6SysLogHandlerTest(SysLogHandlerTest):
1730
1731 """Test for SysLogHandler with IPv6 host."""
1732
1733 server_class = TestUDPServer
1734 address = ('::1', 0)
1735
1736 def setUp(self):
1737 self.server_class.address_family = socket.AF_INET6
1738 super(IPv6SysLogHandlerTest, self).setUp()
1739
1740 def tearDown(self):
1741 self.server_class.address_family = socket.AF_INET
1742 super(IPv6SysLogHandlerTest, self).tearDown()
1743
Vinay Sajip5421f352013-09-27 18:18:28 +01001744@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001745class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001746 """Test for HTTPHandler."""
1747
1748 def setUp(self):
1749 """Set up an HTTP server to receive log messages, and a HTTPHandler
1750 pointing to that server's address and port."""
1751 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001752 self.handled = threading.Event()
1753
Vinay Sajip7367d082011-05-02 13:17:27 +01001754 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001755 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001756 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001757 if self.command == 'POST':
1758 try:
1759 rlen = int(request.headers['Content-Length'])
1760 self.post_data = request.rfile.read(rlen)
1761 except:
1762 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001763 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001764 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001765 self.handled.set()
1766
1767 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001768 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001769 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001770 root_logger = self.root_logger
1771 root_logger.removeHandler(self.root_logger.handlers[0])
1772 for secure in (False, True):
1773 addr = ('localhost', 0)
1774 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001775 try:
1776 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001777 except ImportError:
1778 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001779 else:
1780 here = os.path.dirname(__file__)
1781 localhost_cert = os.path.join(here, "keycert.pem")
1782 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1783 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001784
1785 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001786 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001787 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001788 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001789 self.server = server = TestHTTPServer(addr, self.handle_request,
1790 0.01, sslctx=sslctx)
1791 server.start()
1792 server.ready.wait()
1793 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001794 secure_client = secure and sslctx
1795 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001796 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001797 context=context,
1798 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001799 self.log_data = None
1800 root_logger.addHandler(self.h_hdlr)
1801
1802 for method in ('GET', 'POST'):
1803 self.h_hdlr.method = method
1804 self.handled.clear()
1805 msg = "sp\xe4m"
1806 logger.error(msg)
1807 self.handled.wait()
1808 self.assertEqual(self.log_data.path, '/frob')
1809 self.assertEqual(self.command, method)
1810 if method == 'GET':
1811 d = parse_qs(self.log_data.query)
1812 else:
1813 d = parse_qs(self.post_data.decode('utf-8'))
1814 self.assertEqual(d['name'], ['http'])
1815 self.assertEqual(d['funcName'], ['test_output'])
1816 self.assertEqual(d['msg'], [msg])
1817
1818 self.server.stop(2.0)
1819 self.root_logger.removeHandler(self.h_hdlr)
1820 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001821
Christian Heimes180510d2008-03-03 19:15:45 +00001822class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001823
Christian Heimes180510d2008-03-03 19:15:45 +00001824 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001825
Christian Heimes180510d2008-03-03 19:15:45 +00001826 def setUp(self):
1827 """Create a dict to remember potentially destroyed objects."""
1828 BaseTest.setUp(self)
1829 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001830
Christian Heimes180510d2008-03-03 19:15:45 +00001831 def _watch_for_survival(self, *args):
1832 """Watch the given objects for survival, by creating weakrefs to
1833 them."""
1834 for obj in args:
1835 key = id(obj), repr(obj)
1836 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001837
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001838 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001839 """Assert that all objects watched for survival have survived."""
1840 # Trigger cycle breaking.
1841 gc.collect()
1842 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001843 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001844 if ref() is None:
1845 dead.append(repr_)
1846 if dead:
1847 self.fail("%d objects should have survived "
1848 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001849
Christian Heimes180510d2008-03-03 19:15:45 +00001850 def test_persistent_loggers(self):
1851 # Logger objects are persistent and retain their configuration, even
1852 # if visible references are destroyed.
1853 self.root_logger.setLevel(logging.INFO)
1854 foo = logging.getLogger("foo")
1855 self._watch_for_survival(foo)
1856 foo.setLevel(logging.DEBUG)
1857 self.root_logger.debug(self.next_message())
1858 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001859 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001860 ('foo', 'DEBUG', '2'),
1861 ])
1862 del foo
1863 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001864 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001865 # foo has retained its settings.
1866 bar = logging.getLogger("foo")
1867 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001868 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001869 ('foo', 'DEBUG', '2'),
1870 ('foo', 'DEBUG', '3'),
1871 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001872
Benjamin Petersonf91df042009-02-13 02:50:59 +00001873
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001874class EncodingTest(BaseTest):
1875 def test_encoding_plain_file(self):
1876 # In Python 2.x, a plain file object is treated as having no encoding.
1877 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001878 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1879 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001880 # the non-ascii data we write to the log.
1881 data = "foo\x80"
1882 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001883 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001884 log.addHandler(handler)
1885 try:
1886 # write non-ascii data to the log.
1887 log.warning(data)
1888 finally:
1889 log.removeHandler(handler)
1890 handler.close()
1891 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001892 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001893 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001894 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001895 finally:
1896 f.close()
1897 finally:
1898 if os.path.isfile(fn):
1899 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001900
Benjamin Petersonf91df042009-02-13 02:50:59 +00001901 def test_encoding_cyrillic_unicode(self):
1902 log = logging.getLogger("test")
1903 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1904 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1905 #Ensure it's written in a Cyrillic encoding
1906 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001907 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001908 stream = io.BytesIO()
1909 writer = writer_class(stream, 'strict')
1910 handler = logging.StreamHandler(writer)
1911 log.addHandler(handler)
1912 try:
1913 log.warning(message)
1914 finally:
1915 log.removeHandler(handler)
1916 handler.close()
1917 # check we wrote exactly those bytes, ignoring trailing \n etc
1918 s = stream.getvalue()
1919 #Compare against what the data should be when encoded in CP-1251
1920 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1921
1922
Georg Brandlf9734072008-12-07 15:30:06 +00001923class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001924
Georg Brandlf9734072008-12-07 15:30:06 +00001925 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001926 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001927 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001928 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001929 warnings.filterwarnings("always", category=UserWarning)
1930 stream = io.StringIO()
1931 h = logging.StreamHandler(stream)
1932 logger = logging.getLogger("py.warnings")
1933 logger.addHandler(h)
1934 warnings.warn("I'm warning you...")
1935 logger.removeHandler(h)
1936 s = stream.getvalue()
1937 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001938 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001939
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001940 #See if an explicit file uses the original implementation
1941 a_file = io.StringIO()
1942 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1943 a_file, "Dummy line")
1944 s = a_file.getvalue()
1945 a_file.close()
1946 self.assertEqual(s,
1947 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1948
1949 def test_warnings_no_handlers(self):
1950 with warnings.catch_warnings():
1951 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001952 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001953
1954 # confirm our assumption: no loggers are set
1955 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001956 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001957
1958 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001959 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001960 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001961
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001962
1963def formatFunc(format, datefmt=None):
1964 return logging.Formatter(format, datefmt)
1965
1966def handlerFunc():
1967 return logging.StreamHandler()
1968
1969class CustomHandler(logging.StreamHandler):
1970 pass
1971
1972class ConfigDictTest(BaseTest):
1973
1974 """Reading logging config from a dictionary."""
1975
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001976 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001977
1978 # config0 is a standard configuration.
1979 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001980 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001981 'formatters': {
1982 'form1' : {
1983 'format' : '%(levelname)s ++ %(message)s',
1984 },
1985 },
1986 'handlers' : {
1987 'hand1' : {
1988 'class' : 'logging.StreamHandler',
1989 'formatter' : 'form1',
1990 'level' : 'NOTSET',
1991 'stream' : 'ext://sys.stdout',
1992 },
1993 },
1994 'root' : {
1995 'level' : 'WARNING',
1996 'handlers' : ['hand1'],
1997 },
1998 }
1999
2000 # config1 adds a little to the standard configuration.
2001 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002002 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002003 'formatters': {
2004 'form1' : {
2005 'format' : '%(levelname)s ++ %(message)s',
2006 },
2007 },
2008 'handlers' : {
2009 'hand1' : {
2010 'class' : 'logging.StreamHandler',
2011 'formatter' : 'form1',
2012 'level' : 'NOTSET',
2013 'stream' : 'ext://sys.stdout',
2014 },
2015 },
2016 'loggers' : {
2017 'compiler.parser' : {
2018 'level' : 'DEBUG',
2019 'handlers' : ['hand1'],
2020 },
2021 },
2022 'root' : {
2023 'level' : 'WARNING',
2024 },
2025 }
2026
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002027 # config1a moves the handler to the root. Used with config8a
2028 config1a = {
2029 'version': 1,
2030 'formatters': {
2031 'form1' : {
2032 'format' : '%(levelname)s ++ %(message)s',
2033 },
2034 },
2035 'handlers' : {
2036 'hand1' : {
2037 'class' : 'logging.StreamHandler',
2038 'formatter' : 'form1',
2039 'level' : 'NOTSET',
2040 'stream' : 'ext://sys.stdout',
2041 },
2042 },
2043 'loggers' : {
2044 'compiler.parser' : {
2045 'level' : 'DEBUG',
2046 },
2047 },
2048 'root' : {
2049 'level' : 'WARNING',
2050 'handlers' : ['hand1'],
2051 },
2052 }
2053
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002054 # config2 has a subtle configuration error that should be reported
2055 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002056 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002057 'formatters': {
2058 'form1' : {
2059 'format' : '%(levelname)s ++ %(message)s',
2060 },
2061 },
2062 'handlers' : {
2063 'hand1' : {
2064 'class' : 'logging.StreamHandler',
2065 'formatter' : 'form1',
2066 'level' : 'NOTSET',
2067 'stream' : 'ext://sys.stdbout',
2068 },
2069 },
2070 'loggers' : {
2071 'compiler.parser' : {
2072 'level' : 'DEBUG',
2073 'handlers' : ['hand1'],
2074 },
2075 },
2076 'root' : {
2077 'level' : 'WARNING',
2078 },
2079 }
2080
2081 #As config1 but with a misspelt level on a handler
2082 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002083 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002084 'formatters': {
2085 'form1' : {
2086 'format' : '%(levelname)s ++ %(message)s',
2087 },
2088 },
2089 'handlers' : {
2090 'hand1' : {
2091 'class' : 'logging.StreamHandler',
2092 'formatter' : 'form1',
2093 'level' : 'NTOSET',
2094 'stream' : 'ext://sys.stdout',
2095 },
2096 },
2097 'loggers' : {
2098 'compiler.parser' : {
2099 'level' : 'DEBUG',
2100 'handlers' : ['hand1'],
2101 },
2102 },
2103 'root' : {
2104 'level' : 'WARNING',
2105 },
2106 }
2107
2108
2109 #As config1 but with a misspelt level on a logger
2110 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002111 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002112 'formatters': {
2113 'form1' : {
2114 'format' : '%(levelname)s ++ %(message)s',
2115 },
2116 },
2117 'handlers' : {
2118 'hand1' : {
2119 'class' : 'logging.StreamHandler',
2120 'formatter' : 'form1',
2121 'level' : 'NOTSET',
2122 'stream' : 'ext://sys.stdout',
2123 },
2124 },
2125 'loggers' : {
2126 'compiler.parser' : {
2127 'level' : 'DEBUG',
2128 'handlers' : ['hand1'],
2129 },
2130 },
2131 'root' : {
2132 'level' : 'WRANING',
2133 },
2134 }
2135
2136 # config3 has a less subtle configuration error
2137 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002138 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002139 'formatters': {
2140 'form1' : {
2141 'format' : '%(levelname)s ++ %(message)s',
2142 },
2143 },
2144 'handlers' : {
2145 'hand1' : {
2146 'class' : 'logging.StreamHandler',
2147 'formatter' : 'misspelled_name',
2148 'level' : 'NOTSET',
2149 'stream' : 'ext://sys.stdout',
2150 },
2151 },
2152 'loggers' : {
2153 'compiler.parser' : {
2154 'level' : 'DEBUG',
2155 'handlers' : ['hand1'],
2156 },
2157 },
2158 'root' : {
2159 'level' : 'WARNING',
2160 },
2161 }
2162
2163 # config4 specifies a custom formatter class to be loaded
2164 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002165 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002166 'formatters': {
2167 'form1' : {
2168 '()' : __name__ + '.ExceptionFormatter',
2169 'format' : '%(levelname)s:%(name)s:%(message)s',
2170 },
2171 },
2172 'handlers' : {
2173 'hand1' : {
2174 'class' : 'logging.StreamHandler',
2175 'formatter' : 'form1',
2176 'level' : 'NOTSET',
2177 'stream' : 'ext://sys.stdout',
2178 },
2179 },
2180 'root' : {
2181 'level' : 'NOTSET',
2182 'handlers' : ['hand1'],
2183 },
2184 }
2185
2186 # As config4 but using an actual callable rather than a string
2187 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002188 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002189 'formatters': {
2190 'form1' : {
2191 '()' : ExceptionFormatter,
2192 'format' : '%(levelname)s:%(name)s:%(message)s',
2193 },
2194 'form2' : {
2195 '()' : __name__ + '.formatFunc',
2196 'format' : '%(levelname)s:%(name)s:%(message)s',
2197 },
2198 'form3' : {
2199 '()' : formatFunc,
2200 'format' : '%(levelname)s:%(name)s:%(message)s',
2201 },
2202 },
2203 'handlers' : {
2204 'hand1' : {
2205 'class' : 'logging.StreamHandler',
2206 'formatter' : 'form1',
2207 'level' : 'NOTSET',
2208 'stream' : 'ext://sys.stdout',
2209 },
2210 'hand2' : {
2211 '()' : handlerFunc,
2212 },
2213 },
2214 'root' : {
2215 'level' : 'NOTSET',
2216 'handlers' : ['hand1'],
2217 },
2218 }
2219
2220 # config5 specifies a custom handler class to be loaded
2221 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002222 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002223 'formatters': {
2224 'form1' : {
2225 'format' : '%(levelname)s ++ %(message)s',
2226 },
2227 },
2228 'handlers' : {
2229 'hand1' : {
2230 'class' : __name__ + '.CustomHandler',
2231 'formatter' : 'form1',
2232 'level' : 'NOTSET',
2233 'stream' : 'ext://sys.stdout',
2234 },
2235 },
2236 'loggers' : {
2237 'compiler.parser' : {
2238 'level' : 'DEBUG',
2239 'handlers' : ['hand1'],
2240 },
2241 },
2242 'root' : {
2243 'level' : 'WARNING',
2244 },
2245 }
2246
2247 # config6 specifies a custom handler class to be loaded
2248 # but has bad arguments
2249 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002250 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002251 'formatters': {
2252 'form1' : {
2253 'format' : '%(levelname)s ++ %(message)s',
2254 },
2255 },
2256 'handlers' : {
2257 'hand1' : {
2258 'class' : __name__ + '.CustomHandler',
2259 'formatter' : 'form1',
2260 'level' : 'NOTSET',
2261 'stream' : 'ext://sys.stdout',
2262 '9' : 'invalid parameter name',
2263 },
2264 },
2265 'loggers' : {
2266 'compiler.parser' : {
2267 'level' : 'DEBUG',
2268 'handlers' : ['hand1'],
2269 },
2270 },
2271 'root' : {
2272 'level' : 'WARNING',
2273 },
2274 }
2275
2276 #config 7 does not define compiler.parser but defines compiler.lexer
2277 #so compiler.parser should be disabled after applying it
2278 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002279 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002280 'formatters': {
2281 'form1' : {
2282 'format' : '%(levelname)s ++ %(message)s',
2283 },
2284 },
2285 'handlers' : {
2286 'hand1' : {
2287 'class' : 'logging.StreamHandler',
2288 'formatter' : 'form1',
2289 'level' : 'NOTSET',
2290 'stream' : 'ext://sys.stdout',
2291 },
2292 },
2293 'loggers' : {
2294 'compiler.lexer' : {
2295 'level' : 'DEBUG',
2296 'handlers' : ['hand1'],
2297 },
2298 },
2299 'root' : {
2300 'level' : 'WARNING',
2301 },
2302 }
2303
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002304 # config8 defines both compiler and compiler.lexer
2305 # so compiler.parser should not be disabled (since
2306 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002307 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002308 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002309 'disable_existing_loggers' : False,
2310 'formatters': {
2311 'form1' : {
2312 'format' : '%(levelname)s ++ %(message)s',
2313 },
2314 },
2315 'handlers' : {
2316 'hand1' : {
2317 'class' : 'logging.StreamHandler',
2318 'formatter' : 'form1',
2319 'level' : 'NOTSET',
2320 'stream' : 'ext://sys.stdout',
2321 },
2322 },
2323 'loggers' : {
2324 'compiler' : {
2325 'level' : 'DEBUG',
2326 'handlers' : ['hand1'],
2327 },
2328 'compiler.lexer' : {
2329 },
2330 },
2331 'root' : {
2332 'level' : 'WARNING',
2333 },
2334 }
2335
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002336 # config8a disables existing loggers
2337 config8a = {
2338 'version': 1,
2339 'disable_existing_loggers' : True,
2340 'formatters': {
2341 'form1' : {
2342 'format' : '%(levelname)s ++ %(message)s',
2343 },
2344 },
2345 'handlers' : {
2346 'hand1' : {
2347 'class' : 'logging.StreamHandler',
2348 'formatter' : 'form1',
2349 'level' : 'NOTSET',
2350 'stream' : 'ext://sys.stdout',
2351 },
2352 },
2353 'loggers' : {
2354 'compiler' : {
2355 'level' : 'DEBUG',
2356 'handlers' : ['hand1'],
2357 },
2358 'compiler.lexer' : {
2359 },
2360 },
2361 'root' : {
2362 'level' : 'WARNING',
2363 },
2364 }
2365
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002366 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002367 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002368 'formatters': {
2369 'form1' : {
2370 'format' : '%(levelname)s ++ %(message)s',
2371 },
2372 },
2373 'handlers' : {
2374 'hand1' : {
2375 'class' : 'logging.StreamHandler',
2376 'formatter' : 'form1',
2377 'level' : 'WARNING',
2378 'stream' : 'ext://sys.stdout',
2379 },
2380 },
2381 'loggers' : {
2382 'compiler.parser' : {
2383 'level' : 'WARNING',
2384 'handlers' : ['hand1'],
2385 },
2386 },
2387 'root' : {
2388 'level' : 'NOTSET',
2389 },
2390 }
2391
2392 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002393 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002394 'incremental' : True,
2395 'handlers' : {
2396 'hand1' : {
2397 'level' : 'WARNING',
2398 },
2399 },
2400 'loggers' : {
2401 'compiler.parser' : {
2402 'level' : 'INFO',
2403 },
2404 },
2405 }
2406
2407 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002408 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002409 'incremental' : True,
2410 'handlers' : {
2411 'hand1' : {
2412 'level' : 'INFO',
2413 },
2414 },
2415 'loggers' : {
2416 'compiler.parser' : {
2417 'level' : 'INFO',
2418 },
2419 },
2420 }
2421
2422 #As config1 but with a filter added
2423 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002424 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002425 'formatters': {
2426 'form1' : {
2427 'format' : '%(levelname)s ++ %(message)s',
2428 },
2429 },
2430 'filters' : {
2431 'filt1' : {
2432 'name' : 'compiler.parser',
2433 },
2434 },
2435 'handlers' : {
2436 'hand1' : {
2437 'class' : 'logging.StreamHandler',
2438 'formatter' : 'form1',
2439 'level' : 'NOTSET',
2440 'stream' : 'ext://sys.stdout',
2441 'filters' : ['filt1'],
2442 },
2443 },
2444 'loggers' : {
2445 'compiler.parser' : {
2446 'level' : 'DEBUG',
2447 'filters' : ['filt1'],
2448 },
2449 },
2450 'root' : {
2451 'level' : 'WARNING',
2452 'handlers' : ['hand1'],
2453 },
2454 }
2455
2456 #As config1 but using cfg:// references
2457 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002458 'version': 1,
2459 'true_formatters': {
2460 'form1' : {
2461 'format' : '%(levelname)s ++ %(message)s',
2462 },
2463 },
2464 'handler_configs': {
2465 'hand1' : {
2466 'class' : 'logging.StreamHandler',
2467 'formatter' : 'form1',
2468 'level' : 'NOTSET',
2469 'stream' : 'ext://sys.stdout',
2470 },
2471 },
2472 'formatters' : 'cfg://true_formatters',
2473 'handlers' : {
2474 'hand1' : 'cfg://handler_configs[hand1]',
2475 },
2476 'loggers' : {
2477 'compiler.parser' : {
2478 'level' : 'DEBUG',
2479 'handlers' : ['hand1'],
2480 },
2481 },
2482 'root' : {
2483 'level' : 'WARNING',
2484 },
2485 }
2486
2487 #As config11 but missing the version key
2488 config12 = {
2489 'true_formatters': {
2490 'form1' : {
2491 'format' : '%(levelname)s ++ %(message)s',
2492 },
2493 },
2494 'handler_configs': {
2495 'hand1' : {
2496 'class' : 'logging.StreamHandler',
2497 'formatter' : 'form1',
2498 'level' : 'NOTSET',
2499 'stream' : 'ext://sys.stdout',
2500 },
2501 },
2502 'formatters' : 'cfg://true_formatters',
2503 'handlers' : {
2504 'hand1' : 'cfg://handler_configs[hand1]',
2505 },
2506 'loggers' : {
2507 'compiler.parser' : {
2508 'level' : 'DEBUG',
2509 'handlers' : ['hand1'],
2510 },
2511 },
2512 'root' : {
2513 'level' : 'WARNING',
2514 },
2515 }
2516
2517 #As config11 but using an unsupported version
2518 config13 = {
2519 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002520 'true_formatters': {
2521 'form1' : {
2522 'format' : '%(levelname)s ++ %(message)s',
2523 },
2524 },
2525 'handler_configs': {
2526 'hand1' : {
2527 'class' : 'logging.StreamHandler',
2528 'formatter' : 'form1',
2529 'level' : 'NOTSET',
2530 'stream' : 'ext://sys.stdout',
2531 },
2532 },
2533 'formatters' : 'cfg://true_formatters',
2534 'handlers' : {
2535 'hand1' : 'cfg://handler_configs[hand1]',
2536 },
2537 'loggers' : {
2538 'compiler.parser' : {
2539 'level' : 'DEBUG',
2540 'handlers' : ['hand1'],
2541 },
2542 },
2543 'root' : {
2544 'level' : 'WARNING',
2545 },
2546 }
2547
Vinay Sajip8d270232012-11-15 14:20:18 +00002548 # As config0, but with properties
2549 config14 = {
2550 'version': 1,
2551 'formatters': {
2552 'form1' : {
2553 'format' : '%(levelname)s ++ %(message)s',
2554 },
2555 },
2556 'handlers' : {
2557 'hand1' : {
2558 'class' : 'logging.StreamHandler',
2559 'formatter' : 'form1',
2560 'level' : 'NOTSET',
2561 'stream' : 'ext://sys.stdout',
2562 '.': {
2563 'foo': 'bar',
2564 'terminator': '!\n',
2565 }
2566 },
2567 },
2568 'root' : {
2569 'level' : 'WARNING',
2570 'handlers' : ['hand1'],
2571 },
2572 }
2573
Vinay Sajip3f885b52013-03-22 15:19:54 +00002574 out_of_order = {
2575 "version": 1,
2576 "formatters": {
2577 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002578 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2579 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002580 }
2581 },
2582 "handlers": {
2583 "fileGlobal": {
2584 "class": "logging.StreamHandler",
2585 "level": "DEBUG",
2586 "formatter": "mySimpleFormatter"
2587 },
2588 "bufferGlobal": {
2589 "class": "logging.handlers.MemoryHandler",
2590 "capacity": 5,
2591 "formatter": "mySimpleFormatter",
2592 "target": "fileGlobal",
2593 "level": "DEBUG"
2594 }
2595 },
2596 "loggers": {
2597 "mymodule": {
2598 "level": "DEBUG",
2599 "handlers": ["bufferGlobal"],
2600 "propagate": "true"
2601 }
2602 }
2603 }
2604
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002605 def apply_config(self, conf):
2606 logging.config.dictConfig(conf)
2607
2608 def test_config0_ok(self):
2609 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002610 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002611 self.apply_config(self.config0)
2612 logger = logging.getLogger()
2613 # Won't output anything
2614 logger.info(self.next_message())
2615 # Outputs a message
2616 logger.error(self.next_message())
2617 self.assert_log_lines([
2618 ('ERROR', '2'),
2619 ], stream=output)
2620 # Original logger output is empty.
2621 self.assert_log_lines([])
2622
2623 def test_config1_ok(self, config=config1):
2624 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002625 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002626 self.apply_config(config)
2627 logger = logging.getLogger("compiler.parser")
2628 # Both will output a message
2629 logger.info(self.next_message())
2630 logger.error(self.next_message())
2631 self.assert_log_lines([
2632 ('INFO', '1'),
2633 ('ERROR', '2'),
2634 ], stream=output)
2635 # Original logger output is empty.
2636 self.assert_log_lines([])
2637
2638 def test_config2_failure(self):
2639 # A simple config which overrides the default settings.
2640 self.assertRaises(Exception, self.apply_config, self.config2)
2641
2642 def test_config2a_failure(self):
2643 # A simple config which overrides the default settings.
2644 self.assertRaises(Exception, self.apply_config, self.config2a)
2645
2646 def test_config2b_failure(self):
2647 # A simple config which overrides the default settings.
2648 self.assertRaises(Exception, self.apply_config, self.config2b)
2649
2650 def test_config3_failure(self):
2651 # A simple config which overrides the default settings.
2652 self.assertRaises(Exception, self.apply_config, self.config3)
2653
2654 def test_config4_ok(self):
2655 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002656 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002657 self.apply_config(self.config4)
2658 #logger = logging.getLogger()
2659 try:
2660 raise RuntimeError()
2661 except RuntimeError:
2662 logging.exception("just testing")
2663 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002664 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002665 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2666 # Original logger output is empty
2667 self.assert_log_lines([])
2668
2669 def test_config4a_ok(self):
2670 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002671 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002672 self.apply_config(self.config4a)
2673 #logger = logging.getLogger()
2674 try:
2675 raise RuntimeError()
2676 except RuntimeError:
2677 logging.exception("just testing")
2678 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002679 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002680 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2681 # Original logger output is empty
2682 self.assert_log_lines([])
2683
2684 def test_config5_ok(self):
2685 self.test_config1_ok(config=self.config5)
2686
2687 def test_config6_failure(self):
2688 self.assertRaises(Exception, self.apply_config, self.config6)
2689
2690 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002691 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002692 self.apply_config(self.config1)
2693 logger = logging.getLogger("compiler.parser")
2694 # Both will output a message
2695 logger.info(self.next_message())
2696 logger.error(self.next_message())
2697 self.assert_log_lines([
2698 ('INFO', '1'),
2699 ('ERROR', '2'),
2700 ], stream=output)
2701 # Original logger output is empty.
2702 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002703 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002704 self.apply_config(self.config7)
2705 logger = logging.getLogger("compiler.parser")
2706 self.assertTrue(logger.disabled)
2707 logger = logging.getLogger("compiler.lexer")
2708 # Both will output a message
2709 logger.info(self.next_message())
2710 logger.error(self.next_message())
2711 self.assert_log_lines([
2712 ('INFO', '3'),
2713 ('ERROR', '4'),
2714 ], stream=output)
2715 # Original logger output is empty.
2716 self.assert_log_lines([])
2717
2718 #Same as test_config_7_ok but don't disable old loggers.
2719 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002720 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002721 self.apply_config(self.config1)
2722 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002723 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002724 logger.info(self.next_message())
2725 logger.error(self.next_message())
2726 self.assert_log_lines([
2727 ('INFO', '1'),
2728 ('ERROR', '2'),
2729 ], stream=output)
2730 # Original logger output is empty.
2731 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002732 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002733 self.apply_config(self.config8)
2734 logger = logging.getLogger("compiler.parser")
2735 self.assertFalse(logger.disabled)
2736 # Both will output a message
2737 logger.info(self.next_message())
2738 logger.error(self.next_message())
2739 logger = logging.getLogger("compiler.lexer")
2740 # Both will output a message
2741 logger.info(self.next_message())
2742 logger.error(self.next_message())
2743 self.assert_log_lines([
2744 ('INFO', '3'),
2745 ('ERROR', '4'),
2746 ('INFO', '5'),
2747 ('ERROR', '6'),
2748 ], stream=output)
2749 # Original logger output is empty.
2750 self.assert_log_lines([])
2751
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002752 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002753 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002754 self.apply_config(self.config1a)
2755 logger = logging.getLogger("compiler.parser")
2756 # See issue #11424. compiler-hyphenated sorts
2757 # between compiler and compiler.xyz and this
2758 # was preventing compiler.xyz from being included
2759 # in the child loggers of compiler because of an
2760 # overzealous loop termination condition.
2761 hyphenated = logging.getLogger('compiler-hyphenated')
2762 # All will output a message
2763 logger.info(self.next_message())
2764 logger.error(self.next_message())
2765 hyphenated.critical(self.next_message())
2766 self.assert_log_lines([
2767 ('INFO', '1'),
2768 ('ERROR', '2'),
2769 ('CRITICAL', '3'),
2770 ], stream=output)
2771 # Original logger output is empty.
2772 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002773 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002774 self.apply_config(self.config8a)
2775 logger = logging.getLogger("compiler.parser")
2776 self.assertFalse(logger.disabled)
2777 # Both will output a message
2778 logger.info(self.next_message())
2779 logger.error(self.next_message())
2780 logger = logging.getLogger("compiler.lexer")
2781 # Both will output a message
2782 logger.info(self.next_message())
2783 logger.error(self.next_message())
2784 # Will not appear
2785 hyphenated.critical(self.next_message())
2786 self.assert_log_lines([
2787 ('INFO', '4'),
2788 ('ERROR', '5'),
2789 ('INFO', '6'),
2790 ('ERROR', '7'),
2791 ], stream=output)
2792 # Original logger output is empty.
2793 self.assert_log_lines([])
2794
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002795 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002796 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002797 self.apply_config(self.config9)
2798 logger = logging.getLogger("compiler.parser")
2799 #Nothing will be output since both handler and logger are set to WARNING
2800 logger.info(self.next_message())
2801 self.assert_log_lines([], stream=output)
2802 self.apply_config(self.config9a)
2803 #Nothing will be output since both handler is still set to WARNING
2804 logger.info(self.next_message())
2805 self.assert_log_lines([], stream=output)
2806 self.apply_config(self.config9b)
2807 #Message should now be output
2808 logger.info(self.next_message())
2809 self.assert_log_lines([
2810 ('INFO', '3'),
2811 ], stream=output)
2812
2813 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002814 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002815 self.apply_config(self.config10)
2816 logger = logging.getLogger("compiler.parser")
2817 logger.warning(self.next_message())
2818 logger = logging.getLogger('compiler')
2819 #Not output, because filtered
2820 logger.warning(self.next_message())
2821 logger = logging.getLogger('compiler.lexer')
2822 #Not output, because filtered
2823 logger.warning(self.next_message())
2824 logger = logging.getLogger("compiler.parser.codegen")
2825 #Output, as not filtered
2826 logger.error(self.next_message())
2827 self.assert_log_lines([
2828 ('WARNING', '1'),
2829 ('ERROR', '4'),
2830 ], stream=output)
2831
2832 def test_config11_ok(self):
2833 self.test_config1_ok(self.config11)
2834
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002835 def test_config12_failure(self):
2836 self.assertRaises(Exception, self.apply_config, self.config12)
2837
2838 def test_config13_failure(self):
2839 self.assertRaises(Exception, self.apply_config, self.config13)
2840
Vinay Sajip8d270232012-11-15 14:20:18 +00002841 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002842 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002843 self.apply_config(self.config14)
2844 h = logging._handlers['hand1']
2845 self.assertEqual(h.foo, 'bar')
2846 self.assertEqual(h.terminator, '!\n')
2847 logging.warning('Exclamation')
2848 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2849
Victor Stinner45df8202010-04-28 22:31:17 +00002850 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002851 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002852 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002853 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002854 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002855 t.start()
2856 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002857 # Now get the port allocated
2858 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002859 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002860 try:
2861 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2862 sock.settimeout(2.0)
2863 sock.connect(('localhost', port))
2864
2865 slen = struct.pack('>L', len(text))
2866 s = slen + text
2867 sentsofar = 0
2868 left = len(s)
2869 while left > 0:
2870 sent = sock.send(s[sentsofar:])
2871 sentsofar += sent
2872 left -= sent
2873 sock.close()
2874 finally:
2875 t.ready.wait(2.0)
2876 logging.config.stopListening()
2877 t.join(2.0)
2878
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002879 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002880 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002881 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002882 self.setup_via_listener(json.dumps(self.config10))
2883 logger = logging.getLogger("compiler.parser")
2884 logger.warning(self.next_message())
2885 logger = logging.getLogger('compiler')
2886 #Not output, because filtered
2887 logger.warning(self.next_message())
2888 logger = logging.getLogger('compiler.lexer')
2889 #Not output, because filtered
2890 logger.warning(self.next_message())
2891 logger = logging.getLogger("compiler.parser.codegen")
2892 #Output, as not filtered
2893 logger.error(self.next_message())
2894 self.assert_log_lines([
2895 ('WARNING', '1'),
2896 ('ERROR', '4'),
2897 ], stream=output)
2898
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002899 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002900 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002901 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002902 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2903 logger = logging.getLogger("compiler.parser")
2904 # Both will output a message
2905 logger.info(self.next_message())
2906 logger.error(self.next_message())
2907 self.assert_log_lines([
2908 ('INFO', '1'),
2909 ('ERROR', '2'),
2910 ], stream=output)
2911 # Original logger output is empty.
2912 self.assert_log_lines([])
2913
Vinay Sajip4ded5512012-10-02 15:56:16 +01002914 @unittest.skipUnless(threading, 'Threading required for this test.')
2915 def test_listen_verify(self):
2916
2917 def verify_fail(stuff):
2918 return None
2919
2920 def verify_reverse(stuff):
2921 return stuff[::-1]
2922
2923 logger = logging.getLogger("compiler.parser")
2924 to_send = textwrap.dedent(ConfigFileTest.config1)
2925 # First, specify a verification function that will fail.
2926 # We expect to see no output, since our configuration
2927 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002928 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002929 self.setup_via_listener(to_send, verify_fail)
2930 # Both will output a message
2931 logger.info(self.next_message())
2932 logger.error(self.next_message())
2933 self.assert_log_lines([], stream=output)
2934 # Original logger output has the stuff we logged.
2935 self.assert_log_lines([
2936 ('INFO', '1'),
2937 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002938 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002939
2940 # Now, perform no verification. Our configuration
2941 # should take effect.
2942
Vinay Sajip1feedb42014-05-31 08:19:12 +01002943 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002944 self.setup_via_listener(to_send) # no verify callable specified
2945 logger = logging.getLogger("compiler.parser")
2946 # Both will output a message
2947 logger.info(self.next_message())
2948 logger.error(self.next_message())
2949 self.assert_log_lines([
2950 ('INFO', '3'),
2951 ('ERROR', '4'),
2952 ], stream=output)
2953 # Original logger output still has the stuff we logged before.
2954 self.assert_log_lines([
2955 ('INFO', '1'),
2956 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002957 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002958
2959 # Now, perform verification which transforms the bytes.
2960
Vinay Sajip1feedb42014-05-31 08:19:12 +01002961 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002962 self.setup_via_listener(to_send[::-1], verify_reverse)
2963 logger = logging.getLogger("compiler.parser")
2964 # Both will output a message
2965 logger.info(self.next_message())
2966 logger.error(self.next_message())
2967 self.assert_log_lines([
2968 ('INFO', '5'),
2969 ('ERROR', '6'),
2970 ], stream=output)
2971 # Original logger output still has the stuff we logged before.
2972 self.assert_log_lines([
2973 ('INFO', '1'),
2974 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002975 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002976
Vinay Sajip3f885b52013-03-22 15:19:54 +00002977 def test_out_of_order(self):
2978 self.apply_config(self.out_of_order)
2979 handler = logging.getLogger('mymodule').handlers[0]
2980 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002981 self.assertIsInstance(handler.formatter._style,
2982 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002983
Vinay Sajip373baef2011-04-26 20:05:24 +01002984 def test_baseconfig(self):
2985 d = {
2986 'atuple': (1, 2, 3),
2987 'alist': ['a', 'b', 'c'],
2988 'adict': {'d': 'e', 'f': 3 },
2989 'nest1': ('g', ('h', 'i'), 'j'),
2990 'nest2': ['k', ['l', 'm'], 'n'],
2991 'nest3': ['o', 'cfg://alist', 'p'],
2992 }
2993 bc = logging.config.BaseConfigurator(d)
2994 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2995 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2996 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2997 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2998 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2999 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3000 v = bc.convert('cfg://nest3')
3001 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3002 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3003 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3004 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003005
3006class ManagerTest(BaseTest):
3007 def test_manager_loggerclass(self):
3008 logged = []
3009
3010 class MyLogger(logging.Logger):
3011 def _log(self, level, msg, args, exc_info=None, extra=None):
3012 logged.append(msg)
3013
3014 man = logging.Manager(None)
3015 self.assertRaises(TypeError, man.setLoggerClass, int)
3016 man.setLoggerClass(MyLogger)
3017 logger = man.getLogger('test')
3018 logger.warning('should appear in logged')
3019 logging.warning('should not appear in logged')
3020
3021 self.assertEqual(logged, ['should appear in logged'])
3022
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003023 def test_set_log_record_factory(self):
3024 man = logging.Manager(None)
3025 expected = object()
3026 man.setLogRecordFactory(expected)
3027 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003028
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003029class ChildLoggerTest(BaseTest):
3030 def test_child_loggers(self):
3031 r = logging.getLogger()
3032 l1 = logging.getLogger('abc')
3033 l2 = logging.getLogger('def.ghi')
3034 c1 = r.getChild('xyz')
3035 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003036 self.assertIs(c1, logging.getLogger('xyz'))
3037 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003038 c1 = l1.getChild('def')
3039 c2 = c1.getChild('ghi')
3040 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003041 self.assertIs(c1, logging.getLogger('abc.def'))
3042 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3043 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003044
3045
Vinay Sajip6fac8172010-10-19 20:44:14 +00003046class DerivedLogRecord(logging.LogRecord):
3047 pass
3048
Vinay Sajip61561522010-12-03 11:50:38 +00003049class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003050
3051 def setUp(self):
3052 class CheckingFilter(logging.Filter):
3053 def __init__(self, cls):
3054 self.cls = cls
3055
3056 def filter(self, record):
3057 t = type(record)
3058 if t is not self.cls:
3059 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3060 self.cls)
3061 raise TypeError(msg)
3062 return True
3063
3064 BaseTest.setUp(self)
3065 self.filter = CheckingFilter(DerivedLogRecord)
3066 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003067 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003068
3069 def tearDown(self):
3070 self.root_logger.removeFilter(self.filter)
3071 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003072 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003073
3074 def test_logrecord_class(self):
3075 self.assertRaises(TypeError, self.root_logger.warning,
3076 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003077 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003078 self.root_logger.error(self.next_message())
3079 self.assert_log_lines([
3080 ('root', 'ERROR', '2'),
3081 ])
3082
3083
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003084class QueueHandlerTest(BaseTest):
3085 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003086 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003087
3088 def setUp(self):
3089 BaseTest.setUp(self)
3090 self.queue = queue.Queue(-1)
3091 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3092 self.que_logger = logging.getLogger('que')
3093 self.que_logger.propagate = False
3094 self.que_logger.setLevel(logging.WARNING)
3095 self.que_logger.addHandler(self.que_hdlr)
3096
3097 def tearDown(self):
3098 self.que_hdlr.close()
3099 BaseTest.tearDown(self)
3100
3101 def test_queue_handler(self):
3102 self.que_logger.debug(self.next_message())
3103 self.assertRaises(queue.Empty, self.queue.get_nowait)
3104 self.que_logger.info(self.next_message())
3105 self.assertRaises(queue.Empty, self.queue.get_nowait)
3106 msg = self.next_message()
3107 self.que_logger.warning(msg)
3108 data = self.queue.get_nowait()
3109 self.assertTrue(isinstance(data, logging.LogRecord))
3110 self.assertEqual(data.name, self.que_logger.name)
3111 self.assertEqual((data.msg, data.args), (msg, None))
3112
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003113 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3114 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003115 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003116 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003117 listener = logging.handlers.QueueListener(self.queue, handler)
3118 listener.start()
3119 try:
3120 self.que_logger.warning(self.next_message())
3121 self.que_logger.error(self.next_message())
3122 self.que_logger.critical(self.next_message())
3123 finally:
3124 listener.stop()
3125 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3126 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3127 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003128 handler.close()
3129
3130 # Now test with respect_handler_level set
3131
3132 handler = support.TestHandler(support.Matcher())
3133 handler.setLevel(logging.CRITICAL)
3134 listener = logging.handlers.QueueListener(self.queue, handler,
3135 respect_handler_level=True)
3136 listener.start()
3137 try:
3138 self.que_logger.warning(self.next_message())
3139 self.que_logger.error(self.next_message())
3140 self.que_logger.critical(self.next_message())
3141 finally:
3142 listener.stop()
3143 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3144 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3145 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3146
Vinay Sajipd61910c2016-09-08 01:13:39 +01003147if hasattr(logging.handlers, 'QueueListener'):
3148 import multiprocessing
3149 from unittest.mock import patch
3150
3151 class QueueListenerTest(BaseTest):
3152 """
3153 Tests based on patch submitted for issue #27930. Ensure that
3154 QueueListener handles all log messages.
3155 """
3156
3157 repeat = 20
3158
3159 @staticmethod
3160 def setup_and_log(log_queue, ident):
3161 """
3162 Creates a logger with a QueueHandler that logs to a queue read by a
3163 QueueListener. Starts the listener, logs five messages, and stops
3164 the listener.
3165 """
3166 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3167 logger.setLevel(logging.DEBUG)
3168 handler = logging.handlers.QueueHandler(log_queue)
3169 logger.addHandler(handler)
3170 listener = logging.handlers.QueueListener(log_queue)
3171 listener.start()
3172
3173 logger.info('one')
3174 logger.info('two')
3175 logger.info('three')
3176 logger.info('four')
3177 logger.info('five')
3178
3179 listener.stop()
3180 logger.removeHandler(handler)
3181 handler.close()
3182
3183 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003184 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003185 def test_handle_called_with_queue_queue(self, mock_handle):
3186 for i in range(self.repeat):
3187 log_queue = queue.Queue()
3188 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3189 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3190 'correct number of handled log messages')
3191
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003192 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003193 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003194 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003195 def test_handle_called_with_mp_queue(self, mock_handle):
3196 for i in range(self.repeat):
3197 log_queue = multiprocessing.Queue()
3198 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003199 log_queue.close()
3200 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003201 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3202 'correct number of handled log messages')
3203
3204 @staticmethod
3205 def get_all_from_queue(log_queue):
3206 try:
3207 while True:
3208 yield log_queue.get_nowait()
3209 except queue.Empty:
3210 return []
3211
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003212 @support.requires_multiprocessing_queue
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003213 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003214 def test_no_messages_in_queue_after_stop(self):
3215 """
3216 Five messages are logged then the QueueListener is stopped. This
3217 test then gets everything off the queue. Failure of this test
3218 indicates that messages were not registered on the queue until
3219 _after_ the QueueListener stopped.
3220 """
3221 for i in range(self.repeat):
3222 queue = multiprocessing.Queue()
3223 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3224 # time.sleep(1)
3225 items = list(self.get_all_from_queue(queue))
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003226 queue.close()
3227 queue.join_thread()
3228
Vinay Sajipd61910c2016-09-08 01:13:39 +01003229 expected = [[], [logging.handlers.QueueListener._sentinel]]
3230 self.assertIn(items, expected,
3231 'Found unexpected messages in queue: %s' % (
3232 [m.msg if isinstance(m, logging.LogRecord)
3233 else m for m in items]))
3234
Vinay Sajipe723e962011-04-15 22:27:17 +01003235
Vinay Sajip37eb3382011-04-26 20:26:41 +01003236ZERO = datetime.timedelta(0)
3237
3238class UTC(datetime.tzinfo):
3239 def utcoffset(self, dt):
3240 return ZERO
3241
3242 dst = utcoffset
3243
3244 def tzname(self, dt):
3245 return 'UTC'
3246
3247utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003248
Vinay Sajipa39c5712010-10-25 13:57:39 +00003249class FormatterTest(unittest.TestCase):
3250 def setUp(self):
3251 self.common = {
3252 'name': 'formatter.test',
3253 'level': logging.DEBUG,
3254 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3255 'lineno': 42,
3256 'exc_info': None,
3257 'func': None,
3258 'msg': 'Message with %d %s',
3259 'args': (2, 'placeholders'),
3260 }
3261 self.variants = {
3262 }
3263
3264 def get_record(self, name=None):
3265 result = dict(self.common)
3266 if name is not None:
3267 result.update(self.variants[name])
3268 return logging.makeLogRecord(result)
3269
3270 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003271 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003272 r = self.get_record()
3273 f = logging.Formatter('${%(message)s}')
3274 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3275 f = logging.Formatter('%(random)s')
3276 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003277 self.assertFalse(f.usesTime())
3278 f = logging.Formatter('%(asctime)s')
3279 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003280 f = logging.Formatter('%(asctime)-15s')
3281 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003282 f = logging.Formatter('asctime')
3283 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003284
3285 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003286 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003287 r = self.get_record()
3288 f = logging.Formatter('$%{message}%$', style='{')
3289 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3290 f = logging.Formatter('{random}', style='{')
3291 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003292 self.assertFalse(f.usesTime())
3293 f = logging.Formatter('{asctime}', style='{')
3294 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003295 f = logging.Formatter('{asctime!s:15}', style='{')
3296 self.assertTrue(f.usesTime())
3297 f = logging.Formatter('{asctime:15}', style='{')
3298 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003299 f = logging.Formatter('asctime', style='{')
3300 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003301
3302 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003303 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003304 r = self.get_record()
3305 f = logging.Formatter('$message', style='$')
3306 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3307 f = logging.Formatter('$$%${message}%$$', style='$')
3308 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3309 f = logging.Formatter('${random}', style='$')
3310 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003311 self.assertFalse(f.usesTime())
3312 f = logging.Formatter('${asctime}', style='$')
3313 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003314 f = logging.Formatter('${asctime', style='$')
3315 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003316 f = logging.Formatter('$asctime', style='$')
3317 self.assertTrue(f.usesTime())
3318 f = logging.Formatter('asctime', style='$')
3319 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003320
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003321 def test_invalid_style(self):
3322 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3323
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003324 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003325 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003326 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3327 # We use None to indicate we want the local timezone
3328 # We're essentially converting a UTC time to local time
3329 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003330 r.msecs = 123
3331 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003332 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003333 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3334 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003335 f.format(r)
3336 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3337
3338class TestBufferingFormatter(logging.BufferingFormatter):
3339 def formatHeader(self, records):
3340 return '[(%d)' % len(records)
3341
3342 def formatFooter(self, records):
3343 return '(%d)]' % len(records)
3344
3345class BufferingFormatterTest(unittest.TestCase):
3346 def setUp(self):
3347 self.records = [
3348 logging.makeLogRecord({'msg': 'one'}),
3349 logging.makeLogRecord({'msg': 'two'}),
3350 ]
3351
3352 def test_default(self):
3353 f = logging.BufferingFormatter()
3354 self.assertEqual('', f.format([]))
3355 self.assertEqual('onetwo', f.format(self.records))
3356
3357 def test_custom(self):
3358 f = TestBufferingFormatter()
3359 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3360 lf = logging.Formatter('<%(message)s>')
3361 f = TestBufferingFormatter(lf)
3362 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003363
3364class ExceptionTest(BaseTest):
3365 def test_formatting(self):
3366 r = self.root_logger
3367 h = RecordingHandler()
3368 r.addHandler(h)
3369 try:
3370 raise RuntimeError('deliberate mistake')
3371 except:
3372 logging.exception('failed', stack_info=True)
3373 r.removeHandler(h)
3374 h.close()
3375 r = h.records[0]
3376 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3377 'call last):\n'))
3378 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3379 'deliberate mistake'))
3380 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3381 'call last):\n'))
3382 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3383 'stack_info=True)'))
3384
3385
Vinay Sajip5a27d402010-12-10 11:42:57 +00003386class LastResortTest(BaseTest):
3387 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003388 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003389 root = self.root_logger
3390 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003391 old_lastresort = logging.lastResort
3392 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003393
Vinay Sajip5a27d402010-12-10 11:42:57 +00003394 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003395 with support.captured_stderr() as stderr:
3396 root.debug('This should not appear')
3397 self.assertEqual(stderr.getvalue(), '')
3398 root.warning('Final chance!')
3399 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3400
3401 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003402 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003403 with support.captured_stderr() as stderr:
3404 root.warning('Final chance!')
3405 msg = 'No handlers could be found for logger "root"\n'
3406 self.assertEqual(stderr.getvalue(), msg)
3407
Vinay Sajip5a27d402010-12-10 11:42:57 +00003408 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003409 with support.captured_stderr() as stderr:
3410 root.warning('Final chance!')
3411 self.assertEqual(stderr.getvalue(), '')
3412
3413 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003414 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003415 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003416 with support.captured_stderr() as stderr:
3417 root.warning('Final chance!')
3418 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003419 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003420 root.addHandler(self.root_hdlr)
3421 logging.lastResort = old_lastresort
3422 logging.raiseExceptions = old_raise_exceptions
3423
3424
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003425class FakeHandler:
3426
3427 def __init__(self, identifier, called):
3428 for method in ('acquire', 'flush', 'close', 'release'):
3429 setattr(self, method, self.record_call(identifier, method, called))
3430
3431 def record_call(self, identifier, method_name, called):
3432 def inner():
3433 called.append('{} - {}'.format(identifier, method_name))
3434 return inner
3435
3436
3437class RecordingHandler(logging.NullHandler):
3438
3439 def __init__(self, *args, **kwargs):
3440 super(RecordingHandler, self).__init__(*args, **kwargs)
3441 self.records = []
3442
3443 def handle(self, record):
3444 """Keep track of all the emitted records."""
3445 self.records.append(record)
3446
3447
3448class ShutdownTest(BaseTest):
3449
Vinay Sajip5e66b162011-04-20 15:41:14 +01003450 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003451
3452 def setUp(self):
3453 super(ShutdownTest, self).setUp()
3454 self.called = []
3455
3456 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003457 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003458
3459 def raise_error(self, error):
3460 def inner():
3461 raise error()
3462 return inner
3463
3464 def test_no_failure(self):
3465 # create some fake handlers
3466 handler0 = FakeHandler(0, self.called)
3467 handler1 = FakeHandler(1, self.called)
3468 handler2 = FakeHandler(2, self.called)
3469
3470 # create live weakref to those handlers
3471 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3472
3473 logging.shutdown(handlerList=list(handlers))
3474
3475 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3476 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3477 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3478 self.assertEqual(expected, self.called)
3479
3480 def _test_with_failure_in_method(self, method, error):
3481 handler = FakeHandler(0, self.called)
3482 setattr(handler, method, self.raise_error(error))
3483 handlers = [logging.weakref.ref(handler)]
3484
3485 logging.shutdown(handlerList=list(handlers))
3486
3487 self.assertEqual('0 - release', self.called[-1])
3488
3489 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003490 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003491
3492 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003493 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494
3495 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003496 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003497
3498 def test_with_valueerror_in_acquire(self):
3499 self._test_with_failure_in_method('acquire', ValueError)
3500
3501 def test_with_valueerror_in_flush(self):
3502 self._test_with_failure_in_method('flush', ValueError)
3503
3504 def test_with_valueerror_in_close(self):
3505 self._test_with_failure_in_method('close', ValueError)
3506
3507 def test_with_other_error_in_acquire_without_raise(self):
3508 logging.raiseExceptions = False
3509 self._test_with_failure_in_method('acquire', IndexError)
3510
3511 def test_with_other_error_in_flush_without_raise(self):
3512 logging.raiseExceptions = False
3513 self._test_with_failure_in_method('flush', IndexError)
3514
3515 def test_with_other_error_in_close_without_raise(self):
3516 logging.raiseExceptions = False
3517 self._test_with_failure_in_method('close', IndexError)
3518
3519 def test_with_other_error_in_acquire_with_raise(self):
3520 logging.raiseExceptions = True
3521 self.assertRaises(IndexError, self._test_with_failure_in_method,
3522 'acquire', IndexError)
3523
3524 def test_with_other_error_in_flush_with_raise(self):
3525 logging.raiseExceptions = True
3526 self.assertRaises(IndexError, self._test_with_failure_in_method,
3527 'flush', IndexError)
3528
3529 def test_with_other_error_in_close_with_raise(self):
3530 logging.raiseExceptions = True
3531 self.assertRaises(IndexError, self._test_with_failure_in_method,
3532 'close', IndexError)
3533
3534
3535class ModuleLevelMiscTest(BaseTest):
3536
Vinay Sajip5e66b162011-04-20 15:41:14 +01003537 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003538
3539 def test_disable(self):
3540 old_disable = logging.root.manager.disable
3541 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003542 self.assertEqual(old_disable, 0)
3543 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003544
3545 logging.disable(83)
3546 self.assertEqual(logging.root.manager.disable, 83)
3547
3548 def _test_log(self, method, level=None):
3549 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003550 support.patch(self, logging, 'basicConfig',
3551 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003552
3553 recording = RecordingHandler()
3554 logging.root.addHandler(recording)
3555
3556 log_method = getattr(logging, method)
3557 if level is not None:
3558 log_method(level, "test me: %r", recording)
3559 else:
3560 log_method("test me: %r", recording)
3561
3562 self.assertEqual(len(recording.records), 1)
3563 record = recording.records[0]
3564 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3565
3566 expected_level = level if level is not None else getattr(logging, method.upper())
3567 self.assertEqual(record.levelno, expected_level)
3568
3569 # basicConfig was not called!
3570 self.assertEqual(called, [])
3571
3572 def test_log(self):
3573 self._test_log('log', logging.ERROR)
3574
3575 def test_debug(self):
3576 self._test_log('debug')
3577
3578 def test_info(self):
3579 self._test_log('info')
3580
3581 def test_warning(self):
3582 self._test_log('warning')
3583
3584 def test_error(self):
3585 self._test_log('error')
3586
3587 def test_critical(self):
3588 self._test_log('critical')
3589
3590 def test_set_logger_class(self):
3591 self.assertRaises(TypeError, logging.setLoggerClass, object)
3592
3593 class MyLogger(logging.Logger):
3594 pass
3595
3596 logging.setLoggerClass(MyLogger)
3597 self.assertEqual(logging.getLoggerClass(), MyLogger)
3598
3599 logging.setLoggerClass(logging.Logger)
3600 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3601
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003602 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003603 def test_logging_at_shutdown(self):
3604 # Issue #20037
3605 code = """if 1:
3606 import logging
3607
3608 class A:
3609 def __del__(self):
3610 try:
3611 raise ValueError("some error")
3612 except Exception:
3613 logging.exception("exception in __del__")
3614
3615 a = A()"""
3616 rc, out, err = assert_python_ok("-c", code)
3617 err = err.decode()
3618 self.assertIn("exception in __del__", err)
3619 self.assertIn("ValueError: some error", err)
3620
3621
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003622class LogRecordTest(BaseTest):
3623 def test_str_rep(self):
3624 r = logging.makeLogRecord({})
3625 s = str(r)
3626 self.assertTrue(s.startswith('<LogRecord: '))
3627 self.assertTrue(s.endswith('>'))
3628
3629 def test_dict_arg(self):
3630 h = RecordingHandler()
3631 r = logging.getLogger()
3632 r.addHandler(h)
3633 d = {'less' : 'more' }
3634 logging.warning('less is %(less)s', d)
3635 self.assertIs(h.records[0].args, d)
3636 self.assertEqual(h.records[0].message, 'less is more')
3637 r.removeHandler(h)
3638 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003639
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003640 def test_multiprocessing(self):
3641 r = logging.makeLogRecord({})
3642 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003643 try:
3644 import multiprocessing as mp
3645 r = logging.makeLogRecord({})
3646 self.assertEqual(r.processName, mp.current_process().name)
3647 except ImportError:
3648 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003649
3650 def test_optional(self):
3651 r = logging.makeLogRecord({})
3652 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003653 if threading:
3654 NOT_NONE(r.thread)
3655 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003656 NOT_NONE(r.process)
3657 NOT_NONE(r.processName)
3658 log_threads = logging.logThreads
3659 log_processes = logging.logProcesses
3660 log_multiprocessing = logging.logMultiprocessing
3661 try:
3662 logging.logThreads = False
3663 logging.logProcesses = False
3664 logging.logMultiprocessing = False
3665 r = logging.makeLogRecord({})
3666 NONE = self.assertIsNone
3667 NONE(r.thread)
3668 NONE(r.threadName)
3669 NONE(r.process)
3670 NONE(r.processName)
3671 finally:
3672 logging.logThreads = log_threads
3673 logging.logProcesses = log_processes
3674 logging.logMultiprocessing = log_multiprocessing
3675
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003676class BasicConfigTest(unittest.TestCase):
3677
Vinay Sajip95bf5042011-04-20 11:50:56 +01003678 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003679
3680 def setUp(self):
3681 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003682 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003683 self.saved_handlers = logging._handlers.copy()
3684 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003685 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003686 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003687 logging.root.handlers = []
3688
3689 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003690 for h in logging.root.handlers[:]:
3691 logging.root.removeHandler(h)
3692 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003693 super(BasicConfigTest, self).tearDown()
3694
Vinay Sajip3def7e02011-04-20 10:58:06 +01003695 def cleanup(self):
3696 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003697 logging._handlers.clear()
3698 logging._handlers.update(self.saved_handlers)
3699 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003700 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003701
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003702 def test_no_kwargs(self):
3703 logging.basicConfig()
3704
3705 # handler defaults to a StreamHandler to sys.stderr
3706 self.assertEqual(len(logging.root.handlers), 1)
3707 handler = logging.root.handlers[0]
3708 self.assertIsInstance(handler, logging.StreamHandler)
3709 self.assertEqual(handler.stream, sys.stderr)
3710
3711 formatter = handler.formatter
3712 # format defaults to logging.BASIC_FORMAT
3713 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3714 # datefmt defaults to None
3715 self.assertIsNone(formatter.datefmt)
3716 # style defaults to %
3717 self.assertIsInstance(formatter._style, logging.PercentStyle)
3718
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003719 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003720 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003721
Vinay Sajip1fd12022014-01-13 21:59:56 +00003722 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003723 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003724 logging.basicConfig(stream=sys.stdout, style="{")
3725 logging.error("Log an error")
3726 sys.stdout.seek(0)
3727 self.assertEqual(output.getvalue().strip(),
3728 "ERROR:root:Log an error")
3729
3730 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003731 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003732 logging.basicConfig(stream=sys.stdout, style="$")
3733 logging.error("Log an error")
3734 sys.stdout.seek(0)
3735 self.assertEqual(output.getvalue().strip(),
3736 "ERROR:root:Log an error")
3737
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003738 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003739
3740 def cleanup(h1, h2, fn):
3741 h1.close()
3742 h2.close()
3743 os.remove(fn)
3744
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003745 logging.basicConfig(filename='test.log')
3746
3747 self.assertEqual(len(logging.root.handlers), 1)
3748 handler = logging.root.handlers[0]
3749 self.assertIsInstance(handler, logging.FileHandler)
3750
3751 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003752 self.assertEqual(handler.stream.mode, expected.stream.mode)
3753 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003754 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003755
3756 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003757
3758 def cleanup(h1, h2, fn):
3759 h1.close()
3760 h2.close()
3761 os.remove(fn)
3762
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003763 logging.basicConfig(filename='test.log', filemode='wb')
3764
3765 handler = logging.root.handlers[0]
3766 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003767 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003768 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003769
3770 def test_stream(self):
3771 stream = io.StringIO()
3772 self.addCleanup(stream.close)
3773 logging.basicConfig(stream=stream)
3774
3775 self.assertEqual(len(logging.root.handlers), 1)
3776 handler = logging.root.handlers[0]
3777 self.assertIsInstance(handler, logging.StreamHandler)
3778 self.assertEqual(handler.stream, stream)
3779
3780 def test_format(self):
3781 logging.basicConfig(format='foo')
3782
3783 formatter = logging.root.handlers[0].formatter
3784 self.assertEqual(formatter._style._fmt, 'foo')
3785
3786 def test_datefmt(self):
3787 logging.basicConfig(datefmt='bar')
3788
3789 formatter = logging.root.handlers[0].formatter
3790 self.assertEqual(formatter.datefmt, 'bar')
3791
3792 def test_style(self):
3793 logging.basicConfig(style='$')
3794
3795 formatter = logging.root.handlers[0].formatter
3796 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3797
3798 def test_level(self):
3799 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003800 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003801
3802 logging.basicConfig(level=57)
3803 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003804 # Test that second call has no effect
3805 logging.basicConfig(level=58)
3806 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003807
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003808 def test_incompatible(self):
3809 assertRaises = self.assertRaises
3810 handlers = [logging.StreamHandler()]
3811 stream = sys.stderr
3812 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3813 stream=stream)
3814 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3815 handlers=handlers)
3816 assertRaises(ValueError, logging.basicConfig, stream=stream,
3817 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003818 # Issue 23207: test for invalid kwargs
3819 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3820 # Should pop both filename and filemode even if filename is None
3821 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003822
3823 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003824 handlers = [
3825 logging.StreamHandler(),
3826 logging.StreamHandler(sys.stdout),
3827 logging.StreamHandler(),
3828 ]
3829 f = logging.Formatter()
3830 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003831 logging.basicConfig(handlers=handlers)
3832 self.assertIs(handlers[0], logging.root.handlers[0])
3833 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003834 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003835 self.assertIsNotNone(handlers[0].formatter)
3836 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003837 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003838 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3839
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003840 def _test_log(self, method, level=None):
3841 # logging.root has no handlers so basicConfig should be called
3842 called = []
3843
3844 old_basic_config = logging.basicConfig
3845 def my_basic_config(*a, **kw):
3846 old_basic_config()
3847 old_level = logging.root.level
3848 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003849 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003850 called.append((a, kw))
3851
Vinay Sajip1feedb42014-05-31 08:19:12 +01003852 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003853
3854 log_method = getattr(logging, method)
3855 if level is not None:
3856 log_method(level, "test me")
3857 else:
3858 log_method("test me")
3859
3860 # basicConfig was called with no arguments
3861 self.assertEqual(called, [((), {})])
3862
3863 def test_log(self):
3864 self._test_log('log', logging.WARNING)
3865
3866 def test_debug(self):
3867 self._test_log('debug')
3868
3869 def test_info(self):
3870 self._test_log('info')
3871
3872 def test_warning(self):
3873 self._test_log('warning')
3874
3875 def test_error(self):
3876 self._test_log('error')
3877
3878 def test_critical(self):
3879 self._test_log('critical')
3880
3881
3882class LoggerAdapterTest(unittest.TestCase):
3883
3884 def setUp(self):
3885 super(LoggerAdapterTest, self).setUp()
3886 old_handler_list = logging._handlerList[:]
3887
3888 self.recording = RecordingHandler()
3889 self.logger = logging.root
3890 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003891 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003892 self.addCleanup(self.recording.close)
3893
3894 def cleanup():
3895 logging._handlerList[:] = old_handler_list
3896
3897 self.addCleanup(cleanup)
3898 self.addCleanup(logging.shutdown)
3899 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3900
3901 def test_exception(self):
3902 msg = 'testing exception: %r'
3903 exc = None
3904 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003905 1 / 0
3906 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003907 exc = e
3908 self.adapter.exception(msg, self.recording)
3909
3910 self.assertEqual(len(self.recording.records), 1)
3911 record = self.recording.records[0]
3912 self.assertEqual(record.levelno, logging.ERROR)
3913 self.assertEqual(record.msg, msg)
3914 self.assertEqual(record.args, (self.recording,))
3915 self.assertEqual(record.exc_info,
3916 (exc.__class__, exc, exc.__traceback__))
3917
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003918 def test_exception_excinfo(self):
3919 try:
3920 1 / 0
3921 except ZeroDivisionError as e:
3922 exc = e
3923
3924 self.adapter.exception('exc_info test', exc_info=exc)
3925
3926 self.assertEqual(len(self.recording.records), 1)
3927 record = self.recording.records[0]
3928 self.assertEqual(record.exc_info,
3929 (exc.__class__, exc, exc.__traceback__))
3930
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003931 def test_critical(self):
3932 msg = 'critical test! %r'
3933 self.adapter.critical(msg, self.recording)
3934
3935 self.assertEqual(len(self.recording.records), 1)
3936 record = self.recording.records[0]
3937 self.assertEqual(record.levelno, logging.CRITICAL)
3938 self.assertEqual(record.msg, msg)
3939 self.assertEqual(record.args, (self.recording,))
3940
3941 def test_is_enabled_for(self):
3942 old_disable = self.adapter.logger.manager.disable
3943 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003944 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3945 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003946 self.assertFalse(self.adapter.isEnabledFor(32))
3947
3948 def test_has_handlers(self):
3949 self.assertTrue(self.adapter.hasHandlers())
3950
3951 for handler in self.logger.handlers:
3952 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003953
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003954 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003955 self.assertFalse(self.adapter.hasHandlers())
3956
3957
3958class LoggerTest(BaseTest):
3959
3960 def setUp(self):
3961 super(LoggerTest, self).setUp()
3962 self.recording = RecordingHandler()
3963 self.logger = logging.Logger(name='blah')
3964 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003965 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003966 self.addCleanup(self.recording.close)
3967 self.addCleanup(logging.shutdown)
3968
3969 def test_set_invalid_level(self):
3970 self.assertRaises(TypeError, self.logger.setLevel, object())
3971
3972 def test_exception(self):
3973 msg = 'testing exception: %r'
3974 exc = None
3975 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003976 1 / 0
3977 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003978 exc = e
3979 self.logger.exception(msg, self.recording)
3980
3981 self.assertEqual(len(self.recording.records), 1)
3982 record = self.recording.records[0]
3983 self.assertEqual(record.levelno, logging.ERROR)
3984 self.assertEqual(record.msg, msg)
3985 self.assertEqual(record.args, (self.recording,))
3986 self.assertEqual(record.exc_info,
3987 (exc.__class__, exc, exc.__traceback__))
3988
3989 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003990 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003991 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003992
3993 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003994 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003995 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003996
3997 def test_find_caller_with_stack_info(self):
3998 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003999 support.patch(self, logging.traceback, 'print_stack',
4000 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004001
4002 self.logger.findCaller(stack_info=True)
4003
4004 self.assertEqual(len(called), 1)
4005 self.assertEqual('Stack (most recent call last):\n', called[0])
4006
4007 def test_make_record_with_extra_overwrite(self):
4008 name = 'my record'
4009 level = 13
4010 fn = lno = msg = args = exc_info = func = sinfo = None
4011 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4012 exc_info, func, sinfo)
4013
4014 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4015 extra = {key: 'some value'}
4016 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4017 fn, lno, msg, args, exc_info,
4018 extra=extra, sinfo=sinfo)
4019
4020 def test_make_record_with_extra_no_overwrite(self):
4021 name = 'my record'
4022 level = 13
4023 fn = lno = msg = args = exc_info = func = sinfo = None
4024 extra = {'valid_key': 'some value'}
4025 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4026 exc_info, extra=extra, sinfo=sinfo)
4027 self.assertIn('valid_key', result.__dict__)
4028
4029 def test_has_handlers(self):
4030 self.assertTrue(self.logger.hasHandlers())
4031
4032 for handler in self.logger.handlers:
4033 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004034 self.assertFalse(self.logger.hasHandlers())
4035
4036 def test_has_handlers_no_propagate(self):
4037 child_logger = logging.getLogger('blah.child')
4038 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004039 self.assertFalse(child_logger.hasHandlers())
4040
4041 def test_is_enabled_for(self):
4042 old_disable = self.logger.manager.disable
4043 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004044 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004045 self.assertFalse(self.logger.isEnabledFor(22))
4046
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004047 def test_root_logger_aliases(self):
4048 root = logging.getLogger()
4049 self.assertIs(root, logging.root)
4050 self.assertIs(root, logging.getLogger(None))
4051 self.assertIs(root, logging.getLogger(''))
4052 self.assertIs(root, logging.getLogger('foo').root)
4053 self.assertIs(root, logging.getLogger('foo.bar').root)
4054 self.assertIs(root, logging.getLogger('foo').parent)
4055
4056 self.assertIsNot(root, logging.getLogger('\0'))
4057 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4058
4059 def test_invalid_names(self):
4060 self.assertRaises(TypeError, logging.getLogger, any)
4061 self.assertRaises(TypeError, logging.getLogger, b'foo')
4062
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004063
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004064class BaseFileTest(BaseTest):
4065 "Base class for handler tests that write log files"
4066
4067 def setUp(self):
4068 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004069 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4070 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004071 self.rmfiles = []
4072
4073 def tearDown(self):
4074 for fn in self.rmfiles:
4075 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004076 if os.path.exists(self.fn):
4077 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004078 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004079
4080 def assertLogFile(self, filename):
4081 "Assert a log file is there and register it for deletion"
4082 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004083 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004084 self.rmfiles.append(filename)
4085
4086
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004087class FileHandlerTest(BaseFileTest):
4088 def test_delay(self):
4089 os.unlink(self.fn)
4090 fh = logging.FileHandler(self.fn, delay=True)
4091 self.assertIsNone(fh.stream)
4092 self.assertFalse(os.path.exists(self.fn))
4093 fh.handle(logging.makeLogRecord({}))
4094 self.assertIsNotNone(fh.stream)
4095 self.assertTrue(os.path.exists(self.fn))
4096 fh.close()
4097
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004098class RotatingFileHandlerTest(BaseFileTest):
4099 def next_rec(self):
4100 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4101 self.next_message(), None, None, None)
4102
4103 def test_should_not_rollover(self):
4104 # If maxbytes is zero rollover never occurs
4105 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4106 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004107 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004108
4109 def test_should_rollover(self):
4110 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4111 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004112 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004113
4114 def test_file_created(self):
4115 # checks that the file is created and assumes it was created
4116 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004117 rh = logging.handlers.RotatingFileHandler(self.fn)
4118 rh.emit(self.next_rec())
4119 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004120 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004121
4122 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004123 def namer(name):
4124 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004125 rh = logging.handlers.RotatingFileHandler(
4126 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004127 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004128 rh.emit(self.next_rec())
4129 self.assertLogFile(self.fn)
4130 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004131 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004132 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004133 self.assertLogFile(namer(self.fn + ".2"))
4134 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4135 rh.close()
4136
Vinay Sajip1feedb42014-05-31 08:19:12 +01004137 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004138 def test_rotator(self):
4139 def namer(name):
4140 return name + ".gz"
4141
4142 def rotator(source, dest):
4143 with open(source, "rb") as sf:
4144 data = sf.read()
4145 compressed = zlib.compress(data, 9)
4146 with open(dest, "wb") as df:
4147 df.write(compressed)
4148 os.remove(source)
4149
4150 rh = logging.handlers.RotatingFileHandler(
4151 self.fn, backupCount=2, maxBytes=1)
4152 rh.rotator = rotator
4153 rh.namer = namer
4154 m1 = self.next_rec()
4155 rh.emit(m1)
4156 self.assertLogFile(self.fn)
4157 m2 = self.next_rec()
4158 rh.emit(m2)
4159 fn = namer(self.fn + ".1")
4160 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004161 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004162 with open(fn, "rb") as f:
4163 compressed = f.read()
4164 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004165 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004166 rh.emit(self.next_rec())
4167 fn = namer(self.fn + ".2")
4168 self.assertLogFile(fn)
4169 with open(fn, "rb") as f:
4170 compressed = f.read()
4171 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004172 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004173 rh.emit(self.next_rec())
4174 fn = namer(self.fn + ".2")
4175 with open(fn, "rb") as f:
4176 compressed = f.read()
4177 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004178 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004179 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004180 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004181
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004182class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004183 # other test methods added below
4184 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004185 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4186 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004187 fmt = logging.Formatter('%(asctime)s %(message)s')
4188 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004189 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004190 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004191 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004192 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004193 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004194 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004195 fh.close()
4196 # At this point, we should have a recent rotated file which we
4197 # can test for the existence of. However, in practice, on some
4198 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004199 # in time to go to look for the log file. So, we go back a fair
4200 # bit, and stop as soon as we see a rotated file. In theory this
4201 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004202 found = False
4203 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004204 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004205 for secs in range(GO_BACK):
4206 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004207 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4208 found = os.path.exists(fn)
4209 if found:
4210 self.rmfiles.append(fn)
4211 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004212 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4213 if not found:
4214 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004215 dn, fn = os.path.split(self.fn)
4216 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004217 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4218 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004219 for f in files:
4220 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004221 path = os.path.join(dn, f)
4222 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004223 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004224 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004225
Vinay Sajip0372e102011-05-05 12:59:14 +01004226 def test_invalid(self):
4227 assertRaises = self.assertRaises
4228 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004229 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004230 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004231 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004232 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004233 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004234
Vinay Sajipa7130792013-04-12 17:04:23 +01004235 def test_compute_rollover_daily_attime(self):
4236 currentTime = 0
4237 atTime = datetime.time(12, 0, 0)
4238 rh = logging.handlers.TimedRotatingFileHandler(
4239 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4240 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004241 try:
4242 actual = rh.computeRollover(currentTime)
4243 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004244
Vinay Sajipd86ac962013-04-14 12:20:46 +01004245 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4246 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4247 finally:
4248 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004249
Vinay Sajip10e8c492013-05-18 10:19:54 -07004250 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004251 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004252 currentTime = int(time.time())
4253 today = currentTime - currentTime % 86400
4254
Vinay Sajipa7130792013-04-12 17:04:23 +01004255 atTime = datetime.time(12, 0, 0)
4256
Vinay Sajip10e8c492013-05-18 10:19:54 -07004257 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004258 for day in range(7):
4259 rh = logging.handlers.TimedRotatingFileHandler(
4260 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4261 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004262 try:
4263 if wday > day:
4264 # The rollover day has already passed this week, so we
4265 # go over into next week
4266 expected = (7 - wday + day)
4267 else:
4268 expected = (day - wday)
4269 # At this point expected is in days from now, convert to seconds
4270 expected *= 24 * 60 * 60
4271 # Add in the rollover time
4272 expected += 12 * 60 * 60
4273 # Add in adjustment for today
4274 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004275 actual = rh.computeRollover(today)
4276 if actual != expected:
4277 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004278 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004279 self.assertEqual(actual, expected)
4280 if day == wday:
4281 # goes into following week
4282 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004283 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004284 if actual != expected:
4285 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004286 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004287 self.assertEqual(actual, expected)
4288 finally:
4289 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004290
4291
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004292def secs(**kw):
4293 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4294
4295for when, exp in (('S', 1),
4296 ('M', 60),
4297 ('H', 60 * 60),
4298 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004299 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004300 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004301 ('W0', secs(days=4, hours=24)),
4302 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004303 def test_compute_rollover(self, when=when, exp=exp):
4304 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004305 self.fn, when=when, interval=1, backupCount=0, utc=True)
4306 currentTime = 0.0
4307 actual = rh.computeRollover(currentTime)
4308 if exp != actual:
4309 # Failures occur on some systems for MIDNIGHT and W0.
4310 # Print detailed calculation for MIDNIGHT so we can try to see
4311 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004312 if when == 'MIDNIGHT':
4313 try:
4314 if rh.utc:
4315 t = time.gmtime(currentTime)
4316 else:
4317 t = time.localtime(currentTime)
4318 currentHour = t[3]
4319 currentMinute = t[4]
4320 currentSecond = t[5]
4321 # r is the number of seconds left between now and midnight
4322 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4323 currentMinute) * 60 +
4324 currentSecond)
4325 result = currentTime + r
4326 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4327 print('currentHour: %s' % currentHour, file=sys.stderr)
4328 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4329 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4330 print('r: %s' % r, file=sys.stderr)
4331 print('result: %s' % result, file=sys.stderr)
4332 except Exception:
4333 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4334 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004335 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004336 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4337
Vinay Sajip60ccd822011-05-09 17:32:09 +01004338
Vinay Sajip223349c2015-10-01 20:37:54 +01004339@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004340class NTEventLogHandlerTest(BaseTest):
4341 def test_basic(self):
4342 logtype = 'Application'
4343 elh = win32evtlog.OpenEventLog(None, logtype)
4344 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004345
4346 try:
4347 h = logging.handlers.NTEventLogHandler('test_logging')
4348 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004349 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004350 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004351 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004352
Vinay Sajip60ccd822011-05-09 17:32:09 +01004353 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4354 h.handle(r)
4355 h.close()
4356 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004357 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004358 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4359 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4360 found = False
4361 GO_BACK = 100
4362 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4363 for e in events:
4364 if e.SourceName != 'test_logging':
4365 continue
4366 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4367 if msg != 'Test Log Message\r\n':
4368 continue
4369 found = True
4370 break
4371 msg = 'Record not found in event log, went back %d records' % GO_BACK
4372 self.assertTrue(found, msg=msg)
4373
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004374
4375class MiscTestCase(unittest.TestCase):
4376 def test__all__(self):
4377 blacklist = {'logThreads', 'logMultiprocessing',
4378 'logProcesses', 'currentframe',
4379 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4380 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004381 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004382 support.check__all__(self, logging, blacklist=blacklist)
4383
4384
Christian Heimes180510d2008-03-03 19:15:45 +00004385# Set the locale to the platform-dependent default. I have no idea
4386# why the test does this, but in any case we save the current locale
4387# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004388@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004389def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004390 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004391 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4392 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4393 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4394 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4395 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4396 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4397 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4398 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang95b4da22017-06-01 22:20:27 +08004399 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004400 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004401 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004402 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004403 ]
4404 if hasattr(logging.handlers, 'QueueListener'):
4405 tests.append(QueueListenerTest)
4406 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004407
Christian Heimes180510d2008-03-03 19:15:45 +00004408if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004409 test_main()