blob: 08cdd7f3ebd8e7af18a060021804cd5e251ed4ad [file] [log] [blame]
Vinay Sajipd61910c2016-09-08 01:13:39 +01001# Copyright 2001-2016 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 Sajipd61910c2016-09-08 01:13:39 +010019Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000049try:
50 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010051 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010052 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 from http.server import HTTPServer, BaseHTTPRequestHandler
55 import smtpd
56 from urllib.parse import urlparse, parse_qs
57 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010058 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000059except ImportError:
60 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010061try:
Vinay Sajip223349c2015-10-01 20:37:54 +010062 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010063except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010064 win32evtlog = win32evtlogutil = pywintypes = None
65
Eric V. Smith851cad72012-03-11 22:46:04 -070066try:
67 import zlib
68except ImportError:
69 pass
Christian Heimes18c66892008-02-17 13:31:39 +000070
Christian Heimes180510d2008-03-03 19:15:45 +000071class BaseTest(unittest.TestCase):
72
73 """Base class for logging tests."""
74
75 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030076 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000077 message_num = 0
78
79 def setUp(self):
80 """Setup the default logging stream to an internal StringIO instance,
81 so that we can examine log output as we want."""
82 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000083 logging._acquireLock()
84 try:
Christian Heimes180510d2008-03-03 19:15:45 +000085 self.saved_handlers = logging._handlers.copy()
86 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000087 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070088 self.saved_name_to_level = logging._nameToLevel.copy()
89 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.logger_states = logger_states = {}
91 for name in saved_loggers:
92 logger_states[name] = getattr(saved_loggers[name],
93 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000094 finally:
95 logging._releaseLock()
96
Florent Xicluna5252f9f2011-11-07 19:43:05 +010097 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000098 self.logger1 = logging.getLogger("\xab\xd7\xbb")
99 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000100
Christian Heimes180510d2008-03-03 19:15:45 +0000101 self.root_logger = logging.getLogger("")
102 self.original_logging_level = self.root_logger.getEffectiveLevel()
103
104 self.stream = io.StringIO()
105 self.root_logger.setLevel(logging.DEBUG)
106 self.root_hdlr = logging.StreamHandler(self.stream)
107 self.root_formatter = logging.Formatter(self.log_format)
108 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000109 if self.logger1.hasHandlers():
110 hlist = self.logger1.handlers + self.root_logger.handlers
111 raise AssertionError('Unexpected handlers: %s' % hlist)
112 if self.logger2.hasHandlers():
113 hlist = self.logger2.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000115 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000116 self.assertTrue(self.logger1.hasHandlers())
117 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000118
119 def tearDown(self):
120 """Remove our logging stream, and restore the original logging
121 level."""
122 self.stream.close()
123 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000124 while self.root_logger.handlers:
125 h = self.root_logger.handlers[0]
126 self.root_logger.removeHandler(h)
127 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000128 self.root_logger.setLevel(self.original_logging_level)
129 logging._acquireLock()
130 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700131 logging._levelToName.clear()
132 logging._levelToName.update(self.saved_level_to_name)
133 logging._nameToLevel.clear()
134 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000135 logging._handlers.clear()
136 logging._handlers.update(self.saved_handlers)
137 logging._handlerList[:] = self.saved_handler_list
138 loggerDict = logging.getLogger().manager.loggerDict
139 loggerDict.clear()
140 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000141 logger_states = self.logger_states
142 for name in self.logger_states:
143 if logger_states[name] is not None:
144 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000145 finally:
146 logging._releaseLock()
147
Vinay Sajip4ded5512012-10-02 15:56:16 +0100148 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000149 """Match the collected log lines against the regular expression
150 self.expected_log_pat, and compare the extracted group values to
151 the expected_values list of tuples."""
152 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100153 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300154 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100155 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000156 for actual, expected in zip(actual_lines, expected_values):
157 match = pat.search(actual)
158 if not match:
159 self.fail("Log line does not match expected pattern:\n" +
160 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000161 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000162 s = stream.read()
163 if s:
164 self.fail("Remaining output at end of log stream:\n" + s)
165
166 def next_message(self):
167 """Generate a message consisting solely of an auto-incrementing
168 integer."""
169 self.message_num += 1
170 return "%d" % self.message_num
171
172
173class BuiltinLevelsTest(BaseTest):
174 """Test builtin levels and their inheritance."""
175
176 def test_flat(self):
177 #Logging levels in a flat logger namespace.
178 m = self.next_message
179
180 ERR = logging.getLogger("ERR")
181 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000182 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000183 INF.setLevel(logging.INFO)
184 DEB = logging.getLogger("DEB")
185 DEB.setLevel(logging.DEBUG)
186
187 # These should log.
188 ERR.log(logging.CRITICAL, m())
189 ERR.error(m())
190
191 INF.log(logging.CRITICAL, m())
192 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100193 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000194 INF.info(m())
195
196 DEB.log(logging.CRITICAL, m())
197 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100198 DEB.warning(m())
199 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 DEB.debug(m())
201
202 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100203 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 ERR.info(m())
205 ERR.debug(m())
206
207 INF.debug(m())
208
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000209 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ('ERR', 'CRITICAL', '1'),
211 ('ERR', 'ERROR', '2'),
212 ('INF', 'CRITICAL', '3'),
213 ('INF', 'ERROR', '4'),
214 ('INF', 'WARNING', '5'),
215 ('INF', 'INFO', '6'),
216 ('DEB', 'CRITICAL', '7'),
217 ('DEB', 'ERROR', '8'),
218 ('DEB', 'WARNING', '9'),
219 ('DEB', 'INFO', '10'),
220 ('DEB', 'DEBUG', '11'),
221 ])
222
223 def test_nested_explicit(self):
224 # Logging levels in a nested namespace, all explicitly set.
225 m = self.next_message
226
227 INF = logging.getLogger("INF")
228 INF.setLevel(logging.INFO)
229 INF_ERR = logging.getLogger("INF.ERR")
230 INF_ERR.setLevel(logging.ERROR)
231
232 # These should log.
233 INF_ERR.log(logging.CRITICAL, m())
234 INF_ERR.error(m())
235
236 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100237 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000238 INF_ERR.info(m())
239 INF_ERR.debug(m())
240
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000241 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000242 ('INF.ERR', 'CRITICAL', '1'),
243 ('INF.ERR', 'ERROR', '2'),
244 ])
245
246 def test_nested_inherited(self):
247 #Logging levels in a nested namespace, inherited from parent loggers.
248 m = self.next_message
249
250 INF = logging.getLogger("INF")
251 INF.setLevel(logging.INFO)
252 INF_ERR = logging.getLogger("INF.ERR")
253 INF_ERR.setLevel(logging.ERROR)
254 INF_UNDEF = logging.getLogger("INF.UNDEF")
255 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
256 UNDEF = logging.getLogger("UNDEF")
257
258 # These should log.
259 INF_UNDEF.log(logging.CRITICAL, m())
260 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100261 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000262 INF_UNDEF.info(m())
263 INF_ERR_UNDEF.log(logging.CRITICAL, m())
264 INF_ERR_UNDEF.error(m())
265
266 # These should not log.
267 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100268 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000269 INF_ERR_UNDEF.info(m())
270 INF_ERR_UNDEF.debug(m())
271
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000272 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000273 ('INF.UNDEF', 'CRITICAL', '1'),
274 ('INF.UNDEF', 'ERROR', '2'),
275 ('INF.UNDEF', 'WARNING', '3'),
276 ('INF.UNDEF', 'INFO', '4'),
277 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
278 ('INF.ERR.UNDEF', 'ERROR', '6'),
279 ])
280
281 def test_nested_with_virtual_parent(self):
282 # Logging levels when some parent does not exist yet.
283 m = self.next_message
284
285 INF = logging.getLogger("INF")
286 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
287 CHILD = logging.getLogger("INF.BADPARENT")
288 INF.setLevel(logging.INFO)
289
290 # These should log.
291 GRANDCHILD.log(logging.FATAL, m())
292 GRANDCHILD.info(m())
293 CHILD.log(logging.FATAL, m())
294 CHILD.info(m())
295
296 # These should not log.
297 GRANDCHILD.debug(m())
298 CHILD.debug(m())
299
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000300 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000301 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
302 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
303 ('INF.BADPARENT', 'CRITICAL', '3'),
304 ('INF.BADPARENT', 'INFO', '4'),
305 ])
306
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100307 def test_regression_22386(self):
308 """See issue #22386 for more information."""
309 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
310 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000311
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100312 def test_issue27935(self):
313 fatal = logging.getLevelName('FATAL')
314 self.assertEqual(fatal, logging.FATAL)
315
Christian Heimes180510d2008-03-03 19:15:45 +0000316class BasicFilterTest(BaseTest):
317
318 """Test the bundled Filter class."""
319
320 def test_filter(self):
321 # Only messages satisfying the specified criteria pass through the
322 # filter.
323 filter_ = logging.Filter("spam.eggs")
324 handler = self.root_logger.handlers[0]
325 try:
326 handler.addFilter(filter_)
327 spam = logging.getLogger("spam")
328 spam_eggs = logging.getLogger("spam.eggs")
329 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
330 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
331
332 spam.info(self.next_message())
333 spam_eggs.info(self.next_message()) # Good.
334 spam_eggs_fish.info(self.next_message()) # Good.
335 spam_bakedbeans.info(self.next_message())
336
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000337 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000338 ('spam.eggs', 'INFO', '2'),
339 ('spam.eggs.fish', 'INFO', '3'),
340 ])
341 finally:
342 handler.removeFilter(filter_)
343
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000344 def test_callable_filter(self):
345 # Only messages satisfying the specified criteria pass through the
346 # filter.
347
348 def filterfunc(record):
349 parts = record.name.split('.')
350 prefix = '.'.join(parts[:2])
351 return prefix == 'spam.eggs'
352
353 handler = self.root_logger.handlers[0]
354 try:
355 handler.addFilter(filterfunc)
356 spam = logging.getLogger("spam")
357 spam_eggs = logging.getLogger("spam.eggs")
358 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
359 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
360
361 spam.info(self.next_message())
362 spam_eggs.info(self.next_message()) # Good.
363 spam_eggs_fish.info(self.next_message()) # Good.
364 spam_bakedbeans.info(self.next_message())
365
366 self.assert_log_lines([
367 ('spam.eggs', 'INFO', '2'),
368 ('spam.eggs.fish', 'INFO', '3'),
369 ])
370 finally:
371 handler.removeFilter(filterfunc)
372
Vinay Sajip985ef872011-04-26 19:34:04 +0100373 def test_empty_filter(self):
374 f = logging.Filter()
375 r = logging.makeLogRecord({'name': 'spam.eggs'})
376 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000377
378#
379# First, we define our levels. There can be as many as you want - the only
380# limitations are that they should be integers, the lowest should be > 0 and
381# larger values mean less information being logged. If you need specific
382# level values which do not fit into these limitations, you can use a
383# mapping dictionary to convert between your application levels and the
384# logging system.
385#
386SILENT = 120
387TACITURN = 119
388TERSE = 118
389EFFUSIVE = 117
390SOCIABLE = 116
391VERBOSE = 115
392TALKATIVE = 114
393GARRULOUS = 113
394CHATTERBOX = 112
395BORING = 111
396
397LEVEL_RANGE = range(BORING, SILENT + 1)
398
399#
400# Next, we define names for our levels. You don't need to do this - in which
401# case the system will use "Level n" to denote the text for the level.
402#
403my_logging_levels = {
404 SILENT : 'Silent',
405 TACITURN : 'Taciturn',
406 TERSE : 'Terse',
407 EFFUSIVE : 'Effusive',
408 SOCIABLE : 'Sociable',
409 VERBOSE : 'Verbose',
410 TALKATIVE : 'Talkative',
411 GARRULOUS : 'Garrulous',
412 CHATTERBOX : 'Chatterbox',
413 BORING : 'Boring',
414}
415
416class GarrulousFilter(logging.Filter):
417
418 """A filter which blocks garrulous messages."""
419
420 def filter(self, record):
421 return record.levelno != GARRULOUS
422
423class VerySpecificFilter(logging.Filter):
424
425 """A filter which blocks sociable and taciturn messages."""
426
427 def filter(self, record):
428 return record.levelno not in [SOCIABLE, TACITURN]
429
430
431class CustomLevelsAndFiltersTest(BaseTest):
432
433 """Test various filtering possibilities with custom logging levels."""
434
435 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300436 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000437
438 def setUp(self):
439 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000440 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000441 logging.addLevelName(k, v)
442
443 def log_at_all_levels(self, logger):
444 for lvl in LEVEL_RANGE:
445 logger.log(lvl, self.next_message())
446
447 def test_logger_filter(self):
448 # Filter at logger level.
449 self.root_logger.setLevel(VERBOSE)
450 # Levels >= 'Verbose' are good.
451 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000452 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000453 ('Verbose', '5'),
454 ('Sociable', '6'),
455 ('Effusive', '7'),
456 ('Terse', '8'),
457 ('Taciturn', '9'),
458 ('Silent', '10'),
459 ])
460
461 def test_handler_filter(self):
462 # Filter at handler level.
463 self.root_logger.handlers[0].setLevel(SOCIABLE)
464 try:
465 # Levels >= 'Sociable' are good.
466 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000467 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000468 ('Sociable', '6'),
469 ('Effusive', '7'),
470 ('Terse', '8'),
471 ('Taciturn', '9'),
472 ('Silent', '10'),
473 ])
474 finally:
475 self.root_logger.handlers[0].setLevel(logging.NOTSET)
476
477 def test_specific_filters(self):
478 # Set a specific filter object on the handler, and then add another
479 # filter object on the logger itself.
480 handler = self.root_logger.handlers[0]
481 specific_filter = None
482 garr = GarrulousFilter()
483 handler.addFilter(garr)
484 try:
485 self.log_at_all_levels(self.root_logger)
486 first_lines = [
487 # Notice how 'Garrulous' is missing
488 ('Boring', '1'),
489 ('Chatterbox', '2'),
490 ('Talkative', '4'),
491 ('Verbose', '5'),
492 ('Sociable', '6'),
493 ('Effusive', '7'),
494 ('Terse', '8'),
495 ('Taciturn', '9'),
496 ('Silent', '10'),
497 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000498 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000499
500 specific_filter = VerySpecificFilter()
501 self.root_logger.addFilter(specific_filter)
502 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000503 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000504 # Not only 'Garrulous' is still missing, but also 'Sociable'
505 # and 'Taciturn'
506 ('Boring', '11'),
507 ('Chatterbox', '12'),
508 ('Talkative', '14'),
509 ('Verbose', '15'),
510 ('Effusive', '17'),
511 ('Terse', '18'),
512 ('Silent', '20'),
513 ])
514 finally:
515 if specific_filter:
516 self.root_logger.removeFilter(specific_filter)
517 handler.removeFilter(garr)
518
519
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100520class HandlerTest(BaseTest):
521 def test_name(self):
522 h = logging.Handler()
523 h.name = 'generic'
524 self.assertEqual(h.name, 'generic')
525 h.name = 'anothergeneric'
526 self.assertEqual(h.name, 'anothergeneric')
527 self.assertRaises(NotImplementedError, h.emit, None)
528
Vinay Sajip5a35b062011-04-27 11:31:14 +0100529 def test_builtin_handlers(self):
530 # We can't actually *use* too many handlers in the tests,
531 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200532 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100533 for existing in (True, False):
534 fd, fn = tempfile.mkstemp()
535 os.close(fd)
536 if not existing:
537 os.unlink(fn)
538 h = logging.handlers.WatchedFileHandler(fn, delay=True)
539 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100540 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100541 self.assertEqual(dev, -1)
542 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100543 r = logging.makeLogRecord({'msg': 'Test'})
544 h.handle(r)
545 # Now remove the file.
546 os.unlink(fn)
547 self.assertFalse(os.path.exists(fn))
548 # The next call should recreate the file.
549 h.handle(r)
550 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100551 else:
552 self.assertEqual(h.dev, -1)
553 self.assertEqual(h.ino, -1)
554 h.close()
555 if existing:
556 os.unlink(fn)
557 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100558 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100559 else:
560 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100561 try:
562 h = logging.handlers.SysLogHandler(sockname)
563 self.assertEqual(h.facility, h.LOG_USER)
564 self.assertTrue(h.unixsocket)
565 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200566 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100567 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100568 for method in ('GET', 'POST', 'PUT'):
569 if method == 'PUT':
570 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
571 'localhost', '/log', method)
572 else:
573 h = logging.handlers.HTTPHandler('localhost', '/log', method)
574 h.close()
575 h = logging.handlers.BufferingHandler(0)
576 r = logging.makeLogRecord({})
577 self.assertTrue(h.shouldFlush(r))
578 h.close()
579 h = logging.handlers.BufferingHandler(1)
580 self.assertFalse(h.shouldFlush(r))
581 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100582
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100583 def test_path_objects(self):
584 """
585 Test that Path objects are accepted as filename arguments to handlers.
586
587 See Issue #27493.
588 """
589 fd, fn = tempfile.mkstemp()
590 os.close(fd)
591 os.unlink(fn)
592 pfn = pathlib.Path(fn)
593 cases = (
594 (logging.FileHandler, (pfn, 'w')),
595 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
596 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
597 )
598 if sys.platform in ('linux', 'darwin'):
599 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
600 for cls, args in cases:
601 h = cls(*args)
602 self.assertTrue(os.path.exists(fn))
603 h.close()
604 os.unlink(fn)
605
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100606 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100607 @unittest.skipUnless(threading, 'Threading required for this test.')
608 def test_race(self):
609 # Issue #14632 refers.
610 def remove_loop(fname, tries):
611 for _ in range(tries):
612 try:
613 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000614 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100615 except OSError:
616 pass
617 time.sleep(0.004 * random.randint(0, 4))
618
Vinay Sajipc94871a2012-04-25 10:51:35 +0100619 del_count = 500
620 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100621
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000622 self.handle_time = None
623 self.deletion_time = None
624
Vinay Sajipa5798de2012-04-24 23:33:33 +0100625 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100626 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
627 os.close(fd)
628 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
629 remover.daemon = True
630 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100631 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100632 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
633 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100634 try:
635 for _ in range(log_count):
636 time.sleep(0.005)
637 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000638 try:
639 self.handle_time = time.time()
640 h.handle(r)
641 except Exception:
642 print('Deleted at %s, '
643 'opened at %s' % (self.deletion_time,
644 self.handle_time))
645 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100646 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100647 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100648 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100649 if os.path.exists(fn):
650 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100651
652
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100653class BadStream(object):
654 def write(self, data):
655 raise RuntimeError('deliberate mistake')
656
657class TestStreamHandler(logging.StreamHandler):
658 def handleError(self, record):
659 self.error_record = record
660
661class StreamHandlerTest(BaseTest):
662 def test_error_handling(self):
663 h = TestStreamHandler(BadStream())
664 r = logging.makeLogRecord({})
665 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100666
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100667 try:
668 h.handle(r)
669 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100670
Vinay Sajip985ef872011-04-26 19:34:04 +0100671 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100672 with support.captured_stderr() as stderr:
673 h.handle(r)
674 msg = '\nRuntimeError: deliberate mistake\n'
675 self.assertIn(msg, stderr.getvalue())
676
Vinay Sajip985ef872011-04-26 19:34:04 +0100677 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100678 with support.captured_stderr() as stderr:
679 h.handle(r)
680 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100681 finally:
682 logging.raiseExceptions = old_raise
683
Vinay Sajip7367d082011-05-02 13:17:27 +0100684# -- The following section could be moved into a server_helper.py module
685# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100686
Vinay Sajipce7c9782011-05-17 07:15:53 +0100687if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100688 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100689 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100690 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100691
Vinay Sajipce7c9782011-05-17 07:15:53 +0100692 :param addr: A (host, port) tuple which the server listens on.
693 You can specify a port value of zero: the server's
694 *port* attribute will hold the actual port number
695 used, which can be used in client connections.
696 :param handler: A callable which will be called to process
697 incoming messages. The handler will be passed
698 the client address tuple, who the message is from,
699 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100700 :param poll_interval: The interval, in seconds, used in the underlying
701 :func:`select` or :func:`poll` call by
702 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100703 :param sockmap: A dictionary which will be used to hold
704 :class:`asyncore.dispatcher` instances used by
705 :func:`asyncore.loop`. This avoids changing the
706 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100707 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100708
709 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400710 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
711 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100712 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100713 self._handler = handler
714 self._thread = None
715 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100716
Vinay Sajipce7c9782011-05-17 07:15:53 +0100717 def process_message(self, peer, mailfrom, rcpttos, data):
718 """
719 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100720
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 Typically, this will be a test case method.
722 :param peer: The client (host, port) tuple.
723 :param mailfrom: The address of the sender.
724 :param rcpttos: The addresses of the recipients.
725 :param data: The message.
726 """
727 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100728
Vinay Sajipce7c9782011-05-17 07:15:53 +0100729 def start(self):
730 """
731 Start the server running on a separate daemon thread.
732 """
733 self._thread = t = threading.Thread(target=self.serve_forever,
734 args=(self.poll_interval,))
735 t.setDaemon(True)
736 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100737
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 def serve_forever(self, poll_interval):
739 """
740 Run the :mod:`asyncore` loop until normal termination
741 conditions arise.
742 :param poll_interval: The interval, in seconds, used in the underlying
743 :func:`select` or :func:`poll` call by
744 :func:`asyncore.loop`.
745 """
746 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100747 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200748 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100749 # On FreeBSD 8, closing the server repeatably
750 # raises this error. We swallow it if the
751 # server has been closed.
752 if self.connected or self.accepting:
753 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100754
Vinay Sajipce7c9782011-05-17 07:15:53 +0100755 def stop(self, timeout=None):
756 """
757 Stop the thread by closing the server instance.
758 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100759
Vinay Sajipce7c9782011-05-17 07:15:53 +0100760 :param timeout: How long to wait for the server thread
761 to terminate.
762 """
763 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100764 self._thread.join(timeout)
765 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100766
Vinay Sajipce7c9782011-05-17 07:15:53 +0100767 class ControlMixin(object):
768 """
769 This mixin is used to start a server on a separate thread, and
770 shut it down programmatically. Request handling is simplified - instead
771 of needing to derive a suitable RequestHandler subclass, you just
772 provide a callable which will be passed each received request to be
773 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100774
Vinay Sajipce7c9782011-05-17 07:15:53 +0100775 :param handler: A handler callable which will be called with a
776 single parameter - the request - in order to
777 process the request. This handler is called on the
778 server thread, effectively meaning that requests are
779 processed serially. While not quite Web scale ;-),
780 this should be fine for testing applications.
781 :param poll_interval: The polling interval in seconds.
782 """
783 def __init__(self, handler, poll_interval):
784 self._thread = None
785 self.poll_interval = poll_interval
786 self._handler = handler
787 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100788
Vinay Sajipce7c9782011-05-17 07:15:53 +0100789 def start(self):
790 """
791 Create a daemon thread to run the server, and start it.
792 """
793 self._thread = t = threading.Thread(target=self.serve_forever,
794 args=(self.poll_interval,))
795 t.setDaemon(True)
796 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100797
Vinay Sajipce7c9782011-05-17 07:15:53 +0100798 def serve_forever(self, poll_interval):
799 """
800 Run the server. Set the ready flag before entering the
801 service loop.
802 """
803 self.ready.set()
804 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100805
Vinay Sajipce7c9782011-05-17 07:15:53 +0100806 def stop(self, timeout=None):
807 """
808 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100809
Vinay Sajipce7c9782011-05-17 07:15:53 +0100810 :param timeout: How long to wait for the server thread
811 to terminate.
812 """
813 self.shutdown()
814 if self._thread is not None:
815 self._thread.join(timeout)
816 self._thread = None
817 self.server_close()
818 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100819
Vinay Sajipce7c9782011-05-17 07:15:53 +0100820 class TestHTTPServer(ControlMixin, HTTPServer):
821 """
822 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100823
Vinay Sajipce7c9782011-05-17 07:15:53 +0100824 :param addr: A tuple with the IP address and port to listen on.
825 :param handler: A handler callable which will be called with a
826 single parameter - the request - in order to
827 process the request.
828 :param poll_interval: The polling interval in seconds.
829 :param log: Pass ``True`` to enable log messages.
830 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100831 def __init__(self, addr, handler, poll_interval=0.5,
832 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100833 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
834 def __getattr__(self, name, default=None):
835 if name.startswith('do_'):
836 return self.process_request
837 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100838
Vinay Sajipce7c9782011-05-17 07:15:53 +0100839 def process_request(self):
840 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100841
Vinay Sajipce7c9782011-05-17 07:15:53 +0100842 def log_message(self, format, *args):
843 if log:
844 super(DelegatingHTTPRequestHandler,
845 self).log_message(format, *args)
846 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
847 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100848 self.sslctx = sslctx
849
850 def get_request(self):
851 try:
852 sock, addr = self.socket.accept()
853 if self.sslctx:
854 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200855 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100856 # socket errors are silenced by the caller, print them here
857 sys.stderr.write("Got an error:\n%s\n" % e)
858 raise
859 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 class TestTCPServer(ControlMixin, ThreadingTCPServer):
862 """
863 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100864
Vinay Sajipce7c9782011-05-17 07:15:53 +0100865 :param addr: A tuple with the IP address and port to listen on.
866 :param handler: A handler callable which will be called with a single
867 parameter - the request - in order to process the request.
868 :param poll_interval: The polling interval in seconds.
869 :bind_and_activate: If True (the default), binds the server and starts it
870 listening. If False, you need to call
871 :meth:`server_bind` and :meth:`server_activate` at
872 some later time before calling :meth:`start`, so that
873 the server will set up the socket and listen on it.
874 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100875
Vinay Sajipce7c9782011-05-17 07:15:53 +0100876 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100877
Vinay Sajipce7c9782011-05-17 07:15:53 +0100878 def __init__(self, addr, handler, poll_interval=0.5,
879 bind_and_activate=True):
880 class DelegatingTCPRequestHandler(StreamRequestHandler):
881
882 def handle(self):
883 self.server._handler(self)
884 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
885 bind_and_activate)
886 ControlMixin.__init__(self, handler, poll_interval)
887
888 def server_bind(self):
889 super(TestTCPServer, self).server_bind()
890 self.port = self.socket.getsockname()[1]
891
892 class TestUDPServer(ControlMixin, ThreadingUDPServer):
893 """
894 A UDP server which is controllable using :class:`ControlMixin`.
895
896 :param addr: A tuple with the IP address and port to listen on.
897 :param handler: A handler callable which will be called with a
898 single parameter - the request - in order to
899 process the request.
900 :param poll_interval: The polling interval for shutdown requests,
901 in seconds.
902 :bind_and_activate: If True (the default), binds the server and
903 starts it listening. If False, you need to
904 call :meth:`server_bind` and
905 :meth:`server_activate` at some later time
906 before calling :meth:`start`, so that the server will
907 set up the socket and listen on it.
908 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100909 def __init__(self, addr, handler, poll_interval=0.5,
910 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100911 class DelegatingUDPRequestHandler(DatagramRequestHandler):
912
913 def handle(self):
914 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100915
916 def finish(self):
917 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100918 if data:
919 try:
920 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200921 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100922 if not self.server._closed:
923 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100924
Vinay Sajip3ef12292011-05-23 23:00:42 +0100925 ThreadingUDPServer.__init__(self, addr,
926 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100927 bind_and_activate)
928 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100929 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100930
931 def server_bind(self):
932 super(TestUDPServer, self).server_bind()
933 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100934
Vinay Sajipba980db2011-05-23 21:37:54 +0100935 def server_close(self):
936 super(TestUDPServer, self).server_close()
937 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100938
Victor Stinnerec5a8602014-06-02 14:41:51 +0200939 if hasattr(socket, "AF_UNIX"):
940 class TestUnixStreamServer(TestTCPServer):
941 address_family = socket.AF_UNIX
942
943 class TestUnixDatagramServer(TestUDPServer):
944 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100945
Vinay Sajip7367d082011-05-02 13:17:27 +0100946# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100947
Vinay Sajipce7c9782011-05-17 07:15:53 +0100948@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100949class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000950 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100951 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100952 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800953 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100954 sockmap)
955 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800956 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000957 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
958 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100959 self.assertEqual(h.toaddrs, ['you'])
960 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100961 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100962 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100963 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000964 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100965 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000966 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100967 self.assertEqual(len(self.messages), 1)
968 peer, mailfrom, rcpttos, data = self.messages[0]
969 self.assertEqual(mailfrom, 'me')
970 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100971 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100972 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100973 h.close()
974
975 def process_message(self, *args):
976 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100977 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100978
Christian Heimes180510d2008-03-03 19:15:45 +0000979class MemoryHandlerTest(BaseTest):
980
981 """Tests for the MemoryHandler."""
982
983 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300984 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000985
986 def setUp(self):
987 BaseTest.setUp(self)
988 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100989 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +0000990 self.mem_logger = logging.getLogger('mem')
991 self.mem_logger.propagate = 0
992 self.mem_logger.addHandler(self.mem_hdlr)
993
994 def tearDown(self):
995 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000996 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000997
998 def test_flush(self):
999 # The memory handler flushes to its target handler based on specific
1000 # criteria (message count and message level).
1001 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001002 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001003 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001004 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001005 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001006 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001007 lines = [
1008 ('DEBUG', '1'),
1009 ('INFO', '2'),
1010 ('WARNING', '3'),
1011 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001012 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001013 for n in (4, 14):
1014 for i in range(9):
1015 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001016 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001017 # This will flush because it's the 10th message since the last
1018 # flush.
1019 self.mem_logger.debug(self.next_message())
1020 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001021 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001022
1023 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001024 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001025
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001026 def test_flush_on_close(self):
1027 """
1028 Test that the flush-on-close configuration works as expected.
1029 """
1030 self.mem_logger.debug(self.next_message())
1031 self.assert_log_lines([])
1032 self.mem_logger.info(self.next_message())
1033 self.assert_log_lines([])
1034 self.mem_logger.removeHandler(self.mem_hdlr)
1035 # Default behaviour is to flush on close. Check that it happens.
1036 self.mem_hdlr.close()
1037 lines = [
1038 ('DEBUG', '1'),
1039 ('INFO', '2'),
1040 ]
1041 self.assert_log_lines(lines)
1042 # Now configure for flushing not to be done on close.
1043 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1044 self.root_hdlr,
1045 False)
1046 self.mem_logger.addHandler(self.mem_hdlr)
1047 self.mem_logger.debug(self.next_message())
1048 self.assert_log_lines(lines) # no change
1049 self.mem_logger.info(self.next_message())
1050 self.assert_log_lines(lines) # no change
1051 self.mem_logger.removeHandler(self.mem_hdlr)
1052 self.mem_hdlr.close()
1053 # assert that no new lines have been added
1054 self.assert_log_lines(lines) # no change
1055
Christian Heimes180510d2008-03-03 19:15:45 +00001056
1057class ExceptionFormatter(logging.Formatter):
1058 """A special exception formatter."""
1059 def formatException(self, ei):
1060 return "Got a [%s]" % ei[0].__name__
1061
1062
1063class ConfigFileTest(BaseTest):
1064
1065 """Reading logging config from a .ini-style config file."""
1066
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001067 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001068
1069 # config0 is a standard configuration.
1070 config0 = """
1071 [loggers]
1072 keys=root
1073
1074 [handlers]
1075 keys=hand1
1076
1077 [formatters]
1078 keys=form1
1079
1080 [logger_root]
1081 level=WARNING
1082 handlers=hand1
1083
1084 [handler_hand1]
1085 class=StreamHandler
1086 level=NOTSET
1087 formatter=form1
1088 args=(sys.stdout,)
1089
1090 [formatter_form1]
1091 format=%(levelname)s ++ %(message)s
1092 datefmt=
1093 """
1094
1095 # config1 adds a little to the standard configuration.
1096 config1 = """
1097 [loggers]
1098 keys=root,parser
1099
1100 [handlers]
1101 keys=hand1
1102
1103 [formatters]
1104 keys=form1
1105
1106 [logger_root]
1107 level=WARNING
1108 handlers=
1109
1110 [logger_parser]
1111 level=DEBUG
1112 handlers=hand1
1113 propagate=1
1114 qualname=compiler.parser
1115
1116 [handler_hand1]
1117 class=StreamHandler
1118 level=NOTSET
1119 formatter=form1
1120 args=(sys.stdout,)
1121
1122 [formatter_form1]
1123 format=%(levelname)s ++ %(message)s
1124 datefmt=
1125 """
1126
Vinay Sajip3f84b072011-03-07 17:49:33 +00001127 # config1a moves the handler to the root.
1128 config1a = """
1129 [loggers]
1130 keys=root,parser
1131
1132 [handlers]
1133 keys=hand1
1134
1135 [formatters]
1136 keys=form1
1137
1138 [logger_root]
1139 level=WARNING
1140 handlers=hand1
1141
1142 [logger_parser]
1143 level=DEBUG
1144 handlers=
1145 propagate=1
1146 qualname=compiler.parser
1147
1148 [handler_hand1]
1149 class=StreamHandler
1150 level=NOTSET
1151 formatter=form1
1152 args=(sys.stdout,)
1153
1154 [formatter_form1]
1155 format=%(levelname)s ++ %(message)s
1156 datefmt=
1157 """
1158
Christian Heimes180510d2008-03-03 19:15:45 +00001159 # config2 has a subtle configuration error that should be reported
1160 config2 = config1.replace("sys.stdout", "sys.stbout")
1161
1162 # config3 has a less subtle configuration error
1163 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1164
1165 # config4 specifies a custom formatter class to be loaded
1166 config4 = """
1167 [loggers]
1168 keys=root
1169
1170 [handlers]
1171 keys=hand1
1172
1173 [formatters]
1174 keys=form1
1175
1176 [logger_root]
1177 level=NOTSET
1178 handlers=hand1
1179
1180 [handler_hand1]
1181 class=StreamHandler
1182 level=NOTSET
1183 formatter=form1
1184 args=(sys.stdout,)
1185
1186 [formatter_form1]
1187 class=""" + __name__ + """.ExceptionFormatter
1188 format=%(levelname)s:%(name)s:%(message)s
1189 datefmt=
1190 """
1191
Georg Brandl3dbca812008-07-23 16:10:53 +00001192 # config5 specifies a custom handler class to be loaded
1193 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1194
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001195 # config6 uses ', ' delimiters in the handlers and formatters sections
1196 config6 = """
1197 [loggers]
1198 keys=root,parser
1199
1200 [handlers]
1201 keys=hand1, hand2
1202
1203 [formatters]
1204 keys=form1, form2
1205
1206 [logger_root]
1207 level=WARNING
1208 handlers=
1209
1210 [logger_parser]
1211 level=DEBUG
1212 handlers=hand1
1213 propagate=1
1214 qualname=compiler.parser
1215
1216 [handler_hand1]
1217 class=StreamHandler
1218 level=NOTSET
1219 formatter=form1
1220 args=(sys.stdout,)
1221
1222 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001223 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001224 level=NOTSET
1225 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001226 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001227
1228 [formatter_form1]
1229 format=%(levelname)s ++ %(message)s
1230 datefmt=
1231
1232 [formatter_form2]
1233 format=%(message)s
1234 datefmt=
1235 """
1236
Vinay Sajip3f84b072011-03-07 17:49:33 +00001237 # config7 adds a compiler logger.
1238 config7 = """
1239 [loggers]
1240 keys=root,parser,compiler
1241
1242 [handlers]
1243 keys=hand1
1244
1245 [formatters]
1246 keys=form1
1247
1248 [logger_root]
1249 level=WARNING
1250 handlers=hand1
1251
1252 [logger_compiler]
1253 level=DEBUG
1254 handlers=
1255 propagate=1
1256 qualname=compiler
1257
1258 [logger_parser]
1259 level=DEBUG
1260 handlers=
1261 propagate=1
1262 qualname=compiler.parser
1263
1264 [handler_hand1]
1265 class=StreamHandler
1266 level=NOTSET
1267 formatter=form1
1268 args=(sys.stdout,)
1269
1270 [formatter_form1]
1271 format=%(levelname)s ++ %(message)s
1272 datefmt=
1273 """
1274
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001275 disable_test = """
1276 [loggers]
1277 keys=root
1278
1279 [handlers]
1280 keys=screen
1281
1282 [formatters]
1283 keys=
1284
1285 [logger_root]
1286 level=DEBUG
1287 handlers=screen
1288
1289 [handler_screen]
1290 level=DEBUG
1291 class=StreamHandler
1292 args=(sys.stdout,)
1293 formatter=
1294 """
1295
1296 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001297 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001298 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001299
1300 def test_config0_ok(self):
1301 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001302 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001303 self.apply_config(self.config0)
1304 logger = logging.getLogger()
1305 # Won't output anything
1306 logger.info(self.next_message())
1307 # Outputs a message
1308 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001309 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001310 ('ERROR', '2'),
1311 ], stream=output)
1312 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001313 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001314
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001315 def test_config0_using_cp_ok(self):
1316 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001317 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001318 file = io.StringIO(textwrap.dedent(self.config0))
1319 cp = configparser.ConfigParser()
1320 cp.read_file(file)
1321 logging.config.fileConfig(cp)
1322 logger = logging.getLogger()
1323 # Won't output anything
1324 logger.info(self.next_message())
1325 # Outputs a message
1326 logger.error(self.next_message())
1327 self.assert_log_lines([
1328 ('ERROR', '2'),
1329 ], stream=output)
1330 # Original logger output is empty.
1331 self.assert_log_lines([])
1332
Georg Brandl3dbca812008-07-23 16:10:53 +00001333 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001334 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001335 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001336 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001337 logger = logging.getLogger("compiler.parser")
1338 # Both will output a message
1339 logger.info(self.next_message())
1340 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001341 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001342 ('INFO', '1'),
1343 ('ERROR', '2'),
1344 ], stream=output)
1345 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001346 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001347
1348 def test_config2_failure(self):
1349 # A simple config file which overrides the default settings.
1350 self.assertRaises(Exception, self.apply_config, self.config2)
1351
1352 def test_config3_failure(self):
1353 # A simple config file which overrides the default settings.
1354 self.assertRaises(Exception, self.apply_config, self.config3)
1355
1356 def test_config4_ok(self):
1357 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001358 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001359 self.apply_config(self.config4)
1360 logger = logging.getLogger()
1361 try:
1362 raise RuntimeError()
1363 except RuntimeError:
1364 logging.exception("just testing")
1365 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001366 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001367 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1368 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001369 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001370
Georg Brandl3dbca812008-07-23 16:10:53 +00001371 def test_config5_ok(self):
1372 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001373
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001374 def test_config6_ok(self):
1375 self.test_config1_ok(config=self.config6)
1376
Vinay Sajip3f84b072011-03-07 17:49:33 +00001377 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001378 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001379 self.apply_config(self.config1a)
1380 logger = logging.getLogger("compiler.parser")
1381 # See issue #11424. compiler-hyphenated sorts
1382 # between compiler and compiler.xyz and this
1383 # was preventing compiler.xyz from being included
1384 # in the child loggers of compiler because of an
1385 # overzealous loop termination condition.
1386 hyphenated = logging.getLogger('compiler-hyphenated')
1387 # All will output a message
1388 logger.info(self.next_message())
1389 logger.error(self.next_message())
1390 hyphenated.critical(self.next_message())
1391 self.assert_log_lines([
1392 ('INFO', '1'),
1393 ('ERROR', '2'),
1394 ('CRITICAL', '3'),
1395 ], stream=output)
1396 # Original logger output is empty.
1397 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001398 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001399 self.apply_config(self.config7)
1400 logger = logging.getLogger("compiler.parser")
1401 self.assertFalse(logger.disabled)
1402 # Both will output a message
1403 logger.info(self.next_message())
1404 logger.error(self.next_message())
1405 logger = logging.getLogger("compiler.lexer")
1406 # Both will output a message
1407 logger.info(self.next_message())
1408 logger.error(self.next_message())
1409 # Will not appear
1410 hyphenated.critical(self.next_message())
1411 self.assert_log_lines([
1412 ('INFO', '4'),
1413 ('ERROR', '5'),
1414 ('INFO', '6'),
1415 ('ERROR', '7'),
1416 ], stream=output)
1417 # Original logger output is empty.
1418 self.assert_log_lines([])
1419
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001420 def test_logger_disabling(self):
1421 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001422 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001423 self.assertFalse(logger.disabled)
1424 self.apply_config(self.disable_test)
1425 self.assertTrue(logger.disabled)
1426 self.apply_config(self.disable_test, disable_existing_loggers=False)
1427 self.assertFalse(logger.disabled)
1428
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001429
Victor Stinner45df8202010-04-28 22:31:17 +00001430@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001431class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001432
Christian Heimes180510d2008-03-03 19:15:45 +00001433 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001434
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001435 if threading:
1436 server_class = TestTCPServer
1437 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001438
Christian Heimes180510d2008-03-03 19:15:45 +00001439 def setUp(self):
1440 """Set up a TCP server to receive log messages, and a SocketHandler
1441 pointing to that server's address and port."""
1442 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001443 self.server = server = self.server_class(self.address,
1444 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001445 server.start()
1446 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001447 hcls = logging.handlers.SocketHandler
1448 if isinstance(server.server_address, tuple):
1449 self.sock_hdlr = hcls('localhost', server.port)
1450 else:
1451 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001452 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001453 self.root_logger.removeHandler(self.root_logger.handlers[0])
1454 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001455 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001456
Christian Heimes180510d2008-03-03 19:15:45 +00001457 def tearDown(self):
1458 """Shutdown the TCP server."""
1459 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001460 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001461 self.root_logger.removeHandler(self.sock_hdlr)
1462 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001463 finally:
1464 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001465
Vinay Sajip7367d082011-05-02 13:17:27 +01001466 def handle_socket(self, request):
1467 conn = request.connection
1468 while True:
1469 chunk = conn.recv(4)
1470 if len(chunk) < 4:
1471 break
1472 slen = struct.unpack(">L", chunk)[0]
1473 chunk = conn.recv(slen)
1474 while len(chunk) < slen:
1475 chunk = chunk + conn.recv(slen - len(chunk))
1476 obj = pickle.loads(chunk)
1477 record = logging.makeLogRecord(obj)
1478 self.log_output += record.msg + '\n'
1479 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001480
Christian Heimes180510d2008-03-03 19:15:45 +00001481 def test_output(self):
1482 # The log message sent to the SocketHandler is properly received.
1483 logger = logging.getLogger("tcp")
1484 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001485 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001486 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001487 self.handled.acquire()
1488 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001489
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001490 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001491 # Avoid timing-related failures due to SocketHandler's own hard-wired
1492 # one-second timeout on socket.create_connection() (issue #16264).
1493 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001494 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001495 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001496 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001497 try:
1498 raise RuntimeError('Deliberate mistake')
1499 except RuntimeError:
1500 self.root_logger.exception('Never sent')
1501 self.root_logger.error('Never sent, either')
1502 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001503 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001504 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1505 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001506
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001507def _get_temp_domain_socket():
1508 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1509 os.close(fd)
1510 # just need a name - file can't be present, or we'll get an
1511 # 'address already in use' error.
1512 os.remove(fn)
1513 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001514
Victor Stinnerec5a8602014-06-02 14:41:51 +02001515@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001516@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001517class UnixSocketHandlerTest(SocketHandlerTest):
1518
1519 """Test for SocketHandler with unix sockets."""
1520
Victor Stinnerec5a8602014-06-02 14:41:51 +02001521 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001522 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001523
1524 def setUp(self):
1525 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001526 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001527 SocketHandlerTest.setUp(self)
1528
1529 def tearDown(self):
1530 SocketHandlerTest.tearDown(self)
1531 os.remove(self.address)
1532
1533@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001534class DatagramHandlerTest(BaseTest):
1535
1536 """Test for DatagramHandler."""
1537
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001538 if threading:
1539 server_class = TestUDPServer
1540 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001541
Vinay Sajip7367d082011-05-02 13:17:27 +01001542 def setUp(self):
1543 """Set up a UDP server to receive log messages, and a DatagramHandler
1544 pointing to that server's address and port."""
1545 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001546 self.server = server = self.server_class(self.address,
1547 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001548 server.start()
1549 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001550 hcls = logging.handlers.DatagramHandler
1551 if isinstance(server.server_address, tuple):
1552 self.sock_hdlr = hcls('localhost', server.port)
1553 else:
1554 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001555 self.log_output = ''
1556 self.root_logger.removeHandler(self.root_logger.handlers[0])
1557 self.root_logger.addHandler(self.sock_hdlr)
1558 self.handled = threading.Event()
1559
1560 def tearDown(self):
1561 """Shutdown the UDP server."""
1562 try:
1563 self.server.stop(2.0)
1564 self.root_logger.removeHandler(self.sock_hdlr)
1565 self.sock_hdlr.close()
1566 finally:
1567 BaseTest.tearDown(self)
1568
1569 def handle_datagram(self, request):
1570 slen = struct.pack('>L', 0) # length of prefix
1571 packet = request.packet[len(slen):]
1572 obj = pickle.loads(packet)
1573 record = logging.makeLogRecord(obj)
1574 self.log_output += record.msg + '\n'
1575 self.handled.set()
1576
1577 def test_output(self):
1578 # The log message sent to the DatagramHandler is properly received.
1579 logger = logging.getLogger("udp")
1580 logger.error("spam")
1581 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001582 self.handled.clear()
1583 logger.error("eggs")
1584 self.handled.wait()
1585 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001586
Victor Stinnerec5a8602014-06-02 14:41:51 +02001587@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001588@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001589class UnixDatagramHandlerTest(DatagramHandlerTest):
1590
1591 """Test for DatagramHandler using Unix sockets."""
1592
Victor Stinnerec5a8602014-06-02 14:41:51 +02001593 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001594 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001595
1596 def setUp(self):
1597 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001598 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001599 DatagramHandlerTest.setUp(self)
1600
1601 def tearDown(self):
1602 DatagramHandlerTest.tearDown(self)
1603 os.remove(self.address)
1604
1605@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001606class SysLogHandlerTest(BaseTest):
1607
1608 """Test for SysLogHandler using UDP."""
1609
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001610 if threading:
1611 server_class = TestUDPServer
1612 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001613
Vinay Sajip7367d082011-05-02 13:17:27 +01001614 def setUp(self):
1615 """Set up a UDP server to receive log messages, and a SysLogHandler
1616 pointing to that server's address and port."""
1617 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001618 self.server = server = self.server_class(self.address,
1619 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001620 server.start()
1621 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001622 hcls = logging.handlers.SysLogHandler
1623 if isinstance(server.server_address, tuple):
1624 self.sl_hdlr = hcls(('localhost', server.port))
1625 else:
1626 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001627 self.log_output = ''
1628 self.root_logger.removeHandler(self.root_logger.handlers[0])
1629 self.root_logger.addHandler(self.sl_hdlr)
1630 self.handled = threading.Event()
1631
1632 def tearDown(self):
1633 """Shutdown the UDP server."""
1634 try:
1635 self.server.stop(2.0)
1636 self.root_logger.removeHandler(self.sl_hdlr)
1637 self.sl_hdlr.close()
1638 finally:
1639 BaseTest.tearDown(self)
1640
1641 def handle_datagram(self, request):
1642 self.log_output = request.packet
1643 self.handled.set()
1644
1645 def test_output(self):
1646 # The log message sent to the SysLogHandler is properly received.
1647 logger = logging.getLogger("slh")
1648 logger.error("sp\xe4m")
1649 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001650 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001651 self.handled.clear()
1652 self.sl_hdlr.append_nul = False
1653 logger.error("sp\xe4m")
1654 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001655 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001656 self.handled.clear()
1657 self.sl_hdlr.ident = "h\xe4m-"
1658 logger.error("sp\xe4m")
1659 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001660 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001661
Victor Stinnerec5a8602014-06-02 14:41:51 +02001662@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001663@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001664class UnixSysLogHandlerTest(SysLogHandlerTest):
1665
1666 """Test for SysLogHandler with Unix sockets."""
1667
Victor Stinnerec5a8602014-06-02 14:41:51 +02001668 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001669 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001670
1671 def setUp(self):
1672 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001673 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001674 SysLogHandlerTest.setUp(self)
1675
1676 def tearDown(self):
1677 SysLogHandlerTest.tearDown(self)
1678 os.remove(self.address)
1679
Vinay Sajip5421f352013-09-27 18:18:28 +01001680@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001681class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001682 """Test for HTTPHandler."""
1683
1684 def setUp(self):
1685 """Set up an HTTP server to receive log messages, and a HTTPHandler
1686 pointing to that server's address and port."""
1687 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001688 self.handled = threading.Event()
1689
Vinay Sajip7367d082011-05-02 13:17:27 +01001690 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001691 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001692 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001693 if self.command == 'POST':
1694 try:
1695 rlen = int(request.headers['Content-Length'])
1696 self.post_data = request.rfile.read(rlen)
1697 except:
1698 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001699 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001700 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001701 self.handled.set()
1702
1703 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001704 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001705 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001706 root_logger = self.root_logger
1707 root_logger.removeHandler(self.root_logger.handlers[0])
1708 for secure in (False, True):
1709 addr = ('localhost', 0)
1710 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001711 try:
1712 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001713 except ImportError:
1714 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001715 else:
1716 here = os.path.dirname(__file__)
1717 localhost_cert = os.path.join(here, "keycert.pem")
1718 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1719 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001720
1721 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001722 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001723 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001724 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001725 self.server = server = TestHTTPServer(addr, self.handle_request,
1726 0.01, sslctx=sslctx)
1727 server.start()
1728 server.ready.wait()
1729 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001730 secure_client = secure and sslctx
1731 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001732 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001733 context=context,
1734 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001735 self.log_data = None
1736 root_logger.addHandler(self.h_hdlr)
1737
1738 for method in ('GET', 'POST'):
1739 self.h_hdlr.method = method
1740 self.handled.clear()
1741 msg = "sp\xe4m"
1742 logger.error(msg)
1743 self.handled.wait()
1744 self.assertEqual(self.log_data.path, '/frob')
1745 self.assertEqual(self.command, method)
1746 if method == 'GET':
1747 d = parse_qs(self.log_data.query)
1748 else:
1749 d = parse_qs(self.post_data.decode('utf-8'))
1750 self.assertEqual(d['name'], ['http'])
1751 self.assertEqual(d['funcName'], ['test_output'])
1752 self.assertEqual(d['msg'], [msg])
1753
1754 self.server.stop(2.0)
1755 self.root_logger.removeHandler(self.h_hdlr)
1756 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001757
Christian Heimes180510d2008-03-03 19:15:45 +00001758class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001759
Christian Heimes180510d2008-03-03 19:15:45 +00001760 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001761
Christian Heimes180510d2008-03-03 19:15:45 +00001762 def setUp(self):
1763 """Create a dict to remember potentially destroyed objects."""
1764 BaseTest.setUp(self)
1765 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001766
Christian Heimes180510d2008-03-03 19:15:45 +00001767 def _watch_for_survival(self, *args):
1768 """Watch the given objects for survival, by creating weakrefs to
1769 them."""
1770 for obj in args:
1771 key = id(obj), repr(obj)
1772 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001773
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001774 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001775 """Assert that all objects watched for survival have survived."""
1776 # Trigger cycle breaking.
1777 gc.collect()
1778 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001779 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001780 if ref() is None:
1781 dead.append(repr_)
1782 if dead:
1783 self.fail("%d objects should have survived "
1784 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001785
Christian Heimes180510d2008-03-03 19:15:45 +00001786 def test_persistent_loggers(self):
1787 # Logger objects are persistent and retain their configuration, even
1788 # if visible references are destroyed.
1789 self.root_logger.setLevel(logging.INFO)
1790 foo = logging.getLogger("foo")
1791 self._watch_for_survival(foo)
1792 foo.setLevel(logging.DEBUG)
1793 self.root_logger.debug(self.next_message())
1794 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001795 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001796 ('foo', 'DEBUG', '2'),
1797 ])
1798 del foo
1799 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001800 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001801 # foo has retained its settings.
1802 bar = logging.getLogger("foo")
1803 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001804 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001805 ('foo', 'DEBUG', '2'),
1806 ('foo', 'DEBUG', '3'),
1807 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001808
Benjamin Petersonf91df042009-02-13 02:50:59 +00001809
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001810class EncodingTest(BaseTest):
1811 def test_encoding_plain_file(self):
1812 # In Python 2.x, a plain file object is treated as having no encoding.
1813 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001814 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1815 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001816 # the non-ascii data we write to the log.
1817 data = "foo\x80"
1818 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001819 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001820 log.addHandler(handler)
1821 try:
1822 # write non-ascii data to the log.
1823 log.warning(data)
1824 finally:
1825 log.removeHandler(handler)
1826 handler.close()
1827 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001828 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001829 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001830 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001831 finally:
1832 f.close()
1833 finally:
1834 if os.path.isfile(fn):
1835 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001836
Benjamin Petersonf91df042009-02-13 02:50:59 +00001837 def test_encoding_cyrillic_unicode(self):
1838 log = logging.getLogger("test")
1839 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1840 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1841 #Ensure it's written in a Cyrillic encoding
1842 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001843 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001844 stream = io.BytesIO()
1845 writer = writer_class(stream, 'strict')
1846 handler = logging.StreamHandler(writer)
1847 log.addHandler(handler)
1848 try:
1849 log.warning(message)
1850 finally:
1851 log.removeHandler(handler)
1852 handler.close()
1853 # check we wrote exactly those bytes, ignoring trailing \n etc
1854 s = stream.getvalue()
1855 #Compare against what the data should be when encoded in CP-1251
1856 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1857
1858
Georg Brandlf9734072008-12-07 15:30:06 +00001859class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001860
Georg Brandlf9734072008-12-07 15:30:06 +00001861 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001862 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001863 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001864 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001865 warnings.filterwarnings("always", category=UserWarning)
1866 stream = io.StringIO()
1867 h = logging.StreamHandler(stream)
1868 logger = logging.getLogger("py.warnings")
1869 logger.addHandler(h)
1870 warnings.warn("I'm warning you...")
1871 logger.removeHandler(h)
1872 s = stream.getvalue()
1873 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001874 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001875
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001876 #See if an explicit file uses the original implementation
1877 a_file = io.StringIO()
1878 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1879 a_file, "Dummy line")
1880 s = a_file.getvalue()
1881 a_file.close()
1882 self.assertEqual(s,
1883 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1884
1885 def test_warnings_no_handlers(self):
1886 with warnings.catch_warnings():
1887 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001888 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001889
1890 # confirm our assumption: no loggers are set
1891 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001892 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001893
1894 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001895 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001896 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001897
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001898
1899def formatFunc(format, datefmt=None):
1900 return logging.Formatter(format, datefmt)
1901
1902def handlerFunc():
1903 return logging.StreamHandler()
1904
1905class CustomHandler(logging.StreamHandler):
1906 pass
1907
1908class ConfigDictTest(BaseTest):
1909
1910 """Reading logging config from a dictionary."""
1911
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001912 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001913
1914 # config0 is a standard configuration.
1915 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001916 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001917 'formatters': {
1918 'form1' : {
1919 'format' : '%(levelname)s ++ %(message)s',
1920 },
1921 },
1922 'handlers' : {
1923 'hand1' : {
1924 'class' : 'logging.StreamHandler',
1925 'formatter' : 'form1',
1926 'level' : 'NOTSET',
1927 'stream' : 'ext://sys.stdout',
1928 },
1929 },
1930 'root' : {
1931 'level' : 'WARNING',
1932 'handlers' : ['hand1'],
1933 },
1934 }
1935
1936 # config1 adds a little to the standard configuration.
1937 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001938 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001939 'formatters': {
1940 'form1' : {
1941 'format' : '%(levelname)s ++ %(message)s',
1942 },
1943 },
1944 'handlers' : {
1945 'hand1' : {
1946 'class' : 'logging.StreamHandler',
1947 'formatter' : 'form1',
1948 'level' : 'NOTSET',
1949 'stream' : 'ext://sys.stdout',
1950 },
1951 },
1952 'loggers' : {
1953 'compiler.parser' : {
1954 'level' : 'DEBUG',
1955 'handlers' : ['hand1'],
1956 },
1957 },
1958 'root' : {
1959 'level' : 'WARNING',
1960 },
1961 }
1962
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001963 # config1a moves the handler to the root. Used with config8a
1964 config1a = {
1965 'version': 1,
1966 'formatters': {
1967 'form1' : {
1968 'format' : '%(levelname)s ++ %(message)s',
1969 },
1970 },
1971 'handlers' : {
1972 'hand1' : {
1973 'class' : 'logging.StreamHandler',
1974 'formatter' : 'form1',
1975 'level' : 'NOTSET',
1976 'stream' : 'ext://sys.stdout',
1977 },
1978 },
1979 'loggers' : {
1980 'compiler.parser' : {
1981 'level' : 'DEBUG',
1982 },
1983 },
1984 'root' : {
1985 'level' : 'WARNING',
1986 'handlers' : ['hand1'],
1987 },
1988 }
1989
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001990 # config2 has a subtle configuration error that should be reported
1991 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001992 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001993 'formatters': {
1994 'form1' : {
1995 'format' : '%(levelname)s ++ %(message)s',
1996 },
1997 },
1998 'handlers' : {
1999 'hand1' : {
2000 'class' : 'logging.StreamHandler',
2001 'formatter' : 'form1',
2002 'level' : 'NOTSET',
2003 'stream' : 'ext://sys.stdbout',
2004 },
2005 },
2006 'loggers' : {
2007 'compiler.parser' : {
2008 'level' : 'DEBUG',
2009 'handlers' : ['hand1'],
2010 },
2011 },
2012 'root' : {
2013 'level' : 'WARNING',
2014 },
2015 }
2016
2017 #As config1 but with a misspelt level on a handler
2018 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002019 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002020 'formatters': {
2021 'form1' : {
2022 'format' : '%(levelname)s ++ %(message)s',
2023 },
2024 },
2025 'handlers' : {
2026 'hand1' : {
2027 'class' : 'logging.StreamHandler',
2028 'formatter' : 'form1',
2029 'level' : 'NTOSET',
2030 'stream' : 'ext://sys.stdout',
2031 },
2032 },
2033 'loggers' : {
2034 'compiler.parser' : {
2035 'level' : 'DEBUG',
2036 'handlers' : ['hand1'],
2037 },
2038 },
2039 'root' : {
2040 'level' : 'WARNING',
2041 },
2042 }
2043
2044
2045 #As config1 but with a misspelt level on a logger
2046 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002047 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002048 'formatters': {
2049 'form1' : {
2050 'format' : '%(levelname)s ++ %(message)s',
2051 },
2052 },
2053 'handlers' : {
2054 'hand1' : {
2055 'class' : 'logging.StreamHandler',
2056 'formatter' : 'form1',
2057 'level' : 'NOTSET',
2058 'stream' : 'ext://sys.stdout',
2059 },
2060 },
2061 'loggers' : {
2062 'compiler.parser' : {
2063 'level' : 'DEBUG',
2064 'handlers' : ['hand1'],
2065 },
2066 },
2067 'root' : {
2068 'level' : 'WRANING',
2069 },
2070 }
2071
2072 # config3 has a less subtle configuration error
2073 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002074 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002075 'formatters': {
2076 'form1' : {
2077 'format' : '%(levelname)s ++ %(message)s',
2078 },
2079 },
2080 'handlers' : {
2081 'hand1' : {
2082 'class' : 'logging.StreamHandler',
2083 'formatter' : 'misspelled_name',
2084 'level' : 'NOTSET',
2085 'stream' : 'ext://sys.stdout',
2086 },
2087 },
2088 'loggers' : {
2089 'compiler.parser' : {
2090 'level' : 'DEBUG',
2091 'handlers' : ['hand1'],
2092 },
2093 },
2094 'root' : {
2095 'level' : 'WARNING',
2096 },
2097 }
2098
2099 # config4 specifies a custom formatter class to be loaded
2100 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002101 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002102 'formatters': {
2103 'form1' : {
2104 '()' : __name__ + '.ExceptionFormatter',
2105 'format' : '%(levelname)s:%(name)s:%(message)s',
2106 },
2107 },
2108 'handlers' : {
2109 'hand1' : {
2110 'class' : 'logging.StreamHandler',
2111 'formatter' : 'form1',
2112 'level' : 'NOTSET',
2113 'stream' : 'ext://sys.stdout',
2114 },
2115 },
2116 'root' : {
2117 'level' : 'NOTSET',
2118 'handlers' : ['hand1'],
2119 },
2120 }
2121
2122 # As config4 but using an actual callable rather than a string
2123 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002124 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125 'formatters': {
2126 'form1' : {
2127 '()' : ExceptionFormatter,
2128 'format' : '%(levelname)s:%(name)s:%(message)s',
2129 },
2130 'form2' : {
2131 '()' : __name__ + '.formatFunc',
2132 'format' : '%(levelname)s:%(name)s:%(message)s',
2133 },
2134 'form3' : {
2135 '()' : formatFunc,
2136 'format' : '%(levelname)s:%(name)s:%(message)s',
2137 },
2138 },
2139 'handlers' : {
2140 'hand1' : {
2141 'class' : 'logging.StreamHandler',
2142 'formatter' : 'form1',
2143 'level' : 'NOTSET',
2144 'stream' : 'ext://sys.stdout',
2145 },
2146 'hand2' : {
2147 '()' : handlerFunc,
2148 },
2149 },
2150 'root' : {
2151 'level' : 'NOTSET',
2152 'handlers' : ['hand1'],
2153 },
2154 }
2155
2156 # config5 specifies a custom handler class to be loaded
2157 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002158 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002159 'formatters': {
2160 'form1' : {
2161 'format' : '%(levelname)s ++ %(message)s',
2162 },
2163 },
2164 'handlers' : {
2165 'hand1' : {
2166 'class' : __name__ + '.CustomHandler',
2167 'formatter' : 'form1',
2168 'level' : 'NOTSET',
2169 'stream' : 'ext://sys.stdout',
2170 },
2171 },
2172 'loggers' : {
2173 'compiler.parser' : {
2174 'level' : 'DEBUG',
2175 'handlers' : ['hand1'],
2176 },
2177 },
2178 'root' : {
2179 'level' : 'WARNING',
2180 },
2181 }
2182
2183 # config6 specifies a custom handler class to be loaded
2184 # but has bad arguments
2185 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002186 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002187 'formatters': {
2188 'form1' : {
2189 'format' : '%(levelname)s ++ %(message)s',
2190 },
2191 },
2192 'handlers' : {
2193 'hand1' : {
2194 'class' : __name__ + '.CustomHandler',
2195 'formatter' : 'form1',
2196 'level' : 'NOTSET',
2197 'stream' : 'ext://sys.stdout',
2198 '9' : 'invalid parameter name',
2199 },
2200 },
2201 'loggers' : {
2202 'compiler.parser' : {
2203 'level' : 'DEBUG',
2204 'handlers' : ['hand1'],
2205 },
2206 },
2207 'root' : {
2208 'level' : 'WARNING',
2209 },
2210 }
2211
2212 #config 7 does not define compiler.parser but defines compiler.lexer
2213 #so compiler.parser should be disabled after applying it
2214 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002215 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002216 'formatters': {
2217 'form1' : {
2218 'format' : '%(levelname)s ++ %(message)s',
2219 },
2220 },
2221 'handlers' : {
2222 'hand1' : {
2223 'class' : 'logging.StreamHandler',
2224 'formatter' : 'form1',
2225 'level' : 'NOTSET',
2226 'stream' : 'ext://sys.stdout',
2227 },
2228 },
2229 'loggers' : {
2230 'compiler.lexer' : {
2231 'level' : 'DEBUG',
2232 'handlers' : ['hand1'],
2233 },
2234 },
2235 'root' : {
2236 'level' : 'WARNING',
2237 },
2238 }
2239
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002240 # config8 defines both compiler and compiler.lexer
2241 # so compiler.parser should not be disabled (since
2242 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002243 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002244 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002245 'disable_existing_loggers' : False,
2246 'formatters': {
2247 'form1' : {
2248 'format' : '%(levelname)s ++ %(message)s',
2249 },
2250 },
2251 'handlers' : {
2252 'hand1' : {
2253 'class' : 'logging.StreamHandler',
2254 'formatter' : 'form1',
2255 'level' : 'NOTSET',
2256 'stream' : 'ext://sys.stdout',
2257 },
2258 },
2259 'loggers' : {
2260 'compiler' : {
2261 'level' : 'DEBUG',
2262 'handlers' : ['hand1'],
2263 },
2264 'compiler.lexer' : {
2265 },
2266 },
2267 'root' : {
2268 'level' : 'WARNING',
2269 },
2270 }
2271
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002272 # config8a disables existing loggers
2273 config8a = {
2274 'version': 1,
2275 'disable_existing_loggers' : True,
2276 'formatters': {
2277 'form1' : {
2278 'format' : '%(levelname)s ++ %(message)s',
2279 },
2280 },
2281 'handlers' : {
2282 'hand1' : {
2283 'class' : 'logging.StreamHandler',
2284 'formatter' : 'form1',
2285 'level' : 'NOTSET',
2286 'stream' : 'ext://sys.stdout',
2287 },
2288 },
2289 'loggers' : {
2290 'compiler' : {
2291 'level' : 'DEBUG',
2292 'handlers' : ['hand1'],
2293 },
2294 'compiler.lexer' : {
2295 },
2296 },
2297 'root' : {
2298 'level' : 'WARNING',
2299 },
2300 }
2301
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002302 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002303 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002304 'formatters': {
2305 'form1' : {
2306 'format' : '%(levelname)s ++ %(message)s',
2307 },
2308 },
2309 'handlers' : {
2310 'hand1' : {
2311 'class' : 'logging.StreamHandler',
2312 'formatter' : 'form1',
2313 'level' : 'WARNING',
2314 'stream' : 'ext://sys.stdout',
2315 },
2316 },
2317 'loggers' : {
2318 'compiler.parser' : {
2319 'level' : 'WARNING',
2320 'handlers' : ['hand1'],
2321 },
2322 },
2323 'root' : {
2324 'level' : 'NOTSET',
2325 },
2326 }
2327
2328 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002329 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002330 'incremental' : True,
2331 'handlers' : {
2332 'hand1' : {
2333 'level' : 'WARNING',
2334 },
2335 },
2336 'loggers' : {
2337 'compiler.parser' : {
2338 'level' : 'INFO',
2339 },
2340 },
2341 }
2342
2343 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002344 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002345 'incremental' : True,
2346 'handlers' : {
2347 'hand1' : {
2348 'level' : 'INFO',
2349 },
2350 },
2351 'loggers' : {
2352 'compiler.parser' : {
2353 'level' : 'INFO',
2354 },
2355 },
2356 }
2357
2358 #As config1 but with a filter added
2359 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002360 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002361 'formatters': {
2362 'form1' : {
2363 'format' : '%(levelname)s ++ %(message)s',
2364 },
2365 },
2366 'filters' : {
2367 'filt1' : {
2368 'name' : 'compiler.parser',
2369 },
2370 },
2371 'handlers' : {
2372 'hand1' : {
2373 'class' : 'logging.StreamHandler',
2374 'formatter' : 'form1',
2375 'level' : 'NOTSET',
2376 'stream' : 'ext://sys.stdout',
2377 'filters' : ['filt1'],
2378 },
2379 },
2380 'loggers' : {
2381 'compiler.parser' : {
2382 'level' : 'DEBUG',
2383 'filters' : ['filt1'],
2384 },
2385 },
2386 'root' : {
2387 'level' : 'WARNING',
2388 'handlers' : ['hand1'],
2389 },
2390 }
2391
2392 #As config1 but using cfg:// references
2393 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002394 'version': 1,
2395 'true_formatters': {
2396 'form1' : {
2397 'format' : '%(levelname)s ++ %(message)s',
2398 },
2399 },
2400 'handler_configs': {
2401 'hand1' : {
2402 'class' : 'logging.StreamHandler',
2403 'formatter' : 'form1',
2404 'level' : 'NOTSET',
2405 'stream' : 'ext://sys.stdout',
2406 },
2407 },
2408 'formatters' : 'cfg://true_formatters',
2409 'handlers' : {
2410 'hand1' : 'cfg://handler_configs[hand1]',
2411 },
2412 'loggers' : {
2413 'compiler.parser' : {
2414 'level' : 'DEBUG',
2415 'handlers' : ['hand1'],
2416 },
2417 },
2418 'root' : {
2419 'level' : 'WARNING',
2420 },
2421 }
2422
2423 #As config11 but missing the version key
2424 config12 = {
2425 'true_formatters': {
2426 'form1' : {
2427 'format' : '%(levelname)s ++ %(message)s',
2428 },
2429 },
2430 'handler_configs': {
2431 'hand1' : {
2432 'class' : 'logging.StreamHandler',
2433 'formatter' : 'form1',
2434 'level' : 'NOTSET',
2435 'stream' : 'ext://sys.stdout',
2436 },
2437 },
2438 'formatters' : 'cfg://true_formatters',
2439 'handlers' : {
2440 'hand1' : 'cfg://handler_configs[hand1]',
2441 },
2442 'loggers' : {
2443 'compiler.parser' : {
2444 'level' : 'DEBUG',
2445 'handlers' : ['hand1'],
2446 },
2447 },
2448 'root' : {
2449 'level' : 'WARNING',
2450 },
2451 }
2452
2453 #As config11 but using an unsupported version
2454 config13 = {
2455 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002456 'true_formatters': {
2457 'form1' : {
2458 'format' : '%(levelname)s ++ %(message)s',
2459 },
2460 },
2461 'handler_configs': {
2462 'hand1' : {
2463 'class' : 'logging.StreamHandler',
2464 'formatter' : 'form1',
2465 'level' : 'NOTSET',
2466 'stream' : 'ext://sys.stdout',
2467 },
2468 },
2469 'formatters' : 'cfg://true_formatters',
2470 'handlers' : {
2471 'hand1' : 'cfg://handler_configs[hand1]',
2472 },
2473 'loggers' : {
2474 'compiler.parser' : {
2475 'level' : 'DEBUG',
2476 'handlers' : ['hand1'],
2477 },
2478 },
2479 'root' : {
2480 'level' : 'WARNING',
2481 },
2482 }
2483
Vinay Sajip8d270232012-11-15 14:20:18 +00002484 # As config0, but with properties
2485 config14 = {
2486 'version': 1,
2487 'formatters': {
2488 'form1' : {
2489 'format' : '%(levelname)s ++ %(message)s',
2490 },
2491 },
2492 'handlers' : {
2493 'hand1' : {
2494 'class' : 'logging.StreamHandler',
2495 'formatter' : 'form1',
2496 'level' : 'NOTSET',
2497 'stream' : 'ext://sys.stdout',
2498 '.': {
2499 'foo': 'bar',
2500 'terminator': '!\n',
2501 }
2502 },
2503 },
2504 'root' : {
2505 'level' : 'WARNING',
2506 'handlers' : ['hand1'],
2507 },
2508 }
2509
Vinay Sajip3f885b52013-03-22 15:19:54 +00002510 out_of_order = {
2511 "version": 1,
2512 "formatters": {
2513 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002514 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2515 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002516 }
2517 },
2518 "handlers": {
2519 "fileGlobal": {
2520 "class": "logging.StreamHandler",
2521 "level": "DEBUG",
2522 "formatter": "mySimpleFormatter"
2523 },
2524 "bufferGlobal": {
2525 "class": "logging.handlers.MemoryHandler",
2526 "capacity": 5,
2527 "formatter": "mySimpleFormatter",
2528 "target": "fileGlobal",
2529 "level": "DEBUG"
2530 }
2531 },
2532 "loggers": {
2533 "mymodule": {
2534 "level": "DEBUG",
2535 "handlers": ["bufferGlobal"],
2536 "propagate": "true"
2537 }
2538 }
2539 }
2540
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002541 def apply_config(self, conf):
2542 logging.config.dictConfig(conf)
2543
2544 def test_config0_ok(self):
2545 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002546 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002547 self.apply_config(self.config0)
2548 logger = logging.getLogger()
2549 # Won't output anything
2550 logger.info(self.next_message())
2551 # Outputs a message
2552 logger.error(self.next_message())
2553 self.assert_log_lines([
2554 ('ERROR', '2'),
2555 ], stream=output)
2556 # Original logger output is empty.
2557 self.assert_log_lines([])
2558
2559 def test_config1_ok(self, config=config1):
2560 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002561 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002562 self.apply_config(config)
2563 logger = logging.getLogger("compiler.parser")
2564 # Both will output a message
2565 logger.info(self.next_message())
2566 logger.error(self.next_message())
2567 self.assert_log_lines([
2568 ('INFO', '1'),
2569 ('ERROR', '2'),
2570 ], stream=output)
2571 # Original logger output is empty.
2572 self.assert_log_lines([])
2573
2574 def test_config2_failure(self):
2575 # A simple config which overrides the default settings.
2576 self.assertRaises(Exception, self.apply_config, self.config2)
2577
2578 def test_config2a_failure(self):
2579 # A simple config which overrides the default settings.
2580 self.assertRaises(Exception, self.apply_config, self.config2a)
2581
2582 def test_config2b_failure(self):
2583 # A simple config which overrides the default settings.
2584 self.assertRaises(Exception, self.apply_config, self.config2b)
2585
2586 def test_config3_failure(self):
2587 # A simple config which overrides the default settings.
2588 self.assertRaises(Exception, self.apply_config, self.config3)
2589
2590 def test_config4_ok(self):
2591 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002592 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002593 self.apply_config(self.config4)
2594 #logger = logging.getLogger()
2595 try:
2596 raise RuntimeError()
2597 except RuntimeError:
2598 logging.exception("just testing")
2599 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002600 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002601 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2602 # Original logger output is empty
2603 self.assert_log_lines([])
2604
2605 def test_config4a_ok(self):
2606 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002607 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002608 self.apply_config(self.config4a)
2609 #logger = logging.getLogger()
2610 try:
2611 raise RuntimeError()
2612 except RuntimeError:
2613 logging.exception("just testing")
2614 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002615 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002616 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2617 # Original logger output is empty
2618 self.assert_log_lines([])
2619
2620 def test_config5_ok(self):
2621 self.test_config1_ok(config=self.config5)
2622
2623 def test_config6_failure(self):
2624 self.assertRaises(Exception, self.apply_config, self.config6)
2625
2626 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002627 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002628 self.apply_config(self.config1)
2629 logger = logging.getLogger("compiler.parser")
2630 # Both will output a message
2631 logger.info(self.next_message())
2632 logger.error(self.next_message())
2633 self.assert_log_lines([
2634 ('INFO', '1'),
2635 ('ERROR', '2'),
2636 ], stream=output)
2637 # Original logger output is empty.
2638 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002639 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002640 self.apply_config(self.config7)
2641 logger = logging.getLogger("compiler.parser")
2642 self.assertTrue(logger.disabled)
2643 logger = logging.getLogger("compiler.lexer")
2644 # Both will output a message
2645 logger.info(self.next_message())
2646 logger.error(self.next_message())
2647 self.assert_log_lines([
2648 ('INFO', '3'),
2649 ('ERROR', '4'),
2650 ], stream=output)
2651 # Original logger output is empty.
2652 self.assert_log_lines([])
2653
2654 #Same as test_config_7_ok but don't disable old loggers.
2655 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002656 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002657 self.apply_config(self.config1)
2658 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002659 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002660 logger.info(self.next_message())
2661 logger.error(self.next_message())
2662 self.assert_log_lines([
2663 ('INFO', '1'),
2664 ('ERROR', '2'),
2665 ], stream=output)
2666 # Original logger output is empty.
2667 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002668 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002669 self.apply_config(self.config8)
2670 logger = logging.getLogger("compiler.parser")
2671 self.assertFalse(logger.disabled)
2672 # Both will output a message
2673 logger.info(self.next_message())
2674 logger.error(self.next_message())
2675 logger = logging.getLogger("compiler.lexer")
2676 # Both will output a message
2677 logger.info(self.next_message())
2678 logger.error(self.next_message())
2679 self.assert_log_lines([
2680 ('INFO', '3'),
2681 ('ERROR', '4'),
2682 ('INFO', '5'),
2683 ('ERROR', '6'),
2684 ], stream=output)
2685 # Original logger output is empty.
2686 self.assert_log_lines([])
2687
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002688 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002689 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002690 self.apply_config(self.config1a)
2691 logger = logging.getLogger("compiler.parser")
2692 # See issue #11424. compiler-hyphenated sorts
2693 # between compiler and compiler.xyz and this
2694 # was preventing compiler.xyz from being included
2695 # in the child loggers of compiler because of an
2696 # overzealous loop termination condition.
2697 hyphenated = logging.getLogger('compiler-hyphenated')
2698 # All will output a message
2699 logger.info(self.next_message())
2700 logger.error(self.next_message())
2701 hyphenated.critical(self.next_message())
2702 self.assert_log_lines([
2703 ('INFO', '1'),
2704 ('ERROR', '2'),
2705 ('CRITICAL', '3'),
2706 ], stream=output)
2707 # Original logger output is empty.
2708 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002709 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002710 self.apply_config(self.config8a)
2711 logger = logging.getLogger("compiler.parser")
2712 self.assertFalse(logger.disabled)
2713 # Both will output a message
2714 logger.info(self.next_message())
2715 logger.error(self.next_message())
2716 logger = logging.getLogger("compiler.lexer")
2717 # Both will output a message
2718 logger.info(self.next_message())
2719 logger.error(self.next_message())
2720 # Will not appear
2721 hyphenated.critical(self.next_message())
2722 self.assert_log_lines([
2723 ('INFO', '4'),
2724 ('ERROR', '5'),
2725 ('INFO', '6'),
2726 ('ERROR', '7'),
2727 ], stream=output)
2728 # Original logger output is empty.
2729 self.assert_log_lines([])
2730
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002731 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002732 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002733 self.apply_config(self.config9)
2734 logger = logging.getLogger("compiler.parser")
2735 #Nothing will be output since both handler and logger are set to WARNING
2736 logger.info(self.next_message())
2737 self.assert_log_lines([], stream=output)
2738 self.apply_config(self.config9a)
2739 #Nothing will be output since both handler is still set to WARNING
2740 logger.info(self.next_message())
2741 self.assert_log_lines([], stream=output)
2742 self.apply_config(self.config9b)
2743 #Message should now be output
2744 logger.info(self.next_message())
2745 self.assert_log_lines([
2746 ('INFO', '3'),
2747 ], stream=output)
2748
2749 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002750 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002751 self.apply_config(self.config10)
2752 logger = logging.getLogger("compiler.parser")
2753 logger.warning(self.next_message())
2754 logger = logging.getLogger('compiler')
2755 #Not output, because filtered
2756 logger.warning(self.next_message())
2757 logger = logging.getLogger('compiler.lexer')
2758 #Not output, because filtered
2759 logger.warning(self.next_message())
2760 logger = logging.getLogger("compiler.parser.codegen")
2761 #Output, as not filtered
2762 logger.error(self.next_message())
2763 self.assert_log_lines([
2764 ('WARNING', '1'),
2765 ('ERROR', '4'),
2766 ], stream=output)
2767
2768 def test_config11_ok(self):
2769 self.test_config1_ok(self.config11)
2770
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002771 def test_config12_failure(self):
2772 self.assertRaises(Exception, self.apply_config, self.config12)
2773
2774 def test_config13_failure(self):
2775 self.assertRaises(Exception, self.apply_config, self.config13)
2776
Vinay Sajip8d270232012-11-15 14:20:18 +00002777 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002778 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002779 self.apply_config(self.config14)
2780 h = logging._handlers['hand1']
2781 self.assertEqual(h.foo, 'bar')
2782 self.assertEqual(h.terminator, '!\n')
2783 logging.warning('Exclamation')
2784 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2785
Victor Stinner45df8202010-04-28 22:31:17 +00002786 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002787 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002788 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002789 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002790 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002791 t.start()
2792 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002793 # Now get the port allocated
2794 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002795 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002796 try:
2797 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2798 sock.settimeout(2.0)
2799 sock.connect(('localhost', port))
2800
2801 slen = struct.pack('>L', len(text))
2802 s = slen + text
2803 sentsofar = 0
2804 left = len(s)
2805 while left > 0:
2806 sent = sock.send(s[sentsofar:])
2807 sentsofar += sent
2808 left -= sent
2809 sock.close()
2810 finally:
2811 t.ready.wait(2.0)
2812 logging.config.stopListening()
2813 t.join(2.0)
2814
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002815 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002816 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002817 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002818 self.setup_via_listener(json.dumps(self.config10))
2819 logger = logging.getLogger("compiler.parser")
2820 logger.warning(self.next_message())
2821 logger = logging.getLogger('compiler')
2822 #Not output, because filtered
2823 logger.warning(self.next_message())
2824 logger = logging.getLogger('compiler.lexer')
2825 #Not output, because filtered
2826 logger.warning(self.next_message())
2827 logger = logging.getLogger("compiler.parser.codegen")
2828 #Output, as not filtered
2829 logger.error(self.next_message())
2830 self.assert_log_lines([
2831 ('WARNING', '1'),
2832 ('ERROR', '4'),
2833 ], stream=output)
2834
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002835 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002836 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002837 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002838 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2839 logger = logging.getLogger("compiler.parser")
2840 # Both will output a message
2841 logger.info(self.next_message())
2842 logger.error(self.next_message())
2843 self.assert_log_lines([
2844 ('INFO', '1'),
2845 ('ERROR', '2'),
2846 ], stream=output)
2847 # Original logger output is empty.
2848 self.assert_log_lines([])
2849
Vinay Sajip4ded5512012-10-02 15:56:16 +01002850 @unittest.skipUnless(threading, 'Threading required for this test.')
2851 def test_listen_verify(self):
2852
2853 def verify_fail(stuff):
2854 return None
2855
2856 def verify_reverse(stuff):
2857 return stuff[::-1]
2858
2859 logger = logging.getLogger("compiler.parser")
2860 to_send = textwrap.dedent(ConfigFileTest.config1)
2861 # First, specify a verification function that will fail.
2862 # We expect to see no output, since our configuration
2863 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002864 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002865 self.setup_via_listener(to_send, verify_fail)
2866 # Both will output a message
2867 logger.info(self.next_message())
2868 logger.error(self.next_message())
2869 self.assert_log_lines([], stream=output)
2870 # Original logger output has the stuff we logged.
2871 self.assert_log_lines([
2872 ('INFO', '1'),
2873 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002874 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002875
2876 # Now, perform no verification. Our configuration
2877 # should take effect.
2878
Vinay Sajip1feedb42014-05-31 08:19:12 +01002879 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002880 self.setup_via_listener(to_send) # no verify callable specified
2881 logger = logging.getLogger("compiler.parser")
2882 # Both will output a message
2883 logger.info(self.next_message())
2884 logger.error(self.next_message())
2885 self.assert_log_lines([
2886 ('INFO', '3'),
2887 ('ERROR', '4'),
2888 ], stream=output)
2889 # Original logger output still has the stuff we logged before.
2890 self.assert_log_lines([
2891 ('INFO', '1'),
2892 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002893 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002894
2895 # Now, perform verification which transforms the bytes.
2896
Vinay Sajip1feedb42014-05-31 08:19:12 +01002897 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002898 self.setup_via_listener(to_send[::-1], verify_reverse)
2899 logger = logging.getLogger("compiler.parser")
2900 # Both will output a message
2901 logger.info(self.next_message())
2902 logger.error(self.next_message())
2903 self.assert_log_lines([
2904 ('INFO', '5'),
2905 ('ERROR', '6'),
2906 ], stream=output)
2907 # Original logger output still has the stuff we logged before.
2908 self.assert_log_lines([
2909 ('INFO', '1'),
2910 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002911 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002912
Vinay Sajip3f885b52013-03-22 15:19:54 +00002913 def test_out_of_order(self):
2914 self.apply_config(self.out_of_order)
2915 handler = logging.getLogger('mymodule').handlers[0]
2916 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002917 self.assertIsInstance(handler.formatter._style,
2918 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002919
Vinay Sajip373baef2011-04-26 20:05:24 +01002920 def test_baseconfig(self):
2921 d = {
2922 'atuple': (1, 2, 3),
2923 'alist': ['a', 'b', 'c'],
2924 'adict': {'d': 'e', 'f': 3 },
2925 'nest1': ('g', ('h', 'i'), 'j'),
2926 'nest2': ['k', ['l', 'm'], 'n'],
2927 'nest3': ['o', 'cfg://alist', 'p'],
2928 }
2929 bc = logging.config.BaseConfigurator(d)
2930 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2931 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2932 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2933 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2934 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2935 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2936 v = bc.convert('cfg://nest3')
2937 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2938 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2939 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2940 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002941
2942class ManagerTest(BaseTest):
2943 def test_manager_loggerclass(self):
2944 logged = []
2945
2946 class MyLogger(logging.Logger):
2947 def _log(self, level, msg, args, exc_info=None, extra=None):
2948 logged.append(msg)
2949
2950 man = logging.Manager(None)
2951 self.assertRaises(TypeError, man.setLoggerClass, int)
2952 man.setLoggerClass(MyLogger)
2953 logger = man.getLogger('test')
2954 logger.warning('should appear in logged')
2955 logging.warning('should not appear in logged')
2956
2957 self.assertEqual(logged, ['should appear in logged'])
2958
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002959 def test_set_log_record_factory(self):
2960 man = logging.Manager(None)
2961 expected = object()
2962 man.setLogRecordFactory(expected)
2963 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002964
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002965class ChildLoggerTest(BaseTest):
2966 def test_child_loggers(self):
2967 r = logging.getLogger()
2968 l1 = logging.getLogger('abc')
2969 l2 = logging.getLogger('def.ghi')
2970 c1 = r.getChild('xyz')
2971 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002972 self.assertIs(c1, logging.getLogger('xyz'))
2973 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002974 c1 = l1.getChild('def')
2975 c2 = c1.getChild('ghi')
2976 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002977 self.assertIs(c1, logging.getLogger('abc.def'))
2978 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2979 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002980
2981
Vinay Sajip6fac8172010-10-19 20:44:14 +00002982class DerivedLogRecord(logging.LogRecord):
2983 pass
2984
Vinay Sajip61561522010-12-03 11:50:38 +00002985class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002986
2987 def setUp(self):
2988 class CheckingFilter(logging.Filter):
2989 def __init__(self, cls):
2990 self.cls = cls
2991
2992 def filter(self, record):
2993 t = type(record)
2994 if t is not self.cls:
2995 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2996 self.cls)
2997 raise TypeError(msg)
2998 return True
2999
3000 BaseTest.setUp(self)
3001 self.filter = CheckingFilter(DerivedLogRecord)
3002 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003003 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003004
3005 def tearDown(self):
3006 self.root_logger.removeFilter(self.filter)
3007 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003008 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003009
3010 def test_logrecord_class(self):
3011 self.assertRaises(TypeError, self.root_logger.warning,
3012 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003013 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003014 self.root_logger.error(self.next_message())
3015 self.assert_log_lines([
3016 ('root', 'ERROR', '2'),
3017 ])
3018
3019
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003020class QueueHandlerTest(BaseTest):
3021 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003022 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003023
3024 def setUp(self):
3025 BaseTest.setUp(self)
3026 self.queue = queue.Queue(-1)
3027 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3028 self.que_logger = logging.getLogger('que')
3029 self.que_logger.propagate = False
3030 self.que_logger.setLevel(logging.WARNING)
3031 self.que_logger.addHandler(self.que_hdlr)
3032
3033 def tearDown(self):
3034 self.que_hdlr.close()
3035 BaseTest.tearDown(self)
3036
3037 def test_queue_handler(self):
3038 self.que_logger.debug(self.next_message())
3039 self.assertRaises(queue.Empty, self.queue.get_nowait)
3040 self.que_logger.info(self.next_message())
3041 self.assertRaises(queue.Empty, self.queue.get_nowait)
3042 msg = self.next_message()
3043 self.que_logger.warning(msg)
3044 data = self.queue.get_nowait()
3045 self.assertTrue(isinstance(data, logging.LogRecord))
3046 self.assertEqual(data.name, self.que_logger.name)
3047 self.assertEqual((data.msg, data.args), (msg, None))
3048
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003049 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3050 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003051 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003052 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003053 listener = logging.handlers.QueueListener(self.queue, handler)
3054 listener.start()
3055 try:
3056 self.que_logger.warning(self.next_message())
3057 self.que_logger.error(self.next_message())
3058 self.que_logger.critical(self.next_message())
3059 finally:
3060 listener.stop()
3061 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3062 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3063 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003064 handler.close()
3065
3066 # Now test with respect_handler_level set
3067
3068 handler = support.TestHandler(support.Matcher())
3069 handler.setLevel(logging.CRITICAL)
3070 listener = logging.handlers.QueueListener(self.queue, handler,
3071 respect_handler_level=True)
3072 listener.start()
3073 try:
3074 self.que_logger.warning(self.next_message())
3075 self.que_logger.error(self.next_message())
3076 self.que_logger.critical(self.next_message())
3077 finally:
3078 listener.stop()
3079 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3080 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3081 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3082
Vinay Sajipd61910c2016-09-08 01:13:39 +01003083if hasattr(logging.handlers, 'QueueListener'):
3084 import multiprocessing
3085 from unittest.mock import patch
3086
3087 class QueueListenerTest(BaseTest):
3088 """
3089 Tests based on patch submitted for issue #27930. Ensure that
3090 QueueListener handles all log messages.
3091 """
3092
3093 repeat = 20
3094
3095 @staticmethod
3096 def setup_and_log(log_queue, ident):
3097 """
3098 Creates a logger with a QueueHandler that logs to a queue read by a
3099 QueueListener. Starts the listener, logs five messages, and stops
3100 the listener.
3101 """
3102 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3103 logger.setLevel(logging.DEBUG)
3104 handler = logging.handlers.QueueHandler(log_queue)
3105 logger.addHandler(handler)
3106 listener = logging.handlers.QueueListener(log_queue)
3107 listener.start()
3108
3109 logger.info('one')
3110 logger.info('two')
3111 logger.info('three')
3112 logger.info('four')
3113 logger.info('five')
3114
3115 listener.stop()
3116 logger.removeHandler(handler)
3117 handler.close()
3118
3119 @patch.object(logging.handlers.QueueListener, 'handle')
3120 def test_handle_called_with_queue_queue(self, mock_handle):
3121 for i in range(self.repeat):
3122 log_queue = queue.Queue()
3123 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3124 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3125 'correct number of handled log messages')
3126
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003127 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003128 @patch.object(logging.handlers.QueueListener, 'handle')
3129 def test_handle_called_with_mp_queue(self, mock_handle):
3130 for i in range(self.repeat):
3131 log_queue = multiprocessing.Queue()
3132 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3133 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3134 'correct number of handled log messages')
3135
3136 @staticmethod
3137 def get_all_from_queue(log_queue):
3138 try:
3139 while True:
3140 yield log_queue.get_nowait()
3141 except queue.Empty:
3142 return []
3143
Xavier de Gaye49e8f2d2016-11-15 16:57:52 +01003144 @support.requires_multiprocessing_queue
Vinay Sajipd61910c2016-09-08 01:13:39 +01003145 def test_no_messages_in_queue_after_stop(self):
3146 """
3147 Five messages are logged then the QueueListener is stopped. This
3148 test then gets everything off the queue. Failure of this test
3149 indicates that messages were not registered on the queue until
3150 _after_ the QueueListener stopped.
3151 """
3152 for i in range(self.repeat):
3153 queue = multiprocessing.Queue()
3154 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3155 # time.sleep(1)
3156 items = list(self.get_all_from_queue(queue))
3157 expected = [[], [logging.handlers.QueueListener._sentinel]]
3158 self.assertIn(items, expected,
3159 'Found unexpected messages in queue: %s' % (
3160 [m.msg if isinstance(m, logging.LogRecord)
3161 else m for m in items]))
3162
Vinay Sajipe723e962011-04-15 22:27:17 +01003163
Vinay Sajip37eb3382011-04-26 20:26:41 +01003164ZERO = datetime.timedelta(0)
3165
3166class UTC(datetime.tzinfo):
3167 def utcoffset(self, dt):
3168 return ZERO
3169
3170 dst = utcoffset
3171
3172 def tzname(self, dt):
3173 return 'UTC'
3174
3175utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003176
Vinay Sajipa39c5712010-10-25 13:57:39 +00003177class FormatterTest(unittest.TestCase):
3178 def setUp(self):
3179 self.common = {
3180 'name': 'formatter.test',
3181 'level': logging.DEBUG,
3182 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3183 'lineno': 42,
3184 'exc_info': None,
3185 'func': None,
3186 'msg': 'Message with %d %s',
3187 'args': (2, 'placeholders'),
3188 }
3189 self.variants = {
3190 }
3191
3192 def get_record(self, name=None):
3193 result = dict(self.common)
3194 if name is not None:
3195 result.update(self.variants[name])
3196 return logging.makeLogRecord(result)
3197
3198 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003199 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003200 r = self.get_record()
3201 f = logging.Formatter('${%(message)s}')
3202 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3203 f = logging.Formatter('%(random)s')
3204 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003205 self.assertFalse(f.usesTime())
3206 f = logging.Formatter('%(asctime)s')
3207 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003208 f = logging.Formatter('%(asctime)-15s')
3209 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003210 f = logging.Formatter('asctime')
3211 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003212
3213 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003214 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003215 r = self.get_record()
3216 f = logging.Formatter('$%{message}%$', style='{')
3217 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3218 f = logging.Formatter('{random}', style='{')
3219 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003220 self.assertFalse(f.usesTime())
3221 f = logging.Formatter('{asctime}', style='{')
3222 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003223 f = logging.Formatter('{asctime!s:15}', style='{')
3224 self.assertTrue(f.usesTime())
3225 f = logging.Formatter('{asctime:15}', style='{')
3226 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003227 f = logging.Formatter('asctime', style='{')
3228 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003229
3230 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003231 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003232 r = self.get_record()
3233 f = logging.Formatter('$message', style='$')
3234 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3235 f = logging.Formatter('$$%${message}%$$', style='$')
3236 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3237 f = logging.Formatter('${random}', style='$')
3238 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003239 self.assertFalse(f.usesTime())
3240 f = logging.Formatter('${asctime}', style='$')
3241 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003242 f = logging.Formatter('${asctime', style='$')
3243 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003244 f = logging.Formatter('$asctime', style='$')
3245 self.assertTrue(f.usesTime())
3246 f = logging.Formatter('asctime', style='$')
3247 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003248
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003249 def test_invalid_style(self):
3250 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3251
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003252 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003253 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003254 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3255 # We use None to indicate we want the local timezone
3256 # We're essentially converting a UTC time to local time
3257 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003258 r.msecs = 123
3259 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003260 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003261 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3262 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003263 f.format(r)
3264 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3265
3266class TestBufferingFormatter(logging.BufferingFormatter):
3267 def formatHeader(self, records):
3268 return '[(%d)' % len(records)
3269
3270 def formatFooter(self, records):
3271 return '(%d)]' % len(records)
3272
3273class BufferingFormatterTest(unittest.TestCase):
3274 def setUp(self):
3275 self.records = [
3276 logging.makeLogRecord({'msg': 'one'}),
3277 logging.makeLogRecord({'msg': 'two'}),
3278 ]
3279
3280 def test_default(self):
3281 f = logging.BufferingFormatter()
3282 self.assertEqual('', f.format([]))
3283 self.assertEqual('onetwo', f.format(self.records))
3284
3285 def test_custom(self):
3286 f = TestBufferingFormatter()
3287 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3288 lf = logging.Formatter('<%(message)s>')
3289 f = TestBufferingFormatter(lf)
3290 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003291
3292class ExceptionTest(BaseTest):
3293 def test_formatting(self):
3294 r = self.root_logger
3295 h = RecordingHandler()
3296 r.addHandler(h)
3297 try:
3298 raise RuntimeError('deliberate mistake')
3299 except:
3300 logging.exception('failed', stack_info=True)
3301 r.removeHandler(h)
3302 h.close()
3303 r = h.records[0]
3304 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3305 'call last):\n'))
3306 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3307 'deliberate mistake'))
3308 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3309 'call last):\n'))
3310 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3311 'stack_info=True)'))
3312
3313
Vinay Sajip5a27d402010-12-10 11:42:57 +00003314class LastResortTest(BaseTest):
3315 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003316 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003317 root = self.root_logger
3318 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003319 old_lastresort = logging.lastResort
3320 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003321
Vinay Sajip5a27d402010-12-10 11:42:57 +00003322 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003323 with support.captured_stderr() as stderr:
3324 root.debug('This should not appear')
3325 self.assertEqual(stderr.getvalue(), '')
3326 root.warning('Final chance!')
3327 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3328
3329 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003330 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003331 with support.captured_stderr() as stderr:
3332 root.warning('Final chance!')
3333 msg = 'No handlers could be found for logger "root"\n'
3334 self.assertEqual(stderr.getvalue(), msg)
3335
Vinay Sajip5a27d402010-12-10 11:42:57 +00003336 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003337 with support.captured_stderr() as stderr:
3338 root.warning('Final chance!')
3339 self.assertEqual(stderr.getvalue(), '')
3340
3341 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003342 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003343 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003344 with support.captured_stderr() as stderr:
3345 root.warning('Final chance!')
3346 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003347 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003348 root.addHandler(self.root_hdlr)
3349 logging.lastResort = old_lastresort
3350 logging.raiseExceptions = old_raise_exceptions
3351
3352
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003353class FakeHandler:
3354
3355 def __init__(self, identifier, called):
3356 for method in ('acquire', 'flush', 'close', 'release'):
3357 setattr(self, method, self.record_call(identifier, method, called))
3358
3359 def record_call(self, identifier, method_name, called):
3360 def inner():
3361 called.append('{} - {}'.format(identifier, method_name))
3362 return inner
3363
3364
3365class RecordingHandler(logging.NullHandler):
3366
3367 def __init__(self, *args, **kwargs):
3368 super(RecordingHandler, self).__init__(*args, **kwargs)
3369 self.records = []
3370
3371 def handle(self, record):
3372 """Keep track of all the emitted records."""
3373 self.records.append(record)
3374
3375
3376class ShutdownTest(BaseTest):
3377
Vinay Sajip5e66b162011-04-20 15:41:14 +01003378 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003379
3380 def setUp(self):
3381 super(ShutdownTest, self).setUp()
3382 self.called = []
3383
3384 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003385 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003386
3387 def raise_error(self, error):
3388 def inner():
3389 raise error()
3390 return inner
3391
3392 def test_no_failure(self):
3393 # create some fake handlers
3394 handler0 = FakeHandler(0, self.called)
3395 handler1 = FakeHandler(1, self.called)
3396 handler2 = FakeHandler(2, self.called)
3397
3398 # create live weakref to those handlers
3399 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3400
3401 logging.shutdown(handlerList=list(handlers))
3402
3403 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3404 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3405 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3406 self.assertEqual(expected, self.called)
3407
3408 def _test_with_failure_in_method(self, method, error):
3409 handler = FakeHandler(0, self.called)
3410 setattr(handler, method, self.raise_error(error))
3411 handlers = [logging.weakref.ref(handler)]
3412
3413 logging.shutdown(handlerList=list(handlers))
3414
3415 self.assertEqual('0 - release', self.called[-1])
3416
3417 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003418 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003419
3420 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003421 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003422
3423 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003424 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003425
3426 def test_with_valueerror_in_acquire(self):
3427 self._test_with_failure_in_method('acquire', ValueError)
3428
3429 def test_with_valueerror_in_flush(self):
3430 self._test_with_failure_in_method('flush', ValueError)
3431
3432 def test_with_valueerror_in_close(self):
3433 self._test_with_failure_in_method('close', ValueError)
3434
3435 def test_with_other_error_in_acquire_without_raise(self):
3436 logging.raiseExceptions = False
3437 self._test_with_failure_in_method('acquire', IndexError)
3438
3439 def test_with_other_error_in_flush_without_raise(self):
3440 logging.raiseExceptions = False
3441 self._test_with_failure_in_method('flush', IndexError)
3442
3443 def test_with_other_error_in_close_without_raise(self):
3444 logging.raiseExceptions = False
3445 self._test_with_failure_in_method('close', IndexError)
3446
3447 def test_with_other_error_in_acquire_with_raise(self):
3448 logging.raiseExceptions = True
3449 self.assertRaises(IndexError, self._test_with_failure_in_method,
3450 'acquire', IndexError)
3451
3452 def test_with_other_error_in_flush_with_raise(self):
3453 logging.raiseExceptions = True
3454 self.assertRaises(IndexError, self._test_with_failure_in_method,
3455 'flush', IndexError)
3456
3457 def test_with_other_error_in_close_with_raise(self):
3458 logging.raiseExceptions = True
3459 self.assertRaises(IndexError, self._test_with_failure_in_method,
3460 'close', IndexError)
3461
3462
3463class ModuleLevelMiscTest(BaseTest):
3464
Vinay Sajip5e66b162011-04-20 15:41:14 +01003465 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003466
3467 def test_disable(self):
3468 old_disable = logging.root.manager.disable
3469 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003470 self.assertEqual(old_disable, 0)
3471 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003472
3473 logging.disable(83)
3474 self.assertEqual(logging.root.manager.disable, 83)
3475
3476 def _test_log(self, method, level=None):
3477 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003478 support.patch(self, logging, 'basicConfig',
3479 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003480
3481 recording = RecordingHandler()
3482 logging.root.addHandler(recording)
3483
3484 log_method = getattr(logging, method)
3485 if level is not None:
3486 log_method(level, "test me: %r", recording)
3487 else:
3488 log_method("test me: %r", recording)
3489
3490 self.assertEqual(len(recording.records), 1)
3491 record = recording.records[0]
3492 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3493
3494 expected_level = level if level is not None else getattr(logging, method.upper())
3495 self.assertEqual(record.levelno, expected_level)
3496
3497 # basicConfig was not called!
3498 self.assertEqual(called, [])
3499
3500 def test_log(self):
3501 self._test_log('log', logging.ERROR)
3502
3503 def test_debug(self):
3504 self._test_log('debug')
3505
3506 def test_info(self):
3507 self._test_log('info')
3508
3509 def test_warning(self):
3510 self._test_log('warning')
3511
3512 def test_error(self):
3513 self._test_log('error')
3514
3515 def test_critical(self):
3516 self._test_log('critical')
3517
3518 def test_set_logger_class(self):
3519 self.assertRaises(TypeError, logging.setLoggerClass, object)
3520
3521 class MyLogger(logging.Logger):
3522 pass
3523
3524 logging.setLoggerClass(MyLogger)
3525 self.assertEqual(logging.getLoggerClass(), MyLogger)
3526
3527 logging.setLoggerClass(logging.Logger)
3528 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3529
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003530 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003531 def test_logging_at_shutdown(self):
3532 # Issue #20037
3533 code = """if 1:
3534 import logging
3535
3536 class A:
3537 def __del__(self):
3538 try:
3539 raise ValueError("some error")
3540 except Exception:
3541 logging.exception("exception in __del__")
3542
3543 a = A()"""
3544 rc, out, err = assert_python_ok("-c", code)
3545 err = err.decode()
3546 self.assertIn("exception in __del__", err)
3547 self.assertIn("ValueError: some error", err)
3548
3549
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003550class LogRecordTest(BaseTest):
3551 def test_str_rep(self):
3552 r = logging.makeLogRecord({})
3553 s = str(r)
3554 self.assertTrue(s.startswith('<LogRecord: '))
3555 self.assertTrue(s.endswith('>'))
3556
3557 def test_dict_arg(self):
3558 h = RecordingHandler()
3559 r = logging.getLogger()
3560 r.addHandler(h)
3561 d = {'less' : 'more' }
3562 logging.warning('less is %(less)s', d)
3563 self.assertIs(h.records[0].args, d)
3564 self.assertEqual(h.records[0].message, 'less is more')
3565 r.removeHandler(h)
3566 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003567
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003568 def test_multiprocessing(self):
3569 r = logging.makeLogRecord({})
3570 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003571 try:
3572 import multiprocessing as mp
3573 r = logging.makeLogRecord({})
3574 self.assertEqual(r.processName, mp.current_process().name)
3575 except ImportError:
3576 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003577
3578 def test_optional(self):
3579 r = logging.makeLogRecord({})
3580 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003581 if threading:
3582 NOT_NONE(r.thread)
3583 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003584 NOT_NONE(r.process)
3585 NOT_NONE(r.processName)
3586 log_threads = logging.logThreads
3587 log_processes = logging.logProcesses
3588 log_multiprocessing = logging.logMultiprocessing
3589 try:
3590 logging.logThreads = False
3591 logging.logProcesses = False
3592 logging.logMultiprocessing = False
3593 r = logging.makeLogRecord({})
3594 NONE = self.assertIsNone
3595 NONE(r.thread)
3596 NONE(r.threadName)
3597 NONE(r.process)
3598 NONE(r.processName)
3599 finally:
3600 logging.logThreads = log_threads
3601 logging.logProcesses = log_processes
3602 logging.logMultiprocessing = log_multiprocessing
3603
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003604class BasicConfigTest(unittest.TestCase):
3605
Vinay Sajip95bf5042011-04-20 11:50:56 +01003606 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003607
3608 def setUp(self):
3609 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003610 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003611 self.saved_handlers = logging._handlers.copy()
3612 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003613 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003614 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003615 logging.root.handlers = []
3616
3617 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003618 for h in logging.root.handlers[:]:
3619 logging.root.removeHandler(h)
3620 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003621 super(BasicConfigTest, self).tearDown()
3622
Vinay Sajip3def7e02011-04-20 10:58:06 +01003623 def cleanup(self):
3624 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003625 logging._handlers.clear()
3626 logging._handlers.update(self.saved_handlers)
3627 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003628 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003629
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003630 def test_no_kwargs(self):
3631 logging.basicConfig()
3632
3633 # handler defaults to a StreamHandler to sys.stderr
3634 self.assertEqual(len(logging.root.handlers), 1)
3635 handler = logging.root.handlers[0]
3636 self.assertIsInstance(handler, logging.StreamHandler)
3637 self.assertEqual(handler.stream, sys.stderr)
3638
3639 formatter = handler.formatter
3640 # format defaults to logging.BASIC_FORMAT
3641 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3642 # datefmt defaults to None
3643 self.assertIsNone(formatter.datefmt)
3644 # style defaults to %
3645 self.assertIsInstance(formatter._style, logging.PercentStyle)
3646
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003647 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003648 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003649
Vinay Sajip1fd12022014-01-13 21:59:56 +00003650 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003651 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003652 logging.basicConfig(stream=sys.stdout, style="{")
3653 logging.error("Log an error")
3654 sys.stdout.seek(0)
3655 self.assertEqual(output.getvalue().strip(),
3656 "ERROR:root:Log an error")
3657
3658 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003659 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003660 logging.basicConfig(stream=sys.stdout, style="$")
3661 logging.error("Log an error")
3662 sys.stdout.seek(0)
3663 self.assertEqual(output.getvalue().strip(),
3664 "ERROR:root:Log an error")
3665
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003666 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003667
3668 def cleanup(h1, h2, fn):
3669 h1.close()
3670 h2.close()
3671 os.remove(fn)
3672
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003673 logging.basicConfig(filename='test.log')
3674
3675 self.assertEqual(len(logging.root.handlers), 1)
3676 handler = logging.root.handlers[0]
3677 self.assertIsInstance(handler, logging.FileHandler)
3678
3679 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003680 self.assertEqual(handler.stream.mode, expected.stream.mode)
3681 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003682 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003683
3684 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003685
3686 def cleanup(h1, h2, fn):
3687 h1.close()
3688 h2.close()
3689 os.remove(fn)
3690
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003691 logging.basicConfig(filename='test.log', filemode='wb')
3692
3693 handler = logging.root.handlers[0]
3694 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003695 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003696 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003697
3698 def test_stream(self):
3699 stream = io.StringIO()
3700 self.addCleanup(stream.close)
3701 logging.basicConfig(stream=stream)
3702
3703 self.assertEqual(len(logging.root.handlers), 1)
3704 handler = logging.root.handlers[0]
3705 self.assertIsInstance(handler, logging.StreamHandler)
3706 self.assertEqual(handler.stream, stream)
3707
3708 def test_format(self):
3709 logging.basicConfig(format='foo')
3710
3711 formatter = logging.root.handlers[0].formatter
3712 self.assertEqual(formatter._style._fmt, 'foo')
3713
3714 def test_datefmt(self):
3715 logging.basicConfig(datefmt='bar')
3716
3717 formatter = logging.root.handlers[0].formatter
3718 self.assertEqual(formatter.datefmt, 'bar')
3719
3720 def test_style(self):
3721 logging.basicConfig(style='$')
3722
3723 formatter = logging.root.handlers[0].formatter
3724 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3725
3726 def test_level(self):
3727 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003728 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003729
3730 logging.basicConfig(level=57)
3731 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003732 # Test that second call has no effect
3733 logging.basicConfig(level=58)
3734 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003735
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003736 def test_incompatible(self):
3737 assertRaises = self.assertRaises
3738 handlers = [logging.StreamHandler()]
3739 stream = sys.stderr
3740 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3741 stream=stream)
3742 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3743 handlers=handlers)
3744 assertRaises(ValueError, logging.basicConfig, stream=stream,
3745 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003746 # Issue 23207: test for invalid kwargs
3747 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3748 # Should pop both filename and filemode even if filename is None
3749 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003750
3751 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003752 handlers = [
3753 logging.StreamHandler(),
3754 logging.StreamHandler(sys.stdout),
3755 logging.StreamHandler(),
3756 ]
3757 f = logging.Formatter()
3758 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003759 logging.basicConfig(handlers=handlers)
3760 self.assertIs(handlers[0], logging.root.handlers[0])
3761 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003762 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003763 self.assertIsNotNone(handlers[0].formatter)
3764 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003765 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003766 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3767
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003768 def _test_log(self, method, level=None):
3769 # logging.root has no handlers so basicConfig should be called
3770 called = []
3771
3772 old_basic_config = logging.basicConfig
3773 def my_basic_config(*a, **kw):
3774 old_basic_config()
3775 old_level = logging.root.level
3776 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003777 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003778 called.append((a, kw))
3779
Vinay Sajip1feedb42014-05-31 08:19:12 +01003780 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003781
3782 log_method = getattr(logging, method)
3783 if level is not None:
3784 log_method(level, "test me")
3785 else:
3786 log_method("test me")
3787
3788 # basicConfig was called with no arguments
3789 self.assertEqual(called, [((), {})])
3790
3791 def test_log(self):
3792 self._test_log('log', logging.WARNING)
3793
3794 def test_debug(self):
3795 self._test_log('debug')
3796
3797 def test_info(self):
3798 self._test_log('info')
3799
3800 def test_warning(self):
3801 self._test_log('warning')
3802
3803 def test_error(self):
3804 self._test_log('error')
3805
3806 def test_critical(self):
3807 self._test_log('critical')
3808
3809
3810class LoggerAdapterTest(unittest.TestCase):
3811
3812 def setUp(self):
3813 super(LoggerAdapterTest, self).setUp()
3814 old_handler_list = logging._handlerList[:]
3815
3816 self.recording = RecordingHandler()
3817 self.logger = logging.root
3818 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003819 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003820 self.addCleanup(self.recording.close)
3821
3822 def cleanup():
3823 logging._handlerList[:] = old_handler_list
3824
3825 self.addCleanup(cleanup)
3826 self.addCleanup(logging.shutdown)
3827 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3828
3829 def test_exception(self):
3830 msg = 'testing exception: %r'
3831 exc = None
3832 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003833 1 / 0
3834 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003835 exc = e
3836 self.adapter.exception(msg, self.recording)
3837
3838 self.assertEqual(len(self.recording.records), 1)
3839 record = self.recording.records[0]
3840 self.assertEqual(record.levelno, logging.ERROR)
3841 self.assertEqual(record.msg, msg)
3842 self.assertEqual(record.args, (self.recording,))
3843 self.assertEqual(record.exc_info,
3844 (exc.__class__, exc, exc.__traceback__))
3845
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003846 def test_exception_excinfo(self):
3847 try:
3848 1 / 0
3849 except ZeroDivisionError as e:
3850 exc = e
3851
3852 self.adapter.exception('exc_info test', exc_info=exc)
3853
3854 self.assertEqual(len(self.recording.records), 1)
3855 record = self.recording.records[0]
3856 self.assertEqual(record.exc_info,
3857 (exc.__class__, exc, exc.__traceback__))
3858
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003859 def test_critical(self):
3860 msg = 'critical test! %r'
3861 self.adapter.critical(msg, self.recording)
3862
3863 self.assertEqual(len(self.recording.records), 1)
3864 record = self.recording.records[0]
3865 self.assertEqual(record.levelno, logging.CRITICAL)
3866 self.assertEqual(record.msg, msg)
3867 self.assertEqual(record.args, (self.recording,))
3868
3869 def test_is_enabled_for(self):
3870 old_disable = self.adapter.logger.manager.disable
3871 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003872 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3873 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003874 self.assertFalse(self.adapter.isEnabledFor(32))
3875
3876 def test_has_handlers(self):
3877 self.assertTrue(self.adapter.hasHandlers())
3878
3879 for handler in self.logger.handlers:
3880 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003881
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003882 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003883 self.assertFalse(self.adapter.hasHandlers())
3884
3885
3886class LoggerTest(BaseTest):
3887
3888 def setUp(self):
3889 super(LoggerTest, self).setUp()
3890 self.recording = RecordingHandler()
3891 self.logger = logging.Logger(name='blah')
3892 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003893 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003894 self.addCleanup(self.recording.close)
3895 self.addCleanup(logging.shutdown)
3896
3897 def test_set_invalid_level(self):
3898 self.assertRaises(TypeError, self.logger.setLevel, object())
3899
3900 def test_exception(self):
3901 msg = 'testing exception: %r'
3902 exc = None
3903 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003904 1 / 0
3905 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003906 exc = e
3907 self.logger.exception(msg, self.recording)
3908
3909 self.assertEqual(len(self.recording.records), 1)
3910 record = self.recording.records[0]
3911 self.assertEqual(record.levelno, logging.ERROR)
3912 self.assertEqual(record.msg, msg)
3913 self.assertEqual(record.args, (self.recording,))
3914 self.assertEqual(record.exc_info,
3915 (exc.__class__, exc, exc.__traceback__))
3916
3917 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003918 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003919 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003920
3921 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003922 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003923 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003924
3925 def test_find_caller_with_stack_info(self):
3926 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003927 support.patch(self, logging.traceback, 'print_stack',
3928 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003929
3930 self.logger.findCaller(stack_info=True)
3931
3932 self.assertEqual(len(called), 1)
3933 self.assertEqual('Stack (most recent call last):\n', called[0])
3934
3935 def test_make_record_with_extra_overwrite(self):
3936 name = 'my record'
3937 level = 13
3938 fn = lno = msg = args = exc_info = func = sinfo = None
3939 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3940 exc_info, func, sinfo)
3941
3942 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3943 extra = {key: 'some value'}
3944 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3945 fn, lno, msg, args, exc_info,
3946 extra=extra, sinfo=sinfo)
3947
3948 def test_make_record_with_extra_no_overwrite(self):
3949 name = 'my record'
3950 level = 13
3951 fn = lno = msg = args = exc_info = func = sinfo = None
3952 extra = {'valid_key': 'some value'}
3953 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3954 exc_info, extra=extra, sinfo=sinfo)
3955 self.assertIn('valid_key', result.__dict__)
3956
3957 def test_has_handlers(self):
3958 self.assertTrue(self.logger.hasHandlers())
3959
3960 for handler in self.logger.handlers:
3961 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003962 self.assertFalse(self.logger.hasHandlers())
3963
3964 def test_has_handlers_no_propagate(self):
3965 child_logger = logging.getLogger('blah.child')
3966 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003967 self.assertFalse(child_logger.hasHandlers())
3968
3969 def test_is_enabled_for(self):
3970 old_disable = self.logger.manager.disable
3971 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003972 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003973 self.assertFalse(self.logger.isEnabledFor(22))
3974
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003975 def test_root_logger_aliases(self):
3976 root = logging.getLogger()
3977 self.assertIs(root, logging.root)
3978 self.assertIs(root, logging.getLogger(None))
3979 self.assertIs(root, logging.getLogger(''))
3980 self.assertIs(root, logging.getLogger('foo').root)
3981 self.assertIs(root, logging.getLogger('foo.bar').root)
3982 self.assertIs(root, logging.getLogger('foo').parent)
3983
3984 self.assertIsNot(root, logging.getLogger('\0'))
3985 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3986
3987 def test_invalid_names(self):
3988 self.assertRaises(TypeError, logging.getLogger, any)
3989 self.assertRaises(TypeError, logging.getLogger, b'foo')
3990
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003991
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003992class BaseFileTest(BaseTest):
3993 "Base class for handler tests that write log files"
3994
3995 def setUp(self):
3996 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003997 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3998 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003999 self.rmfiles = []
4000
4001 def tearDown(self):
4002 for fn in self.rmfiles:
4003 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004004 if os.path.exists(self.fn):
4005 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004006 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004007
4008 def assertLogFile(self, filename):
4009 "Assert a log file is there and register it for deletion"
4010 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004011 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004012 self.rmfiles.append(filename)
4013
4014
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004015class FileHandlerTest(BaseFileTest):
4016 def test_delay(self):
4017 os.unlink(self.fn)
4018 fh = logging.FileHandler(self.fn, delay=True)
4019 self.assertIsNone(fh.stream)
4020 self.assertFalse(os.path.exists(self.fn))
4021 fh.handle(logging.makeLogRecord({}))
4022 self.assertIsNotNone(fh.stream)
4023 self.assertTrue(os.path.exists(self.fn))
4024 fh.close()
4025
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004026class RotatingFileHandlerTest(BaseFileTest):
4027 def next_rec(self):
4028 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4029 self.next_message(), None, None, None)
4030
4031 def test_should_not_rollover(self):
4032 # If maxbytes is zero rollover never occurs
4033 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4034 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004035 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004036
4037 def test_should_rollover(self):
4038 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4039 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004040 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004041
4042 def test_file_created(self):
4043 # checks that the file is created and assumes it was created
4044 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004045 rh = logging.handlers.RotatingFileHandler(self.fn)
4046 rh.emit(self.next_rec())
4047 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004048 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004049
4050 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004051 def namer(name):
4052 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004053 rh = logging.handlers.RotatingFileHandler(
4054 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004055 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004056 rh.emit(self.next_rec())
4057 self.assertLogFile(self.fn)
4058 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004059 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004060 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004061 self.assertLogFile(namer(self.fn + ".2"))
4062 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4063 rh.close()
4064
Vinay Sajip1feedb42014-05-31 08:19:12 +01004065 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004066 def test_rotator(self):
4067 def namer(name):
4068 return name + ".gz"
4069
4070 def rotator(source, dest):
4071 with open(source, "rb") as sf:
4072 data = sf.read()
4073 compressed = zlib.compress(data, 9)
4074 with open(dest, "wb") as df:
4075 df.write(compressed)
4076 os.remove(source)
4077
4078 rh = logging.handlers.RotatingFileHandler(
4079 self.fn, backupCount=2, maxBytes=1)
4080 rh.rotator = rotator
4081 rh.namer = namer
4082 m1 = self.next_rec()
4083 rh.emit(m1)
4084 self.assertLogFile(self.fn)
4085 m2 = self.next_rec()
4086 rh.emit(m2)
4087 fn = namer(self.fn + ".1")
4088 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004089 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004090 with open(fn, "rb") as f:
4091 compressed = f.read()
4092 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004093 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004094 rh.emit(self.next_rec())
4095 fn = namer(self.fn + ".2")
4096 self.assertLogFile(fn)
4097 with open(fn, "rb") as f:
4098 compressed = f.read()
4099 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004100 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004101 rh.emit(self.next_rec())
4102 fn = namer(self.fn + ".2")
4103 with open(fn, "rb") as f:
4104 compressed = f.read()
4105 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004106 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004107 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004108 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004109
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004110class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004111 # other test methods added below
4112 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004113 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4114 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004115 fmt = logging.Formatter('%(asctime)s %(message)s')
4116 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004117 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004118 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004119 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004120 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004121 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004122 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004123 fh.close()
4124 # At this point, we should have a recent rotated file which we
4125 # can test for the existence of. However, in practice, on some
4126 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004127 # in time to go to look for the log file. So, we go back a fair
4128 # bit, and stop as soon as we see a rotated file. In theory this
4129 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004130 found = False
4131 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004132 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004133 for secs in range(GO_BACK):
4134 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004135 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4136 found = os.path.exists(fn)
4137 if found:
4138 self.rmfiles.append(fn)
4139 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004140 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4141 if not found:
4142 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004143 dn, fn = os.path.split(self.fn)
4144 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004145 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4146 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004147 for f in files:
4148 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004149 path = os.path.join(dn, f)
4150 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004151 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004152 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004153
Vinay Sajip0372e102011-05-05 12:59:14 +01004154 def test_invalid(self):
4155 assertRaises = self.assertRaises
4156 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004157 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004158 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004159 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004160 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004161 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004162
Vinay Sajipa7130792013-04-12 17:04:23 +01004163 def test_compute_rollover_daily_attime(self):
4164 currentTime = 0
4165 atTime = datetime.time(12, 0, 0)
4166 rh = logging.handlers.TimedRotatingFileHandler(
4167 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4168 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004169 try:
4170 actual = rh.computeRollover(currentTime)
4171 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004172
Vinay Sajipd86ac962013-04-14 12:20:46 +01004173 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4174 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4175 finally:
4176 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004177
Vinay Sajip10e8c492013-05-18 10:19:54 -07004178 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004179 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004180 currentTime = int(time.time())
4181 today = currentTime - currentTime % 86400
4182
Vinay Sajipa7130792013-04-12 17:04:23 +01004183 atTime = datetime.time(12, 0, 0)
4184
Vinay Sajip10e8c492013-05-18 10:19:54 -07004185 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004186 for day in range(7):
4187 rh = logging.handlers.TimedRotatingFileHandler(
4188 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4189 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004190 try:
4191 if wday > day:
4192 # The rollover day has already passed this week, so we
4193 # go over into next week
4194 expected = (7 - wday + day)
4195 else:
4196 expected = (day - wday)
4197 # At this point expected is in days from now, convert to seconds
4198 expected *= 24 * 60 * 60
4199 # Add in the rollover time
4200 expected += 12 * 60 * 60
4201 # Add in adjustment for today
4202 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004203 actual = rh.computeRollover(today)
4204 if actual != expected:
4205 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004206 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004207 self.assertEqual(actual, expected)
4208 if day == wday:
4209 # goes into following week
4210 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004211 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004212 if actual != expected:
4213 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004214 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004215 self.assertEqual(actual, expected)
4216 finally:
4217 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004218
4219
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004220def secs(**kw):
4221 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4222
4223for when, exp in (('S', 1),
4224 ('M', 60),
4225 ('H', 60 * 60),
4226 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004227 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004228 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004229 ('W0', secs(days=4, hours=24)),
4230 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004231 def test_compute_rollover(self, when=when, exp=exp):
4232 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004233 self.fn, when=when, interval=1, backupCount=0, utc=True)
4234 currentTime = 0.0
4235 actual = rh.computeRollover(currentTime)
4236 if exp != actual:
4237 # Failures occur on some systems for MIDNIGHT and W0.
4238 # Print detailed calculation for MIDNIGHT so we can try to see
4239 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004240 if when == 'MIDNIGHT':
4241 try:
4242 if rh.utc:
4243 t = time.gmtime(currentTime)
4244 else:
4245 t = time.localtime(currentTime)
4246 currentHour = t[3]
4247 currentMinute = t[4]
4248 currentSecond = t[5]
4249 # r is the number of seconds left between now and midnight
4250 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4251 currentMinute) * 60 +
4252 currentSecond)
4253 result = currentTime + r
4254 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4255 print('currentHour: %s' % currentHour, file=sys.stderr)
4256 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4257 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4258 print('r: %s' % r, file=sys.stderr)
4259 print('result: %s' % result, file=sys.stderr)
4260 except Exception:
4261 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4262 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004263 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004264 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4265
Vinay Sajip60ccd822011-05-09 17:32:09 +01004266
Vinay Sajip223349c2015-10-01 20:37:54 +01004267@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004268class NTEventLogHandlerTest(BaseTest):
4269 def test_basic(self):
4270 logtype = 'Application'
4271 elh = win32evtlog.OpenEventLog(None, logtype)
4272 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004273
4274 try:
4275 h = logging.handlers.NTEventLogHandler('test_logging')
4276 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004277 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004278 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004279 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004280
Vinay Sajip60ccd822011-05-09 17:32:09 +01004281 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4282 h.handle(r)
4283 h.close()
4284 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004285 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004286 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4287 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4288 found = False
4289 GO_BACK = 100
4290 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4291 for e in events:
4292 if e.SourceName != 'test_logging':
4293 continue
4294 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4295 if msg != 'Test Log Message\r\n':
4296 continue
4297 found = True
4298 break
4299 msg = 'Record not found in event log, went back %d records' % GO_BACK
4300 self.assertTrue(found, msg=msg)
4301
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004302
4303class MiscTestCase(unittest.TestCase):
4304 def test__all__(self):
4305 blacklist = {'logThreads', 'logMultiprocessing',
4306 'logProcesses', 'currentframe',
4307 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4308 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004309 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004310 support.check__all__(self, logging, blacklist=blacklist)
4311
4312
Christian Heimes180510d2008-03-03 19:15:45 +00004313# Set the locale to the platform-dependent default. I have no idea
4314# why the test does this, but in any case we save the current locale
4315# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004316@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004317def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004318 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004319 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4320 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4321 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4322 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4323 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4324 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4325 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4326 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4327 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4328 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004329 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004330 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004331 ]
4332 if hasattr(logging.handlers, 'QueueListener'):
4333 tests.append(QueueListenerTest)
4334 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004335
Christian Heimes180510d2008-03-03 19:15:45 +00004336if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004337 test_main()