blob: 0a2584c6103c3277417c7402d6460ddec72adc67 [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):
1666 self.sl_hdlr = hcls(('localhost', server.port))
1667 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
Vinay Sajip5421f352013-09-27 18:18:28 +01001726@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001727class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001728 """Test for HTTPHandler."""
1729
1730 def setUp(self):
1731 """Set up an HTTP server to receive log messages, and a HTTPHandler
1732 pointing to that server's address and port."""
1733 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001734 self.handled = threading.Event()
1735
Vinay Sajip7367d082011-05-02 13:17:27 +01001736 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001737 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001738 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001739 if self.command == 'POST':
1740 try:
1741 rlen = int(request.headers['Content-Length'])
1742 self.post_data = request.rfile.read(rlen)
1743 except:
1744 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001745 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001746 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001747 self.handled.set()
1748
1749 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001750 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001751 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001752 root_logger = self.root_logger
1753 root_logger.removeHandler(self.root_logger.handlers[0])
1754 for secure in (False, True):
1755 addr = ('localhost', 0)
1756 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001757 try:
1758 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001759 except ImportError:
1760 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001761 else:
1762 here = os.path.dirname(__file__)
1763 localhost_cert = os.path.join(here, "keycert.pem")
1764 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1765 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001766
1767 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001768 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001769 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001770 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001771 self.server = server = TestHTTPServer(addr, self.handle_request,
1772 0.01, sslctx=sslctx)
1773 server.start()
1774 server.ready.wait()
1775 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001776 secure_client = secure and sslctx
1777 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001778 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001779 context=context,
1780 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001781 self.log_data = None
1782 root_logger.addHandler(self.h_hdlr)
1783
1784 for method in ('GET', 'POST'):
1785 self.h_hdlr.method = method
1786 self.handled.clear()
1787 msg = "sp\xe4m"
1788 logger.error(msg)
1789 self.handled.wait()
1790 self.assertEqual(self.log_data.path, '/frob')
1791 self.assertEqual(self.command, method)
1792 if method == 'GET':
1793 d = parse_qs(self.log_data.query)
1794 else:
1795 d = parse_qs(self.post_data.decode('utf-8'))
1796 self.assertEqual(d['name'], ['http'])
1797 self.assertEqual(d['funcName'], ['test_output'])
1798 self.assertEqual(d['msg'], [msg])
1799
1800 self.server.stop(2.0)
1801 self.root_logger.removeHandler(self.h_hdlr)
1802 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001803
Christian Heimes180510d2008-03-03 19:15:45 +00001804class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001805
Christian Heimes180510d2008-03-03 19:15:45 +00001806 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001807
Christian Heimes180510d2008-03-03 19:15:45 +00001808 def setUp(self):
1809 """Create a dict to remember potentially destroyed objects."""
1810 BaseTest.setUp(self)
1811 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001812
Christian Heimes180510d2008-03-03 19:15:45 +00001813 def _watch_for_survival(self, *args):
1814 """Watch the given objects for survival, by creating weakrefs to
1815 them."""
1816 for obj in args:
1817 key = id(obj), repr(obj)
1818 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001819
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001820 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001821 """Assert that all objects watched for survival have survived."""
1822 # Trigger cycle breaking.
1823 gc.collect()
1824 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001825 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001826 if ref() is None:
1827 dead.append(repr_)
1828 if dead:
1829 self.fail("%d objects should have survived "
1830 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001831
Christian Heimes180510d2008-03-03 19:15:45 +00001832 def test_persistent_loggers(self):
1833 # Logger objects are persistent and retain their configuration, even
1834 # if visible references are destroyed.
1835 self.root_logger.setLevel(logging.INFO)
1836 foo = logging.getLogger("foo")
1837 self._watch_for_survival(foo)
1838 foo.setLevel(logging.DEBUG)
1839 self.root_logger.debug(self.next_message())
1840 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001841 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001842 ('foo', 'DEBUG', '2'),
1843 ])
1844 del foo
1845 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001846 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001847 # foo has retained its settings.
1848 bar = logging.getLogger("foo")
1849 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001850 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001851 ('foo', 'DEBUG', '2'),
1852 ('foo', 'DEBUG', '3'),
1853 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001854
Benjamin Petersonf91df042009-02-13 02:50:59 +00001855
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001856class EncodingTest(BaseTest):
1857 def test_encoding_plain_file(self):
1858 # In Python 2.x, a plain file object is treated as having no encoding.
1859 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001860 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1861 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001862 # the non-ascii data we write to the log.
1863 data = "foo\x80"
1864 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001865 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001866 log.addHandler(handler)
1867 try:
1868 # write non-ascii data to the log.
1869 log.warning(data)
1870 finally:
1871 log.removeHandler(handler)
1872 handler.close()
1873 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001874 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001875 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001876 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001877 finally:
1878 f.close()
1879 finally:
1880 if os.path.isfile(fn):
1881 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001882
Benjamin Petersonf91df042009-02-13 02:50:59 +00001883 def test_encoding_cyrillic_unicode(self):
1884 log = logging.getLogger("test")
1885 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1886 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1887 #Ensure it's written in a Cyrillic encoding
1888 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001889 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001890 stream = io.BytesIO()
1891 writer = writer_class(stream, 'strict')
1892 handler = logging.StreamHandler(writer)
1893 log.addHandler(handler)
1894 try:
1895 log.warning(message)
1896 finally:
1897 log.removeHandler(handler)
1898 handler.close()
1899 # check we wrote exactly those bytes, ignoring trailing \n etc
1900 s = stream.getvalue()
1901 #Compare against what the data should be when encoded in CP-1251
1902 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1903
1904
Georg Brandlf9734072008-12-07 15:30:06 +00001905class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001906
Georg Brandlf9734072008-12-07 15:30:06 +00001907 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001908 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001909 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001910 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001911 warnings.filterwarnings("always", category=UserWarning)
1912 stream = io.StringIO()
1913 h = logging.StreamHandler(stream)
1914 logger = logging.getLogger("py.warnings")
1915 logger.addHandler(h)
1916 warnings.warn("I'm warning you...")
1917 logger.removeHandler(h)
1918 s = stream.getvalue()
1919 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001920 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001921
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001922 #See if an explicit file uses the original implementation
1923 a_file = io.StringIO()
1924 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1925 a_file, "Dummy line")
1926 s = a_file.getvalue()
1927 a_file.close()
1928 self.assertEqual(s,
1929 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1930
1931 def test_warnings_no_handlers(self):
1932 with warnings.catch_warnings():
1933 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001934 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001935
1936 # confirm our assumption: no loggers are set
1937 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001938 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001939
1940 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001941 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001942 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001943
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001944
1945def formatFunc(format, datefmt=None):
1946 return logging.Formatter(format, datefmt)
1947
1948def handlerFunc():
1949 return logging.StreamHandler()
1950
1951class CustomHandler(logging.StreamHandler):
1952 pass
1953
1954class ConfigDictTest(BaseTest):
1955
1956 """Reading logging config from a dictionary."""
1957
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001958 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001959
1960 # config0 is a standard configuration.
1961 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001962 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001963 'formatters': {
1964 'form1' : {
1965 'format' : '%(levelname)s ++ %(message)s',
1966 },
1967 },
1968 'handlers' : {
1969 'hand1' : {
1970 'class' : 'logging.StreamHandler',
1971 'formatter' : 'form1',
1972 'level' : 'NOTSET',
1973 'stream' : 'ext://sys.stdout',
1974 },
1975 },
1976 'root' : {
1977 'level' : 'WARNING',
1978 'handlers' : ['hand1'],
1979 },
1980 }
1981
1982 # config1 adds a little to the standard configuration.
1983 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001984 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001985 'formatters': {
1986 'form1' : {
1987 'format' : '%(levelname)s ++ %(message)s',
1988 },
1989 },
1990 'handlers' : {
1991 'hand1' : {
1992 'class' : 'logging.StreamHandler',
1993 'formatter' : 'form1',
1994 'level' : 'NOTSET',
1995 'stream' : 'ext://sys.stdout',
1996 },
1997 },
1998 'loggers' : {
1999 'compiler.parser' : {
2000 'level' : 'DEBUG',
2001 'handlers' : ['hand1'],
2002 },
2003 },
2004 'root' : {
2005 'level' : 'WARNING',
2006 },
2007 }
2008
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002009 # config1a moves the handler to the root. Used with config8a
2010 config1a = {
2011 'version': 1,
2012 'formatters': {
2013 'form1' : {
2014 'format' : '%(levelname)s ++ %(message)s',
2015 },
2016 },
2017 'handlers' : {
2018 'hand1' : {
2019 'class' : 'logging.StreamHandler',
2020 'formatter' : 'form1',
2021 'level' : 'NOTSET',
2022 'stream' : 'ext://sys.stdout',
2023 },
2024 },
2025 'loggers' : {
2026 'compiler.parser' : {
2027 'level' : 'DEBUG',
2028 },
2029 },
2030 'root' : {
2031 'level' : 'WARNING',
2032 'handlers' : ['hand1'],
2033 },
2034 }
2035
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002036 # config2 has a subtle configuration error that should be reported
2037 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002038 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002039 'formatters': {
2040 'form1' : {
2041 'format' : '%(levelname)s ++ %(message)s',
2042 },
2043 },
2044 'handlers' : {
2045 'hand1' : {
2046 'class' : 'logging.StreamHandler',
2047 'formatter' : 'form1',
2048 'level' : 'NOTSET',
2049 'stream' : 'ext://sys.stdbout',
2050 },
2051 },
2052 'loggers' : {
2053 'compiler.parser' : {
2054 'level' : 'DEBUG',
2055 'handlers' : ['hand1'],
2056 },
2057 },
2058 'root' : {
2059 'level' : 'WARNING',
2060 },
2061 }
2062
2063 #As config1 but with a misspelt level on a handler
2064 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002065 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002066 'formatters': {
2067 'form1' : {
2068 'format' : '%(levelname)s ++ %(message)s',
2069 },
2070 },
2071 'handlers' : {
2072 'hand1' : {
2073 'class' : 'logging.StreamHandler',
2074 'formatter' : 'form1',
2075 'level' : 'NTOSET',
2076 'stream' : 'ext://sys.stdout',
2077 },
2078 },
2079 'loggers' : {
2080 'compiler.parser' : {
2081 'level' : 'DEBUG',
2082 'handlers' : ['hand1'],
2083 },
2084 },
2085 'root' : {
2086 'level' : 'WARNING',
2087 },
2088 }
2089
2090
2091 #As config1 but with a misspelt level on a logger
2092 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002093 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002094 'formatters': {
2095 'form1' : {
2096 'format' : '%(levelname)s ++ %(message)s',
2097 },
2098 },
2099 'handlers' : {
2100 'hand1' : {
2101 'class' : 'logging.StreamHandler',
2102 'formatter' : 'form1',
2103 'level' : 'NOTSET',
2104 'stream' : 'ext://sys.stdout',
2105 },
2106 },
2107 'loggers' : {
2108 'compiler.parser' : {
2109 'level' : 'DEBUG',
2110 'handlers' : ['hand1'],
2111 },
2112 },
2113 'root' : {
2114 'level' : 'WRANING',
2115 },
2116 }
2117
2118 # config3 has a less subtle configuration error
2119 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002120 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002121 'formatters': {
2122 'form1' : {
2123 'format' : '%(levelname)s ++ %(message)s',
2124 },
2125 },
2126 'handlers' : {
2127 'hand1' : {
2128 'class' : 'logging.StreamHandler',
2129 'formatter' : 'misspelled_name',
2130 'level' : 'NOTSET',
2131 'stream' : 'ext://sys.stdout',
2132 },
2133 },
2134 'loggers' : {
2135 'compiler.parser' : {
2136 'level' : 'DEBUG',
2137 'handlers' : ['hand1'],
2138 },
2139 },
2140 'root' : {
2141 'level' : 'WARNING',
2142 },
2143 }
2144
2145 # config4 specifies a custom formatter class to be loaded
2146 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002147 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002148 'formatters': {
2149 'form1' : {
2150 '()' : __name__ + '.ExceptionFormatter',
2151 'format' : '%(levelname)s:%(name)s:%(message)s',
2152 },
2153 },
2154 'handlers' : {
2155 'hand1' : {
2156 'class' : 'logging.StreamHandler',
2157 'formatter' : 'form1',
2158 'level' : 'NOTSET',
2159 'stream' : 'ext://sys.stdout',
2160 },
2161 },
2162 'root' : {
2163 'level' : 'NOTSET',
2164 'handlers' : ['hand1'],
2165 },
2166 }
2167
2168 # As config4 but using an actual callable rather than a string
2169 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002170 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002171 'formatters': {
2172 'form1' : {
2173 '()' : ExceptionFormatter,
2174 'format' : '%(levelname)s:%(name)s:%(message)s',
2175 },
2176 'form2' : {
2177 '()' : __name__ + '.formatFunc',
2178 'format' : '%(levelname)s:%(name)s:%(message)s',
2179 },
2180 'form3' : {
2181 '()' : formatFunc,
2182 'format' : '%(levelname)s:%(name)s:%(message)s',
2183 },
2184 },
2185 'handlers' : {
2186 'hand1' : {
2187 'class' : 'logging.StreamHandler',
2188 'formatter' : 'form1',
2189 'level' : 'NOTSET',
2190 'stream' : 'ext://sys.stdout',
2191 },
2192 'hand2' : {
2193 '()' : handlerFunc,
2194 },
2195 },
2196 'root' : {
2197 'level' : 'NOTSET',
2198 'handlers' : ['hand1'],
2199 },
2200 }
2201
2202 # config5 specifies a custom handler class to be loaded
2203 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002204 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002205 'formatters': {
2206 'form1' : {
2207 'format' : '%(levelname)s ++ %(message)s',
2208 },
2209 },
2210 'handlers' : {
2211 'hand1' : {
2212 'class' : __name__ + '.CustomHandler',
2213 'formatter' : 'form1',
2214 'level' : 'NOTSET',
2215 'stream' : 'ext://sys.stdout',
2216 },
2217 },
2218 'loggers' : {
2219 'compiler.parser' : {
2220 'level' : 'DEBUG',
2221 'handlers' : ['hand1'],
2222 },
2223 },
2224 'root' : {
2225 'level' : 'WARNING',
2226 },
2227 }
2228
2229 # config6 specifies a custom handler class to be loaded
2230 # but has bad arguments
2231 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002232 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002233 'formatters': {
2234 'form1' : {
2235 'format' : '%(levelname)s ++ %(message)s',
2236 },
2237 },
2238 'handlers' : {
2239 'hand1' : {
2240 'class' : __name__ + '.CustomHandler',
2241 'formatter' : 'form1',
2242 'level' : 'NOTSET',
2243 'stream' : 'ext://sys.stdout',
2244 '9' : 'invalid parameter name',
2245 },
2246 },
2247 'loggers' : {
2248 'compiler.parser' : {
2249 'level' : 'DEBUG',
2250 'handlers' : ['hand1'],
2251 },
2252 },
2253 'root' : {
2254 'level' : 'WARNING',
2255 },
2256 }
2257
2258 #config 7 does not define compiler.parser but defines compiler.lexer
2259 #so compiler.parser should be disabled after applying it
2260 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002261 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002262 'formatters': {
2263 'form1' : {
2264 'format' : '%(levelname)s ++ %(message)s',
2265 },
2266 },
2267 'handlers' : {
2268 'hand1' : {
2269 'class' : 'logging.StreamHandler',
2270 'formatter' : 'form1',
2271 'level' : 'NOTSET',
2272 'stream' : 'ext://sys.stdout',
2273 },
2274 },
2275 'loggers' : {
2276 'compiler.lexer' : {
2277 'level' : 'DEBUG',
2278 'handlers' : ['hand1'],
2279 },
2280 },
2281 'root' : {
2282 'level' : 'WARNING',
2283 },
2284 }
2285
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002286 # config8 defines both compiler and compiler.lexer
2287 # so compiler.parser should not be disabled (since
2288 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002289 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002290 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002291 'disable_existing_loggers' : False,
2292 'formatters': {
2293 'form1' : {
2294 'format' : '%(levelname)s ++ %(message)s',
2295 },
2296 },
2297 'handlers' : {
2298 'hand1' : {
2299 'class' : 'logging.StreamHandler',
2300 'formatter' : 'form1',
2301 'level' : 'NOTSET',
2302 'stream' : 'ext://sys.stdout',
2303 },
2304 },
2305 'loggers' : {
2306 'compiler' : {
2307 'level' : 'DEBUG',
2308 'handlers' : ['hand1'],
2309 },
2310 'compiler.lexer' : {
2311 },
2312 },
2313 'root' : {
2314 'level' : 'WARNING',
2315 },
2316 }
2317
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002318 # config8a disables existing loggers
2319 config8a = {
2320 'version': 1,
2321 'disable_existing_loggers' : True,
2322 'formatters': {
2323 'form1' : {
2324 'format' : '%(levelname)s ++ %(message)s',
2325 },
2326 },
2327 'handlers' : {
2328 'hand1' : {
2329 'class' : 'logging.StreamHandler',
2330 'formatter' : 'form1',
2331 'level' : 'NOTSET',
2332 'stream' : 'ext://sys.stdout',
2333 },
2334 },
2335 'loggers' : {
2336 'compiler' : {
2337 'level' : 'DEBUG',
2338 'handlers' : ['hand1'],
2339 },
2340 'compiler.lexer' : {
2341 },
2342 },
2343 'root' : {
2344 'level' : 'WARNING',
2345 },
2346 }
2347
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002348 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002349 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002350 'formatters': {
2351 'form1' : {
2352 'format' : '%(levelname)s ++ %(message)s',
2353 },
2354 },
2355 'handlers' : {
2356 'hand1' : {
2357 'class' : 'logging.StreamHandler',
2358 'formatter' : 'form1',
2359 'level' : 'WARNING',
2360 'stream' : 'ext://sys.stdout',
2361 },
2362 },
2363 'loggers' : {
2364 'compiler.parser' : {
2365 'level' : 'WARNING',
2366 'handlers' : ['hand1'],
2367 },
2368 },
2369 'root' : {
2370 'level' : 'NOTSET',
2371 },
2372 }
2373
2374 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002375 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002376 'incremental' : True,
2377 'handlers' : {
2378 'hand1' : {
2379 'level' : 'WARNING',
2380 },
2381 },
2382 'loggers' : {
2383 'compiler.parser' : {
2384 'level' : 'INFO',
2385 },
2386 },
2387 }
2388
2389 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002390 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002391 'incremental' : True,
2392 'handlers' : {
2393 'hand1' : {
2394 'level' : 'INFO',
2395 },
2396 },
2397 'loggers' : {
2398 'compiler.parser' : {
2399 'level' : 'INFO',
2400 },
2401 },
2402 }
2403
2404 #As config1 but with a filter added
2405 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002406 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002407 'formatters': {
2408 'form1' : {
2409 'format' : '%(levelname)s ++ %(message)s',
2410 },
2411 },
2412 'filters' : {
2413 'filt1' : {
2414 'name' : 'compiler.parser',
2415 },
2416 },
2417 'handlers' : {
2418 'hand1' : {
2419 'class' : 'logging.StreamHandler',
2420 'formatter' : 'form1',
2421 'level' : 'NOTSET',
2422 'stream' : 'ext://sys.stdout',
2423 'filters' : ['filt1'],
2424 },
2425 },
2426 'loggers' : {
2427 'compiler.parser' : {
2428 'level' : 'DEBUG',
2429 'filters' : ['filt1'],
2430 },
2431 },
2432 'root' : {
2433 'level' : 'WARNING',
2434 'handlers' : ['hand1'],
2435 },
2436 }
2437
2438 #As config1 but using cfg:// references
2439 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002440 'version': 1,
2441 'true_formatters': {
2442 'form1' : {
2443 'format' : '%(levelname)s ++ %(message)s',
2444 },
2445 },
2446 'handler_configs': {
2447 'hand1' : {
2448 'class' : 'logging.StreamHandler',
2449 'formatter' : 'form1',
2450 'level' : 'NOTSET',
2451 'stream' : 'ext://sys.stdout',
2452 },
2453 },
2454 'formatters' : 'cfg://true_formatters',
2455 'handlers' : {
2456 'hand1' : 'cfg://handler_configs[hand1]',
2457 },
2458 'loggers' : {
2459 'compiler.parser' : {
2460 'level' : 'DEBUG',
2461 'handlers' : ['hand1'],
2462 },
2463 },
2464 'root' : {
2465 'level' : 'WARNING',
2466 },
2467 }
2468
2469 #As config11 but missing the version key
2470 config12 = {
2471 'true_formatters': {
2472 'form1' : {
2473 'format' : '%(levelname)s ++ %(message)s',
2474 },
2475 },
2476 'handler_configs': {
2477 'hand1' : {
2478 'class' : 'logging.StreamHandler',
2479 'formatter' : 'form1',
2480 'level' : 'NOTSET',
2481 'stream' : 'ext://sys.stdout',
2482 },
2483 },
2484 'formatters' : 'cfg://true_formatters',
2485 'handlers' : {
2486 'hand1' : 'cfg://handler_configs[hand1]',
2487 },
2488 'loggers' : {
2489 'compiler.parser' : {
2490 'level' : 'DEBUG',
2491 'handlers' : ['hand1'],
2492 },
2493 },
2494 'root' : {
2495 'level' : 'WARNING',
2496 },
2497 }
2498
2499 #As config11 but using an unsupported version
2500 config13 = {
2501 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002502 'true_formatters': {
2503 'form1' : {
2504 'format' : '%(levelname)s ++ %(message)s',
2505 },
2506 },
2507 'handler_configs': {
2508 'hand1' : {
2509 'class' : 'logging.StreamHandler',
2510 'formatter' : 'form1',
2511 'level' : 'NOTSET',
2512 'stream' : 'ext://sys.stdout',
2513 },
2514 },
2515 'formatters' : 'cfg://true_formatters',
2516 'handlers' : {
2517 'hand1' : 'cfg://handler_configs[hand1]',
2518 },
2519 'loggers' : {
2520 'compiler.parser' : {
2521 'level' : 'DEBUG',
2522 'handlers' : ['hand1'],
2523 },
2524 },
2525 'root' : {
2526 'level' : 'WARNING',
2527 },
2528 }
2529
Vinay Sajip8d270232012-11-15 14:20:18 +00002530 # As config0, but with properties
2531 config14 = {
2532 'version': 1,
2533 'formatters': {
2534 'form1' : {
2535 'format' : '%(levelname)s ++ %(message)s',
2536 },
2537 },
2538 'handlers' : {
2539 'hand1' : {
2540 'class' : 'logging.StreamHandler',
2541 'formatter' : 'form1',
2542 'level' : 'NOTSET',
2543 'stream' : 'ext://sys.stdout',
2544 '.': {
2545 'foo': 'bar',
2546 'terminator': '!\n',
2547 }
2548 },
2549 },
2550 'root' : {
2551 'level' : 'WARNING',
2552 'handlers' : ['hand1'],
2553 },
2554 }
2555
Vinay Sajip3f885b52013-03-22 15:19:54 +00002556 out_of_order = {
2557 "version": 1,
2558 "formatters": {
2559 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002560 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2561 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002562 }
2563 },
2564 "handlers": {
2565 "fileGlobal": {
2566 "class": "logging.StreamHandler",
2567 "level": "DEBUG",
2568 "formatter": "mySimpleFormatter"
2569 },
2570 "bufferGlobal": {
2571 "class": "logging.handlers.MemoryHandler",
2572 "capacity": 5,
2573 "formatter": "mySimpleFormatter",
2574 "target": "fileGlobal",
2575 "level": "DEBUG"
2576 }
2577 },
2578 "loggers": {
2579 "mymodule": {
2580 "level": "DEBUG",
2581 "handlers": ["bufferGlobal"],
2582 "propagate": "true"
2583 }
2584 }
2585 }
2586
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002587 def apply_config(self, conf):
2588 logging.config.dictConfig(conf)
2589
2590 def test_config0_ok(self):
2591 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002592 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002593 self.apply_config(self.config0)
2594 logger = logging.getLogger()
2595 # Won't output anything
2596 logger.info(self.next_message())
2597 # Outputs a message
2598 logger.error(self.next_message())
2599 self.assert_log_lines([
2600 ('ERROR', '2'),
2601 ], stream=output)
2602 # Original logger output is empty.
2603 self.assert_log_lines([])
2604
2605 def test_config1_ok(self, config=config1):
2606 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002607 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002608 self.apply_config(config)
2609 logger = logging.getLogger("compiler.parser")
2610 # Both will output a message
2611 logger.info(self.next_message())
2612 logger.error(self.next_message())
2613 self.assert_log_lines([
2614 ('INFO', '1'),
2615 ('ERROR', '2'),
2616 ], stream=output)
2617 # Original logger output is empty.
2618 self.assert_log_lines([])
2619
2620 def test_config2_failure(self):
2621 # A simple config which overrides the default settings.
2622 self.assertRaises(Exception, self.apply_config, self.config2)
2623
2624 def test_config2a_failure(self):
2625 # A simple config which overrides the default settings.
2626 self.assertRaises(Exception, self.apply_config, self.config2a)
2627
2628 def test_config2b_failure(self):
2629 # A simple config which overrides the default settings.
2630 self.assertRaises(Exception, self.apply_config, self.config2b)
2631
2632 def test_config3_failure(self):
2633 # A simple config which overrides the default settings.
2634 self.assertRaises(Exception, self.apply_config, self.config3)
2635
2636 def test_config4_ok(self):
2637 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002638 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002639 self.apply_config(self.config4)
2640 #logger = logging.getLogger()
2641 try:
2642 raise RuntimeError()
2643 except RuntimeError:
2644 logging.exception("just testing")
2645 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002646 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002647 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2648 # Original logger output is empty
2649 self.assert_log_lines([])
2650
2651 def test_config4a_ok(self):
2652 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002653 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002654 self.apply_config(self.config4a)
2655 #logger = logging.getLogger()
2656 try:
2657 raise RuntimeError()
2658 except RuntimeError:
2659 logging.exception("just testing")
2660 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002661 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002662 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2663 # Original logger output is empty
2664 self.assert_log_lines([])
2665
2666 def test_config5_ok(self):
2667 self.test_config1_ok(config=self.config5)
2668
2669 def test_config6_failure(self):
2670 self.assertRaises(Exception, self.apply_config, self.config6)
2671
2672 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002673 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002674 self.apply_config(self.config1)
2675 logger = logging.getLogger("compiler.parser")
2676 # Both will output a message
2677 logger.info(self.next_message())
2678 logger.error(self.next_message())
2679 self.assert_log_lines([
2680 ('INFO', '1'),
2681 ('ERROR', '2'),
2682 ], stream=output)
2683 # Original logger output is empty.
2684 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002685 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002686 self.apply_config(self.config7)
2687 logger = logging.getLogger("compiler.parser")
2688 self.assertTrue(logger.disabled)
2689 logger = logging.getLogger("compiler.lexer")
2690 # Both will output a message
2691 logger.info(self.next_message())
2692 logger.error(self.next_message())
2693 self.assert_log_lines([
2694 ('INFO', '3'),
2695 ('ERROR', '4'),
2696 ], stream=output)
2697 # Original logger output is empty.
2698 self.assert_log_lines([])
2699
2700 #Same as test_config_7_ok but don't disable old loggers.
2701 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002702 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002703 self.apply_config(self.config1)
2704 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002705 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002706 logger.info(self.next_message())
2707 logger.error(self.next_message())
2708 self.assert_log_lines([
2709 ('INFO', '1'),
2710 ('ERROR', '2'),
2711 ], stream=output)
2712 # Original logger output is empty.
2713 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002714 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002715 self.apply_config(self.config8)
2716 logger = logging.getLogger("compiler.parser")
2717 self.assertFalse(logger.disabled)
2718 # Both will output a message
2719 logger.info(self.next_message())
2720 logger.error(self.next_message())
2721 logger = logging.getLogger("compiler.lexer")
2722 # Both will output a message
2723 logger.info(self.next_message())
2724 logger.error(self.next_message())
2725 self.assert_log_lines([
2726 ('INFO', '3'),
2727 ('ERROR', '4'),
2728 ('INFO', '5'),
2729 ('ERROR', '6'),
2730 ], stream=output)
2731 # Original logger output is empty.
2732 self.assert_log_lines([])
2733
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002734 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002735 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002736 self.apply_config(self.config1a)
2737 logger = logging.getLogger("compiler.parser")
2738 # See issue #11424. compiler-hyphenated sorts
2739 # between compiler and compiler.xyz and this
2740 # was preventing compiler.xyz from being included
2741 # in the child loggers of compiler because of an
2742 # overzealous loop termination condition.
2743 hyphenated = logging.getLogger('compiler-hyphenated')
2744 # All will output a message
2745 logger.info(self.next_message())
2746 logger.error(self.next_message())
2747 hyphenated.critical(self.next_message())
2748 self.assert_log_lines([
2749 ('INFO', '1'),
2750 ('ERROR', '2'),
2751 ('CRITICAL', '3'),
2752 ], stream=output)
2753 # Original logger output is empty.
2754 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002755 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002756 self.apply_config(self.config8a)
2757 logger = logging.getLogger("compiler.parser")
2758 self.assertFalse(logger.disabled)
2759 # Both will output a message
2760 logger.info(self.next_message())
2761 logger.error(self.next_message())
2762 logger = logging.getLogger("compiler.lexer")
2763 # Both will output a message
2764 logger.info(self.next_message())
2765 logger.error(self.next_message())
2766 # Will not appear
2767 hyphenated.critical(self.next_message())
2768 self.assert_log_lines([
2769 ('INFO', '4'),
2770 ('ERROR', '5'),
2771 ('INFO', '6'),
2772 ('ERROR', '7'),
2773 ], stream=output)
2774 # Original logger output is empty.
2775 self.assert_log_lines([])
2776
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002777 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002778 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002779 self.apply_config(self.config9)
2780 logger = logging.getLogger("compiler.parser")
2781 #Nothing will be output since both handler and logger are set to WARNING
2782 logger.info(self.next_message())
2783 self.assert_log_lines([], stream=output)
2784 self.apply_config(self.config9a)
2785 #Nothing will be output since both handler is still set to WARNING
2786 logger.info(self.next_message())
2787 self.assert_log_lines([], stream=output)
2788 self.apply_config(self.config9b)
2789 #Message should now be output
2790 logger.info(self.next_message())
2791 self.assert_log_lines([
2792 ('INFO', '3'),
2793 ], stream=output)
2794
2795 def test_config_10_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.config10)
2798 logger = logging.getLogger("compiler.parser")
2799 logger.warning(self.next_message())
2800 logger = logging.getLogger('compiler')
2801 #Not output, because filtered
2802 logger.warning(self.next_message())
2803 logger = logging.getLogger('compiler.lexer')
2804 #Not output, because filtered
2805 logger.warning(self.next_message())
2806 logger = logging.getLogger("compiler.parser.codegen")
2807 #Output, as not filtered
2808 logger.error(self.next_message())
2809 self.assert_log_lines([
2810 ('WARNING', '1'),
2811 ('ERROR', '4'),
2812 ], stream=output)
2813
2814 def test_config11_ok(self):
2815 self.test_config1_ok(self.config11)
2816
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002817 def test_config12_failure(self):
2818 self.assertRaises(Exception, self.apply_config, self.config12)
2819
2820 def test_config13_failure(self):
2821 self.assertRaises(Exception, self.apply_config, self.config13)
2822
Vinay Sajip8d270232012-11-15 14:20:18 +00002823 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002824 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002825 self.apply_config(self.config14)
2826 h = logging._handlers['hand1']
2827 self.assertEqual(h.foo, 'bar')
2828 self.assertEqual(h.terminator, '!\n')
2829 logging.warning('Exclamation')
2830 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2831
Victor Stinner45df8202010-04-28 22:31:17 +00002832 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002833 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002834 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002835 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002836 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002837 t.start()
2838 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002839 # Now get the port allocated
2840 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002841 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002842 try:
2843 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2844 sock.settimeout(2.0)
2845 sock.connect(('localhost', port))
2846
2847 slen = struct.pack('>L', len(text))
2848 s = slen + text
2849 sentsofar = 0
2850 left = len(s)
2851 while left > 0:
2852 sent = sock.send(s[sentsofar:])
2853 sentsofar += sent
2854 left -= sent
2855 sock.close()
2856 finally:
2857 t.ready.wait(2.0)
2858 logging.config.stopListening()
2859 t.join(2.0)
2860
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002861 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002862 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002863 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002864 self.setup_via_listener(json.dumps(self.config10))
2865 logger = logging.getLogger("compiler.parser")
2866 logger.warning(self.next_message())
2867 logger = logging.getLogger('compiler')
2868 #Not output, because filtered
2869 logger.warning(self.next_message())
2870 logger = logging.getLogger('compiler.lexer')
2871 #Not output, because filtered
2872 logger.warning(self.next_message())
2873 logger = logging.getLogger("compiler.parser.codegen")
2874 #Output, as not filtered
2875 logger.error(self.next_message())
2876 self.assert_log_lines([
2877 ('WARNING', '1'),
2878 ('ERROR', '4'),
2879 ], stream=output)
2880
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002881 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002882 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002883 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002884 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2885 logger = logging.getLogger("compiler.parser")
2886 # Both will output a message
2887 logger.info(self.next_message())
2888 logger.error(self.next_message())
2889 self.assert_log_lines([
2890 ('INFO', '1'),
2891 ('ERROR', '2'),
2892 ], stream=output)
2893 # Original logger output is empty.
2894 self.assert_log_lines([])
2895
Vinay Sajip4ded5512012-10-02 15:56:16 +01002896 @unittest.skipUnless(threading, 'Threading required for this test.')
2897 def test_listen_verify(self):
2898
2899 def verify_fail(stuff):
2900 return None
2901
2902 def verify_reverse(stuff):
2903 return stuff[::-1]
2904
2905 logger = logging.getLogger("compiler.parser")
2906 to_send = textwrap.dedent(ConfigFileTest.config1)
2907 # First, specify a verification function that will fail.
2908 # We expect to see no output, since our configuration
2909 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002910 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002911 self.setup_via_listener(to_send, verify_fail)
2912 # Both will output a message
2913 logger.info(self.next_message())
2914 logger.error(self.next_message())
2915 self.assert_log_lines([], stream=output)
2916 # Original logger output has the stuff we logged.
2917 self.assert_log_lines([
2918 ('INFO', '1'),
2919 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002920 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002921
2922 # Now, perform no verification. Our configuration
2923 # should take effect.
2924
Vinay Sajip1feedb42014-05-31 08:19:12 +01002925 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002926 self.setup_via_listener(to_send) # no verify callable specified
2927 logger = logging.getLogger("compiler.parser")
2928 # Both will output a message
2929 logger.info(self.next_message())
2930 logger.error(self.next_message())
2931 self.assert_log_lines([
2932 ('INFO', '3'),
2933 ('ERROR', '4'),
2934 ], stream=output)
2935 # Original logger output still has the stuff we logged before.
2936 self.assert_log_lines([
2937 ('INFO', '1'),
2938 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002939 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002940
2941 # Now, perform verification which transforms the bytes.
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[::-1], verify_reverse)
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', '5'),
2951 ('ERROR', '6'),
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
Vinay Sajip3f885b52013-03-22 15:19:54 +00002959 def test_out_of_order(self):
2960 self.apply_config(self.out_of_order)
2961 handler = logging.getLogger('mymodule').handlers[0]
2962 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002963 self.assertIsInstance(handler.formatter._style,
2964 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002965
Vinay Sajip373baef2011-04-26 20:05:24 +01002966 def test_baseconfig(self):
2967 d = {
2968 'atuple': (1, 2, 3),
2969 'alist': ['a', 'b', 'c'],
2970 'adict': {'d': 'e', 'f': 3 },
2971 'nest1': ('g', ('h', 'i'), 'j'),
2972 'nest2': ['k', ['l', 'm'], 'n'],
2973 'nest3': ['o', 'cfg://alist', 'p'],
2974 }
2975 bc = logging.config.BaseConfigurator(d)
2976 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2977 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2978 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2979 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2980 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2981 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2982 v = bc.convert('cfg://nest3')
2983 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2984 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2985 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2986 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002987
2988class ManagerTest(BaseTest):
2989 def test_manager_loggerclass(self):
2990 logged = []
2991
2992 class MyLogger(logging.Logger):
2993 def _log(self, level, msg, args, exc_info=None, extra=None):
2994 logged.append(msg)
2995
2996 man = logging.Manager(None)
2997 self.assertRaises(TypeError, man.setLoggerClass, int)
2998 man.setLoggerClass(MyLogger)
2999 logger = man.getLogger('test')
3000 logger.warning('should appear in logged')
3001 logging.warning('should not appear in logged')
3002
3003 self.assertEqual(logged, ['should appear in logged'])
3004
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003005 def test_set_log_record_factory(self):
3006 man = logging.Manager(None)
3007 expected = object()
3008 man.setLogRecordFactory(expected)
3009 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003010
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003011class ChildLoggerTest(BaseTest):
3012 def test_child_loggers(self):
3013 r = logging.getLogger()
3014 l1 = logging.getLogger('abc')
3015 l2 = logging.getLogger('def.ghi')
3016 c1 = r.getChild('xyz')
3017 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003018 self.assertIs(c1, logging.getLogger('xyz'))
3019 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003020 c1 = l1.getChild('def')
3021 c2 = c1.getChild('ghi')
3022 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003023 self.assertIs(c1, logging.getLogger('abc.def'))
3024 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3025 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003026
3027
Vinay Sajip6fac8172010-10-19 20:44:14 +00003028class DerivedLogRecord(logging.LogRecord):
3029 pass
3030
Vinay Sajip61561522010-12-03 11:50:38 +00003031class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003032
3033 def setUp(self):
3034 class CheckingFilter(logging.Filter):
3035 def __init__(self, cls):
3036 self.cls = cls
3037
3038 def filter(self, record):
3039 t = type(record)
3040 if t is not self.cls:
3041 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3042 self.cls)
3043 raise TypeError(msg)
3044 return True
3045
3046 BaseTest.setUp(self)
3047 self.filter = CheckingFilter(DerivedLogRecord)
3048 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003049 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003050
3051 def tearDown(self):
3052 self.root_logger.removeFilter(self.filter)
3053 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003054 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003055
3056 def test_logrecord_class(self):
3057 self.assertRaises(TypeError, self.root_logger.warning,
3058 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003059 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003060 self.root_logger.error(self.next_message())
3061 self.assert_log_lines([
3062 ('root', 'ERROR', '2'),
3063 ])
3064
3065
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003066class QueueHandlerTest(BaseTest):
3067 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003068 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003069
3070 def setUp(self):
3071 BaseTest.setUp(self)
3072 self.queue = queue.Queue(-1)
3073 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3074 self.que_logger = logging.getLogger('que')
3075 self.que_logger.propagate = False
3076 self.que_logger.setLevel(logging.WARNING)
3077 self.que_logger.addHandler(self.que_hdlr)
3078
3079 def tearDown(self):
3080 self.que_hdlr.close()
3081 BaseTest.tearDown(self)
3082
3083 def test_queue_handler(self):
3084 self.que_logger.debug(self.next_message())
3085 self.assertRaises(queue.Empty, self.queue.get_nowait)
3086 self.que_logger.info(self.next_message())
3087 self.assertRaises(queue.Empty, self.queue.get_nowait)
3088 msg = self.next_message()
3089 self.que_logger.warning(msg)
3090 data = self.queue.get_nowait()
3091 self.assertTrue(isinstance(data, logging.LogRecord))
3092 self.assertEqual(data.name, self.que_logger.name)
3093 self.assertEqual((data.msg, data.args), (msg, None))
3094
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003095 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3096 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003097 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003098 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003099 listener = logging.handlers.QueueListener(self.queue, handler)
3100 listener.start()
3101 try:
3102 self.que_logger.warning(self.next_message())
3103 self.que_logger.error(self.next_message())
3104 self.que_logger.critical(self.next_message())
3105 finally:
3106 listener.stop()
3107 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3108 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3109 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003110 handler.close()
3111
3112 # Now test with respect_handler_level set
3113
3114 handler = support.TestHandler(support.Matcher())
3115 handler.setLevel(logging.CRITICAL)
3116 listener = logging.handlers.QueueListener(self.queue, handler,
3117 respect_handler_level=True)
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.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3126 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3127 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3128
Vinay Sajipd61910c2016-09-08 01:13:39 +01003129if hasattr(logging.handlers, 'QueueListener'):
3130 import multiprocessing
3131 from unittest.mock import patch
3132
3133 class QueueListenerTest(BaseTest):
3134 """
3135 Tests based on patch submitted for issue #27930. Ensure that
3136 QueueListener handles all log messages.
3137 """
3138
3139 repeat = 20
3140
3141 @staticmethod
3142 def setup_and_log(log_queue, ident):
3143 """
3144 Creates a logger with a QueueHandler that logs to a queue read by a
3145 QueueListener. Starts the listener, logs five messages, and stops
3146 the listener.
3147 """
3148 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3149 logger.setLevel(logging.DEBUG)
3150 handler = logging.handlers.QueueHandler(log_queue)
3151 logger.addHandler(handler)
3152 listener = logging.handlers.QueueListener(log_queue)
3153 listener.start()
3154
3155 logger.info('one')
3156 logger.info('two')
3157 logger.info('three')
3158 logger.info('four')
3159 logger.info('five')
3160
3161 listener.stop()
3162 logger.removeHandler(handler)
3163 handler.close()
3164
3165 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003166 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003167 def test_handle_called_with_queue_queue(self, mock_handle):
3168 for i in range(self.repeat):
3169 log_queue = queue.Queue()
3170 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3171 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3172 'correct number of handled log messages')
3173
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003174 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003175 @patch.object(logging.handlers.QueueListener, 'handle')
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003176 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003177 def test_handle_called_with_mp_queue(self, mock_handle):
3178 for i in range(self.repeat):
3179 log_queue = multiprocessing.Queue()
3180 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003181 log_queue.close()
3182 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003183 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3184 'correct number of handled log messages')
3185
3186 @staticmethod
3187 def get_all_from_queue(log_queue):
3188 try:
3189 while True:
3190 yield log_queue.get_nowait()
3191 except queue.Empty:
3192 return []
3193
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003194 @support.requires_multiprocessing_queue
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003195 @support.reap_threads
Vinay Sajipd61910c2016-09-08 01:13:39 +01003196 def test_no_messages_in_queue_after_stop(self):
3197 """
3198 Five messages are logged then the QueueListener is stopped. This
3199 test then gets everything off the queue. Failure of this test
3200 indicates that messages were not registered on the queue until
3201 _after_ the QueueListener stopped.
3202 """
3203 for i in range(self.repeat):
3204 queue = multiprocessing.Queue()
3205 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3206 # time.sleep(1)
3207 items = list(self.get_all_from_queue(queue))
Victor Stinnercb21f5f2017-04-28 04:13:53 +02003208 queue.close()
3209 queue.join_thread()
3210
Vinay Sajipd61910c2016-09-08 01:13:39 +01003211 expected = [[], [logging.handlers.QueueListener._sentinel]]
3212 self.assertIn(items, expected,
3213 'Found unexpected messages in queue: %s' % (
3214 [m.msg if isinstance(m, logging.LogRecord)
3215 else m for m in items]))
3216
Vinay Sajipe723e962011-04-15 22:27:17 +01003217
Vinay Sajip37eb3382011-04-26 20:26:41 +01003218ZERO = datetime.timedelta(0)
3219
3220class UTC(datetime.tzinfo):
3221 def utcoffset(self, dt):
3222 return ZERO
3223
3224 dst = utcoffset
3225
3226 def tzname(self, dt):
3227 return 'UTC'
3228
3229utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003230
Vinay Sajipa39c5712010-10-25 13:57:39 +00003231class FormatterTest(unittest.TestCase):
3232 def setUp(self):
3233 self.common = {
3234 'name': 'formatter.test',
3235 'level': logging.DEBUG,
3236 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3237 'lineno': 42,
3238 'exc_info': None,
3239 'func': None,
3240 'msg': 'Message with %d %s',
3241 'args': (2, 'placeholders'),
3242 }
3243 self.variants = {
3244 }
3245
3246 def get_record(self, name=None):
3247 result = dict(self.common)
3248 if name is not None:
3249 result.update(self.variants[name])
3250 return logging.makeLogRecord(result)
3251
3252 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003253 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003254 r = self.get_record()
3255 f = logging.Formatter('${%(message)s}')
3256 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3257 f = logging.Formatter('%(random)s')
3258 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003259 self.assertFalse(f.usesTime())
3260 f = logging.Formatter('%(asctime)s')
3261 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003262 f = logging.Formatter('%(asctime)-15s')
3263 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003264 f = logging.Formatter('asctime')
3265 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003266
3267 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003268 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003269 r = self.get_record()
3270 f = logging.Formatter('$%{message}%$', style='{')
3271 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3272 f = logging.Formatter('{random}', style='{')
3273 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003274 self.assertFalse(f.usesTime())
3275 f = logging.Formatter('{asctime}', style='{')
3276 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003277 f = logging.Formatter('{asctime!s:15}', style='{')
3278 self.assertTrue(f.usesTime())
3279 f = logging.Formatter('{asctime:15}', style='{')
3280 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003281 f = logging.Formatter('asctime', style='{')
3282 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003283
3284 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003285 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003286 r = self.get_record()
3287 f = logging.Formatter('$message', style='$')
3288 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3289 f = logging.Formatter('$$%${message}%$$', style='$')
3290 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3291 f = logging.Formatter('${random}', style='$')
3292 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003293 self.assertFalse(f.usesTime())
3294 f = logging.Formatter('${asctime}', style='$')
3295 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003296 f = logging.Formatter('${asctime', style='$')
3297 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003298 f = logging.Formatter('$asctime', style='$')
3299 self.assertTrue(f.usesTime())
3300 f = logging.Formatter('asctime', style='$')
3301 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003302
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003303 def test_invalid_style(self):
3304 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3305
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003306 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003307 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003308 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3309 # We use None to indicate we want the local timezone
3310 # We're essentially converting a UTC time to local time
3311 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003312 r.msecs = 123
3313 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003314 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003315 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3316 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003317 f.format(r)
3318 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3319
3320class TestBufferingFormatter(logging.BufferingFormatter):
3321 def formatHeader(self, records):
3322 return '[(%d)' % len(records)
3323
3324 def formatFooter(self, records):
3325 return '(%d)]' % len(records)
3326
3327class BufferingFormatterTest(unittest.TestCase):
3328 def setUp(self):
3329 self.records = [
3330 logging.makeLogRecord({'msg': 'one'}),
3331 logging.makeLogRecord({'msg': 'two'}),
3332 ]
3333
3334 def test_default(self):
3335 f = logging.BufferingFormatter()
3336 self.assertEqual('', f.format([]))
3337 self.assertEqual('onetwo', f.format(self.records))
3338
3339 def test_custom(self):
3340 f = TestBufferingFormatter()
3341 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3342 lf = logging.Formatter('<%(message)s>')
3343 f = TestBufferingFormatter(lf)
3344 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003345
3346class ExceptionTest(BaseTest):
3347 def test_formatting(self):
3348 r = self.root_logger
3349 h = RecordingHandler()
3350 r.addHandler(h)
3351 try:
3352 raise RuntimeError('deliberate mistake')
3353 except:
3354 logging.exception('failed', stack_info=True)
3355 r.removeHandler(h)
3356 h.close()
3357 r = h.records[0]
3358 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3359 'call last):\n'))
3360 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3361 'deliberate mistake'))
3362 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3363 'call last):\n'))
3364 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3365 'stack_info=True)'))
3366
3367
Vinay Sajip5a27d402010-12-10 11:42:57 +00003368class LastResortTest(BaseTest):
3369 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003370 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003371 root = self.root_logger
3372 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003373 old_lastresort = logging.lastResort
3374 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003375
Vinay Sajip5a27d402010-12-10 11:42:57 +00003376 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003377 with support.captured_stderr() as stderr:
3378 root.debug('This should not appear')
3379 self.assertEqual(stderr.getvalue(), '')
3380 root.warning('Final chance!')
3381 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3382
3383 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003384 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003385 with support.captured_stderr() as stderr:
3386 root.warning('Final chance!')
3387 msg = 'No handlers could be found for logger "root"\n'
3388 self.assertEqual(stderr.getvalue(), msg)
3389
Vinay Sajip5a27d402010-12-10 11:42:57 +00003390 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003391 with support.captured_stderr() as stderr:
3392 root.warning('Final chance!')
3393 self.assertEqual(stderr.getvalue(), '')
3394
3395 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003396 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003397 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003398 with support.captured_stderr() as stderr:
3399 root.warning('Final chance!')
3400 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003401 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003402 root.addHandler(self.root_hdlr)
3403 logging.lastResort = old_lastresort
3404 logging.raiseExceptions = old_raise_exceptions
3405
3406
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003407class FakeHandler:
3408
3409 def __init__(self, identifier, called):
3410 for method in ('acquire', 'flush', 'close', 'release'):
3411 setattr(self, method, self.record_call(identifier, method, called))
3412
3413 def record_call(self, identifier, method_name, called):
3414 def inner():
3415 called.append('{} - {}'.format(identifier, method_name))
3416 return inner
3417
3418
3419class RecordingHandler(logging.NullHandler):
3420
3421 def __init__(self, *args, **kwargs):
3422 super(RecordingHandler, self).__init__(*args, **kwargs)
3423 self.records = []
3424
3425 def handle(self, record):
3426 """Keep track of all the emitted records."""
3427 self.records.append(record)
3428
3429
3430class ShutdownTest(BaseTest):
3431
Vinay Sajip5e66b162011-04-20 15:41:14 +01003432 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003433
3434 def setUp(self):
3435 super(ShutdownTest, self).setUp()
3436 self.called = []
3437
3438 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003439 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003440
3441 def raise_error(self, error):
3442 def inner():
3443 raise error()
3444 return inner
3445
3446 def test_no_failure(self):
3447 # create some fake handlers
3448 handler0 = FakeHandler(0, self.called)
3449 handler1 = FakeHandler(1, self.called)
3450 handler2 = FakeHandler(2, self.called)
3451
3452 # create live weakref to those handlers
3453 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3454
3455 logging.shutdown(handlerList=list(handlers))
3456
3457 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3458 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3459 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3460 self.assertEqual(expected, self.called)
3461
3462 def _test_with_failure_in_method(self, method, error):
3463 handler = FakeHandler(0, self.called)
3464 setattr(handler, method, self.raise_error(error))
3465 handlers = [logging.weakref.ref(handler)]
3466
3467 logging.shutdown(handlerList=list(handlers))
3468
3469 self.assertEqual('0 - release', self.called[-1])
3470
3471 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003472 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003473
3474 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003475 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003476
3477 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003478 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003479
3480 def test_with_valueerror_in_acquire(self):
3481 self._test_with_failure_in_method('acquire', ValueError)
3482
3483 def test_with_valueerror_in_flush(self):
3484 self._test_with_failure_in_method('flush', ValueError)
3485
3486 def test_with_valueerror_in_close(self):
3487 self._test_with_failure_in_method('close', ValueError)
3488
3489 def test_with_other_error_in_acquire_without_raise(self):
3490 logging.raiseExceptions = False
3491 self._test_with_failure_in_method('acquire', IndexError)
3492
3493 def test_with_other_error_in_flush_without_raise(self):
3494 logging.raiseExceptions = False
3495 self._test_with_failure_in_method('flush', IndexError)
3496
3497 def test_with_other_error_in_close_without_raise(self):
3498 logging.raiseExceptions = False
3499 self._test_with_failure_in_method('close', IndexError)
3500
3501 def test_with_other_error_in_acquire_with_raise(self):
3502 logging.raiseExceptions = True
3503 self.assertRaises(IndexError, self._test_with_failure_in_method,
3504 'acquire', IndexError)
3505
3506 def test_with_other_error_in_flush_with_raise(self):
3507 logging.raiseExceptions = True
3508 self.assertRaises(IndexError, self._test_with_failure_in_method,
3509 'flush', IndexError)
3510
3511 def test_with_other_error_in_close_with_raise(self):
3512 logging.raiseExceptions = True
3513 self.assertRaises(IndexError, self._test_with_failure_in_method,
3514 'close', IndexError)
3515
3516
3517class ModuleLevelMiscTest(BaseTest):
3518
Vinay Sajip5e66b162011-04-20 15:41:14 +01003519 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003520
3521 def test_disable(self):
3522 old_disable = logging.root.manager.disable
3523 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003524 self.assertEqual(old_disable, 0)
3525 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003526
3527 logging.disable(83)
3528 self.assertEqual(logging.root.manager.disable, 83)
3529
3530 def _test_log(self, method, level=None):
3531 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003532 support.patch(self, logging, 'basicConfig',
3533 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003534
3535 recording = RecordingHandler()
3536 logging.root.addHandler(recording)
3537
3538 log_method = getattr(logging, method)
3539 if level is not None:
3540 log_method(level, "test me: %r", recording)
3541 else:
3542 log_method("test me: %r", recording)
3543
3544 self.assertEqual(len(recording.records), 1)
3545 record = recording.records[0]
3546 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3547
3548 expected_level = level if level is not None else getattr(logging, method.upper())
3549 self.assertEqual(record.levelno, expected_level)
3550
3551 # basicConfig was not called!
3552 self.assertEqual(called, [])
3553
3554 def test_log(self):
3555 self._test_log('log', logging.ERROR)
3556
3557 def test_debug(self):
3558 self._test_log('debug')
3559
3560 def test_info(self):
3561 self._test_log('info')
3562
3563 def test_warning(self):
3564 self._test_log('warning')
3565
3566 def test_error(self):
3567 self._test_log('error')
3568
3569 def test_critical(self):
3570 self._test_log('critical')
3571
3572 def test_set_logger_class(self):
3573 self.assertRaises(TypeError, logging.setLoggerClass, object)
3574
3575 class MyLogger(logging.Logger):
3576 pass
3577
3578 logging.setLoggerClass(MyLogger)
3579 self.assertEqual(logging.getLoggerClass(), MyLogger)
3580
3581 logging.setLoggerClass(logging.Logger)
3582 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3583
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003584 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003585 def test_logging_at_shutdown(self):
3586 # Issue #20037
3587 code = """if 1:
3588 import logging
3589
3590 class A:
3591 def __del__(self):
3592 try:
3593 raise ValueError("some error")
3594 except Exception:
3595 logging.exception("exception in __del__")
3596
3597 a = A()"""
3598 rc, out, err = assert_python_ok("-c", code)
3599 err = err.decode()
3600 self.assertIn("exception in __del__", err)
3601 self.assertIn("ValueError: some error", err)
3602
3603
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003604class LogRecordTest(BaseTest):
3605 def test_str_rep(self):
3606 r = logging.makeLogRecord({})
3607 s = str(r)
3608 self.assertTrue(s.startswith('<LogRecord: '))
3609 self.assertTrue(s.endswith('>'))
3610
3611 def test_dict_arg(self):
3612 h = RecordingHandler()
3613 r = logging.getLogger()
3614 r.addHandler(h)
3615 d = {'less' : 'more' }
3616 logging.warning('less is %(less)s', d)
3617 self.assertIs(h.records[0].args, d)
3618 self.assertEqual(h.records[0].message, 'less is more')
3619 r.removeHandler(h)
3620 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003621
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003622 def test_multiprocessing(self):
3623 r = logging.makeLogRecord({})
3624 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003625 try:
3626 import multiprocessing as mp
3627 r = logging.makeLogRecord({})
3628 self.assertEqual(r.processName, mp.current_process().name)
3629 except ImportError:
3630 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003631
3632 def test_optional(self):
3633 r = logging.makeLogRecord({})
3634 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003635 if threading:
3636 NOT_NONE(r.thread)
3637 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003638 NOT_NONE(r.process)
3639 NOT_NONE(r.processName)
3640 log_threads = logging.logThreads
3641 log_processes = logging.logProcesses
3642 log_multiprocessing = logging.logMultiprocessing
3643 try:
3644 logging.logThreads = False
3645 logging.logProcesses = False
3646 logging.logMultiprocessing = False
3647 r = logging.makeLogRecord({})
3648 NONE = self.assertIsNone
3649 NONE(r.thread)
3650 NONE(r.threadName)
3651 NONE(r.process)
3652 NONE(r.processName)
3653 finally:
3654 logging.logThreads = log_threads
3655 logging.logProcesses = log_processes
3656 logging.logMultiprocessing = log_multiprocessing
3657
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003658class BasicConfigTest(unittest.TestCase):
3659
Vinay Sajip95bf5042011-04-20 11:50:56 +01003660 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003661
3662 def setUp(self):
3663 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003664 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003665 self.saved_handlers = logging._handlers.copy()
3666 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003667 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003668 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003669 logging.root.handlers = []
3670
3671 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003672 for h in logging.root.handlers[:]:
3673 logging.root.removeHandler(h)
3674 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003675 super(BasicConfigTest, self).tearDown()
3676
Vinay Sajip3def7e02011-04-20 10:58:06 +01003677 def cleanup(self):
3678 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003679 logging._handlers.clear()
3680 logging._handlers.update(self.saved_handlers)
3681 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003682 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003683
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003684 def test_no_kwargs(self):
3685 logging.basicConfig()
3686
3687 # handler defaults to a StreamHandler to sys.stderr
3688 self.assertEqual(len(logging.root.handlers), 1)
3689 handler = logging.root.handlers[0]
3690 self.assertIsInstance(handler, logging.StreamHandler)
3691 self.assertEqual(handler.stream, sys.stderr)
3692
3693 formatter = handler.formatter
3694 # format defaults to logging.BASIC_FORMAT
3695 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3696 # datefmt defaults to None
3697 self.assertIsNone(formatter.datefmt)
3698 # style defaults to %
3699 self.assertIsInstance(formatter._style, logging.PercentStyle)
3700
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003701 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003702 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003703
Vinay Sajip1fd12022014-01-13 21:59:56 +00003704 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003705 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003706 logging.basicConfig(stream=sys.stdout, style="{")
3707 logging.error("Log an error")
3708 sys.stdout.seek(0)
3709 self.assertEqual(output.getvalue().strip(),
3710 "ERROR:root:Log an error")
3711
3712 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003713 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003714 logging.basicConfig(stream=sys.stdout, style="$")
3715 logging.error("Log an error")
3716 sys.stdout.seek(0)
3717 self.assertEqual(output.getvalue().strip(),
3718 "ERROR:root:Log an error")
3719
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003720 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003721
3722 def cleanup(h1, h2, fn):
3723 h1.close()
3724 h2.close()
3725 os.remove(fn)
3726
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003727 logging.basicConfig(filename='test.log')
3728
3729 self.assertEqual(len(logging.root.handlers), 1)
3730 handler = logging.root.handlers[0]
3731 self.assertIsInstance(handler, logging.FileHandler)
3732
3733 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003734 self.assertEqual(handler.stream.mode, expected.stream.mode)
3735 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003736 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003737
3738 def test_filemode(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', filemode='wb')
3746
3747 handler = logging.root.handlers[0]
3748 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003749 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003750 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751
3752 def test_stream(self):
3753 stream = io.StringIO()
3754 self.addCleanup(stream.close)
3755 logging.basicConfig(stream=stream)
3756
3757 self.assertEqual(len(logging.root.handlers), 1)
3758 handler = logging.root.handlers[0]
3759 self.assertIsInstance(handler, logging.StreamHandler)
3760 self.assertEqual(handler.stream, stream)
3761
3762 def test_format(self):
3763 logging.basicConfig(format='foo')
3764
3765 formatter = logging.root.handlers[0].formatter
3766 self.assertEqual(formatter._style._fmt, 'foo')
3767
3768 def test_datefmt(self):
3769 logging.basicConfig(datefmt='bar')
3770
3771 formatter = logging.root.handlers[0].formatter
3772 self.assertEqual(formatter.datefmt, 'bar')
3773
3774 def test_style(self):
3775 logging.basicConfig(style='$')
3776
3777 formatter = logging.root.handlers[0].formatter
3778 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3779
3780 def test_level(self):
3781 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003782 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003783
3784 logging.basicConfig(level=57)
3785 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003786 # Test that second call has no effect
3787 logging.basicConfig(level=58)
3788 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003789
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003790 def test_incompatible(self):
3791 assertRaises = self.assertRaises
3792 handlers = [logging.StreamHandler()]
3793 stream = sys.stderr
3794 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3795 stream=stream)
3796 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3797 handlers=handlers)
3798 assertRaises(ValueError, logging.basicConfig, stream=stream,
3799 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003800 # Issue 23207: test for invalid kwargs
3801 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3802 # Should pop both filename and filemode even if filename is None
3803 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003804
3805 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003806 handlers = [
3807 logging.StreamHandler(),
3808 logging.StreamHandler(sys.stdout),
3809 logging.StreamHandler(),
3810 ]
3811 f = logging.Formatter()
3812 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003813 logging.basicConfig(handlers=handlers)
3814 self.assertIs(handlers[0], logging.root.handlers[0])
3815 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003816 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003817 self.assertIsNotNone(handlers[0].formatter)
3818 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003819 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003820 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3821
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003822 def _test_log(self, method, level=None):
3823 # logging.root has no handlers so basicConfig should be called
3824 called = []
3825
3826 old_basic_config = logging.basicConfig
3827 def my_basic_config(*a, **kw):
3828 old_basic_config()
3829 old_level = logging.root.level
3830 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003831 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003832 called.append((a, kw))
3833
Vinay Sajip1feedb42014-05-31 08:19:12 +01003834 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003835
3836 log_method = getattr(logging, method)
3837 if level is not None:
3838 log_method(level, "test me")
3839 else:
3840 log_method("test me")
3841
3842 # basicConfig was called with no arguments
3843 self.assertEqual(called, [((), {})])
3844
3845 def test_log(self):
3846 self._test_log('log', logging.WARNING)
3847
3848 def test_debug(self):
3849 self._test_log('debug')
3850
3851 def test_info(self):
3852 self._test_log('info')
3853
3854 def test_warning(self):
3855 self._test_log('warning')
3856
3857 def test_error(self):
3858 self._test_log('error')
3859
3860 def test_critical(self):
3861 self._test_log('critical')
3862
3863
3864class LoggerAdapterTest(unittest.TestCase):
3865
3866 def setUp(self):
3867 super(LoggerAdapterTest, self).setUp()
3868 old_handler_list = logging._handlerList[:]
3869
3870 self.recording = RecordingHandler()
3871 self.logger = logging.root
3872 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003873 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003874 self.addCleanup(self.recording.close)
3875
3876 def cleanup():
3877 logging._handlerList[:] = old_handler_list
3878
3879 self.addCleanup(cleanup)
3880 self.addCleanup(logging.shutdown)
3881 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3882
3883 def test_exception(self):
3884 msg = 'testing exception: %r'
3885 exc = None
3886 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003887 1 / 0
3888 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003889 exc = e
3890 self.adapter.exception(msg, self.recording)
3891
3892 self.assertEqual(len(self.recording.records), 1)
3893 record = self.recording.records[0]
3894 self.assertEqual(record.levelno, logging.ERROR)
3895 self.assertEqual(record.msg, msg)
3896 self.assertEqual(record.args, (self.recording,))
3897 self.assertEqual(record.exc_info,
3898 (exc.__class__, exc, exc.__traceback__))
3899
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003900 def test_exception_excinfo(self):
3901 try:
3902 1 / 0
3903 except ZeroDivisionError as e:
3904 exc = e
3905
3906 self.adapter.exception('exc_info test', exc_info=exc)
3907
3908 self.assertEqual(len(self.recording.records), 1)
3909 record = self.recording.records[0]
3910 self.assertEqual(record.exc_info,
3911 (exc.__class__, exc, exc.__traceback__))
3912
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003913 def test_critical(self):
3914 msg = 'critical test! %r'
3915 self.adapter.critical(msg, self.recording)
3916
3917 self.assertEqual(len(self.recording.records), 1)
3918 record = self.recording.records[0]
3919 self.assertEqual(record.levelno, logging.CRITICAL)
3920 self.assertEqual(record.msg, msg)
3921 self.assertEqual(record.args, (self.recording,))
3922
3923 def test_is_enabled_for(self):
3924 old_disable = self.adapter.logger.manager.disable
3925 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003926 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3927 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003928 self.assertFalse(self.adapter.isEnabledFor(32))
3929
3930 def test_has_handlers(self):
3931 self.assertTrue(self.adapter.hasHandlers())
3932
3933 for handler in self.logger.handlers:
3934 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003935
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003936 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003937 self.assertFalse(self.adapter.hasHandlers())
3938
3939
3940class LoggerTest(BaseTest):
3941
3942 def setUp(self):
3943 super(LoggerTest, self).setUp()
3944 self.recording = RecordingHandler()
3945 self.logger = logging.Logger(name='blah')
3946 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003947 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003948 self.addCleanup(self.recording.close)
3949 self.addCleanup(logging.shutdown)
3950
3951 def test_set_invalid_level(self):
3952 self.assertRaises(TypeError, self.logger.setLevel, object())
3953
3954 def test_exception(self):
3955 msg = 'testing exception: %r'
3956 exc = None
3957 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003958 1 / 0
3959 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003960 exc = e
3961 self.logger.exception(msg, self.recording)
3962
3963 self.assertEqual(len(self.recording.records), 1)
3964 record = self.recording.records[0]
3965 self.assertEqual(record.levelno, logging.ERROR)
3966 self.assertEqual(record.msg, msg)
3967 self.assertEqual(record.args, (self.recording,))
3968 self.assertEqual(record.exc_info,
3969 (exc.__class__, exc, exc.__traceback__))
3970
3971 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003972 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003973 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003974
3975 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003976 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003977 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003978
3979 def test_find_caller_with_stack_info(self):
3980 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003981 support.patch(self, logging.traceback, 'print_stack',
3982 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003983
3984 self.logger.findCaller(stack_info=True)
3985
3986 self.assertEqual(len(called), 1)
3987 self.assertEqual('Stack (most recent call last):\n', called[0])
3988
3989 def test_make_record_with_extra_overwrite(self):
3990 name = 'my record'
3991 level = 13
3992 fn = lno = msg = args = exc_info = func = sinfo = None
3993 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3994 exc_info, func, sinfo)
3995
3996 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3997 extra = {key: 'some value'}
3998 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3999 fn, lno, msg, args, exc_info,
4000 extra=extra, sinfo=sinfo)
4001
4002 def test_make_record_with_extra_no_overwrite(self):
4003 name = 'my record'
4004 level = 13
4005 fn = lno = msg = args = exc_info = func = sinfo = None
4006 extra = {'valid_key': 'some value'}
4007 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4008 exc_info, extra=extra, sinfo=sinfo)
4009 self.assertIn('valid_key', result.__dict__)
4010
4011 def test_has_handlers(self):
4012 self.assertTrue(self.logger.hasHandlers())
4013
4014 for handler in self.logger.handlers:
4015 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004016 self.assertFalse(self.logger.hasHandlers())
4017
4018 def test_has_handlers_no_propagate(self):
4019 child_logger = logging.getLogger('blah.child')
4020 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004021 self.assertFalse(child_logger.hasHandlers())
4022
4023 def test_is_enabled_for(self):
4024 old_disable = self.logger.manager.disable
4025 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004026 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004027 self.assertFalse(self.logger.isEnabledFor(22))
4028
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004029 def test_root_logger_aliases(self):
4030 root = logging.getLogger()
4031 self.assertIs(root, logging.root)
4032 self.assertIs(root, logging.getLogger(None))
4033 self.assertIs(root, logging.getLogger(''))
4034 self.assertIs(root, logging.getLogger('foo').root)
4035 self.assertIs(root, logging.getLogger('foo.bar').root)
4036 self.assertIs(root, logging.getLogger('foo').parent)
4037
4038 self.assertIsNot(root, logging.getLogger('\0'))
4039 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4040
4041 def test_invalid_names(self):
4042 self.assertRaises(TypeError, logging.getLogger, any)
4043 self.assertRaises(TypeError, logging.getLogger, b'foo')
4044
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004045
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004046class BaseFileTest(BaseTest):
4047 "Base class for handler tests that write log files"
4048
4049 def setUp(self):
4050 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004051 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4052 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004053 self.rmfiles = []
4054
4055 def tearDown(self):
4056 for fn in self.rmfiles:
4057 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004058 if os.path.exists(self.fn):
4059 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004060 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004061
4062 def assertLogFile(self, filename):
4063 "Assert a log file is there and register it for deletion"
4064 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004065 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004066 self.rmfiles.append(filename)
4067
4068
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004069class FileHandlerTest(BaseFileTest):
4070 def test_delay(self):
4071 os.unlink(self.fn)
4072 fh = logging.FileHandler(self.fn, delay=True)
4073 self.assertIsNone(fh.stream)
4074 self.assertFalse(os.path.exists(self.fn))
4075 fh.handle(logging.makeLogRecord({}))
4076 self.assertIsNotNone(fh.stream)
4077 self.assertTrue(os.path.exists(self.fn))
4078 fh.close()
4079
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004080class RotatingFileHandlerTest(BaseFileTest):
4081 def next_rec(self):
4082 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4083 self.next_message(), None, None, None)
4084
4085 def test_should_not_rollover(self):
4086 # If maxbytes is zero rollover never occurs
4087 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4088 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004089 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004090
4091 def test_should_rollover(self):
4092 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4093 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004094 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004095
4096 def test_file_created(self):
4097 # checks that the file is created and assumes it was created
4098 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004099 rh = logging.handlers.RotatingFileHandler(self.fn)
4100 rh.emit(self.next_rec())
4101 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004102 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004103
4104 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004105 def namer(name):
4106 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004107 rh = logging.handlers.RotatingFileHandler(
4108 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004109 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004110 rh.emit(self.next_rec())
4111 self.assertLogFile(self.fn)
4112 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004113 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004114 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004115 self.assertLogFile(namer(self.fn + ".2"))
4116 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4117 rh.close()
4118
Vinay Sajip1feedb42014-05-31 08:19:12 +01004119 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004120 def test_rotator(self):
4121 def namer(name):
4122 return name + ".gz"
4123
4124 def rotator(source, dest):
4125 with open(source, "rb") as sf:
4126 data = sf.read()
4127 compressed = zlib.compress(data, 9)
4128 with open(dest, "wb") as df:
4129 df.write(compressed)
4130 os.remove(source)
4131
4132 rh = logging.handlers.RotatingFileHandler(
4133 self.fn, backupCount=2, maxBytes=1)
4134 rh.rotator = rotator
4135 rh.namer = namer
4136 m1 = self.next_rec()
4137 rh.emit(m1)
4138 self.assertLogFile(self.fn)
4139 m2 = self.next_rec()
4140 rh.emit(m2)
4141 fn = namer(self.fn + ".1")
4142 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004143 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004144 with open(fn, "rb") as f:
4145 compressed = f.read()
4146 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004147 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004148 rh.emit(self.next_rec())
4149 fn = namer(self.fn + ".2")
4150 self.assertLogFile(fn)
4151 with open(fn, "rb") as f:
4152 compressed = f.read()
4153 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004154 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004155 rh.emit(self.next_rec())
4156 fn = namer(self.fn + ".2")
4157 with open(fn, "rb") as f:
4158 compressed = f.read()
4159 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004160 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004161 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004162 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004163
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004164class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004165 # other test methods added below
4166 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004167 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4168 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004169 fmt = logging.Formatter('%(asctime)s %(message)s')
4170 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004171 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004172 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004173 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004174 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004175 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004176 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004177 fh.close()
4178 # At this point, we should have a recent rotated file which we
4179 # can test for the existence of. However, in practice, on some
4180 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004181 # in time to go to look for the log file. So, we go back a fair
4182 # bit, and stop as soon as we see a rotated file. In theory this
4183 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004184 found = False
4185 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004186 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004187 for secs in range(GO_BACK):
4188 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004189 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4190 found = os.path.exists(fn)
4191 if found:
4192 self.rmfiles.append(fn)
4193 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004194 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4195 if not found:
4196 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004197 dn, fn = os.path.split(self.fn)
4198 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004199 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4200 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004201 for f in files:
4202 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004203 path = os.path.join(dn, f)
4204 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004205 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004206 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004207
Vinay Sajip0372e102011-05-05 12:59:14 +01004208 def test_invalid(self):
4209 assertRaises = self.assertRaises
4210 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004211 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004212 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004213 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004214 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004215 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004216
Vinay Sajipa7130792013-04-12 17:04:23 +01004217 def test_compute_rollover_daily_attime(self):
4218 currentTime = 0
4219 atTime = datetime.time(12, 0, 0)
4220 rh = logging.handlers.TimedRotatingFileHandler(
4221 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4222 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004223 try:
4224 actual = rh.computeRollover(currentTime)
4225 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004226
Vinay Sajipd86ac962013-04-14 12:20:46 +01004227 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4228 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4229 finally:
4230 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004231
Vinay Sajip10e8c492013-05-18 10:19:54 -07004232 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004233 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004234 currentTime = int(time.time())
4235 today = currentTime - currentTime % 86400
4236
Vinay Sajipa7130792013-04-12 17:04:23 +01004237 atTime = datetime.time(12, 0, 0)
4238
Vinay Sajip10e8c492013-05-18 10:19:54 -07004239 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004240 for day in range(7):
4241 rh = logging.handlers.TimedRotatingFileHandler(
4242 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4243 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004244 try:
4245 if wday > day:
4246 # The rollover day has already passed this week, so we
4247 # go over into next week
4248 expected = (7 - wday + day)
4249 else:
4250 expected = (day - wday)
4251 # At this point expected is in days from now, convert to seconds
4252 expected *= 24 * 60 * 60
4253 # Add in the rollover time
4254 expected += 12 * 60 * 60
4255 # Add in adjustment for today
4256 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004257 actual = rh.computeRollover(today)
4258 if actual != expected:
4259 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004260 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004261 self.assertEqual(actual, expected)
4262 if day == wday:
4263 # goes into following week
4264 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004265 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004266 if actual != expected:
4267 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004268 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004269 self.assertEqual(actual, expected)
4270 finally:
4271 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004272
4273
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004274def secs(**kw):
4275 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4276
4277for when, exp in (('S', 1),
4278 ('M', 60),
4279 ('H', 60 * 60),
4280 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004281 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004282 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004283 ('W0', secs(days=4, hours=24)),
4284 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004285 def test_compute_rollover(self, when=when, exp=exp):
4286 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004287 self.fn, when=when, interval=1, backupCount=0, utc=True)
4288 currentTime = 0.0
4289 actual = rh.computeRollover(currentTime)
4290 if exp != actual:
4291 # Failures occur on some systems for MIDNIGHT and W0.
4292 # Print detailed calculation for MIDNIGHT so we can try to see
4293 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004294 if when == 'MIDNIGHT':
4295 try:
4296 if rh.utc:
4297 t = time.gmtime(currentTime)
4298 else:
4299 t = time.localtime(currentTime)
4300 currentHour = t[3]
4301 currentMinute = t[4]
4302 currentSecond = t[5]
4303 # r is the number of seconds left between now and midnight
4304 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4305 currentMinute) * 60 +
4306 currentSecond)
4307 result = currentTime + r
4308 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4309 print('currentHour: %s' % currentHour, file=sys.stderr)
4310 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4311 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4312 print('r: %s' % r, file=sys.stderr)
4313 print('result: %s' % result, file=sys.stderr)
4314 except Exception:
4315 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4316 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004317 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004318 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4319
Vinay Sajip60ccd822011-05-09 17:32:09 +01004320
Vinay Sajip223349c2015-10-01 20:37:54 +01004321@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004322class NTEventLogHandlerTest(BaseTest):
4323 def test_basic(self):
4324 logtype = 'Application'
4325 elh = win32evtlog.OpenEventLog(None, logtype)
4326 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004327
4328 try:
4329 h = logging.handlers.NTEventLogHandler('test_logging')
4330 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004331 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004332 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004333 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004334
Vinay Sajip60ccd822011-05-09 17:32:09 +01004335 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4336 h.handle(r)
4337 h.close()
4338 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004339 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004340 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4341 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4342 found = False
4343 GO_BACK = 100
4344 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4345 for e in events:
4346 if e.SourceName != 'test_logging':
4347 continue
4348 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4349 if msg != 'Test Log Message\r\n':
4350 continue
4351 found = True
4352 break
4353 msg = 'Record not found in event log, went back %d records' % GO_BACK
4354 self.assertTrue(found, msg=msg)
4355
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004356
4357class MiscTestCase(unittest.TestCase):
4358 def test__all__(self):
4359 blacklist = {'logThreads', 'logMultiprocessing',
4360 'logProcesses', 'currentframe',
4361 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4362 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004363 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004364 support.check__all__(self, logging, blacklist=blacklist)
4365
4366
Christian Heimes180510d2008-03-03 19:15:45 +00004367# Set the locale to the platform-dependent default. I have no idea
4368# why the test does this, but in any case we save the current locale
4369# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004370@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004371def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004372 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004373 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4374 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4375 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4376 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4377 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4378 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4379 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4380 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4381 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4382 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004383 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004384 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004385 ]
4386 if hasattr(logging.handlers, 'QueueListener'):
4387 tests.append(QueueListenerTest)
4388 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004389
Christian Heimes180510d2008-03-03 19:15:45 +00004390if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004391 test_main()