blob: 9f482e1b30499bfbaca0b8ab4f969f8d344f9440 [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 Sajip8b866d52017-01-11 06:57:55 +0000312 def test_regression_29220(self):
313 """See issue #29220 for more information."""
314 logging.addLevelName(logging.INFO, '')
315 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
316 self.assertEqual(logging.getLevelName(logging.INFO), '')
317
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100318 def test_issue27935(self):
319 fatal = logging.getLevelName('FATAL')
320 self.assertEqual(fatal, logging.FATAL)
321
Vinay Sajip924aaae2017-01-11 17:35:36 +0000322 def test_regression_29220(self):
323 """See issue #29220 for more information."""
324 logging.addLevelName(logging.INFO, '')
325 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
326 self.assertEqual(logging.getLevelName(logging.INFO), '')
327 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
328 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
329
Christian Heimes180510d2008-03-03 19:15:45 +0000330class BasicFilterTest(BaseTest):
331
332 """Test the bundled Filter class."""
333
334 def test_filter(self):
335 # Only messages satisfying the specified criteria pass through the
336 # filter.
337 filter_ = logging.Filter("spam.eggs")
338 handler = self.root_logger.handlers[0]
339 try:
340 handler.addFilter(filter_)
341 spam = logging.getLogger("spam")
342 spam_eggs = logging.getLogger("spam.eggs")
343 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
344 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
345
346 spam.info(self.next_message())
347 spam_eggs.info(self.next_message()) # Good.
348 spam_eggs_fish.info(self.next_message()) # Good.
349 spam_bakedbeans.info(self.next_message())
350
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000351 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000352 ('spam.eggs', 'INFO', '2'),
353 ('spam.eggs.fish', 'INFO', '3'),
354 ])
355 finally:
356 handler.removeFilter(filter_)
357
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000358 def test_callable_filter(self):
359 # Only messages satisfying the specified criteria pass through the
360 # filter.
361
362 def filterfunc(record):
363 parts = record.name.split('.')
364 prefix = '.'.join(parts[:2])
365 return prefix == 'spam.eggs'
366
367 handler = self.root_logger.handlers[0]
368 try:
369 handler.addFilter(filterfunc)
370 spam = logging.getLogger("spam")
371 spam_eggs = logging.getLogger("spam.eggs")
372 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
373 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
374
375 spam.info(self.next_message())
376 spam_eggs.info(self.next_message()) # Good.
377 spam_eggs_fish.info(self.next_message()) # Good.
378 spam_bakedbeans.info(self.next_message())
379
380 self.assert_log_lines([
381 ('spam.eggs', 'INFO', '2'),
382 ('spam.eggs.fish', 'INFO', '3'),
383 ])
384 finally:
385 handler.removeFilter(filterfunc)
386
Vinay Sajip985ef872011-04-26 19:34:04 +0100387 def test_empty_filter(self):
388 f = logging.Filter()
389 r = logging.makeLogRecord({'name': 'spam.eggs'})
390 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000391
392#
393# First, we define our levels. There can be as many as you want - the only
394# limitations are that they should be integers, the lowest should be > 0 and
395# larger values mean less information being logged. If you need specific
396# level values which do not fit into these limitations, you can use a
397# mapping dictionary to convert between your application levels and the
398# logging system.
399#
400SILENT = 120
401TACITURN = 119
402TERSE = 118
403EFFUSIVE = 117
404SOCIABLE = 116
405VERBOSE = 115
406TALKATIVE = 114
407GARRULOUS = 113
408CHATTERBOX = 112
409BORING = 111
410
411LEVEL_RANGE = range(BORING, SILENT + 1)
412
413#
414# Next, we define names for our levels. You don't need to do this - in which
415# case the system will use "Level n" to denote the text for the level.
416#
417my_logging_levels = {
418 SILENT : 'Silent',
419 TACITURN : 'Taciturn',
420 TERSE : 'Terse',
421 EFFUSIVE : 'Effusive',
422 SOCIABLE : 'Sociable',
423 VERBOSE : 'Verbose',
424 TALKATIVE : 'Talkative',
425 GARRULOUS : 'Garrulous',
426 CHATTERBOX : 'Chatterbox',
427 BORING : 'Boring',
428}
429
430class GarrulousFilter(logging.Filter):
431
432 """A filter which blocks garrulous messages."""
433
434 def filter(self, record):
435 return record.levelno != GARRULOUS
436
437class VerySpecificFilter(logging.Filter):
438
439 """A filter which blocks sociable and taciturn messages."""
440
441 def filter(self, record):
442 return record.levelno not in [SOCIABLE, TACITURN]
443
444
445class CustomLevelsAndFiltersTest(BaseTest):
446
447 """Test various filtering possibilities with custom logging levels."""
448
449 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300450 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000451
452 def setUp(self):
453 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000454 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000455 logging.addLevelName(k, v)
456
457 def log_at_all_levels(self, logger):
458 for lvl in LEVEL_RANGE:
459 logger.log(lvl, self.next_message())
460
461 def test_logger_filter(self):
462 # Filter at logger level.
463 self.root_logger.setLevel(VERBOSE)
464 # Levels >= 'Verbose' are good.
465 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000466 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000467 ('Verbose', '5'),
468 ('Sociable', '6'),
469 ('Effusive', '7'),
470 ('Terse', '8'),
471 ('Taciturn', '9'),
472 ('Silent', '10'),
473 ])
474
475 def test_handler_filter(self):
476 # Filter at handler level.
477 self.root_logger.handlers[0].setLevel(SOCIABLE)
478 try:
479 # Levels >= 'Sociable' are good.
480 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000481 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000482 ('Sociable', '6'),
483 ('Effusive', '7'),
484 ('Terse', '8'),
485 ('Taciturn', '9'),
486 ('Silent', '10'),
487 ])
488 finally:
489 self.root_logger.handlers[0].setLevel(logging.NOTSET)
490
491 def test_specific_filters(self):
492 # Set a specific filter object on the handler, and then add another
493 # filter object on the logger itself.
494 handler = self.root_logger.handlers[0]
495 specific_filter = None
496 garr = GarrulousFilter()
497 handler.addFilter(garr)
498 try:
499 self.log_at_all_levels(self.root_logger)
500 first_lines = [
501 # Notice how 'Garrulous' is missing
502 ('Boring', '1'),
503 ('Chatterbox', '2'),
504 ('Talkative', '4'),
505 ('Verbose', '5'),
506 ('Sociable', '6'),
507 ('Effusive', '7'),
508 ('Terse', '8'),
509 ('Taciturn', '9'),
510 ('Silent', '10'),
511 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000512 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000513
514 specific_filter = VerySpecificFilter()
515 self.root_logger.addFilter(specific_filter)
516 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000517 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000518 # Not only 'Garrulous' is still missing, but also 'Sociable'
519 # and 'Taciturn'
520 ('Boring', '11'),
521 ('Chatterbox', '12'),
522 ('Talkative', '14'),
523 ('Verbose', '15'),
524 ('Effusive', '17'),
525 ('Terse', '18'),
526 ('Silent', '20'),
527 ])
528 finally:
529 if specific_filter:
530 self.root_logger.removeFilter(specific_filter)
531 handler.removeFilter(garr)
532
533
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100534class HandlerTest(BaseTest):
535 def test_name(self):
536 h = logging.Handler()
537 h.name = 'generic'
538 self.assertEqual(h.name, 'generic')
539 h.name = 'anothergeneric'
540 self.assertEqual(h.name, 'anothergeneric')
541 self.assertRaises(NotImplementedError, h.emit, None)
542
Vinay Sajip5a35b062011-04-27 11:31:14 +0100543 def test_builtin_handlers(self):
544 # We can't actually *use* too many handlers in the tests,
545 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200546 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 for existing in (True, False):
548 fd, fn = tempfile.mkstemp()
549 os.close(fd)
550 if not existing:
551 os.unlink(fn)
552 h = logging.handlers.WatchedFileHandler(fn, delay=True)
553 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100554 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100555 self.assertEqual(dev, -1)
556 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100557 r = logging.makeLogRecord({'msg': 'Test'})
558 h.handle(r)
559 # Now remove the file.
560 os.unlink(fn)
561 self.assertFalse(os.path.exists(fn))
562 # The next call should recreate the file.
563 h.handle(r)
564 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100565 else:
566 self.assertEqual(h.dev, -1)
567 self.assertEqual(h.ino, -1)
568 h.close()
569 if existing:
570 os.unlink(fn)
571 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100572 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100573 else:
574 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100575 try:
576 h = logging.handlers.SysLogHandler(sockname)
577 self.assertEqual(h.facility, h.LOG_USER)
578 self.assertTrue(h.unixsocket)
579 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200580 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100581 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100582 for method in ('GET', 'POST', 'PUT'):
583 if method == 'PUT':
584 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
585 'localhost', '/log', method)
586 else:
587 h = logging.handlers.HTTPHandler('localhost', '/log', method)
588 h.close()
589 h = logging.handlers.BufferingHandler(0)
590 r = logging.makeLogRecord({})
591 self.assertTrue(h.shouldFlush(r))
592 h.close()
593 h = logging.handlers.BufferingHandler(1)
594 self.assertFalse(h.shouldFlush(r))
595 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100596
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100597 def test_path_objects(self):
598 """
599 Test that Path objects are accepted as filename arguments to handlers.
600
601 See Issue #27493.
602 """
603 fd, fn = tempfile.mkstemp()
604 os.close(fd)
605 os.unlink(fn)
606 pfn = pathlib.Path(fn)
607 cases = (
608 (logging.FileHandler, (pfn, 'w')),
609 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
610 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
611 )
612 if sys.platform in ('linux', 'darwin'):
613 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
614 for cls, args in cases:
615 h = cls(*args)
616 self.assertTrue(os.path.exists(fn))
617 h.close()
618 os.unlink(fn)
619
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100620 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100621 @unittest.skipUnless(threading, 'Threading required for this test.')
622 def test_race(self):
623 # Issue #14632 refers.
624 def remove_loop(fname, tries):
625 for _ in range(tries):
626 try:
627 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000628 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100629 except OSError:
630 pass
631 time.sleep(0.004 * random.randint(0, 4))
632
Vinay Sajipc94871a2012-04-25 10:51:35 +0100633 del_count = 500
634 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100635
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000636 self.handle_time = None
637 self.deletion_time = None
638
Vinay Sajipa5798de2012-04-24 23:33:33 +0100639 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100640 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
641 os.close(fd)
642 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
643 remover.daemon = True
644 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100645 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100646 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
647 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100648 try:
649 for _ in range(log_count):
650 time.sleep(0.005)
651 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000652 try:
653 self.handle_time = time.time()
654 h.handle(r)
655 except Exception:
656 print('Deleted at %s, '
657 'opened at %s' % (self.deletion_time,
658 self.handle_time))
659 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100660 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100661 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100662 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100663 if os.path.exists(fn):
664 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100665
666
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100667class BadStream(object):
668 def write(self, data):
669 raise RuntimeError('deliberate mistake')
670
671class TestStreamHandler(logging.StreamHandler):
672 def handleError(self, record):
673 self.error_record = record
674
675class StreamHandlerTest(BaseTest):
676 def test_error_handling(self):
677 h = TestStreamHandler(BadStream())
678 r = logging.makeLogRecord({})
679 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100680
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100681 try:
682 h.handle(r)
683 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100684
Vinay Sajip985ef872011-04-26 19:34:04 +0100685 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100686 with support.captured_stderr() as stderr:
687 h.handle(r)
688 msg = '\nRuntimeError: deliberate mistake\n'
689 self.assertIn(msg, stderr.getvalue())
690
Vinay Sajip985ef872011-04-26 19:34:04 +0100691 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100692 with support.captured_stderr() as stderr:
693 h.handle(r)
694 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100695 finally:
696 logging.raiseExceptions = old_raise
697
Vinay Sajip7367d082011-05-02 13:17:27 +0100698# -- The following section could be moved into a server_helper.py module
699# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100703 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100704 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100705
Vinay Sajipce7c9782011-05-17 07:15:53 +0100706 :param addr: A (host, port) tuple which the server listens on.
707 You can specify a port value of zero: the server's
708 *port* attribute will hold the actual port number
709 used, which can be used in client connections.
710 :param handler: A callable which will be called to process
711 incoming messages. The handler will be passed
712 the client address tuple, who the message is from,
713 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100714 :param poll_interval: The interval, in seconds, used in the underlying
715 :func:`select` or :func:`poll` call by
716 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100717 :param sockmap: A dictionary which will be used to hold
718 :class:`asyncore.dispatcher` instances used by
719 :func:`asyncore.loop`. This avoids changing the
720 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100721 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100722
723 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400724 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
725 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100726 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 self._handler = handler
728 self._thread = None
729 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100730
Vinay Sajipce7c9782011-05-17 07:15:53 +0100731 def process_message(self, peer, mailfrom, rcpttos, data):
732 """
733 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100734
Vinay Sajipce7c9782011-05-17 07:15:53 +0100735 Typically, this will be a test case method.
736 :param peer: The client (host, port) tuple.
737 :param mailfrom: The address of the sender.
738 :param rcpttos: The addresses of the recipients.
739 :param data: The message.
740 """
741 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100742
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743 def start(self):
744 """
745 Start the server running on a separate daemon thread.
746 """
747 self._thread = t = threading.Thread(target=self.serve_forever,
748 args=(self.poll_interval,))
749 t.setDaemon(True)
750 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100751
Vinay Sajipce7c9782011-05-17 07:15:53 +0100752 def serve_forever(self, poll_interval):
753 """
754 Run the :mod:`asyncore` loop until normal termination
755 conditions arise.
756 :param poll_interval: The interval, in seconds, used in the underlying
757 :func:`select` or :func:`poll` call by
758 :func:`asyncore.loop`.
759 """
760 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100761 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200762 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100763 # On FreeBSD 8, closing the server repeatably
764 # raises this error. We swallow it if the
765 # server has been closed.
766 if self.connected or self.accepting:
767 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100768
Vinay Sajipce7c9782011-05-17 07:15:53 +0100769 def stop(self, timeout=None):
770 """
771 Stop the thread by closing the server instance.
772 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100773
Vinay Sajipce7c9782011-05-17 07:15:53 +0100774 :param timeout: How long to wait for the server thread
775 to terminate.
776 """
777 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100778 self._thread.join(timeout)
779 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100780
Vinay Sajipce7c9782011-05-17 07:15:53 +0100781 class ControlMixin(object):
782 """
783 This mixin is used to start a server on a separate thread, and
784 shut it down programmatically. Request handling is simplified - instead
785 of needing to derive a suitable RequestHandler subclass, you just
786 provide a callable which will be passed each received request to be
787 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100788
Vinay Sajipce7c9782011-05-17 07:15:53 +0100789 :param handler: A handler callable which will be called with a
790 single parameter - the request - in order to
791 process the request. This handler is called on the
792 server thread, effectively meaning that requests are
793 processed serially. While not quite Web scale ;-),
794 this should be fine for testing applications.
795 :param poll_interval: The polling interval in seconds.
796 """
797 def __init__(self, handler, poll_interval):
798 self._thread = None
799 self.poll_interval = poll_interval
800 self._handler = handler
801 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100802
Vinay Sajipce7c9782011-05-17 07:15:53 +0100803 def start(self):
804 """
805 Create a daemon thread to run the server, and start it.
806 """
807 self._thread = t = threading.Thread(target=self.serve_forever,
808 args=(self.poll_interval,))
809 t.setDaemon(True)
810 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100811
Vinay Sajipce7c9782011-05-17 07:15:53 +0100812 def serve_forever(self, poll_interval):
813 """
814 Run the server. Set the ready flag before entering the
815 service loop.
816 """
817 self.ready.set()
818 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100819
Vinay Sajipce7c9782011-05-17 07:15:53 +0100820 def stop(self, timeout=None):
821 """
822 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100823
Vinay Sajipce7c9782011-05-17 07:15:53 +0100824 :param timeout: How long to wait for the server thread
825 to terminate.
826 """
827 self.shutdown()
828 if self._thread is not None:
829 self._thread.join(timeout)
830 self._thread = None
831 self.server_close()
832 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100833
Vinay Sajipce7c9782011-05-17 07:15:53 +0100834 class TestHTTPServer(ControlMixin, HTTPServer):
835 """
836 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100837
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 :param addr: A tuple with the IP address and port to listen on.
839 :param handler: A handler callable which will be called with a
840 single parameter - the request - in order to
841 process the request.
842 :param poll_interval: The polling interval in seconds.
843 :param log: Pass ``True`` to enable log messages.
844 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100845 def __init__(self, addr, handler, poll_interval=0.5,
846 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100847 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
848 def __getattr__(self, name, default=None):
849 if name.startswith('do_'):
850 return self.process_request
851 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100852
Vinay Sajipce7c9782011-05-17 07:15:53 +0100853 def process_request(self):
854 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100855
Vinay Sajipce7c9782011-05-17 07:15:53 +0100856 def log_message(self, format, *args):
857 if log:
858 super(DelegatingHTTPRequestHandler,
859 self).log_message(format, *args)
860 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
861 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100862 self.sslctx = sslctx
863
864 def get_request(self):
865 try:
866 sock, addr = self.socket.accept()
867 if self.sslctx:
868 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200869 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100870 # socket errors are silenced by the caller, print them here
871 sys.stderr.write("Got an error:\n%s\n" % e)
872 raise
873 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100874
Vinay Sajipce7c9782011-05-17 07:15:53 +0100875 class TestTCPServer(ControlMixin, ThreadingTCPServer):
876 """
877 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100878
Vinay Sajipce7c9782011-05-17 07:15:53 +0100879 :param addr: A tuple with the IP address and port to listen on.
880 :param handler: A handler callable which will be called with a single
881 parameter - the request - in order to process the request.
882 :param poll_interval: The polling interval in seconds.
883 :bind_and_activate: If True (the default), binds the server and starts it
884 listening. If False, you need to call
885 :meth:`server_bind` and :meth:`server_activate` at
886 some later time before calling :meth:`start`, so that
887 the server will set up the socket and listen on it.
888 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100889
Vinay Sajipce7c9782011-05-17 07:15:53 +0100890 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100891
Vinay Sajipce7c9782011-05-17 07:15:53 +0100892 def __init__(self, addr, handler, poll_interval=0.5,
893 bind_and_activate=True):
894 class DelegatingTCPRequestHandler(StreamRequestHandler):
895
896 def handle(self):
897 self.server._handler(self)
898 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
899 bind_and_activate)
900 ControlMixin.__init__(self, handler, poll_interval)
901
902 def server_bind(self):
903 super(TestTCPServer, self).server_bind()
904 self.port = self.socket.getsockname()[1]
905
906 class TestUDPServer(ControlMixin, ThreadingUDPServer):
907 """
908 A UDP server which is controllable using :class:`ControlMixin`.
909
910 :param addr: A tuple with the IP address and port to listen on.
911 :param handler: A handler callable which will be called with a
912 single parameter - the request - in order to
913 process the request.
914 :param poll_interval: The polling interval for shutdown requests,
915 in seconds.
916 :bind_and_activate: If True (the default), binds the server and
917 starts it listening. If False, you need to
918 call :meth:`server_bind` and
919 :meth:`server_activate` at some later time
920 before calling :meth:`start`, so that the server will
921 set up the socket and listen on it.
922 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100923 def __init__(self, addr, handler, poll_interval=0.5,
924 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100925 class DelegatingUDPRequestHandler(DatagramRequestHandler):
926
927 def handle(self):
928 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100929
930 def finish(self):
931 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100932 if data:
933 try:
934 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200935 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100936 if not self.server._closed:
937 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100938
Vinay Sajip3ef12292011-05-23 23:00:42 +0100939 ThreadingUDPServer.__init__(self, addr,
940 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100941 bind_and_activate)
942 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100943 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100944
945 def server_bind(self):
946 super(TestUDPServer, self).server_bind()
947 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100948
Vinay Sajipba980db2011-05-23 21:37:54 +0100949 def server_close(self):
950 super(TestUDPServer, self).server_close()
951 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100952
Victor Stinnerec5a8602014-06-02 14:41:51 +0200953 if hasattr(socket, "AF_UNIX"):
954 class TestUnixStreamServer(TestTCPServer):
955 address_family = socket.AF_UNIX
956
957 class TestUnixDatagramServer(TestUDPServer):
958 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100959
Vinay Sajip7367d082011-05-02 13:17:27 +0100960# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100961
Vinay Sajipce7c9782011-05-17 07:15:53 +0100962@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100963class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000964 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100965 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100966 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800967 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100968 sockmap)
969 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800970 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000971 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
972 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100973 self.assertEqual(h.toaddrs, ['you'])
974 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100975 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100976 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100977 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000978 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100979 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000980 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100981 self.assertEqual(len(self.messages), 1)
982 peer, mailfrom, rcpttos, data = self.messages[0]
983 self.assertEqual(mailfrom, 'me')
984 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100985 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100986 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100987 h.close()
988
989 def process_message(self, *args):
990 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100991 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100992
Christian Heimes180510d2008-03-03 19:15:45 +0000993class MemoryHandlerTest(BaseTest):
994
995 """Tests for the MemoryHandler."""
996
997 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300998 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000999
1000 def setUp(self):
1001 BaseTest.setUp(self)
1002 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001003 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001004 self.mem_logger = logging.getLogger('mem')
1005 self.mem_logger.propagate = 0
1006 self.mem_logger.addHandler(self.mem_hdlr)
1007
1008 def tearDown(self):
1009 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001010 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001011
1012 def test_flush(self):
1013 # The memory handler flushes to its target handler based on specific
1014 # criteria (message count and message level).
1015 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001016 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001017 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001018 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001019 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001020 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001021 lines = [
1022 ('DEBUG', '1'),
1023 ('INFO', '2'),
1024 ('WARNING', '3'),
1025 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001026 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001027 for n in (4, 14):
1028 for i in range(9):
1029 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001030 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001031 # This will flush because it's the 10th message since the last
1032 # flush.
1033 self.mem_logger.debug(self.next_message())
1034 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001035 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001036
1037 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001038 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001039
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001040 def test_flush_on_close(self):
1041 """
1042 Test that the flush-on-close configuration works as expected.
1043 """
1044 self.mem_logger.debug(self.next_message())
1045 self.assert_log_lines([])
1046 self.mem_logger.info(self.next_message())
1047 self.assert_log_lines([])
1048 self.mem_logger.removeHandler(self.mem_hdlr)
1049 # Default behaviour is to flush on close. Check that it happens.
1050 self.mem_hdlr.close()
1051 lines = [
1052 ('DEBUG', '1'),
1053 ('INFO', '2'),
1054 ]
1055 self.assert_log_lines(lines)
1056 # Now configure for flushing not to be done on close.
1057 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1058 self.root_hdlr,
1059 False)
1060 self.mem_logger.addHandler(self.mem_hdlr)
1061 self.mem_logger.debug(self.next_message())
1062 self.assert_log_lines(lines) # no change
1063 self.mem_logger.info(self.next_message())
1064 self.assert_log_lines(lines) # no change
1065 self.mem_logger.removeHandler(self.mem_hdlr)
1066 self.mem_hdlr.close()
1067 # assert that no new lines have been added
1068 self.assert_log_lines(lines) # no change
1069
Christian Heimes180510d2008-03-03 19:15:45 +00001070
1071class ExceptionFormatter(logging.Formatter):
1072 """A special exception formatter."""
1073 def formatException(self, ei):
1074 return "Got a [%s]" % ei[0].__name__
1075
1076
1077class ConfigFileTest(BaseTest):
1078
1079 """Reading logging config from a .ini-style config file."""
1080
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001081 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001082
1083 # config0 is a standard configuration.
1084 config0 = """
1085 [loggers]
1086 keys=root
1087
1088 [handlers]
1089 keys=hand1
1090
1091 [formatters]
1092 keys=form1
1093
1094 [logger_root]
1095 level=WARNING
1096 handlers=hand1
1097
1098 [handler_hand1]
1099 class=StreamHandler
1100 level=NOTSET
1101 formatter=form1
1102 args=(sys.stdout,)
1103
1104 [formatter_form1]
1105 format=%(levelname)s ++ %(message)s
1106 datefmt=
1107 """
1108
1109 # config1 adds a little to the standard configuration.
1110 config1 = """
1111 [loggers]
1112 keys=root,parser
1113
1114 [handlers]
1115 keys=hand1
1116
1117 [formatters]
1118 keys=form1
1119
1120 [logger_root]
1121 level=WARNING
1122 handlers=
1123
1124 [logger_parser]
1125 level=DEBUG
1126 handlers=hand1
1127 propagate=1
1128 qualname=compiler.parser
1129
1130 [handler_hand1]
1131 class=StreamHandler
1132 level=NOTSET
1133 formatter=form1
1134 args=(sys.stdout,)
1135
1136 [formatter_form1]
1137 format=%(levelname)s ++ %(message)s
1138 datefmt=
1139 """
1140
Vinay Sajip3f84b072011-03-07 17:49:33 +00001141 # config1a moves the handler to the root.
1142 config1a = """
1143 [loggers]
1144 keys=root,parser
1145
1146 [handlers]
1147 keys=hand1
1148
1149 [formatters]
1150 keys=form1
1151
1152 [logger_root]
1153 level=WARNING
1154 handlers=hand1
1155
1156 [logger_parser]
1157 level=DEBUG
1158 handlers=
1159 propagate=1
1160 qualname=compiler.parser
1161
1162 [handler_hand1]
1163 class=StreamHandler
1164 level=NOTSET
1165 formatter=form1
1166 args=(sys.stdout,)
1167
1168 [formatter_form1]
1169 format=%(levelname)s ++ %(message)s
1170 datefmt=
1171 """
1172
Christian Heimes180510d2008-03-03 19:15:45 +00001173 # config2 has a subtle configuration error that should be reported
1174 config2 = config1.replace("sys.stdout", "sys.stbout")
1175
1176 # config3 has a less subtle configuration error
1177 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1178
1179 # config4 specifies a custom formatter class to be loaded
1180 config4 = """
1181 [loggers]
1182 keys=root
1183
1184 [handlers]
1185 keys=hand1
1186
1187 [formatters]
1188 keys=form1
1189
1190 [logger_root]
1191 level=NOTSET
1192 handlers=hand1
1193
1194 [handler_hand1]
1195 class=StreamHandler
1196 level=NOTSET
1197 formatter=form1
1198 args=(sys.stdout,)
1199
1200 [formatter_form1]
1201 class=""" + __name__ + """.ExceptionFormatter
1202 format=%(levelname)s:%(name)s:%(message)s
1203 datefmt=
1204 """
1205
Georg Brandl3dbca812008-07-23 16:10:53 +00001206 # config5 specifies a custom handler class to be loaded
1207 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1208
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001209 # config6 uses ', ' delimiters in the handlers and formatters sections
1210 config6 = """
1211 [loggers]
1212 keys=root,parser
1213
1214 [handlers]
1215 keys=hand1, hand2
1216
1217 [formatters]
1218 keys=form1, form2
1219
1220 [logger_root]
1221 level=WARNING
1222 handlers=
1223
1224 [logger_parser]
1225 level=DEBUG
1226 handlers=hand1
1227 propagate=1
1228 qualname=compiler.parser
1229
1230 [handler_hand1]
1231 class=StreamHandler
1232 level=NOTSET
1233 formatter=form1
1234 args=(sys.stdout,)
1235
1236 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001237 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001238 level=NOTSET
1239 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001240 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001241
1242 [formatter_form1]
1243 format=%(levelname)s ++ %(message)s
1244 datefmt=
1245
1246 [formatter_form2]
1247 format=%(message)s
1248 datefmt=
1249 """
1250
Vinay Sajip3f84b072011-03-07 17:49:33 +00001251 # config7 adds a compiler logger.
1252 config7 = """
1253 [loggers]
1254 keys=root,parser,compiler
1255
1256 [handlers]
1257 keys=hand1
1258
1259 [formatters]
1260 keys=form1
1261
1262 [logger_root]
1263 level=WARNING
1264 handlers=hand1
1265
1266 [logger_compiler]
1267 level=DEBUG
1268 handlers=
1269 propagate=1
1270 qualname=compiler
1271
1272 [logger_parser]
1273 level=DEBUG
1274 handlers=
1275 propagate=1
1276 qualname=compiler.parser
1277
1278 [handler_hand1]
1279 class=StreamHandler
1280 level=NOTSET
1281 formatter=form1
1282 args=(sys.stdout,)
1283
1284 [formatter_form1]
1285 format=%(levelname)s ++ %(message)s
1286 datefmt=
1287 """
1288
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001289 disable_test = """
1290 [loggers]
1291 keys=root
1292
1293 [handlers]
1294 keys=screen
1295
1296 [formatters]
1297 keys=
1298
1299 [logger_root]
1300 level=DEBUG
1301 handlers=screen
1302
1303 [handler_screen]
1304 level=DEBUG
1305 class=StreamHandler
1306 args=(sys.stdout,)
1307 formatter=
1308 """
1309
1310 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001311 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001312 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001313
1314 def test_config0_ok(self):
1315 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001316 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001317 self.apply_config(self.config0)
1318 logger = logging.getLogger()
1319 # Won't output anything
1320 logger.info(self.next_message())
1321 # Outputs a message
1322 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001323 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001324 ('ERROR', '2'),
1325 ], stream=output)
1326 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001327 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001328
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001329 def test_config0_using_cp_ok(self):
1330 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001331 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001332 file = io.StringIO(textwrap.dedent(self.config0))
1333 cp = configparser.ConfigParser()
1334 cp.read_file(file)
1335 logging.config.fileConfig(cp)
1336 logger = logging.getLogger()
1337 # Won't output anything
1338 logger.info(self.next_message())
1339 # Outputs a message
1340 logger.error(self.next_message())
1341 self.assert_log_lines([
1342 ('ERROR', '2'),
1343 ], stream=output)
1344 # Original logger output is empty.
1345 self.assert_log_lines([])
1346
Georg Brandl3dbca812008-07-23 16:10:53 +00001347 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001348 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001349 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001350 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001351 logger = logging.getLogger("compiler.parser")
1352 # Both will output a message
1353 logger.info(self.next_message())
1354 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001355 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001356 ('INFO', '1'),
1357 ('ERROR', '2'),
1358 ], stream=output)
1359 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001360 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001361
1362 def test_config2_failure(self):
1363 # A simple config file which overrides the default settings.
1364 self.assertRaises(Exception, self.apply_config, self.config2)
1365
1366 def test_config3_failure(self):
1367 # A simple config file which overrides the default settings.
1368 self.assertRaises(Exception, self.apply_config, self.config3)
1369
1370 def test_config4_ok(self):
1371 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001372 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001373 self.apply_config(self.config4)
1374 logger = logging.getLogger()
1375 try:
1376 raise RuntimeError()
1377 except RuntimeError:
1378 logging.exception("just testing")
1379 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001380 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001381 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1382 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001383 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001384
Georg Brandl3dbca812008-07-23 16:10:53 +00001385 def test_config5_ok(self):
1386 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001387
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001388 def test_config6_ok(self):
1389 self.test_config1_ok(config=self.config6)
1390
Vinay Sajip3f84b072011-03-07 17:49:33 +00001391 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001392 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001393 self.apply_config(self.config1a)
1394 logger = logging.getLogger("compiler.parser")
1395 # See issue #11424. compiler-hyphenated sorts
1396 # between compiler and compiler.xyz and this
1397 # was preventing compiler.xyz from being included
1398 # in the child loggers of compiler because of an
1399 # overzealous loop termination condition.
1400 hyphenated = logging.getLogger('compiler-hyphenated')
1401 # All will output a message
1402 logger.info(self.next_message())
1403 logger.error(self.next_message())
1404 hyphenated.critical(self.next_message())
1405 self.assert_log_lines([
1406 ('INFO', '1'),
1407 ('ERROR', '2'),
1408 ('CRITICAL', '3'),
1409 ], stream=output)
1410 # Original logger output is empty.
1411 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001412 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001413 self.apply_config(self.config7)
1414 logger = logging.getLogger("compiler.parser")
1415 self.assertFalse(logger.disabled)
1416 # Both will output a message
1417 logger.info(self.next_message())
1418 logger.error(self.next_message())
1419 logger = logging.getLogger("compiler.lexer")
1420 # Both will output a message
1421 logger.info(self.next_message())
1422 logger.error(self.next_message())
1423 # Will not appear
1424 hyphenated.critical(self.next_message())
1425 self.assert_log_lines([
1426 ('INFO', '4'),
1427 ('ERROR', '5'),
1428 ('INFO', '6'),
1429 ('ERROR', '7'),
1430 ], stream=output)
1431 # Original logger output is empty.
1432 self.assert_log_lines([])
1433
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001434 def test_logger_disabling(self):
1435 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001436 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001437 self.assertFalse(logger.disabled)
1438 self.apply_config(self.disable_test)
1439 self.assertTrue(logger.disabled)
1440 self.apply_config(self.disable_test, disable_existing_loggers=False)
1441 self.assertFalse(logger.disabled)
1442
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001443
Victor Stinner45df8202010-04-28 22:31:17 +00001444@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001445class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001446
Christian Heimes180510d2008-03-03 19:15:45 +00001447 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001448
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001449 if threading:
1450 server_class = TestTCPServer
1451 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001452
Christian Heimes180510d2008-03-03 19:15:45 +00001453 def setUp(self):
1454 """Set up a TCP server to receive log messages, and a SocketHandler
1455 pointing to that server's address and port."""
1456 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001457 # Issue #29177: deal with errors that happen during setup
1458 self.server = self.sock_hdlr = self.server_exception = None
1459 try:
1460 self.server = server = self.server_class(self.address,
1461 self.handle_socket, 0.01)
1462 server.start()
1463 # Uncomment next line to test error recovery in setUp()
1464 # raise OSError('dummy error raised')
1465 except OSError as e:
1466 self.server_exception = e
1467 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001468 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001469 hcls = logging.handlers.SocketHandler
1470 if isinstance(server.server_address, tuple):
1471 self.sock_hdlr = hcls('localhost', server.port)
1472 else:
1473 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001474 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001475 self.root_logger.removeHandler(self.root_logger.handlers[0])
1476 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001477 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001478
Christian Heimes180510d2008-03-03 19:15:45 +00001479 def tearDown(self):
1480 """Shutdown the TCP server."""
1481 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001482 if self.server:
1483 self.server.stop(2.0)
1484 if self.sock_hdlr:
1485 self.root_logger.removeHandler(self.sock_hdlr)
1486 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001487 finally:
1488 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001489
Vinay Sajip7367d082011-05-02 13:17:27 +01001490 def handle_socket(self, request):
1491 conn = request.connection
1492 while True:
1493 chunk = conn.recv(4)
1494 if len(chunk) < 4:
1495 break
1496 slen = struct.unpack(">L", chunk)[0]
1497 chunk = conn.recv(slen)
1498 while len(chunk) < slen:
1499 chunk = chunk + conn.recv(slen - len(chunk))
1500 obj = pickle.loads(chunk)
1501 record = logging.makeLogRecord(obj)
1502 self.log_output += record.msg + '\n'
1503 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001504
Christian Heimes180510d2008-03-03 19:15:45 +00001505 def test_output(self):
1506 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001507 if self.server_exception:
1508 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001509 logger = logging.getLogger("tcp")
1510 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001511 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001512 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001513 self.handled.acquire()
1514 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001515
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001516 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001517 if self.server_exception:
1518 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001519 # Avoid timing-related failures due to SocketHandler's own hard-wired
1520 # one-second timeout on socket.create_connection() (issue #16264).
1521 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001522 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001523 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001524 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001525 try:
1526 raise RuntimeError('Deliberate mistake')
1527 except RuntimeError:
1528 self.root_logger.exception('Never sent')
1529 self.root_logger.error('Never sent, either')
1530 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001531 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001532 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1533 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001534
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001535def _get_temp_domain_socket():
1536 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1537 os.close(fd)
1538 # just need a name - file can't be present, or we'll get an
1539 # 'address already in use' error.
1540 os.remove(fn)
1541 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001542
Victor Stinnerec5a8602014-06-02 14:41:51 +02001543@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001544@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001545class UnixSocketHandlerTest(SocketHandlerTest):
1546
1547 """Test for SocketHandler with unix sockets."""
1548
Victor Stinnerec5a8602014-06-02 14:41:51 +02001549 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001550 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001551
1552 def setUp(self):
1553 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001554 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001555 SocketHandlerTest.setUp(self)
1556
1557 def tearDown(self):
1558 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001559 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001560
1561@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001562class DatagramHandlerTest(BaseTest):
1563
1564 """Test for DatagramHandler."""
1565
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001566 if threading:
1567 server_class = TestUDPServer
1568 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001569
Vinay Sajip7367d082011-05-02 13:17:27 +01001570 def setUp(self):
1571 """Set up a UDP server to receive log messages, and a DatagramHandler
1572 pointing to that server's address and port."""
1573 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001574 # Issue #29177: deal with errors that happen during setup
1575 self.server = self.sock_hdlr = self.server_exception = None
1576 try:
1577 self.server = server = self.server_class(self.address,
1578 self.handle_datagram, 0.01)
1579 server.start()
1580 # Uncomment next line to test error recovery in setUp()
1581 # raise OSError('dummy error raised')
1582 except OSError as e:
1583 self.server_exception = e
1584 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001585 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001586 hcls = logging.handlers.DatagramHandler
1587 if isinstance(server.server_address, tuple):
1588 self.sock_hdlr = hcls('localhost', server.port)
1589 else:
1590 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001591 self.log_output = ''
1592 self.root_logger.removeHandler(self.root_logger.handlers[0])
1593 self.root_logger.addHandler(self.sock_hdlr)
1594 self.handled = threading.Event()
1595
1596 def tearDown(self):
1597 """Shutdown the UDP server."""
1598 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001599 if self.server:
1600 self.server.stop(2.0)
1601 if self.sock_hdlr:
1602 self.root_logger.removeHandler(self.sock_hdlr)
1603 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001604 finally:
1605 BaseTest.tearDown(self)
1606
1607 def handle_datagram(self, request):
1608 slen = struct.pack('>L', 0) # length of prefix
1609 packet = request.packet[len(slen):]
1610 obj = pickle.loads(packet)
1611 record = logging.makeLogRecord(obj)
1612 self.log_output += record.msg + '\n'
1613 self.handled.set()
1614
1615 def test_output(self):
1616 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001617 if self.server_exception:
1618 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001619 logger = logging.getLogger("udp")
1620 logger.error("spam")
1621 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001622 self.handled.clear()
1623 logger.error("eggs")
1624 self.handled.wait()
1625 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001626
Victor Stinnerec5a8602014-06-02 14:41:51 +02001627@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001628@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001629class UnixDatagramHandlerTest(DatagramHandlerTest):
1630
1631 """Test for DatagramHandler using Unix sockets."""
1632
Victor Stinnerec5a8602014-06-02 14:41:51 +02001633 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001634 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001635
1636 def setUp(self):
1637 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001638 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001639 DatagramHandlerTest.setUp(self)
1640
1641 def tearDown(self):
1642 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001643 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001644
1645@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001646class SysLogHandlerTest(BaseTest):
1647
1648 """Test for SysLogHandler using UDP."""
1649
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001650 if threading:
1651 server_class = TestUDPServer
1652 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001653
Vinay Sajip7367d082011-05-02 13:17:27 +01001654 def setUp(self):
1655 """Set up a UDP server to receive log messages, and a SysLogHandler
1656 pointing to that server's address and port."""
1657 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001658 # Issue #29177: deal with errors that happen during setup
1659 self.server = self.sl_hdlr = self.server_exception = None
1660 try:
1661 self.server = server = self.server_class(self.address,
1662 self.handle_datagram, 0.01)
1663 server.start()
1664 # Uncomment next line to test error recovery in setUp()
1665 # raise OSError('dummy error raised')
1666 except OSError as e:
1667 self.server_exception = e
1668 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001669 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001670 hcls = logging.handlers.SysLogHandler
1671 if isinstance(server.server_address, tuple):
1672 self.sl_hdlr = hcls(('localhost', server.port))
1673 else:
1674 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001675 self.log_output = ''
1676 self.root_logger.removeHandler(self.root_logger.handlers[0])
1677 self.root_logger.addHandler(self.sl_hdlr)
1678 self.handled = threading.Event()
1679
1680 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001681 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001682 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001683 if self.server:
1684 self.server.stop(2.0)
1685 if self.sl_hdlr:
1686 self.root_logger.removeHandler(self.sl_hdlr)
1687 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001688 finally:
1689 BaseTest.tearDown(self)
1690
1691 def handle_datagram(self, request):
1692 self.log_output = request.packet
1693 self.handled.set()
1694
1695 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001696 if self.server_exception:
1697 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001698 # The log message sent to the SysLogHandler is properly received.
1699 logger = logging.getLogger("slh")
1700 logger.error("sp\xe4m")
1701 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001702 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001703 self.handled.clear()
1704 self.sl_hdlr.append_nul = False
1705 logger.error("sp\xe4m")
1706 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001707 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001708 self.handled.clear()
1709 self.sl_hdlr.ident = "h\xe4m-"
1710 logger.error("sp\xe4m")
1711 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001712 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001713
Victor Stinnerec5a8602014-06-02 14:41:51 +02001714@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001715@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001716class UnixSysLogHandlerTest(SysLogHandlerTest):
1717
1718 """Test for SysLogHandler with Unix sockets."""
1719
Victor Stinnerec5a8602014-06-02 14:41:51 +02001720 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001721 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001722
1723 def setUp(self):
1724 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001725 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001726 SysLogHandlerTest.setUp(self)
1727
1728 def tearDown(self):
1729 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001730 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001731
Vinay Sajip5421f352013-09-27 18:18:28 +01001732@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001733class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001734 """Test for HTTPHandler."""
1735
1736 def setUp(self):
1737 """Set up an HTTP server to receive log messages, and a HTTPHandler
1738 pointing to that server's address and port."""
1739 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001740 self.handled = threading.Event()
1741
Vinay Sajip7367d082011-05-02 13:17:27 +01001742 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001743 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001744 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001745 if self.command == 'POST':
1746 try:
1747 rlen = int(request.headers['Content-Length'])
1748 self.post_data = request.rfile.read(rlen)
1749 except:
1750 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001751 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001752 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001753 self.handled.set()
1754
1755 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001756 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001757 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001758 root_logger = self.root_logger
1759 root_logger.removeHandler(self.root_logger.handlers[0])
1760 for secure in (False, True):
1761 addr = ('localhost', 0)
1762 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001763 try:
1764 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001765 except ImportError:
1766 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001767 else:
1768 here = os.path.dirname(__file__)
1769 localhost_cert = os.path.join(here, "keycert.pem")
1770 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1771 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001772
1773 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001774 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001775 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001776 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001777 self.server = server = TestHTTPServer(addr, self.handle_request,
1778 0.01, sslctx=sslctx)
1779 server.start()
1780 server.ready.wait()
1781 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001782 secure_client = secure and sslctx
1783 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001784 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001785 context=context,
1786 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001787 self.log_data = None
1788 root_logger.addHandler(self.h_hdlr)
1789
1790 for method in ('GET', 'POST'):
1791 self.h_hdlr.method = method
1792 self.handled.clear()
1793 msg = "sp\xe4m"
1794 logger.error(msg)
1795 self.handled.wait()
1796 self.assertEqual(self.log_data.path, '/frob')
1797 self.assertEqual(self.command, method)
1798 if method == 'GET':
1799 d = parse_qs(self.log_data.query)
1800 else:
1801 d = parse_qs(self.post_data.decode('utf-8'))
1802 self.assertEqual(d['name'], ['http'])
1803 self.assertEqual(d['funcName'], ['test_output'])
1804 self.assertEqual(d['msg'], [msg])
1805
1806 self.server.stop(2.0)
1807 self.root_logger.removeHandler(self.h_hdlr)
1808 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001809
Christian Heimes180510d2008-03-03 19:15:45 +00001810class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001811
Christian Heimes180510d2008-03-03 19:15:45 +00001812 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001813
Christian Heimes180510d2008-03-03 19:15:45 +00001814 def setUp(self):
1815 """Create a dict to remember potentially destroyed objects."""
1816 BaseTest.setUp(self)
1817 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001818
Christian Heimes180510d2008-03-03 19:15:45 +00001819 def _watch_for_survival(self, *args):
1820 """Watch the given objects for survival, by creating weakrefs to
1821 them."""
1822 for obj in args:
1823 key = id(obj), repr(obj)
1824 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001825
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001826 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001827 """Assert that all objects watched for survival have survived."""
1828 # Trigger cycle breaking.
1829 gc.collect()
1830 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001831 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001832 if ref() is None:
1833 dead.append(repr_)
1834 if dead:
1835 self.fail("%d objects should have survived "
1836 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001837
Christian Heimes180510d2008-03-03 19:15:45 +00001838 def test_persistent_loggers(self):
1839 # Logger objects are persistent and retain their configuration, even
1840 # if visible references are destroyed.
1841 self.root_logger.setLevel(logging.INFO)
1842 foo = logging.getLogger("foo")
1843 self._watch_for_survival(foo)
1844 foo.setLevel(logging.DEBUG)
1845 self.root_logger.debug(self.next_message())
1846 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001847 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001848 ('foo', 'DEBUG', '2'),
1849 ])
1850 del foo
1851 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001852 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001853 # foo has retained its settings.
1854 bar = logging.getLogger("foo")
1855 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001856 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001857 ('foo', 'DEBUG', '2'),
1858 ('foo', 'DEBUG', '3'),
1859 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001860
Benjamin Petersonf91df042009-02-13 02:50:59 +00001861
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001862class EncodingTest(BaseTest):
1863 def test_encoding_plain_file(self):
1864 # In Python 2.x, a plain file object is treated as having no encoding.
1865 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001866 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1867 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001868 # the non-ascii data we write to the log.
1869 data = "foo\x80"
1870 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001871 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001872 log.addHandler(handler)
1873 try:
1874 # write non-ascii data to the log.
1875 log.warning(data)
1876 finally:
1877 log.removeHandler(handler)
1878 handler.close()
1879 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001880 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001881 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001882 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001883 finally:
1884 f.close()
1885 finally:
1886 if os.path.isfile(fn):
1887 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001888
Benjamin Petersonf91df042009-02-13 02:50:59 +00001889 def test_encoding_cyrillic_unicode(self):
1890 log = logging.getLogger("test")
1891 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1892 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1893 #Ensure it's written in a Cyrillic encoding
1894 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001895 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001896 stream = io.BytesIO()
1897 writer = writer_class(stream, 'strict')
1898 handler = logging.StreamHandler(writer)
1899 log.addHandler(handler)
1900 try:
1901 log.warning(message)
1902 finally:
1903 log.removeHandler(handler)
1904 handler.close()
1905 # check we wrote exactly those bytes, ignoring trailing \n etc
1906 s = stream.getvalue()
1907 #Compare against what the data should be when encoded in CP-1251
1908 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1909
1910
Georg Brandlf9734072008-12-07 15:30:06 +00001911class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001912
Georg Brandlf9734072008-12-07 15:30:06 +00001913 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001914 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001915 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001916 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001917 warnings.filterwarnings("always", category=UserWarning)
1918 stream = io.StringIO()
1919 h = logging.StreamHandler(stream)
1920 logger = logging.getLogger("py.warnings")
1921 logger.addHandler(h)
1922 warnings.warn("I'm warning you...")
1923 logger.removeHandler(h)
1924 s = stream.getvalue()
1925 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001926 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001927
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001928 #See if an explicit file uses the original implementation
1929 a_file = io.StringIO()
1930 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1931 a_file, "Dummy line")
1932 s = a_file.getvalue()
1933 a_file.close()
1934 self.assertEqual(s,
1935 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1936
1937 def test_warnings_no_handlers(self):
1938 with warnings.catch_warnings():
1939 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001940 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001941
1942 # confirm our assumption: no loggers are set
1943 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001944 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001945
1946 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001947 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001948 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001949
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001950
1951def formatFunc(format, datefmt=None):
1952 return logging.Formatter(format, datefmt)
1953
1954def handlerFunc():
1955 return logging.StreamHandler()
1956
1957class CustomHandler(logging.StreamHandler):
1958 pass
1959
1960class ConfigDictTest(BaseTest):
1961
1962 """Reading logging config from a dictionary."""
1963
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001964 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001965
1966 # config0 is a standard configuration.
1967 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001968 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001969 'formatters': {
1970 'form1' : {
1971 'format' : '%(levelname)s ++ %(message)s',
1972 },
1973 },
1974 'handlers' : {
1975 'hand1' : {
1976 'class' : 'logging.StreamHandler',
1977 'formatter' : 'form1',
1978 'level' : 'NOTSET',
1979 'stream' : 'ext://sys.stdout',
1980 },
1981 },
1982 'root' : {
1983 'level' : 'WARNING',
1984 'handlers' : ['hand1'],
1985 },
1986 }
1987
1988 # config1 adds a little to the standard configuration.
1989 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001990 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001991 'formatters': {
1992 'form1' : {
1993 'format' : '%(levelname)s ++ %(message)s',
1994 },
1995 },
1996 'handlers' : {
1997 'hand1' : {
1998 'class' : 'logging.StreamHandler',
1999 'formatter' : 'form1',
2000 'level' : 'NOTSET',
2001 'stream' : 'ext://sys.stdout',
2002 },
2003 },
2004 'loggers' : {
2005 'compiler.parser' : {
2006 'level' : 'DEBUG',
2007 'handlers' : ['hand1'],
2008 },
2009 },
2010 'root' : {
2011 'level' : 'WARNING',
2012 },
2013 }
2014
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002015 # config1a moves the handler to the root. Used with config8a
2016 config1a = {
2017 'version': 1,
2018 'formatters': {
2019 'form1' : {
2020 'format' : '%(levelname)s ++ %(message)s',
2021 },
2022 },
2023 'handlers' : {
2024 'hand1' : {
2025 'class' : 'logging.StreamHandler',
2026 'formatter' : 'form1',
2027 'level' : 'NOTSET',
2028 'stream' : 'ext://sys.stdout',
2029 },
2030 },
2031 'loggers' : {
2032 'compiler.parser' : {
2033 'level' : 'DEBUG',
2034 },
2035 },
2036 'root' : {
2037 'level' : 'WARNING',
2038 'handlers' : ['hand1'],
2039 },
2040 }
2041
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002042 # config2 has a subtle configuration error that should be reported
2043 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002044 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002045 'formatters': {
2046 'form1' : {
2047 'format' : '%(levelname)s ++ %(message)s',
2048 },
2049 },
2050 'handlers' : {
2051 'hand1' : {
2052 'class' : 'logging.StreamHandler',
2053 'formatter' : 'form1',
2054 'level' : 'NOTSET',
2055 'stream' : 'ext://sys.stdbout',
2056 },
2057 },
2058 'loggers' : {
2059 'compiler.parser' : {
2060 'level' : 'DEBUG',
2061 'handlers' : ['hand1'],
2062 },
2063 },
2064 'root' : {
2065 'level' : 'WARNING',
2066 },
2067 }
2068
2069 #As config1 but with a misspelt level on a handler
2070 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002071 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002072 'formatters': {
2073 'form1' : {
2074 'format' : '%(levelname)s ++ %(message)s',
2075 },
2076 },
2077 'handlers' : {
2078 'hand1' : {
2079 'class' : 'logging.StreamHandler',
2080 'formatter' : 'form1',
2081 'level' : 'NTOSET',
2082 'stream' : 'ext://sys.stdout',
2083 },
2084 },
2085 'loggers' : {
2086 'compiler.parser' : {
2087 'level' : 'DEBUG',
2088 'handlers' : ['hand1'],
2089 },
2090 },
2091 'root' : {
2092 'level' : 'WARNING',
2093 },
2094 }
2095
2096
2097 #As config1 but with a misspelt level on a logger
2098 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002099 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002100 'formatters': {
2101 'form1' : {
2102 'format' : '%(levelname)s ++ %(message)s',
2103 },
2104 },
2105 'handlers' : {
2106 'hand1' : {
2107 'class' : 'logging.StreamHandler',
2108 'formatter' : 'form1',
2109 'level' : 'NOTSET',
2110 'stream' : 'ext://sys.stdout',
2111 },
2112 },
2113 'loggers' : {
2114 'compiler.parser' : {
2115 'level' : 'DEBUG',
2116 'handlers' : ['hand1'],
2117 },
2118 },
2119 'root' : {
2120 'level' : 'WRANING',
2121 },
2122 }
2123
2124 # config3 has a less subtle configuration error
2125 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002126 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002127 'formatters': {
2128 'form1' : {
2129 'format' : '%(levelname)s ++ %(message)s',
2130 },
2131 },
2132 'handlers' : {
2133 'hand1' : {
2134 'class' : 'logging.StreamHandler',
2135 'formatter' : 'misspelled_name',
2136 'level' : 'NOTSET',
2137 'stream' : 'ext://sys.stdout',
2138 },
2139 },
2140 'loggers' : {
2141 'compiler.parser' : {
2142 'level' : 'DEBUG',
2143 'handlers' : ['hand1'],
2144 },
2145 },
2146 'root' : {
2147 'level' : 'WARNING',
2148 },
2149 }
2150
2151 # config4 specifies a custom formatter class to be loaded
2152 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002153 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002154 'formatters': {
2155 'form1' : {
2156 '()' : __name__ + '.ExceptionFormatter',
2157 'format' : '%(levelname)s:%(name)s:%(message)s',
2158 },
2159 },
2160 'handlers' : {
2161 'hand1' : {
2162 'class' : 'logging.StreamHandler',
2163 'formatter' : 'form1',
2164 'level' : 'NOTSET',
2165 'stream' : 'ext://sys.stdout',
2166 },
2167 },
2168 'root' : {
2169 'level' : 'NOTSET',
2170 'handlers' : ['hand1'],
2171 },
2172 }
2173
2174 # As config4 but using an actual callable rather than a string
2175 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002176 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002177 'formatters': {
2178 'form1' : {
2179 '()' : ExceptionFormatter,
2180 'format' : '%(levelname)s:%(name)s:%(message)s',
2181 },
2182 'form2' : {
2183 '()' : __name__ + '.formatFunc',
2184 'format' : '%(levelname)s:%(name)s:%(message)s',
2185 },
2186 'form3' : {
2187 '()' : formatFunc,
2188 'format' : '%(levelname)s:%(name)s:%(message)s',
2189 },
2190 },
2191 'handlers' : {
2192 'hand1' : {
2193 'class' : 'logging.StreamHandler',
2194 'formatter' : 'form1',
2195 'level' : 'NOTSET',
2196 'stream' : 'ext://sys.stdout',
2197 },
2198 'hand2' : {
2199 '()' : handlerFunc,
2200 },
2201 },
2202 'root' : {
2203 'level' : 'NOTSET',
2204 'handlers' : ['hand1'],
2205 },
2206 }
2207
2208 # config5 specifies a custom handler class to be loaded
2209 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002210 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002211 'formatters': {
2212 'form1' : {
2213 'format' : '%(levelname)s ++ %(message)s',
2214 },
2215 },
2216 'handlers' : {
2217 'hand1' : {
2218 'class' : __name__ + '.CustomHandler',
2219 'formatter' : 'form1',
2220 'level' : 'NOTSET',
2221 'stream' : 'ext://sys.stdout',
2222 },
2223 },
2224 'loggers' : {
2225 'compiler.parser' : {
2226 'level' : 'DEBUG',
2227 'handlers' : ['hand1'],
2228 },
2229 },
2230 'root' : {
2231 'level' : 'WARNING',
2232 },
2233 }
2234
2235 # config6 specifies a custom handler class to be loaded
2236 # but has bad arguments
2237 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002238 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002239 'formatters': {
2240 'form1' : {
2241 'format' : '%(levelname)s ++ %(message)s',
2242 },
2243 },
2244 'handlers' : {
2245 'hand1' : {
2246 'class' : __name__ + '.CustomHandler',
2247 'formatter' : 'form1',
2248 'level' : 'NOTSET',
2249 'stream' : 'ext://sys.stdout',
2250 '9' : 'invalid parameter name',
2251 },
2252 },
2253 'loggers' : {
2254 'compiler.parser' : {
2255 'level' : 'DEBUG',
2256 'handlers' : ['hand1'],
2257 },
2258 },
2259 'root' : {
2260 'level' : 'WARNING',
2261 },
2262 }
2263
2264 #config 7 does not define compiler.parser but defines compiler.lexer
2265 #so compiler.parser should be disabled after applying it
2266 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002267 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002268 'formatters': {
2269 'form1' : {
2270 'format' : '%(levelname)s ++ %(message)s',
2271 },
2272 },
2273 'handlers' : {
2274 'hand1' : {
2275 'class' : 'logging.StreamHandler',
2276 'formatter' : 'form1',
2277 'level' : 'NOTSET',
2278 'stream' : 'ext://sys.stdout',
2279 },
2280 },
2281 'loggers' : {
2282 'compiler.lexer' : {
2283 'level' : 'DEBUG',
2284 'handlers' : ['hand1'],
2285 },
2286 },
2287 'root' : {
2288 'level' : 'WARNING',
2289 },
2290 }
2291
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002292 # config8 defines both compiler and compiler.lexer
2293 # so compiler.parser should not be disabled (since
2294 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002295 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002296 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002297 'disable_existing_loggers' : False,
2298 'formatters': {
2299 'form1' : {
2300 'format' : '%(levelname)s ++ %(message)s',
2301 },
2302 },
2303 'handlers' : {
2304 'hand1' : {
2305 'class' : 'logging.StreamHandler',
2306 'formatter' : 'form1',
2307 'level' : 'NOTSET',
2308 'stream' : 'ext://sys.stdout',
2309 },
2310 },
2311 'loggers' : {
2312 'compiler' : {
2313 'level' : 'DEBUG',
2314 'handlers' : ['hand1'],
2315 },
2316 'compiler.lexer' : {
2317 },
2318 },
2319 'root' : {
2320 'level' : 'WARNING',
2321 },
2322 }
2323
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002324 # config8a disables existing loggers
2325 config8a = {
2326 'version': 1,
2327 'disable_existing_loggers' : True,
2328 'formatters': {
2329 'form1' : {
2330 'format' : '%(levelname)s ++ %(message)s',
2331 },
2332 },
2333 'handlers' : {
2334 'hand1' : {
2335 'class' : 'logging.StreamHandler',
2336 'formatter' : 'form1',
2337 'level' : 'NOTSET',
2338 'stream' : 'ext://sys.stdout',
2339 },
2340 },
2341 'loggers' : {
2342 'compiler' : {
2343 'level' : 'DEBUG',
2344 'handlers' : ['hand1'],
2345 },
2346 'compiler.lexer' : {
2347 },
2348 },
2349 'root' : {
2350 'level' : 'WARNING',
2351 },
2352 }
2353
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002354 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002355 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002356 'formatters': {
2357 'form1' : {
2358 'format' : '%(levelname)s ++ %(message)s',
2359 },
2360 },
2361 'handlers' : {
2362 'hand1' : {
2363 'class' : 'logging.StreamHandler',
2364 'formatter' : 'form1',
2365 'level' : 'WARNING',
2366 'stream' : 'ext://sys.stdout',
2367 },
2368 },
2369 'loggers' : {
2370 'compiler.parser' : {
2371 'level' : 'WARNING',
2372 'handlers' : ['hand1'],
2373 },
2374 },
2375 'root' : {
2376 'level' : 'NOTSET',
2377 },
2378 }
2379
2380 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002381 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002382 'incremental' : True,
2383 'handlers' : {
2384 'hand1' : {
2385 'level' : 'WARNING',
2386 },
2387 },
2388 'loggers' : {
2389 'compiler.parser' : {
2390 'level' : 'INFO',
2391 },
2392 },
2393 }
2394
2395 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002396 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002397 'incremental' : True,
2398 'handlers' : {
2399 'hand1' : {
2400 'level' : 'INFO',
2401 },
2402 },
2403 'loggers' : {
2404 'compiler.parser' : {
2405 'level' : 'INFO',
2406 },
2407 },
2408 }
2409
2410 #As config1 but with a filter added
2411 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002412 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002413 'formatters': {
2414 'form1' : {
2415 'format' : '%(levelname)s ++ %(message)s',
2416 },
2417 },
2418 'filters' : {
2419 'filt1' : {
2420 'name' : 'compiler.parser',
2421 },
2422 },
2423 'handlers' : {
2424 'hand1' : {
2425 'class' : 'logging.StreamHandler',
2426 'formatter' : 'form1',
2427 'level' : 'NOTSET',
2428 'stream' : 'ext://sys.stdout',
2429 'filters' : ['filt1'],
2430 },
2431 },
2432 'loggers' : {
2433 'compiler.parser' : {
2434 'level' : 'DEBUG',
2435 'filters' : ['filt1'],
2436 },
2437 },
2438 'root' : {
2439 'level' : 'WARNING',
2440 'handlers' : ['hand1'],
2441 },
2442 }
2443
2444 #As config1 but using cfg:// references
2445 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002446 'version': 1,
2447 'true_formatters': {
2448 'form1' : {
2449 'format' : '%(levelname)s ++ %(message)s',
2450 },
2451 },
2452 'handler_configs': {
2453 'hand1' : {
2454 'class' : 'logging.StreamHandler',
2455 'formatter' : 'form1',
2456 'level' : 'NOTSET',
2457 'stream' : 'ext://sys.stdout',
2458 },
2459 },
2460 'formatters' : 'cfg://true_formatters',
2461 'handlers' : {
2462 'hand1' : 'cfg://handler_configs[hand1]',
2463 },
2464 'loggers' : {
2465 'compiler.parser' : {
2466 'level' : 'DEBUG',
2467 'handlers' : ['hand1'],
2468 },
2469 },
2470 'root' : {
2471 'level' : 'WARNING',
2472 },
2473 }
2474
2475 #As config11 but missing the version key
2476 config12 = {
2477 'true_formatters': {
2478 'form1' : {
2479 'format' : '%(levelname)s ++ %(message)s',
2480 },
2481 },
2482 'handler_configs': {
2483 'hand1' : {
2484 'class' : 'logging.StreamHandler',
2485 'formatter' : 'form1',
2486 'level' : 'NOTSET',
2487 'stream' : 'ext://sys.stdout',
2488 },
2489 },
2490 'formatters' : 'cfg://true_formatters',
2491 'handlers' : {
2492 'hand1' : 'cfg://handler_configs[hand1]',
2493 },
2494 'loggers' : {
2495 'compiler.parser' : {
2496 'level' : 'DEBUG',
2497 'handlers' : ['hand1'],
2498 },
2499 },
2500 'root' : {
2501 'level' : 'WARNING',
2502 },
2503 }
2504
2505 #As config11 but using an unsupported version
2506 config13 = {
2507 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002508 'true_formatters': {
2509 'form1' : {
2510 'format' : '%(levelname)s ++ %(message)s',
2511 },
2512 },
2513 'handler_configs': {
2514 'hand1' : {
2515 'class' : 'logging.StreamHandler',
2516 'formatter' : 'form1',
2517 'level' : 'NOTSET',
2518 'stream' : 'ext://sys.stdout',
2519 },
2520 },
2521 'formatters' : 'cfg://true_formatters',
2522 'handlers' : {
2523 'hand1' : 'cfg://handler_configs[hand1]',
2524 },
2525 'loggers' : {
2526 'compiler.parser' : {
2527 'level' : 'DEBUG',
2528 'handlers' : ['hand1'],
2529 },
2530 },
2531 'root' : {
2532 'level' : 'WARNING',
2533 },
2534 }
2535
Vinay Sajip8d270232012-11-15 14:20:18 +00002536 # As config0, but with properties
2537 config14 = {
2538 'version': 1,
2539 'formatters': {
2540 'form1' : {
2541 'format' : '%(levelname)s ++ %(message)s',
2542 },
2543 },
2544 'handlers' : {
2545 'hand1' : {
2546 'class' : 'logging.StreamHandler',
2547 'formatter' : 'form1',
2548 'level' : 'NOTSET',
2549 'stream' : 'ext://sys.stdout',
2550 '.': {
2551 'foo': 'bar',
2552 'terminator': '!\n',
2553 }
2554 },
2555 },
2556 'root' : {
2557 'level' : 'WARNING',
2558 'handlers' : ['hand1'],
2559 },
2560 }
2561
Vinay Sajip3f885b52013-03-22 15:19:54 +00002562 out_of_order = {
2563 "version": 1,
2564 "formatters": {
2565 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002566 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2567 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002568 }
2569 },
2570 "handlers": {
2571 "fileGlobal": {
2572 "class": "logging.StreamHandler",
2573 "level": "DEBUG",
2574 "formatter": "mySimpleFormatter"
2575 },
2576 "bufferGlobal": {
2577 "class": "logging.handlers.MemoryHandler",
2578 "capacity": 5,
2579 "formatter": "mySimpleFormatter",
2580 "target": "fileGlobal",
2581 "level": "DEBUG"
2582 }
2583 },
2584 "loggers": {
2585 "mymodule": {
2586 "level": "DEBUG",
2587 "handlers": ["bufferGlobal"],
2588 "propagate": "true"
2589 }
2590 }
2591 }
2592
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002593 def apply_config(self, conf):
2594 logging.config.dictConfig(conf)
2595
2596 def test_config0_ok(self):
2597 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002598 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002599 self.apply_config(self.config0)
2600 logger = logging.getLogger()
2601 # Won't output anything
2602 logger.info(self.next_message())
2603 # Outputs a message
2604 logger.error(self.next_message())
2605 self.assert_log_lines([
2606 ('ERROR', '2'),
2607 ], stream=output)
2608 # Original logger output is empty.
2609 self.assert_log_lines([])
2610
2611 def test_config1_ok(self, config=config1):
2612 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002613 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002614 self.apply_config(config)
2615 logger = logging.getLogger("compiler.parser")
2616 # Both will output a message
2617 logger.info(self.next_message())
2618 logger.error(self.next_message())
2619 self.assert_log_lines([
2620 ('INFO', '1'),
2621 ('ERROR', '2'),
2622 ], stream=output)
2623 # Original logger output is empty.
2624 self.assert_log_lines([])
2625
2626 def test_config2_failure(self):
2627 # A simple config which overrides the default settings.
2628 self.assertRaises(Exception, self.apply_config, self.config2)
2629
2630 def test_config2a_failure(self):
2631 # A simple config which overrides the default settings.
2632 self.assertRaises(Exception, self.apply_config, self.config2a)
2633
2634 def test_config2b_failure(self):
2635 # A simple config which overrides the default settings.
2636 self.assertRaises(Exception, self.apply_config, self.config2b)
2637
2638 def test_config3_failure(self):
2639 # A simple config which overrides the default settings.
2640 self.assertRaises(Exception, self.apply_config, self.config3)
2641
2642 def test_config4_ok(self):
2643 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002644 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002645 self.apply_config(self.config4)
2646 #logger = logging.getLogger()
2647 try:
2648 raise RuntimeError()
2649 except RuntimeError:
2650 logging.exception("just testing")
2651 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002652 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002653 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2654 # Original logger output is empty
2655 self.assert_log_lines([])
2656
2657 def test_config4a_ok(self):
2658 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002659 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002660 self.apply_config(self.config4a)
2661 #logger = logging.getLogger()
2662 try:
2663 raise RuntimeError()
2664 except RuntimeError:
2665 logging.exception("just testing")
2666 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002667 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002668 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2669 # Original logger output is empty
2670 self.assert_log_lines([])
2671
2672 def test_config5_ok(self):
2673 self.test_config1_ok(config=self.config5)
2674
2675 def test_config6_failure(self):
2676 self.assertRaises(Exception, self.apply_config, self.config6)
2677
2678 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002679 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002680 self.apply_config(self.config1)
2681 logger = logging.getLogger("compiler.parser")
2682 # Both will output a message
2683 logger.info(self.next_message())
2684 logger.error(self.next_message())
2685 self.assert_log_lines([
2686 ('INFO', '1'),
2687 ('ERROR', '2'),
2688 ], stream=output)
2689 # Original logger output is empty.
2690 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002691 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002692 self.apply_config(self.config7)
2693 logger = logging.getLogger("compiler.parser")
2694 self.assertTrue(logger.disabled)
2695 logger = logging.getLogger("compiler.lexer")
2696 # Both will output a message
2697 logger.info(self.next_message())
2698 logger.error(self.next_message())
2699 self.assert_log_lines([
2700 ('INFO', '3'),
2701 ('ERROR', '4'),
2702 ], stream=output)
2703 # Original logger output is empty.
2704 self.assert_log_lines([])
2705
2706 #Same as test_config_7_ok but don't disable old loggers.
2707 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002708 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002709 self.apply_config(self.config1)
2710 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002711 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002712 logger.info(self.next_message())
2713 logger.error(self.next_message())
2714 self.assert_log_lines([
2715 ('INFO', '1'),
2716 ('ERROR', '2'),
2717 ], stream=output)
2718 # Original logger output is empty.
2719 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002720 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002721 self.apply_config(self.config8)
2722 logger = logging.getLogger("compiler.parser")
2723 self.assertFalse(logger.disabled)
2724 # Both will output a message
2725 logger.info(self.next_message())
2726 logger.error(self.next_message())
2727 logger = logging.getLogger("compiler.lexer")
2728 # Both will output a message
2729 logger.info(self.next_message())
2730 logger.error(self.next_message())
2731 self.assert_log_lines([
2732 ('INFO', '3'),
2733 ('ERROR', '4'),
2734 ('INFO', '5'),
2735 ('ERROR', '6'),
2736 ], stream=output)
2737 # Original logger output is empty.
2738 self.assert_log_lines([])
2739
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002740 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002741 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002742 self.apply_config(self.config1a)
2743 logger = logging.getLogger("compiler.parser")
2744 # See issue #11424. compiler-hyphenated sorts
2745 # between compiler and compiler.xyz and this
2746 # was preventing compiler.xyz from being included
2747 # in the child loggers of compiler because of an
2748 # overzealous loop termination condition.
2749 hyphenated = logging.getLogger('compiler-hyphenated')
2750 # All will output a message
2751 logger.info(self.next_message())
2752 logger.error(self.next_message())
2753 hyphenated.critical(self.next_message())
2754 self.assert_log_lines([
2755 ('INFO', '1'),
2756 ('ERROR', '2'),
2757 ('CRITICAL', '3'),
2758 ], stream=output)
2759 # Original logger output is empty.
2760 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002761 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002762 self.apply_config(self.config8a)
2763 logger = logging.getLogger("compiler.parser")
2764 self.assertFalse(logger.disabled)
2765 # Both will output a message
2766 logger.info(self.next_message())
2767 logger.error(self.next_message())
2768 logger = logging.getLogger("compiler.lexer")
2769 # Both will output a message
2770 logger.info(self.next_message())
2771 logger.error(self.next_message())
2772 # Will not appear
2773 hyphenated.critical(self.next_message())
2774 self.assert_log_lines([
2775 ('INFO', '4'),
2776 ('ERROR', '5'),
2777 ('INFO', '6'),
2778 ('ERROR', '7'),
2779 ], stream=output)
2780 # Original logger output is empty.
2781 self.assert_log_lines([])
2782
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002783 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002784 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002785 self.apply_config(self.config9)
2786 logger = logging.getLogger("compiler.parser")
2787 #Nothing will be output since both handler and logger are set to WARNING
2788 logger.info(self.next_message())
2789 self.assert_log_lines([], stream=output)
2790 self.apply_config(self.config9a)
2791 #Nothing will be output since both handler is still set to WARNING
2792 logger.info(self.next_message())
2793 self.assert_log_lines([], stream=output)
2794 self.apply_config(self.config9b)
2795 #Message should now be output
2796 logger.info(self.next_message())
2797 self.assert_log_lines([
2798 ('INFO', '3'),
2799 ], stream=output)
2800
2801 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002802 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002803 self.apply_config(self.config10)
2804 logger = logging.getLogger("compiler.parser")
2805 logger.warning(self.next_message())
2806 logger = logging.getLogger('compiler')
2807 #Not output, because filtered
2808 logger.warning(self.next_message())
2809 logger = logging.getLogger('compiler.lexer')
2810 #Not output, because filtered
2811 logger.warning(self.next_message())
2812 logger = logging.getLogger("compiler.parser.codegen")
2813 #Output, as not filtered
2814 logger.error(self.next_message())
2815 self.assert_log_lines([
2816 ('WARNING', '1'),
2817 ('ERROR', '4'),
2818 ], stream=output)
2819
2820 def test_config11_ok(self):
2821 self.test_config1_ok(self.config11)
2822
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002823 def test_config12_failure(self):
2824 self.assertRaises(Exception, self.apply_config, self.config12)
2825
2826 def test_config13_failure(self):
2827 self.assertRaises(Exception, self.apply_config, self.config13)
2828
Vinay Sajip8d270232012-11-15 14:20:18 +00002829 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002830 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002831 self.apply_config(self.config14)
2832 h = logging._handlers['hand1']
2833 self.assertEqual(h.foo, 'bar')
2834 self.assertEqual(h.terminator, '!\n')
2835 logging.warning('Exclamation')
2836 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2837
Victor Stinner45df8202010-04-28 22:31:17 +00002838 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002839 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002840 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002841 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002842 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002843 t.start()
2844 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002845 # Now get the port allocated
2846 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002847 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002848 try:
2849 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2850 sock.settimeout(2.0)
2851 sock.connect(('localhost', port))
2852
2853 slen = struct.pack('>L', len(text))
2854 s = slen + text
2855 sentsofar = 0
2856 left = len(s)
2857 while left > 0:
2858 sent = sock.send(s[sentsofar:])
2859 sentsofar += sent
2860 left -= sent
2861 sock.close()
2862 finally:
2863 t.ready.wait(2.0)
2864 logging.config.stopListening()
2865 t.join(2.0)
2866
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002867 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002868 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002869 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002870 self.setup_via_listener(json.dumps(self.config10))
2871 logger = logging.getLogger("compiler.parser")
2872 logger.warning(self.next_message())
2873 logger = logging.getLogger('compiler')
2874 #Not output, because filtered
2875 logger.warning(self.next_message())
2876 logger = logging.getLogger('compiler.lexer')
2877 #Not output, because filtered
2878 logger.warning(self.next_message())
2879 logger = logging.getLogger("compiler.parser.codegen")
2880 #Output, as not filtered
2881 logger.error(self.next_message())
2882 self.assert_log_lines([
2883 ('WARNING', '1'),
2884 ('ERROR', '4'),
2885 ], stream=output)
2886
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002887 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002888 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002889 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2891 logger = logging.getLogger("compiler.parser")
2892 # Both will output a message
2893 logger.info(self.next_message())
2894 logger.error(self.next_message())
2895 self.assert_log_lines([
2896 ('INFO', '1'),
2897 ('ERROR', '2'),
2898 ], stream=output)
2899 # Original logger output is empty.
2900 self.assert_log_lines([])
2901
Vinay Sajip4ded5512012-10-02 15:56:16 +01002902 @unittest.skipUnless(threading, 'Threading required for this test.')
2903 def test_listen_verify(self):
2904
2905 def verify_fail(stuff):
2906 return None
2907
2908 def verify_reverse(stuff):
2909 return stuff[::-1]
2910
2911 logger = logging.getLogger("compiler.parser")
2912 to_send = textwrap.dedent(ConfigFileTest.config1)
2913 # First, specify a verification function that will fail.
2914 # We expect to see no output, since our configuration
2915 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002916 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002917 self.setup_via_listener(to_send, verify_fail)
2918 # Both will output a message
2919 logger.info(self.next_message())
2920 logger.error(self.next_message())
2921 self.assert_log_lines([], stream=output)
2922 # Original logger output has the stuff we logged.
2923 self.assert_log_lines([
2924 ('INFO', '1'),
2925 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002926 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002927
2928 # Now, perform no verification. Our configuration
2929 # should take effect.
2930
Vinay Sajip1feedb42014-05-31 08:19:12 +01002931 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002932 self.setup_via_listener(to_send) # no verify callable specified
2933 logger = logging.getLogger("compiler.parser")
2934 # Both will output a message
2935 logger.info(self.next_message())
2936 logger.error(self.next_message())
2937 self.assert_log_lines([
2938 ('INFO', '3'),
2939 ('ERROR', '4'),
2940 ], stream=output)
2941 # Original logger output still has the stuff we logged before.
2942 self.assert_log_lines([
2943 ('INFO', '1'),
2944 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002945 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002946
2947 # Now, perform verification which transforms the bytes.
2948
Vinay Sajip1feedb42014-05-31 08:19:12 +01002949 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002950 self.setup_via_listener(to_send[::-1], verify_reverse)
2951 logger = logging.getLogger("compiler.parser")
2952 # Both will output a message
2953 logger.info(self.next_message())
2954 logger.error(self.next_message())
2955 self.assert_log_lines([
2956 ('INFO', '5'),
2957 ('ERROR', '6'),
2958 ], stream=output)
2959 # Original logger output still has the stuff we logged before.
2960 self.assert_log_lines([
2961 ('INFO', '1'),
2962 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002963 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002964
Vinay Sajip3f885b52013-03-22 15:19:54 +00002965 def test_out_of_order(self):
2966 self.apply_config(self.out_of_order)
2967 handler = logging.getLogger('mymodule').handlers[0]
2968 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002969 self.assertIsInstance(handler.formatter._style,
2970 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002971
Vinay Sajip373baef2011-04-26 20:05:24 +01002972 def test_baseconfig(self):
2973 d = {
2974 'atuple': (1, 2, 3),
2975 'alist': ['a', 'b', 'c'],
2976 'adict': {'d': 'e', 'f': 3 },
2977 'nest1': ('g', ('h', 'i'), 'j'),
2978 'nest2': ['k', ['l', 'm'], 'n'],
2979 'nest3': ['o', 'cfg://alist', 'p'],
2980 }
2981 bc = logging.config.BaseConfigurator(d)
2982 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2983 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2984 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2985 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2986 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2987 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2988 v = bc.convert('cfg://nest3')
2989 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2990 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2991 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2992 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002993
2994class ManagerTest(BaseTest):
2995 def test_manager_loggerclass(self):
2996 logged = []
2997
2998 class MyLogger(logging.Logger):
2999 def _log(self, level, msg, args, exc_info=None, extra=None):
3000 logged.append(msg)
3001
3002 man = logging.Manager(None)
3003 self.assertRaises(TypeError, man.setLoggerClass, int)
3004 man.setLoggerClass(MyLogger)
3005 logger = man.getLogger('test')
3006 logger.warning('should appear in logged')
3007 logging.warning('should not appear in logged')
3008
3009 self.assertEqual(logged, ['should appear in logged'])
3010
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003011 def test_set_log_record_factory(self):
3012 man = logging.Manager(None)
3013 expected = object()
3014 man.setLogRecordFactory(expected)
3015 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003016
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003017class ChildLoggerTest(BaseTest):
3018 def test_child_loggers(self):
3019 r = logging.getLogger()
3020 l1 = logging.getLogger('abc')
3021 l2 = logging.getLogger('def.ghi')
3022 c1 = r.getChild('xyz')
3023 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003024 self.assertIs(c1, logging.getLogger('xyz'))
3025 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003026 c1 = l1.getChild('def')
3027 c2 = c1.getChild('ghi')
3028 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003029 self.assertIs(c1, logging.getLogger('abc.def'))
3030 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3031 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003032
3033
Vinay Sajip6fac8172010-10-19 20:44:14 +00003034class DerivedLogRecord(logging.LogRecord):
3035 pass
3036
Vinay Sajip61561522010-12-03 11:50:38 +00003037class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003038
3039 def setUp(self):
3040 class CheckingFilter(logging.Filter):
3041 def __init__(self, cls):
3042 self.cls = cls
3043
3044 def filter(self, record):
3045 t = type(record)
3046 if t is not self.cls:
3047 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3048 self.cls)
3049 raise TypeError(msg)
3050 return True
3051
3052 BaseTest.setUp(self)
3053 self.filter = CheckingFilter(DerivedLogRecord)
3054 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003055 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003056
3057 def tearDown(self):
3058 self.root_logger.removeFilter(self.filter)
3059 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003060 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003061
3062 def test_logrecord_class(self):
3063 self.assertRaises(TypeError, self.root_logger.warning,
3064 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003065 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003066 self.root_logger.error(self.next_message())
3067 self.assert_log_lines([
3068 ('root', 'ERROR', '2'),
3069 ])
3070
3071
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003072class QueueHandlerTest(BaseTest):
3073 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003074 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003075
3076 def setUp(self):
3077 BaseTest.setUp(self)
3078 self.queue = queue.Queue(-1)
3079 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3080 self.que_logger = logging.getLogger('que')
3081 self.que_logger.propagate = False
3082 self.que_logger.setLevel(logging.WARNING)
3083 self.que_logger.addHandler(self.que_hdlr)
3084
3085 def tearDown(self):
3086 self.que_hdlr.close()
3087 BaseTest.tearDown(self)
3088
3089 def test_queue_handler(self):
3090 self.que_logger.debug(self.next_message())
3091 self.assertRaises(queue.Empty, self.queue.get_nowait)
3092 self.que_logger.info(self.next_message())
3093 self.assertRaises(queue.Empty, self.queue.get_nowait)
3094 msg = self.next_message()
3095 self.que_logger.warning(msg)
3096 data = self.queue.get_nowait()
3097 self.assertTrue(isinstance(data, logging.LogRecord))
3098 self.assertEqual(data.name, self.que_logger.name)
3099 self.assertEqual((data.msg, data.args), (msg, None))
3100
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003101 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3102 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003103 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003104 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003105 listener = logging.handlers.QueueListener(self.queue, handler)
3106 listener.start()
3107 try:
3108 self.que_logger.warning(self.next_message())
3109 self.que_logger.error(self.next_message())
3110 self.que_logger.critical(self.next_message())
3111 finally:
3112 listener.stop()
3113 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3114 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3115 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003116 handler.close()
3117
3118 # Now test with respect_handler_level set
3119
3120 handler = support.TestHandler(support.Matcher())
3121 handler.setLevel(logging.CRITICAL)
3122 listener = logging.handlers.QueueListener(self.queue, handler,
3123 respect_handler_level=True)
3124 listener.start()
3125 try:
3126 self.que_logger.warning(self.next_message())
3127 self.que_logger.error(self.next_message())
3128 self.que_logger.critical(self.next_message())
3129 finally:
3130 listener.stop()
3131 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3132 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3133 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3134
Vinay Sajipd61910c2016-09-08 01:13:39 +01003135if hasattr(logging.handlers, 'QueueListener'):
3136 import multiprocessing
3137 from unittest.mock import patch
3138
3139 class QueueListenerTest(BaseTest):
3140 """
3141 Tests based on patch submitted for issue #27930. Ensure that
3142 QueueListener handles all log messages.
3143 """
3144
3145 repeat = 20
3146
3147 @staticmethod
3148 def setup_and_log(log_queue, ident):
3149 """
3150 Creates a logger with a QueueHandler that logs to a queue read by a
3151 QueueListener. Starts the listener, logs five messages, and stops
3152 the listener.
3153 """
3154 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3155 logger.setLevel(logging.DEBUG)
3156 handler = logging.handlers.QueueHandler(log_queue)
3157 logger.addHandler(handler)
3158 listener = logging.handlers.QueueListener(log_queue)
3159 listener.start()
3160
3161 logger.info('one')
3162 logger.info('two')
3163 logger.info('three')
3164 logger.info('four')
3165 logger.info('five')
3166
3167 listener.stop()
3168 logger.removeHandler(handler)
3169 handler.close()
3170
3171 @patch.object(logging.handlers.QueueListener, 'handle')
3172 def test_handle_called_with_queue_queue(self, mock_handle):
3173 for i in range(self.repeat):
3174 log_queue = queue.Queue()
3175 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3176 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3177 'correct number of handled log messages')
3178
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003179 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003180 @patch.object(logging.handlers.QueueListener, 'handle')
3181 def test_handle_called_with_mp_queue(self, mock_handle):
3182 for i in range(self.repeat):
3183 log_queue = multiprocessing.Queue()
3184 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3185 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3186 'correct number of handled log messages')
3187
3188 @staticmethod
3189 def get_all_from_queue(log_queue):
3190 try:
3191 while True:
3192 yield log_queue.get_nowait()
3193 except queue.Empty:
3194 return []
3195
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003196 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003197 def test_no_messages_in_queue_after_stop(self):
3198 """
3199 Five messages are logged then the QueueListener is stopped. This
3200 test then gets everything off the queue. Failure of this test
3201 indicates that messages were not registered on the queue until
3202 _after_ the QueueListener stopped.
3203 """
3204 for i in range(self.repeat):
3205 queue = multiprocessing.Queue()
3206 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3207 # time.sleep(1)
3208 items = list(self.get_all_from_queue(queue))
3209 expected = [[], [logging.handlers.QueueListener._sentinel]]
3210 self.assertIn(items, expected,
3211 'Found unexpected messages in queue: %s' % (
3212 [m.msg if isinstance(m, logging.LogRecord)
3213 else m for m in items]))
3214
Vinay Sajipe723e962011-04-15 22:27:17 +01003215
Vinay Sajip37eb3382011-04-26 20:26:41 +01003216ZERO = datetime.timedelta(0)
3217
3218class UTC(datetime.tzinfo):
3219 def utcoffset(self, dt):
3220 return ZERO
3221
3222 dst = utcoffset
3223
3224 def tzname(self, dt):
3225 return 'UTC'
3226
3227utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003228
Vinay Sajipa39c5712010-10-25 13:57:39 +00003229class FormatterTest(unittest.TestCase):
3230 def setUp(self):
3231 self.common = {
3232 'name': 'formatter.test',
3233 'level': logging.DEBUG,
3234 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3235 'lineno': 42,
3236 'exc_info': None,
3237 'func': None,
3238 'msg': 'Message with %d %s',
3239 'args': (2, 'placeholders'),
3240 }
3241 self.variants = {
3242 }
3243
3244 def get_record(self, name=None):
3245 result = dict(self.common)
3246 if name is not None:
3247 result.update(self.variants[name])
3248 return logging.makeLogRecord(result)
3249
3250 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003251 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003252 r = self.get_record()
3253 f = logging.Formatter('${%(message)s}')
3254 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3255 f = logging.Formatter('%(random)s')
3256 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003257 self.assertFalse(f.usesTime())
3258 f = logging.Formatter('%(asctime)s')
3259 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003260 f = logging.Formatter('%(asctime)-15s')
3261 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003262 f = logging.Formatter('asctime')
3263 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003264
3265 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003266 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003267 r = self.get_record()
3268 f = logging.Formatter('$%{message}%$', style='{')
3269 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3270 f = logging.Formatter('{random}', style='{')
3271 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003272 self.assertFalse(f.usesTime())
3273 f = logging.Formatter('{asctime}', style='{')
3274 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003275 f = logging.Formatter('{asctime!s:15}', style='{')
3276 self.assertTrue(f.usesTime())
3277 f = logging.Formatter('{asctime:15}', style='{')
3278 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003279 f = logging.Formatter('asctime', style='{')
3280 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003281
3282 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003283 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003284 r = self.get_record()
3285 f = logging.Formatter('$message', style='$')
3286 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3287 f = logging.Formatter('$$%${message}%$$', style='$')
3288 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3289 f = logging.Formatter('${random}', style='$')
3290 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003291 self.assertFalse(f.usesTime())
3292 f = logging.Formatter('${asctime}', style='$')
3293 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003294 f = logging.Formatter('${asctime', style='$')
3295 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003296 f = logging.Formatter('$asctime', style='$')
3297 self.assertTrue(f.usesTime())
3298 f = logging.Formatter('asctime', style='$')
3299 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003300
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003301 def test_invalid_style(self):
3302 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3303
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003304 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003305 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003306 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3307 # We use None to indicate we want the local timezone
3308 # We're essentially converting a UTC time to local time
3309 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003310 r.msecs = 123
3311 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003312 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003313 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3314 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003315 f.format(r)
3316 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3317
3318class TestBufferingFormatter(logging.BufferingFormatter):
3319 def formatHeader(self, records):
3320 return '[(%d)' % len(records)
3321
3322 def formatFooter(self, records):
3323 return '(%d)]' % len(records)
3324
3325class BufferingFormatterTest(unittest.TestCase):
3326 def setUp(self):
3327 self.records = [
3328 logging.makeLogRecord({'msg': 'one'}),
3329 logging.makeLogRecord({'msg': 'two'}),
3330 ]
3331
3332 def test_default(self):
3333 f = logging.BufferingFormatter()
3334 self.assertEqual('', f.format([]))
3335 self.assertEqual('onetwo', f.format(self.records))
3336
3337 def test_custom(self):
3338 f = TestBufferingFormatter()
3339 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3340 lf = logging.Formatter('<%(message)s>')
3341 f = TestBufferingFormatter(lf)
3342 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003343
3344class ExceptionTest(BaseTest):
3345 def test_formatting(self):
3346 r = self.root_logger
3347 h = RecordingHandler()
3348 r.addHandler(h)
3349 try:
3350 raise RuntimeError('deliberate mistake')
3351 except:
3352 logging.exception('failed', stack_info=True)
3353 r.removeHandler(h)
3354 h.close()
3355 r = h.records[0]
3356 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3357 'call last):\n'))
3358 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3359 'deliberate mistake'))
3360 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3361 'call last):\n'))
3362 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3363 'stack_info=True)'))
3364
3365
Vinay Sajip5a27d402010-12-10 11:42:57 +00003366class LastResortTest(BaseTest):
3367 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003368 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003369 root = self.root_logger
3370 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003371 old_lastresort = logging.lastResort
3372 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003373
Vinay Sajip5a27d402010-12-10 11:42:57 +00003374 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003375 with support.captured_stderr() as stderr:
3376 root.debug('This should not appear')
3377 self.assertEqual(stderr.getvalue(), '')
3378 root.warning('Final chance!')
3379 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3380
3381 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003382 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003383 with support.captured_stderr() as stderr:
3384 root.warning('Final chance!')
3385 msg = 'No handlers could be found for logger "root"\n'
3386 self.assertEqual(stderr.getvalue(), msg)
3387
Vinay Sajip5a27d402010-12-10 11:42:57 +00003388 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003389 with support.captured_stderr() as stderr:
3390 root.warning('Final chance!')
3391 self.assertEqual(stderr.getvalue(), '')
3392
3393 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003394 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003395 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003396 with support.captured_stderr() as stderr:
3397 root.warning('Final chance!')
3398 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003399 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003400 root.addHandler(self.root_hdlr)
3401 logging.lastResort = old_lastresort
3402 logging.raiseExceptions = old_raise_exceptions
3403
3404
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003405class FakeHandler:
3406
3407 def __init__(self, identifier, called):
3408 for method in ('acquire', 'flush', 'close', 'release'):
3409 setattr(self, method, self.record_call(identifier, method, called))
3410
3411 def record_call(self, identifier, method_name, called):
3412 def inner():
3413 called.append('{} - {}'.format(identifier, method_name))
3414 return inner
3415
3416
3417class RecordingHandler(logging.NullHandler):
3418
3419 def __init__(self, *args, **kwargs):
3420 super(RecordingHandler, self).__init__(*args, **kwargs)
3421 self.records = []
3422
3423 def handle(self, record):
3424 """Keep track of all the emitted records."""
3425 self.records.append(record)
3426
3427
3428class ShutdownTest(BaseTest):
3429
Vinay Sajip5e66b162011-04-20 15:41:14 +01003430 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003431
3432 def setUp(self):
3433 super(ShutdownTest, self).setUp()
3434 self.called = []
3435
3436 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003437 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003438
3439 def raise_error(self, error):
3440 def inner():
3441 raise error()
3442 return inner
3443
3444 def test_no_failure(self):
3445 # create some fake handlers
3446 handler0 = FakeHandler(0, self.called)
3447 handler1 = FakeHandler(1, self.called)
3448 handler2 = FakeHandler(2, self.called)
3449
3450 # create live weakref to those handlers
3451 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3452
3453 logging.shutdown(handlerList=list(handlers))
3454
3455 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3456 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3457 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3458 self.assertEqual(expected, self.called)
3459
3460 def _test_with_failure_in_method(self, method, error):
3461 handler = FakeHandler(0, self.called)
3462 setattr(handler, method, self.raise_error(error))
3463 handlers = [logging.weakref.ref(handler)]
3464
3465 logging.shutdown(handlerList=list(handlers))
3466
3467 self.assertEqual('0 - release', self.called[-1])
3468
3469 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003470 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003471
3472 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003473 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003474
3475 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003476 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003477
3478 def test_with_valueerror_in_acquire(self):
3479 self._test_with_failure_in_method('acquire', ValueError)
3480
3481 def test_with_valueerror_in_flush(self):
3482 self._test_with_failure_in_method('flush', ValueError)
3483
3484 def test_with_valueerror_in_close(self):
3485 self._test_with_failure_in_method('close', ValueError)
3486
3487 def test_with_other_error_in_acquire_without_raise(self):
3488 logging.raiseExceptions = False
3489 self._test_with_failure_in_method('acquire', IndexError)
3490
3491 def test_with_other_error_in_flush_without_raise(self):
3492 logging.raiseExceptions = False
3493 self._test_with_failure_in_method('flush', IndexError)
3494
3495 def test_with_other_error_in_close_without_raise(self):
3496 logging.raiseExceptions = False
3497 self._test_with_failure_in_method('close', IndexError)
3498
3499 def test_with_other_error_in_acquire_with_raise(self):
3500 logging.raiseExceptions = True
3501 self.assertRaises(IndexError, self._test_with_failure_in_method,
3502 'acquire', IndexError)
3503
3504 def test_with_other_error_in_flush_with_raise(self):
3505 logging.raiseExceptions = True
3506 self.assertRaises(IndexError, self._test_with_failure_in_method,
3507 'flush', IndexError)
3508
3509 def test_with_other_error_in_close_with_raise(self):
3510 logging.raiseExceptions = True
3511 self.assertRaises(IndexError, self._test_with_failure_in_method,
3512 'close', IndexError)
3513
3514
3515class ModuleLevelMiscTest(BaseTest):
3516
Vinay Sajip5e66b162011-04-20 15:41:14 +01003517 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518
3519 def test_disable(self):
3520 old_disable = logging.root.manager.disable
3521 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003522 self.assertEqual(old_disable, 0)
3523 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003524
3525 logging.disable(83)
3526 self.assertEqual(logging.root.manager.disable, 83)
3527
Vinay Sajipd489ac92016-12-31 11:40:11 +00003528 # test the default value introduced in 3.7
3529 # (Issue #28524)
3530 logging.disable()
3531 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3532
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003533 def _test_log(self, method, level=None):
3534 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003535 support.patch(self, logging, 'basicConfig',
3536 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003537
3538 recording = RecordingHandler()
3539 logging.root.addHandler(recording)
3540
3541 log_method = getattr(logging, method)
3542 if level is not None:
3543 log_method(level, "test me: %r", recording)
3544 else:
3545 log_method("test me: %r", recording)
3546
3547 self.assertEqual(len(recording.records), 1)
3548 record = recording.records[0]
3549 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3550
3551 expected_level = level if level is not None else getattr(logging, method.upper())
3552 self.assertEqual(record.levelno, expected_level)
3553
3554 # basicConfig was not called!
3555 self.assertEqual(called, [])
3556
3557 def test_log(self):
3558 self._test_log('log', logging.ERROR)
3559
3560 def test_debug(self):
3561 self._test_log('debug')
3562
3563 def test_info(self):
3564 self._test_log('info')
3565
3566 def test_warning(self):
3567 self._test_log('warning')
3568
3569 def test_error(self):
3570 self._test_log('error')
3571
3572 def test_critical(self):
3573 self._test_log('critical')
3574
3575 def test_set_logger_class(self):
3576 self.assertRaises(TypeError, logging.setLoggerClass, object)
3577
3578 class MyLogger(logging.Logger):
3579 pass
3580
3581 logging.setLoggerClass(MyLogger)
3582 self.assertEqual(logging.getLoggerClass(), MyLogger)
3583
3584 logging.setLoggerClass(logging.Logger)
3585 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3586
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003587 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003588 def test_logging_at_shutdown(self):
3589 # Issue #20037
3590 code = """if 1:
3591 import logging
3592
3593 class A:
3594 def __del__(self):
3595 try:
3596 raise ValueError("some error")
3597 except Exception:
3598 logging.exception("exception in __del__")
3599
3600 a = A()"""
3601 rc, out, err = assert_python_ok("-c", code)
3602 err = err.decode()
3603 self.assertIn("exception in __del__", err)
3604 self.assertIn("ValueError: some error", err)
3605
3606
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003607class LogRecordTest(BaseTest):
3608 def test_str_rep(self):
3609 r = logging.makeLogRecord({})
3610 s = str(r)
3611 self.assertTrue(s.startswith('<LogRecord: '))
3612 self.assertTrue(s.endswith('>'))
3613
3614 def test_dict_arg(self):
3615 h = RecordingHandler()
3616 r = logging.getLogger()
3617 r.addHandler(h)
3618 d = {'less' : 'more' }
3619 logging.warning('less is %(less)s', d)
3620 self.assertIs(h.records[0].args, d)
3621 self.assertEqual(h.records[0].message, 'less is more')
3622 r.removeHandler(h)
3623 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003624
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003625 def test_multiprocessing(self):
3626 r = logging.makeLogRecord({})
3627 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003628 try:
3629 import multiprocessing as mp
3630 r = logging.makeLogRecord({})
3631 self.assertEqual(r.processName, mp.current_process().name)
3632 except ImportError:
3633 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003634
3635 def test_optional(self):
3636 r = logging.makeLogRecord({})
3637 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003638 if threading:
3639 NOT_NONE(r.thread)
3640 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003641 NOT_NONE(r.process)
3642 NOT_NONE(r.processName)
3643 log_threads = logging.logThreads
3644 log_processes = logging.logProcesses
3645 log_multiprocessing = logging.logMultiprocessing
3646 try:
3647 logging.logThreads = False
3648 logging.logProcesses = False
3649 logging.logMultiprocessing = False
3650 r = logging.makeLogRecord({})
3651 NONE = self.assertIsNone
3652 NONE(r.thread)
3653 NONE(r.threadName)
3654 NONE(r.process)
3655 NONE(r.processName)
3656 finally:
3657 logging.logThreads = log_threads
3658 logging.logProcesses = log_processes
3659 logging.logMultiprocessing = log_multiprocessing
3660
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003661class BasicConfigTest(unittest.TestCase):
3662
Vinay Sajip95bf5042011-04-20 11:50:56 +01003663 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003664
3665 def setUp(self):
3666 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003667 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003668 self.saved_handlers = logging._handlers.copy()
3669 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003670 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003671 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003672 logging.root.handlers = []
3673
3674 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003675 for h in logging.root.handlers[:]:
3676 logging.root.removeHandler(h)
3677 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003678 super(BasicConfigTest, self).tearDown()
3679
Vinay Sajip3def7e02011-04-20 10:58:06 +01003680 def cleanup(self):
3681 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003682 logging._handlers.clear()
3683 logging._handlers.update(self.saved_handlers)
3684 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003685 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003686
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003687 def test_no_kwargs(self):
3688 logging.basicConfig()
3689
3690 # handler defaults to a StreamHandler to sys.stderr
3691 self.assertEqual(len(logging.root.handlers), 1)
3692 handler = logging.root.handlers[0]
3693 self.assertIsInstance(handler, logging.StreamHandler)
3694 self.assertEqual(handler.stream, sys.stderr)
3695
3696 formatter = handler.formatter
3697 # format defaults to logging.BASIC_FORMAT
3698 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3699 # datefmt defaults to None
3700 self.assertIsNone(formatter.datefmt)
3701 # style defaults to %
3702 self.assertIsInstance(formatter._style, logging.PercentStyle)
3703
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003704 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003705 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003706
Vinay Sajip1fd12022014-01-13 21:59:56 +00003707 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003708 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003709 logging.basicConfig(stream=sys.stdout, style="{")
3710 logging.error("Log an error")
3711 sys.stdout.seek(0)
3712 self.assertEqual(output.getvalue().strip(),
3713 "ERROR:root:Log an error")
3714
3715 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003716 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003717 logging.basicConfig(stream=sys.stdout, style="$")
3718 logging.error("Log an error")
3719 sys.stdout.seek(0)
3720 self.assertEqual(output.getvalue().strip(),
3721 "ERROR:root:Log an error")
3722
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003723 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003724
3725 def cleanup(h1, h2, fn):
3726 h1.close()
3727 h2.close()
3728 os.remove(fn)
3729
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003730 logging.basicConfig(filename='test.log')
3731
3732 self.assertEqual(len(logging.root.handlers), 1)
3733 handler = logging.root.handlers[0]
3734 self.assertIsInstance(handler, logging.FileHandler)
3735
3736 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003737 self.assertEqual(handler.stream.mode, expected.stream.mode)
3738 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003739 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003740
3741 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003742
3743 def cleanup(h1, h2, fn):
3744 h1.close()
3745 h2.close()
3746 os.remove(fn)
3747
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003748 logging.basicConfig(filename='test.log', filemode='wb')
3749
3750 handler = logging.root.handlers[0]
3751 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003752 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003753 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003754
3755 def test_stream(self):
3756 stream = io.StringIO()
3757 self.addCleanup(stream.close)
3758 logging.basicConfig(stream=stream)
3759
3760 self.assertEqual(len(logging.root.handlers), 1)
3761 handler = logging.root.handlers[0]
3762 self.assertIsInstance(handler, logging.StreamHandler)
3763 self.assertEqual(handler.stream, stream)
3764
3765 def test_format(self):
3766 logging.basicConfig(format='foo')
3767
3768 formatter = logging.root.handlers[0].formatter
3769 self.assertEqual(formatter._style._fmt, 'foo')
3770
3771 def test_datefmt(self):
3772 logging.basicConfig(datefmt='bar')
3773
3774 formatter = logging.root.handlers[0].formatter
3775 self.assertEqual(formatter.datefmt, 'bar')
3776
3777 def test_style(self):
3778 logging.basicConfig(style='$')
3779
3780 formatter = logging.root.handlers[0].formatter
3781 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3782
3783 def test_level(self):
3784 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003785 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003786
3787 logging.basicConfig(level=57)
3788 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003789 # Test that second call has no effect
3790 logging.basicConfig(level=58)
3791 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003792
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003793 def test_incompatible(self):
3794 assertRaises = self.assertRaises
3795 handlers = [logging.StreamHandler()]
3796 stream = sys.stderr
3797 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3798 stream=stream)
3799 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3800 handlers=handlers)
3801 assertRaises(ValueError, logging.basicConfig, stream=stream,
3802 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003803 # Issue 23207: test for invalid kwargs
3804 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3805 # Should pop both filename and filemode even if filename is None
3806 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003807
3808 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003809 handlers = [
3810 logging.StreamHandler(),
3811 logging.StreamHandler(sys.stdout),
3812 logging.StreamHandler(),
3813 ]
3814 f = logging.Formatter()
3815 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003816 logging.basicConfig(handlers=handlers)
3817 self.assertIs(handlers[0], logging.root.handlers[0])
3818 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003819 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003820 self.assertIsNotNone(handlers[0].formatter)
3821 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003822 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003823 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3824
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825 def _test_log(self, method, level=None):
3826 # logging.root has no handlers so basicConfig should be called
3827 called = []
3828
3829 old_basic_config = logging.basicConfig
3830 def my_basic_config(*a, **kw):
3831 old_basic_config()
3832 old_level = logging.root.level
3833 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003834 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003835 called.append((a, kw))
3836
Vinay Sajip1feedb42014-05-31 08:19:12 +01003837 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003838
3839 log_method = getattr(logging, method)
3840 if level is not None:
3841 log_method(level, "test me")
3842 else:
3843 log_method("test me")
3844
3845 # basicConfig was called with no arguments
3846 self.assertEqual(called, [((), {})])
3847
3848 def test_log(self):
3849 self._test_log('log', logging.WARNING)
3850
3851 def test_debug(self):
3852 self._test_log('debug')
3853
3854 def test_info(self):
3855 self._test_log('info')
3856
3857 def test_warning(self):
3858 self._test_log('warning')
3859
3860 def test_error(self):
3861 self._test_log('error')
3862
3863 def test_critical(self):
3864 self._test_log('critical')
3865
3866
3867class LoggerAdapterTest(unittest.TestCase):
3868
3869 def setUp(self):
3870 super(LoggerAdapterTest, self).setUp()
3871 old_handler_list = logging._handlerList[:]
3872
3873 self.recording = RecordingHandler()
3874 self.logger = logging.root
3875 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003876 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003877 self.addCleanup(self.recording.close)
3878
3879 def cleanup():
3880 logging._handlerList[:] = old_handler_list
3881
3882 self.addCleanup(cleanup)
3883 self.addCleanup(logging.shutdown)
3884 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3885
3886 def test_exception(self):
3887 msg = 'testing exception: %r'
3888 exc = None
3889 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003890 1 / 0
3891 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003892 exc = e
3893 self.adapter.exception(msg, self.recording)
3894
3895 self.assertEqual(len(self.recording.records), 1)
3896 record = self.recording.records[0]
3897 self.assertEqual(record.levelno, logging.ERROR)
3898 self.assertEqual(record.msg, msg)
3899 self.assertEqual(record.args, (self.recording,))
3900 self.assertEqual(record.exc_info,
3901 (exc.__class__, exc, exc.__traceback__))
3902
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003903 def test_exception_excinfo(self):
3904 try:
3905 1 / 0
3906 except ZeroDivisionError as e:
3907 exc = e
3908
3909 self.adapter.exception('exc_info test', exc_info=exc)
3910
3911 self.assertEqual(len(self.recording.records), 1)
3912 record = self.recording.records[0]
3913 self.assertEqual(record.exc_info,
3914 (exc.__class__, exc, exc.__traceback__))
3915
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003916 def test_critical(self):
3917 msg = 'critical test! %r'
3918 self.adapter.critical(msg, self.recording)
3919
3920 self.assertEqual(len(self.recording.records), 1)
3921 record = self.recording.records[0]
3922 self.assertEqual(record.levelno, logging.CRITICAL)
3923 self.assertEqual(record.msg, msg)
3924 self.assertEqual(record.args, (self.recording,))
3925
3926 def test_is_enabled_for(self):
3927 old_disable = self.adapter.logger.manager.disable
3928 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003929 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3930 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003931 self.assertFalse(self.adapter.isEnabledFor(32))
3932
3933 def test_has_handlers(self):
3934 self.assertTrue(self.adapter.hasHandlers())
3935
3936 for handler in self.logger.handlers:
3937 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003938
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003939 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003940 self.assertFalse(self.adapter.hasHandlers())
3941
3942
3943class LoggerTest(BaseTest):
3944
3945 def setUp(self):
3946 super(LoggerTest, self).setUp()
3947 self.recording = RecordingHandler()
3948 self.logger = logging.Logger(name='blah')
3949 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003950 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003951 self.addCleanup(self.recording.close)
3952 self.addCleanup(logging.shutdown)
3953
3954 def test_set_invalid_level(self):
3955 self.assertRaises(TypeError, self.logger.setLevel, object())
3956
3957 def test_exception(self):
3958 msg = 'testing exception: %r'
3959 exc = None
3960 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003961 1 / 0
3962 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003963 exc = e
3964 self.logger.exception(msg, self.recording)
3965
3966 self.assertEqual(len(self.recording.records), 1)
3967 record = self.recording.records[0]
3968 self.assertEqual(record.levelno, logging.ERROR)
3969 self.assertEqual(record.msg, msg)
3970 self.assertEqual(record.args, (self.recording,))
3971 self.assertEqual(record.exc_info,
3972 (exc.__class__, exc, exc.__traceback__))
3973
3974 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003975 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003976 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003977
3978 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003979 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003980 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003981
3982 def test_find_caller_with_stack_info(self):
3983 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003984 support.patch(self, logging.traceback, 'print_stack',
3985 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003986
3987 self.logger.findCaller(stack_info=True)
3988
3989 self.assertEqual(len(called), 1)
3990 self.assertEqual('Stack (most recent call last):\n', called[0])
3991
3992 def test_make_record_with_extra_overwrite(self):
3993 name = 'my record'
3994 level = 13
3995 fn = lno = msg = args = exc_info = func = sinfo = None
3996 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3997 exc_info, func, sinfo)
3998
3999 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4000 extra = {key: 'some value'}
4001 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4002 fn, lno, msg, args, exc_info,
4003 extra=extra, sinfo=sinfo)
4004
4005 def test_make_record_with_extra_no_overwrite(self):
4006 name = 'my record'
4007 level = 13
4008 fn = lno = msg = args = exc_info = func = sinfo = None
4009 extra = {'valid_key': 'some value'}
4010 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4011 exc_info, extra=extra, sinfo=sinfo)
4012 self.assertIn('valid_key', result.__dict__)
4013
4014 def test_has_handlers(self):
4015 self.assertTrue(self.logger.hasHandlers())
4016
4017 for handler in self.logger.handlers:
4018 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004019 self.assertFalse(self.logger.hasHandlers())
4020
4021 def test_has_handlers_no_propagate(self):
4022 child_logger = logging.getLogger('blah.child')
4023 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004024 self.assertFalse(child_logger.hasHandlers())
4025
4026 def test_is_enabled_for(self):
4027 old_disable = self.logger.manager.disable
4028 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004029 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004030 self.assertFalse(self.logger.isEnabledFor(22))
4031
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004032 def test_root_logger_aliases(self):
4033 root = logging.getLogger()
4034 self.assertIs(root, logging.root)
4035 self.assertIs(root, logging.getLogger(None))
4036 self.assertIs(root, logging.getLogger(''))
4037 self.assertIs(root, logging.getLogger('foo').root)
4038 self.assertIs(root, logging.getLogger('foo.bar').root)
4039 self.assertIs(root, logging.getLogger('foo').parent)
4040
4041 self.assertIsNot(root, logging.getLogger('\0'))
4042 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4043
4044 def test_invalid_names(self):
4045 self.assertRaises(TypeError, logging.getLogger, any)
4046 self.assertRaises(TypeError, logging.getLogger, b'foo')
4047
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004048
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004049class BaseFileTest(BaseTest):
4050 "Base class for handler tests that write log files"
4051
4052 def setUp(self):
4053 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004054 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4055 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004056 self.rmfiles = []
4057
4058 def tearDown(self):
4059 for fn in self.rmfiles:
4060 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004061 if os.path.exists(self.fn):
4062 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004063 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004064
4065 def assertLogFile(self, filename):
4066 "Assert a log file is there and register it for deletion"
4067 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004068 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004069 self.rmfiles.append(filename)
4070
4071
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004072class FileHandlerTest(BaseFileTest):
4073 def test_delay(self):
4074 os.unlink(self.fn)
4075 fh = logging.FileHandler(self.fn, delay=True)
4076 self.assertIsNone(fh.stream)
4077 self.assertFalse(os.path.exists(self.fn))
4078 fh.handle(logging.makeLogRecord({}))
4079 self.assertIsNotNone(fh.stream)
4080 self.assertTrue(os.path.exists(self.fn))
4081 fh.close()
4082
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004083class RotatingFileHandlerTest(BaseFileTest):
4084 def next_rec(self):
4085 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4086 self.next_message(), None, None, None)
4087
4088 def test_should_not_rollover(self):
4089 # If maxbytes is zero rollover never occurs
4090 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4091 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004092 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004093
4094 def test_should_rollover(self):
4095 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4096 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004097 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004098
4099 def test_file_created(self):
4100 # checks that the file is created and assumes it was created
4101 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004102 rh = logging.handlers.RotatingFileHandler(self.fn)
4103 rh.emit(self.next_rec())
4104 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004105 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004106
4107 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004108 def namer(name):
4109 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004110 rh = logging.handlers.RotatingFileHandler(
4111 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004112 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004113 rh.emit(self.next_rec())
4114 self.assertLogFile(self.fn)
4115 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004116 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004117 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004118 self.assertLogFile(namer(self.fn + ".2"))
4119 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4120 rh.close()
4121
Vinay Sajip1feedb42014-05-31 08:19:12 +01004122 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004123 def test_rotator(self):
4124 def namer(name):
4125 return name + ".gz"
4126
4127 def rotator(source, dest):
4128 with open(source, "rb") as sf:
4129 data = sf.read()
4130 compressed = zlib.compress(data, 9)
4131 with open(dest, "wb") as df:
4132 df.write(compressed)
4133 os.remove(source)
4134
4135 rh = logging.handlers.RotatingFileHandler(
4136 self.fn, backupCount=2, maxBytes=1)
4137 rh.rotator = rotator
4138 rh.namer = namer
4139 m1 = self.next_rec()
4140 rh.emit(m1)
4141 self.assertLogFile(self.fn)
4142 m2 = self.next_rec()
4143 rh.emit(m2)
4144 fn = namer(self.fn + ".1")
4145 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004146 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004147 with open(fn, "rb") as f:
4148 compressed = f.read()
4149 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004150 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004151 rh.emit(self.next_rec())
4152 fn = namer(self.fn + ".2")
4153 self.assertLogFile(fn)
4154 with open(fn, "rb") as f:
4155 compressed = f.read()
4156 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004157 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004158 rh.emit(self.next_rec())
4159 fn = namer(self.fn + ".2")
4160 with open(fn, "rb") as f:
4161 compressed = f.read()
4162 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004163 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004164 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004165 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004166
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004167class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004168 # other test methods added below
4169 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004170 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4171 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004172 fmt = logging.Formatter('%(asctime)s %(message)s')
4173 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004174 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004175 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004176 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004177 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004178 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004179 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004180 fh.close()
4181 # At this point, we should have a recent rotated file which we
4182 # can test for the existence of. However, in practice, on some
4183 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004184 # in time to go to look for the log file. So, we go back a fair
4185 # bit, and stop as soon as we see a rotated file. In theory this
4186 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004187 found = False
4188 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004189 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004190 for secs in range(GO_BACK):
4191 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004192 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4193 found = os.path.exists(fn)
4194 if found:
4195 self.rmfiles.append(fn)
4196 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004197 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4198 if not found:
4199 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004200 dn, fn = os.path.split(self.fn)
4201 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004202 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4203 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004204 for f in files:
4205 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004206 path = os.path.join(dn, f)
4207 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004208 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004209 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004210
Vinay Sajip0372e102011-05-05 12:59:14 +01004211 def test_invalid(self):
4212 assertRaises = self.assertRaises
4213 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004214 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004215 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004216 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004217 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004218 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004219
Vinay Sajipa7130792013-04-12 17:04:23 +01004220 def test_compute_rollover_daily_attime(self):
4221 currentTime = 0
4222 atTime = datetime.time(12, 0, 0)
4223 rh = logging.handlers.TimedRotatingFileHandler(
4224 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4225 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004226 try:
4227 actual = rh.computeRollover(currentTime)
4228 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004229
Vinay Sajipd86ac962013-04-14 12:20:46 +01004230 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4231 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4232 finally:
4233 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004234
Vinay Sajip10e8c492013-05-18 10:19:54 -07004235 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004236 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004237 currentTime = int(time.time())
4238 today = currentTime - currentTime % 86400
4239
Vinay Sajipa7130792013-04-12 17:04:23 +01004240 atTime = datetime.time(12, 0, 0)
4241
Vinay Sajip10e8c492013-05-18 10:19:54 -07004242 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004243 for day in range(7):
4244 rh = logging.handlers.TimedRotatingFileHandler(
4245 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4246 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004247 try:
4248 if wday > day:
4249 # The rollover day has already passed this week, so we
4250 # go over into next week
4251 expected = (7 - wday + day)
4252 else:
4253 expected = (day - wday)
4254 # At this point expected is in days from now, convert to seconds
4255 expected *= 24 * 60 * 60
4256 # Add in the rollover time
4257 expected += 12 * 60 * 60
4258 # Add in adjustment for today
4259 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004260 actual = rh.computeRollover(today)
4261 if actual != expected:
4262 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004263 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004264 self.assertEqual(actual, expected)
4265 if day == wday:
4266 # goes into following week
4267 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004268 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004269 if actual != expected:
4270 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004271 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004272 self.assertEqual(actual, expected)
4273 finally:
4274 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004275
4276
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004277def secs(**kw):
4278 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4279
4280for when, exp in (('S', 1),
4281 ('M', 60),
4282 ('H', 60 * 60),
4283 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004284 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004285 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004286 ('W0', secs(days=4, hours=24)),
4287 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004288 def test_compute_rollover(self, when=when, exp=exp):
4289 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004290 self.fn, when=when, interval=1, backupCount=0, utc=True)
4291 currentTime = 0.0
4292 actual = rh.computeRollover(currentTime)
4293 if exp != actual:
4294 # Failures occur on some systems for MIDNIGHT and W0.
4295 # Print detailed calculation for MIDNIGHT so we can try to see
4296 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004297 if when == 'MIDNIGHT':
4298 try:
4299 if rh.utc:
4300 t = time.gmtime(currentTime)
4301 else:
4302 t = time.localtime(currentTime)
4303 currentHour = t[3]
4304 currentMinute = t[4]
4305 currentSecond = t[5]
4306 # r is the number of seconds left between now and midnight
4307 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4308 currentMinute) * 60 +
4309 currentSecond)
4310 result = currentTime + r
4311 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4312 print('currentHour: %s' % currentHour, file=sys.stderr)
4313 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4314 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4315 print('r: %s' % r, file=sys.stderr)
4316 print('result: %s' % result, file=sys.stderr)
4317 except Exception:
4318 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4319 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004320 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004321 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4322
Vinay Sajip60ccd822011-05-09 17:32:09 +01004323
Vinay Sajip223349c2015-10-01 20:37:54 +01004324@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004325class NTEventLogHandlerTest(BaseTest):
4326 def test_basic(self):
4327 logtype = 'Application'
4328 elh = win32evtlog.OpenEventLog(None, logtype)
4329 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004330
4331 try:
4332 h = logging.handlers.NTEventLogHandler('test_logging')
4333 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004334 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004335 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004336 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004337
Vinay Sajip60ccd822011-05-09 17:32:09 +01004338 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4339 h.handle(r)
4340 h.close()
4341 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004342 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004343 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4344 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4345 found = False
4346 GO_BACK = 100
4347 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4348 for e in events:
4349 if e.SourceName != 'test_logging':
4350 continue
4351 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4352 if msg != 'Test Log Message\r\n':
4353 continue
4354 found = True
4355 break
4356 msg = 'Record not found in event log, went back %d records' % GO_BACK
4357 self.assertTrue(found, msg=msg)
4358
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004359
4360class MiscTestCase(unittest.TestCase):
4361 def test__all__(self):
4362 blacklist = {'logThreads', 'logMultiprocessing',
4363 'logProcesses', 'currentframe',
4364 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4365 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004366 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004367 support.check__all__(self, logging, blacklist=blacklist)
4368
4369
Christian Heimes180510d2008-03-03 19:15:45 +00004370# Set the locale to the platform-dependent default. I have no idea
4371# why the test does this, but in any case we save the current locale
4372# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004373@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004374def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004375 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004376 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4377 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4378 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4379 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4380 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4381 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4382 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4383 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4384 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4385 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004386 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004387 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004388 ]
4389 if hasattr(logging.handlers, 'QueueListener'):
4390 tests.append(QueueListenerTest)
4391 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004392
Christian Heimes180510d2008-03-03 19:15:45 +00004393if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004394 test_main()