blob: e998f6038eea389529ef6642d1bb750189f64b80 [file] [log] [blame]
Vinay Sajip1feedb42014-05-31 08:19:12 +01001# Copyright 2001-2014 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 Sajip1feedb42014-05-31 08:19:12 +010019Copyright (C) 2001-2014 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 Sajip638e6222016-07-22 18:23:04 +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
312class BasicFilterTest(BaseTest):
313
314 """Test the bundled Filter class."""
315
316 def test_filter(self):
317 # Only messages satisfying the specified criteria pass through the
318 # filter.
319 filter_ = logging.Filter("spam.eggs")
320 handler = self.root_logger.handlers[0]
321 try:
322 handler.addFilter(filter_)
323 spam = logging.getLogger("spam")
324 spam_eggs = logging.getLogger("spam.eggs")
325 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
326 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
327
328 spam.info(self.next_message())
329 spam_eggs.info(self.next_message()) # Good.
330 spam_eggs_fish.info(self.next_message()) # Good.
331 spam_bakedbeans.info(self.next_message())
332
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000333 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000334 ('spam.eggs', 'INFO', '2'),
335 ('spam.eggs.fish', 'INFO', '3'),
336 ])
337 finally:
338 handler.removeFilter(filter_)
339
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000340 def test_callable_filter(self):
341 # Only messages satisfying the specified criteria pass through the
342 # filter.
343
344 def filterfunc(record):
345 parts = record.name.split('.')
346 prefix = '.'.join(parts[:2])
347 return prefix == 'spam.eggs'
348
349 handler = self.root_logger.handlers[0]
350 try:
351 handler.addFilter(filterfunc)
352 spam = logging.getLogger("spam")
353 spam_eggs = logging.getLogger("spam.eggs")
354 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
355 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
356
357 spam.info(self.next_message())
358 spam_eggs.info(self.next_message()) # Good.
359 spam_eggs_fish.info(self.next_message()) # Good.
360 spam_bakedbeans.info(self.next_message())
361
362 self.assert_log_lines([
363 ('spam.eggs', 'INFO', '2'),
364 ('spam.eggs.fish', 'INFO', '3'),
365 ])
366 finally:
367 handler.removeFilter(filterfunc)
368
Vinay Sajip985ef872011-04-26 19:34:04 +0100369 def test_empty_filter(self):
370 f = logging.Filter()
371 r = logging.makeLogRecord({'name': 'spam.eggs'})
372 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000373
374#
375# First, we define our levels. There can be as many as you want - the only
376# limitations are that they should be integers, the lowest should be > 0 and
377# larger values mean less information being logged. If you need specific
378# level values which do not fit into these limitations, you can use a
379# mapping dictionary to convert between your application levels and the
380# logging system.
381#
382SILENT = 120
383TACITURN = 119
384TERSE = 118
385EFFUSIVE = 117
386SOCIABLE = 116
387VERBOSE = 115
388TALKATIVE = 114
389GARRULOUS = 113
390CHATTERBOX = 112
391BORING = 111
392
393LEVEL_RANGE = range(BORING, SILENT + 1)
394
395#
396# Next, we define names for our levels. You don't need to do this - in which
397# case the system will use "Level n" to denote the text for the level.
398#
399my_logging_levels = {
400 SILENT : 'Silent',
401 TACITURN : 'Taciturn',
402 TERSE : 'Terse',
403 EFFUSIVE : 'Effusive',
404 SOCIABLE : 'Sociable',
405 VERBOSE : 'Verbose',
406 TALKATIVE : 'Talkative',
407 GARRULOUS : 'Garrulous',
408 CHATTERBOX : 'Chatterbox',
409 BORING : 'Boring',
410}
411
412class GarrulousFilter(logging.Filter):
413
414 """A filter which blocks garrulous messages."""
415
416 def filter(self, record):
417 return record.levelno != GARRULOUS
418
419class VerySpecificFilter(logging.Filter):
420
421 """A filter which blocks sociable and taciturn messages."""
422
423 def filter(self, record):
424 return record.levelno not in [SOCIABLE, TACITURN]
425
426
427class CustomLevelsAndFiltersTest(BaseTest):
428
429 """Test various filtering possibilities with custom logging levels."""
430
431 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300432 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000433
434 def setUp(self):
435 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000436 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000437 logging.addLevelName(k, v)
438
439 def log_at_all_levels(self, logger):
440 for lvl in LEVEL_RANGE:
441 logger.log(lvl, self.next_message())
442
443 def test_logger_filter(self):
444 # Filter at logger level.
445 self.root_logger.setLevel(VERBOSE)
446 # Levels >= 'Verbose' are good.
447 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000448 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000449 ('Verbose', '5'),
450 ('Sociable', '6'),
451 ('Effusive', '7'),
452 ('Terse', '8'),
453 ('Taciturn', '9'),
454 ('Silent', '10'),
455 ])
456
457 def test_handler_filter(self):
458 # Filter at handler level.
459 self.root_logger.handlers[0].setLevel(SOCIABLE)
460 try:
461 # Levels >= 'Sociable' are good.
462 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000463 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000464 ('Sociable', '6'),
465 ('Effusive', '7'),
466 ('Terse', '8'),
467 ('Taciturn', '9'),
468 ('Silent', '10'),
469 ])
470 finally:
471 self.root_logger.handlers[0].setLevel(logging.NOTSET)
472
473 def test_specific_filters(self):
474 # Set a specific filter object on the handler, and then add another
475 # filter object on the logger itself.
476 handler = self.root_logger.handlers[0]
477 specific_filter = None
478 garr = GarrulousFilter()
479 handler.addFilter(garr)
480 try:
481 self.log_at_all_levels(self.root_logger)
482 first_lines = [
483 # Notice how 'Garrulous' is missing
484 ('Boring', '1'),
485 ('Chatterbox', '2'),
486 ('Talkative', '4'),
487 ('Verbose', '5'),
488 ('Sociable', '6'),
489 ('Effusive', '7'),
490 ('Terse', '8'),
491 ('Taciturn', '9'),
492 ('Silent', '10'),
493 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000494 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000495
496 specific_filter = VerySpecificFilter()
497 self.root_logger.addFilter(specific_filter)
498 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000499 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000500 # Not only 'Garrulous' is still missing, but also 'Sociable'
501 # and 'Taciturn'
502 ('Boring', '11'),
503 ('Chatterbox', '12'),
504 ('Talkative', '14'),
505 ('Verbose', '15'),
506 ('Effusive', '17'),
507 ('Terse', '18'),
508 ('Silent', '20'),
509 ])
510 finally:
511 if specific_filter:
512 self.root_logger.removeFilter(specific_filter)
513 handler.removeFilter(garr)
514
515
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100516class HandlerTest(BaseTest):
517 def test_name(self):
518 h = logging.Handler()
519 h.name = 'generic'
520 self.assertEqual(h.name, 'generic')
521 h.name = 'anothergeneric'
522 self.assertEqual(h.name, 'anothergeneric')
523 self.assertRaises(NotImplementedError, h.emit, None)
524
Vinay Sajip5a35b062011-04-27 11:31:14 +0100525 def test_builtin_handlers(self):
526 # We can't actually *use* too many handlers in the tests,
527 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200528 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100529 for existing in (True, False):
530 fd, fn = tempfile.mkstemp()
531 os.close(fd)
532 if not existing:
533 os.unlink(fn)
534 h = logging.handlers.WatchedFileHandler(fn, delay=True)
535 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100536 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100537 self.assertEqual(dev, -1)
538 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100539 r = logging.makeLogRecord({'msg': 'Test'})
540 h.handle(r)
541 # Now remove the file.
542 os.unlink(fn)
543 self.assertFalse(os.path.exists(fn))
544 # The next call should recreate the file.
545 h.handle(r)
546 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 else:
548 self.assertEqual(h.dev, -1)
549 self.assertEqual(h.ino, -1)
550 h.close()
551 if existing:
552 os.unlink(fn)
553 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100554 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100555 else:
556 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100557 try:
558 h = logging.handlers.SysLogHandler(sockname)
559 self.assertEqual(h.facility, h.LOG_USER)
560 self.assertTrue(h.unixsocket)
561 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200562 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100563 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100564 for method in ('GET', 'POST', 'PUT'):
565 if method == 'PUT':
566 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
567 'localhost', '/log', method)
568 else:
569 h = logging.handlers.HTTPHandler('localhost', '/log', method)
570 h.close()
571 h = logging.handlers.BufferingHandler(0)
572 r = logging.makeLogRecord({})
573 self.assertTrue(h.shouldFlush(r))
574 h.close()
575 h = logging.handlers.BufferingHandler(1)
576 self.assertFalse(h.shouldFlush(r))
577 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100578
Vinay Sajip638e6222016-07-22 18:23:04 +0100579 def test_path_objects(self):
580 """
581 Test that Path objects are accepted as filename arguments to handlers.
582
583 See Issue #27493.
584 """
585 fd, fn = tempfile.mkstemp()
586 os.close(fd)
587 os.unlink(fn)
588 pfn = pathlib.Path(fn)
589 cases = (
590 (logging.FileHandler, (pfn, 'w')),
591 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
592 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
593 )
594 if sys.platform in ('linux', 'darwin'):
595 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
596 for cls, args in cases:
597 h = cls(*args)
598 self.assertTrue(os.path.exists(fn))
599 os.unlink(fn)
600 h.close()
601
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100602 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603 @unittest.skipUnless(threading, 'Threading required for this test.')
604 def test_race(self):
605 # Issue #14632 refers.
606 def remove_loop(fname, tries):
607 for _ in range(tries):
608 try:
609 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000610 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100611 except OSError:
612 pass
613 time.sleep(0.004 * random.randint(0, 4))
614
Vinay Sajipc94871a2012-04-25 10:51:35 +0100615 del_count = 500
616 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100617
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000618 self.handle_time = None
619 self.deletion_time = None
620
Vinay Sajipa5798de2012-04-24 23:33:33 +0100621 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100622 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
623 os.close(fd)
624 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
625 remover.daemon = True
626 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100627 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100628 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
629 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100630 try:
631 for _ in range(log_count):
632 time.sleep(0.005)
633 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000634 try:
635 self.handle_time = time.time()
636 h.handle(r)
637 except Exception:
638 print('Deleted at %s, '
639 'opened at %s' % (self.deletion_time,
640 self.handle_time))
641 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100642 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100643 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100644 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100645 if os.path.exists(fn):
646 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100647
648
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100649class BadStream(object):
650 def write(self, data):
651 raise RuntimeError('deliberate mistake')
652
653class TestStreamHandler(logging.StreamHandler):
654 def handleError(self, record):
655 self.error_record = record
656
657class StreamHandlerTest(BaseTest):
658 def test_error_handling(self):
659 h = TestStreamHandler(BadStream())
660 r = logging.makeLogRecord({})
661 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100662
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100663 try:
664 h.handle(r)
665 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100666
Vinay Sajip985ef872011-04-26 19:34:04 +0100667 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100668 with support.captured_stderr() as stderr:
669 h.handle(r)
670 msg = '\nRuntimeError: deliberate mistake\n'
671 self.assertIn(msg, stderr.getvalue())
672
Vinay Sajip985ef872011-04-26 19:34:04 +0100673 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100674 with support.captured_stderr() as stderr:
675 h.handle(r)
676 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100677 finally:
678 logging.raiseExceptions = old_raise
679
Vinay Sajip7367d082011-05-02 13:17:27 +0100680# -- The following section could be moved into a server_helper.py module
681# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100682
Vinay Sajipce7c9782011-05-17 07:15:53 +0100683if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100684 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100685 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100686 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100687
Vinay Sajipce7c9782011-05-17 07:15:53 +0100688 :param addr: A (host, port) tuple which the server listens on.
689 You can specify a port value of zero: the server's
690 *port* attribute will hold the actual port number
691 used, which can be used in client connections.
692 :param handler: A callable which will be called to process
693 incoming messages. The handler will be passed
694 the client address tuple, who the message is from,
695 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100696 :param poll_interval: The interval, in seconds, used in the underlying
697 :func:`select` or :func:`poll` call by
698 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100699 :param sockmap: A dictionary which will be used to hold
700 :class:`asyncore.dispatcher` instances used by
701 :func:`asyncore.loop`. This avoids changing the
702 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100703 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100704
705 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400706 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
707 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100708 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100709 self._handler = handler
710 self._thread = None
711 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100712
Vinay Sajipce7c9782011-05-17 07:15:53 +0100713 def process_message(self, peer, mailfrom, rcpttos, data):
714 """
715 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100716
Vinay Sajipce7c9782011-05-17 07:15:53 +0100717 Typically, this will be a test case method.
718 :param peer: The client (host, port) tuple.
719 :param mailfrom: The address of the sender.
720 :param rcpttos: The addresses of the recipients.
721 :param data: The message.
722 """
723 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100724
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 def start(self):
726 """
727 Start the server running on a separate daemon thread.
728 """
729 self._thread = t = threading.Thread(target=self.serve_forever,
730 args=(self.poll_interval,))
731 t.setDaemon(True)
732 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100733
Vinay Sajipce7c9782011-05-17 07:15:53 +0100734 def serve_forever(self, poll_interval):
735 """
736 Run the :mod:`asyncore` loop until normal termination
737 conditions arise.
738 :param poll_interval: The interval, in seconds, used in the underlying
739 :func:`select` or :func:`poll` call by
740 :func:`asyncore.loop`.
741 """
742 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100743 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200744 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100745 # On FreeBSD 8, closing the server repeatably
746 # raises this error. We swallow it if the
747 # server has been closed.
748 if self.connected or self.accepting:
749 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100750
Vinay Sajipce7c9782011-05-17 07:15:53 +0100751 def stop(self, timeout=None):
752 """
753 Stop the thread by closing the server instance.
754 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100755
Vinay Sajipce7c9782011-05-17 07:15:53 +0100756 :param timeout: How long to wait for the server thread
757 to terminate.
758 """
759 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100760 self._thread.join(timeout)
761 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100762
Vinay Sajipce7c9782011-05-17 07:15:53 +0100763 class ControlMixin(object):
764 """
765 This mixin is used to start a server on a separate thread, and
766 shut it down programmatically. Request handling is simplified - instead
767 of needing to derive a suitable RequestHandler subclass, you just
768 provide a callable which will be passed each received request to be
769 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100770
Vinay Sajipce7c9782011-05-17 07:15:53 +0100771 :param handler: A handler callable which will be called with a
772 single parameter - the request - in order to
773 process the request. This handler is called on the
774 server thread, effectively meaning that requests are
775 processed serially. While not quite Web scale ;-),
776 this should be fine for testing applications.
777 :param poll_interval: The polling interval in seconds.
778 """
779 def __init__(self, handler, poll_interval):
780 self._thread = None
781 self.poll_interval = poll_interval
782 self._handler = handler
783 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100784
Vinay Sajipce7c9782011-05-17 07:15:53 +0100785 def start(self):
786 """
787 Create a daemon thread to run the server, and start it.
788 """
789 self._thread = t = threading.Thread(target=self.serve_forever,
790 args=(self.poll_interval,))
791 t.setDaemon(True)
792 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100793
Vinay Sajipce7c9782011-05-17 07:15:53 +0100794 def serve_forever(self, poll_interval):
795 """
796 Run the server. Set the ready flag before entering the
797 service loop.
798 """
799 self.ready.set()
800 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100801
Vinay Sajipce7c9782011-05-17 07:15:53 +0100802 def stop(self, timeout=None):
803 """
804 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100805
Vinay Sajipce7c9782011-05-17 07:15:53 +0100806 :param timeout: How long to wait for the server thread
807 to terminate.
808 """
809 self.shutdown()
810 if self._thread is not None:
811 self._thread.join(timeout)
812 self._thread = None
813 self.server_close()
814 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100815
Vinay Sajipce7c9782011-05-17 07:15:53 +0100816 class TestHTTPServer(ControlMixin, HTTPServer):
817 """
818 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100819
Vinay Sajipce7c9782011-05-17 07:15:53 +0100820 :param addr: A tuple with the IP address and port to listen on.
821 :param handler: A handler callable which will be called with a
822 single parameter - the request - in order to
823 process the request.
824 :param poll_interval: The polling interval in seconds.
825 :param log: Pass ``True`` to enable log messages.
826 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100827 def __init__(self, addr, handler, poll_interval=0.5,
828 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100829 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
830 def __getattr__(self, name, default=None):
831 if name.startswith('do_'):
832 return self.process_request
833 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100834
Vinay Sajipce7c9782011-05-17 07:15:53 +0100835 def process_request(self):
836 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100837
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 def log_message(self, format, *args):
839 if log:
840 super(DelegatingHTTPRequestHandler,
841 self).log_message(format, *args)
842 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
843 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100844 self.sslctx = sslctx
845
846 def get_request(self):
847 try:
848 sock, addr = self.socket.accept()
849 if self.sslctx:
850 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200851 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100852 # socket errors are silenced by the caller, print them here
853 sys.stderr.write("Got an error:\n%s\n" % e)
854 raise
855 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100856
Vinay Sajipce7c9782011-05-17 07:15:53 +0100857 class TestTCPServer(ControlMixin, ThreadingTCPServer):
858 """
859 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 :param addr: A tuple with the IP address and port to listen on.
862 :param handler: A handler callable which will be called with a single
863 parameter - the request - in order to process the request.
864 :param poll_interval: The polling interval in seconds.
865 :bind_and_activate: If True (the default), binds the server and starts it
866 listening. If False, you need to call
867 :meth:`server_bind` and :meth:`server_activate` at
868 some later time before calling :meth:`start`, so that
869 the server will set up the socket and listen on it.
870 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100871
Vinay Sajipce7c9782011-05-17 07:15:53 +0100872 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100873
Vinay Sajipce7c9782011-05-17 07:15:53 +0100874 def __init__(self, addr, handler, poll_interval=0.5,
875 bind_and_activate=True):
876 class DelegatingTCPRequestHandler(StreamRequestHandler):
877
878 def handle(self):
879 self.server._handler(self)
880 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
881 bind_and_activate)
882 ControlMixin.__init__(self, handler, poll_interval)
883
884 def server_bind(self):
885 super(TestTCPServer, self).server_bind()
886 self.port = self.socket.getsockname()[1]
887
888 class TestUDPServer(ControlMixin, ThreadingUDPServer):
889 """
890 A UDP server which is controllable using :class:`ControlMixin`.
891
892 :param addr: A tuple with the IP address and port to listen on.
893 :param handler: A handler callable which will be called with a
894 single parameter - the request - in order to
895 process the request.
896 :param poll_interval: The polling interval for shutdown requests,
897 in seconds.
898 :bind_and_activate: If True (the default), binds the server and
899 starts it listening. If False, you need to
900 call :meth:`server_bind` and
901 :meth:`server_activate` at some later time
902 before calling :meth:`start`, so that the server will
903 set up the socket and listen on it.
904 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100905 def __init__(self, addr, handler, poll_interval=0.5,
906 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100907 class DelegatingUDPRequestHandler(DatagramRequestHandler):
908
909 def handle(self):
910 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100911
912 def finish(self):
913 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100914 if data:
915 try:
916 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200917 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100918 if not self.server._closed:
919 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100920
Vinay Sajip3ef12292011-05-23 23:00:42 +0100921 ThreadingUDPServer.__init__(self, addr,
922 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100923 bind_and_activate)
924 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100925 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100926
927 def server_bind(self):
928 super(TestUDPServer, self).server_bind()
929 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100930
Vinay Sajipba980db2011-05-23 21:37:54 +0100931 def server_close(self):
932 super(TestUDPServer, self).server_close()
933 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100934
Victor Stinnerec5a8602014-06-02 14:41:51 +0200935 if hasattr(socket, "AF_UNIX"):
936 class TestUnixStreamServer(TestTCPServer):
937 address_family = socket.AF_UNIX
938
939 class TestUnixDatagramServer(TestUDPServer):
940 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100941
Vinay Sajip7367d082011-05-02 13:17:27 +0100942# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100943
Vinay Sajipce7c9782011-05-17 07:15:53 +0100944@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100945class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000946 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100947 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100948 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800949 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100950 sockmap)
951 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800952 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000953 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
954 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100955 self.assertEqual(h.toaddrs, ['you'])
956 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100957 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100958 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100959 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000960 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100961 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000962 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100963 self.assertEqual(len(self.messages), 1)
964 peer, mailfrom, rcpttos, data = self.messages[0]
965 self.assertEqual(mailfrom, 'me')
966 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100967 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100968 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100969 h.close()
970
971 def process_message(self, *args):
972 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100973 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100974
Christian Heimes180510d2008-03-03 19:15:45 +0000975class MemoryHandlerTest(BaseTest):
976
977 """Tests for the MemoryHandler."""
978
979 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300980 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000981
982 def setUp(self):
983 BaseTest.setUp(self)
984 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipcccf6062016-07-22 16:27:31 +0100985 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +0000986 self.mem_logger = logging.getLogger('mem')
987 self.mem_logger.propagate = 0
988 self.mem_logger.addHandler(self.mem_hdlr)
989
990 def tearDown(self):
991 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000992 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000993
994 def test_flush(self):
995 # The memory handler flushes to its target handler based on specific
996 # criteria (message count and message level).
997 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000998 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000999 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001000 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001001 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001002 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001003 lines = [
1004 ('DEBUG', '1'),
1005 ('INFO', '2'),
1006 ('WARNING', '3'),
1007 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001008 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001009 for n in (4, 14):
1010 for i in range(9):
1011 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001012 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001013 # This will flush because it's the 10th message since the last
1014 # flush.
1015 self.mem_logger.debug(self.next_message())
1016 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001017 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001018
1019 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001020 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001021
Vinay Sajipcccf6062016-07-22 16:27:31 +01001022 def test_flush_on_close(self):
1023 """
1024 Test that the flush-on-close configuration works as expected.
1025 """
1026 self.mem_logger.debug(self.next_message())
1027 self.assert_log_lines([])
1028 self.mem_logger.info(self.next_message())
1029 self.assert_log_lines([])
1030 self.mem_logger.removeHandler(self.mem_hdlr)
1031 # Default behaviour is to flush on close. Check that it happens.
1032 self.mem_hdlr.close()
1033 lines = [
1034 ('DEBUG', '1'),
1035 ('INFO', '2'),
1036 ]
1037 self.assert_log_lines(lines)
1038 # Now configure for flushing not to be done on close.
1039 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1040 self.root_hdlr,
1041 False)
1042 self.mem_logger.addHandler(self.mem_hdlr)
1043 self.mem_logger.debug(self.next_message())
1044 self.assert_log_lines(lines) # no change
1045 self.mem_logger.info(self.next_message())
1046 self.assert_log_lines(lines) # no change
1047 self.mem_logger.removeHandler(self.mem_hdlr)
1048 self.mem_hdlr.close()
1049 # assert that no new lines have been added
1050 self.assert_log_lines(lines) # no change
1051
Christian Heimes180510d2008-03-03 19:15:45 +00001052
1053class ExceptionFormatter(logging.Formatter):
1054 """A special exception formatter."""
1055 def formatException(self, ei):
1056 return "Got a [%s]" % ei[0].__name__
1057
1058
1059class ConfigFileTest(BaseTest):
1060
1061 """Reading logging config from a .ini-style config file."""
1062
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001063 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001064
1065 # config0 is a standard configuration.
1066 config0 = """
1067 [loggers]
1068 keys=root
1069
1070 [handlers]
1071 keys=hand1
1072
1073 [formatters]
1074 keys=form1
1075
1076 [logger_root]
1077 level=WARNING
1078 handlers=hand1
1079
1080 [handler_hand1]
1081 class=StreamHandler
1082 level=NOTSET
1083 formatter=form1
1084 args=(sys.stdout,)
1085
1086 [formatter_form1]
1087 format=%(levelname)s ++ %(message)s
1088 datefmt=
1089 """
1090
1091 # config1 adds a little to the standard configuration.
1092 config1 = """
1093 [loggers]
1094 keys=root,parser
1095
1096 [handlers]
1097 keys=hand1
1098
1099 [formatters]
1100 keys=form1
1101
1102 [logger_root]
1103 level=WARNING
1104 handlers=
1105
1106 [logger_parser]
1107 level=DEBUG
1108 handlers=hand1
1109 propagate=1
1110 qualname=compiler.parser
1111
1112 [handler_hand1]
1113 class=StreamHandler
1114 level=NOTSET
1115 formatter=form1
1116 args=(sys.stdout,)
1117
1118 [formatter_form1]
1119 format=%(levelname)s ++ %(message)s
1120 datefmt=
1121 """
1122
Vinay Sajip3f84b072011-03-07 17:49:33 +00001123 # config1a moves the handler to the root.
1124 config1a = """
1125 [loggers]
1126 keys=root,parser
1127
1128 [handlers]
1129 keys=hand1
1130
1131 [formatters]
1132 keys=form1
1133
1134 [logger_root]
1135 level=WARNING
1136 handlers=hand1
1137
1138 [logger_parser]
1139 level=DEBUG
1140 handlers=
1141 propagate=1
1142 qualname=compiler.parser
1143
1144 [handler_hand1]
1145 class=StreamHandler
1146 level=NOTSET
1147 formatter=form1
1148 args=(sys.stdout,)
1149
1150 [formatter_form1]
1151 format=%(levelname)s ++ %(message)s
1152 datefmt=
1153 """
1154
Christian Heimes180510d2008-03-03 19:15:45 +00001155 # config2 has a subtle configuration error that should be reported
1156 config2 = config1.replace("sys.stdout", "sys.stbout")
1157
1158 # config3 has a less subtle configuration error
1159 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1160
1161 # config4 specifies a custom formatter class to be loaded
1162 config4 = """
1163 [loggers]
1164 keys=root
1165
1166 [handlers]
1167 keys=hand1
1168
1169 [formatters]
1170 keys=form1
1171
1172 [logger_root]
1173 level=NOTSET
1174 handlers=hand1
1175
1176 [handler_hand1]
1177 class=StreamHandler
1178 level=NOTSET
1179 formatter=form1
1180 args=(sys.stdout,)
1181
1182 [formatter_form1]
1183 class=""" + __name__ + """.ExceptionFormatter
1184 format=%(levelname)s:%(name)s:%(message)s
1185 datefmt=
1186 """
1187
Georg Brandl3dbca812008-07-23 16:10:53 +00001188 # config5 specifies a custom handler class to be loaded
1189 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1190
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001191 # config6 uses ', ' delimiters in the handlers and formatters sections
1192 config6 = """
1193 [loggers]
1194 keys=root,parser
1195
1196 [handlers]
1197 keys=hand1, hand2
1198
1199 [formatters]
1200 keys=form1, form2
1201
1202 [logger_root]
1203 level=WARNING
1204 handlers=
1205
1206 [logger_parser]
1207 level=DEBUG
1208 handlers=hand1
1209 propagate=1
1210 qualname=compiler.parser
1211
1212 [handler_hand1]
1213 class=StreamHandler
1214 level=NOTSET
1215 formatter=form1
1216 args=(sys.stdout,)
1217
1218 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001219 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001220 level=NOTSET
1221 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001222 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001223
1224 [formatter_form1]
1225 format=%(levelname)s ++ %(message)s
1226 datefmt=
1227
1228 [formatter_form2]
1229 format=%(message)s
1230 datefmt=
1231 """
1232
Vinay Sajip3f84b072011-03-07 17:49:33 +00001233 # config7 adds a compiler logger.
1234 config7 = """
1235 [loggers]
1236 keys=root,parser,compiler
1237
1238 [handlers]
1239 keys=hand1
1240
1241 [formatters]
1242 keys=form1
1243
1244 [logger_root]
1245 level=WARNING
1246 handlers=hand1
1247
1248 [logger_compiler]
1249 level=DEBUG
1250 handlers=
1251 propagate=1
1252 qualname=compiler
1253
1254 [logger_parser]
1255 level=DEBUG
1256 handlers=
1257 propagate=1
1258 qualname=compiler.parser
1259
1260 [handler_hand1]
1261 class=StreamHandler
1262 level=NOTSET
1263 formatter=form1
1264 args=(sys.stdout,)
1265
1266 [formatter_form1]
1267 format=%(levelname)s ++ %(message)s
1268 datefmt=
1269 """
1270
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001271 disable_test = """
1272 [loggers]
1273 keys=root
1274
1275 [handlers]
1276 keys=screen
1277
1278 [formatters]
1279 keys=
1280
1281 [logger_root]
1282 level=DEBUG
1283 handlers=screen
1284
1285 [handler_screen]
1286 level=DEBUG
1287 class=StreamHandler
1288 args=(sys.stdout,)
1289 formatter=
1290 """
1291
1292 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001293 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001294 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001295
1296 def test_config0_ok(self):
1297 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001298 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001299 self.apply_config(self.config0)
1300 logger = logging.getLogger()
1301 # Won't output anything
1302 logger.info(self.next_message())
1303 # Outputs a message
1304 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001305 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001306 ('ERROR', '2'),
1307 ], stream=output)
1308 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001309 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001310
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001311 def test_config0_using_cp_ok(self):
1312 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001313 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001314 file = io.StringIO(textwrap.dedent(self.config0))
1315 cp = configparser.ConfigParser()
1316 cp.read_file(file)
1317 logging.config.fileConfig(cp)
1318 logger = logging.getLogger()
1319 # Won't output anything
1320 logger.info(self.next_message())
1321 # Outputs a message
1322 logger.error(self.next_message())
1323 self.assert_log_lines([
1324 ('ERROR', '2'),
1325 ], stream=output)
1326 # Original logger output is empty.
1327 self.assert_log_lines([])
1328
Georg Brandl3dbca812008-07-23 16:10:53 +00001329 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001330 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001331 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001332 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001333 logger = logging.getLogger("compiler.parser")
1334 # Both will output a message
1335 logger.info(self.next_message())
1336 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001337 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001338 ('INFO', '1'),
1339 ('ERROR', '2'),
1340 ], stream=output)
1341 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001342 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001343
1344 def test_config2_failure(self):
1345 # A simple config file which overrides the default settings.
1346 self.assertRaises(Exception, self.apply_config, self.config2)
1347
1348 def test_config3_failure(self):
1349 # A simple config file which overrides the default settings.
1350 self.assertRaises(Exception, self.apply_config, self.config3)
1351
1352 def test_config4_ok(self):
1353 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001354 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001355 self.apply_config(self.config4)
1356 logger = logging.getLogger()
1357 try:
1358 raise RuntimeError()
1359 except RuntimeError:
1360 logging.exception("just testing")
1361 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001362 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001363 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1364 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001365 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001366
Georg Brandl3dbca812008-07-23 16:10:53 +00001367 def test_config5_ok(self):
1368 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001369
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001370 def test_config6_ok(self):
1371 self.test_config1_ok(config=self.config6)
1372
Vinay Sajip3f84b072011-03-07 17:49:33 +00001373 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001374 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001375 self.apply_config(self.config1a)
1376 logger = logging.getLogger("compiler.parser")
1377 # See issue #11424. compiler-hyphenated sorts
1378 # between compiler and compiler.xyz and this
1379 # was preventing compiler.xyz from being included
1380 # in the child loggers of compiler because of an
1381 # overzealous loop termination condition.
1382 hyphenated = logging.getLogger('compiler-hyphenated')
1383 # All will output a message
1384 logger.info(self.next_message())
1385 logger.error(self.next_message())
1386 hyphenated.critical(self.next_message())
1387 self.assert_log_lines([
1388 ('INFO', '1'),
1389 ('ERROR', '2'),
1390 ('CRITICAL', '3'),
1391 ], stream=output)
1392 # Original logger output is empty.
1393 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001394 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001395 self.apply_config(self.config7)
1396 logger = logging.getLogger("compiler.parser")
1397 self.assertFalse(logger.disabled)
1398 # Both will output a message
1399 logger.info(self.next_message())
1400 logger.error(self.next_message())
1401 logger = logging.getLogger("compiler.lexer")
1402 # Both will output a message
1403 logger.info(self.next_message())
1404 logger.error(self.next_message())
1405 # Will not appear
1406 hyphenated.critical(self.next_message())
1407 self.assert_log_lines([
1408 ('INFO', '4'),
1409 ('ERROR', '5'),
1410 ('INFO', '6'),
1411 ('ERROR', '7'),
1412 ], stream=output)
1413 # Original logger output is empty.
1414 self.assert_log_lines([])
1415
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001416 def test_logger_disabling(self):
1417 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001418 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001419 self.assertFalse(logger.disabled)
1420 self.apply_config(self.disable_test)
1421 self.assertTrue(logger.disabled)
1422 self.apply_config(self.disable_test, disable_existing_loggers=False)
1423 self.assertFalse(logger.disabled)
1424
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001425
Victor Stinner45df8202010-04-28 22:31:17 +00001426@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001427class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001428
Christian Heimes180510d2008-03-03 19:15:45 +00001429 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001430
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001431 if threading:
1432 server_class = TestTCPServer
1433 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001434
Christian Heimes180510d2008-03-03 19:15:45 +00001435 def setUp(self):
1436 """Set up a TCP server to receive log messages, and a SocketHandler
1437 pointing to that server's address and port."""
1438 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001439 self.server = server = self.server_class(self.address,
1440 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001441 server.start()
1442 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001443 hcls = logging.handlers.SocketHandler
1444 if isinstance(server.server_address, tuple):
1445 self.sock_hdlr = hcls('localhost', server.port)
1446 else:
1447 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001448 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001449 self.root_logger.removeHandler(self.root_logger.handlers[0])
1450 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001451 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001452
Christian Heimes180510d2008-03-03 19:15:45 +00001453 def tearDown(self):
1454 """Shutdown the TCP server."""
1455 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001456 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001457 self.root_logger.removeHandler(self.sock_hdlr)
1458 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001459 finally:
1460 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001461
Vinay Sajip7367d082011-05-02 13:17:27 +01001462 def handle_socket(self, request):
1463 conn = request.connection
1464 while True:
1465 chunk = conn.recv(4)
1466 if len(chunk) < 4:
1467 break
1468 slen = struct.unpack(">L", chunk)[0]
1469 chunk = conn.recv(slen)
1470 while len(chunk) < slen:
1471 chunk = chunk + conn.recv(slen - len(chunk))
1472 obj = pickle.loads(chunk)
1473 record = logging.makeLogRecord(obj)
1474 self.log_output += record.msg + '\n'
1475 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001476
Christian Heimes180510d2008-03-03 19:15:45 +00001477 def test_output(self):
1478 # The log message sent to the SocketHandler is properly received.
1479 logger = logging.getLogger("tcp")
1480 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001481 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001482 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001483 self.handled.acquire()
1484 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001485
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001486 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001487 # Avoid timing-related failures due to SocketHandler's own hard-wired
1488 # one-second timeout on socket.create_connection() (issue #16264).
1489 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001490 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001491 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001492 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001493 try:
1494 raise RuntimeError('Deliberate mistake')
1495 except RuntimeError:
1496 self.root_logger.exception('Never sent')
1497 self.root_logger.error('Never sent, either')
1498 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001499 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001500 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1501 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001502
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001503def _get_temp_domain_socket():
1504 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1505 os.close(fd)
1506 # just need a name - file can't be present, or we'll get an
1507 # 'address already in use' error.
1508 os.remove(fn)
1509 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001510
Victor Stinnerec5a8602014-06-02 14:41:51 +02001511@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001512@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001513class UnixSocketHandlerTest(SocketHandlerTest):
1514
1515 """Test for SocketHandler with unix sockets."""
1516
Victor Stinnerec5a8602014-06-02 14:41:51 +02001517 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001518 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001519
1520 def setUp(self):
1521 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001522 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001523 SocketHandlerTest.setUp(self)
1524
1525 def tearDown(self):
1526 SocketHandlerTest.tearDown(self)
1527 os.remove(self.address)
1528
1529@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001530class DatagramHandlerTest(BaseTest):
1531
1532 """Test for DatagramHandler."""
1533
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001534 if threading:
1535 server_class = TestUDPServer
1536 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001537
Vinay Sajip7367d082011-05-02 13:17:27 +01001538 def setUp(self):
1539 """Set up a UDP server to receive log messages, and a DatagramHandler
1540 pointing to that server's address and port."""
1541 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001542 self.server = server = self.server_class(self.address,
1543 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001544 server.start()
1545 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001546 hcls = logging.handlers.DatagramHandler
1547 if isinstance(server.server_address, tuple):
1548 self.sock_hdlr = hcls('localhost', server.port)
1549 else:
1550 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001551 self.log_output = ''
1552 self.root_logger.removeHandler(self.root_logger.handlers[0])
1553 self.root_logger.addHandler(self.sock_hdlr)
1554 self.handled = threading.Event()
1555
1556 def tearDown(self):
1557 """Shutdown the UDP server."""
1558 try:
1559 self.server.stop(2.0)
1560 self.root_logger.removeHandler(self.sock_hdlr)
1561 self.sock_hdlr.close()
1562 finally:
1563 BaseTest.tearDown(self)
1564
1565 def handle_datagram(self, request):
1566 slen = struct.pack('>L', 0) # length of prefix
1567 packet = request.packet[len(slen):]
1568 obj = pickle.loads(packet)
1569 record = logging.makeLogRecord(obj)
1570 self.log_output += record.msg + '\n'
1571 self.handled.set()
1572
1573 def test_output(self):
1574 # The log message sent to the DatagramHandler is properly received.
1575 logger = logging.getLogger("udp")
1576 logger.error("spam")
1577 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001578 self.handled.clear()
1579 logger.error("eggs")
1580 self.handled.wait()
1581 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001582
Victor Stinnerec5a8602014-06-02 14:41:51 +02001583@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001584@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001585class UnixDatagramHandlerTest(DatagramHandlerTest):
1586
1587 """Test for DatagramHandler using Unix sockets."""
1588
Victor Stinnerec5a8602014-06-02 14:41:51 +02001589 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001590 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001591
1592 def setUp(self):
1593 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001594 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001595 DatagramHandlerTest.setUp(self)
1596
1597 def tearDown(self):
1598 DatagramHandlerTest.tearDown(self)
1599 os.remove(self.address)
1600
1601@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001602class SysLogHandlerTest(BaseTest):
1603
1604 """Test for SysLogHandler using UDP."""
1605
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001606 if threading:
1607 server_class = TestUDPServer
1608 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001609
Vinay Sajip7367d082011-05-02 13:17:27 +01001610 def setUp(self):
1611 """Set up a UDP server to receive log messages, and a SysLogHandler
1612 pointing to that server's address and port."""
1613 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001614 self.server = server = self.server_class(self.address,
1615 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001616 server.start()
1617 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001618 hcls = logging.handlers.SysLogHandler
1619 if isinstance(server.server_address, tuple):
1620 self.sl_hdlr = hcls(('localhost', server.port))
1621 else:
1622 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001623 self.log_output = ''
1624 self.root_logger.removeHandler(self.root_logger.handlers[0])
1625 self.root_logger.addHandler(self.sl_hdlr)
1626 self.handled = threading.Event()
1627
1628 def tearDown(self):
1629 """Shutdown the UDP server."""
1630 try:
1631 self.server.stop(2.0)
1632 self.root_logger.removeHandler(self.sl_hdlr)
1633 self.sl_hdlr.close()
1634 finally:
1635 BaseTest.tearDown(self)
1636
1637 def handle_datagram(self, request):
1638 self.log_output = request.packet
1639 self.handled.set()
1640
1641 def test_output(self):
1642 # The log message sent to the SysLogHandler is properly received.
1643 logger = logging.getLogger("slh")
1644 logger.error("sp\xe4m")
1645 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001646 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001647 self.handled.clear()
1648 self.sl_hdlr.append_nul = False
1649 logger.error("sp\xe4m")
1650 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001651 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001652 self.handled.clear()
1653 self.sl_hdlr.ident = "h\xe4m-"
1654 logger.error("sp\xe4m")
1655 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001656 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001657
Victor Stinnerec5a8602014-06-02 14:41:51 +02001658@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001659@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001660class UnixSysLogHandlerTest(SysLogHandlerTest):
1661
1662 """Test for SysLogHandler with Unix sockets."""
1663
Victor Stinnerec5a8602014-06-02 14:41:51 +02001664 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001665 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001666
1667 def setUp(self):
1668 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001669 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001670 SysLogHandlerTest.setUp(self)
1671
1672 def tearDown(self):
1673 SysLogHandlerTest.tearDown(self)
1674 os.remove(self.address)
1675
Vinay Sajip5421f352013-09-27 18:18:28 +01001676@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001677class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001678 """Test for HTTPHandler."""
1679
1680 def setUp(self):
1681 """Set up an HTTP server to receive log messages, and a HTTPHandler
1682 pointing to that server's address and port."""
1683 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001684 self.handled = threading.Event()
1685
Vinay Sajip7367d082011-05-02 13:17:27 +01001686 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001687 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001688 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001689 if self.command == 'POST':
1690 try:
1691 rlen = int(request.headers['Content-Length'])
1692 self.post_data = request.rfile.read(rlen)
1693 except:
1694 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001695 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001696 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001697 self.handled.set()
1698
1699 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001700 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001701 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001702 root_logger = self.root_logger
1703 root_logger.removeHandler(self.root_logger.handlers[0])
1704 for secure in (False, True):
1705 addr = ('localhost', 0)
1706 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001707 try:
1708 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001709 except ImportError:
1710 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001711 else:
1712 here = os.path.dirname(__file__)
1713 localhost_cert = os.path.join(here, "keycert.pem")
1714 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1715 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001716
1717 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001718 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001719 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001720 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001721 self.server = server = TestHTTPServer(addr, self.handle_request,
1722 0.01, sslctx=sslctx)
1723 server.start()
1724 server.ready.wait()
1725 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001726 secure_client = secure and sslctx
1727 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001728 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001729 context=context,
1730 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001731 self.log_data = None
1732 root_logger.addHandler(self.h_hdlr)
1733
1734 for method in ('GET', 'POST'):
1735 self.h_hdlr.method = method
1736 self.handled.clear()
1737 msg = "sp\xe4m"
1738 logger.error(msg)
1739 self.handled.wait()
1740 self.assertEqual(self.log_data.path, '/frob')
1741 self.assertEqual(self.command, method)
1742 if method == 'GET':
1743 d = parse_qs(self.log_data.query)
1744 else:
1745 d = parse_qs(self.post_data.decode('utf-8'))
1746 self.assertEqual(d['name'], ['http'])
1747 self.assertEqual(d['funcName'], ['test_output'])
1748 self.assertEqual(d['msg'], [msg])
1749
1750 self.server.stop(2.0)
1751 self.root_logger.removeHandler(self.h_hdlr)
1752 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001753
Christian Heimes180510d2008-03-03 19:15:45 +00001754class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001755
Christian Heimes180510d2008-03-03 19:15:45 +00001756 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001757
Christian Heimes180510d2008-03-03 19:15:45 +00001758 def setUp(self):
1759 """Create a dict to remember potentially destroyed objects."""
1760 BaseTest.setUp(self)
1761 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001762
Christian Heimes180510d2008-03-03 19:15:45 +00001763 def _watch_for_survival(self, *args):
1764 """Watch the given objects for survival, by creating weakrefs to
1765 them."""
1766 for obj in args:
1767 key = id(obj), repr(obj)
1768 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001769
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001770 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001771 """Assert that all objects watched for survival have survived."""
1772 # Trigger cycle breaking.
1773 gc.collect()
1774 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001775 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001776 if ref() is None:
1777 dead.append(repr_)
1778 if dead:
1779 self.fail("%d objects should have survived "
1780 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001781
Christian Heimes180510d2008-03-03 19:15:45 +00001782 def test_persistent_loggers(self):
1783 # Logger objects are persistent and retain their configuration, even
1784 # if visible references are destroyed.
1785 self.root_logger.setLevel(logging.INFO)
1786 foo = logging.getLogger("foo")
1787 self._watch_for_survival(foo)
1788 foo.setLevel(logging.DEBUG)
1789 self.root_logger.debug(self.next_message())
1790 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001791 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001792 ('foo', 'DEBUG', '2'),
1793 ])
1794 del foo
1795 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001796 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001797 # foo has retained its settings.
1798 bar = logging.getLogger("foo")
1799 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001800 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001801 ('foo', 'DEBUG', '2'),
1802 ('foo', 'DEBUG', '3'),
1803 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001804
Benjamin Petersonf91df042009-02-13 02:50:59 +00001805
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001806class EncodingTest(BaseTest):
1807 def test_encoding_plain_file(self):
1808 # In Python 2.x, a plain file object is treated as having no encoding.
1809 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001810 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1811 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001812 # the non-ascii data we write to the log.
1813 data = "foo\x80"
1814 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001815 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001816 log.addHandler(handler)
1817 try:
1818 # write non-ascii data to the log.
1819 log.warning(data)
1820 finally:
1821 log.removeHandler(handler)
1822 handler.close()
1823 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001824 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001825 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001826 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001827 finally:
1828 f.close()
1829 finally:
1830 if os.path.isfile(fn):
1831 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001832
Benjamin Petersonf91df042009-02-13 02:50:59 +00001833 def test_encoding_cyrillic_unicode(self):
1834 log = logging.getLogger("test")
1835 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1836 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1837 #Ensure it's written in a Cyrillic encoding
1838 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001839 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001840 stream = io.BytesIO()
1841 writer = writer_class(stream, 'strict')
1842 handler = logging.StreamHandler(writer)
1843 log.addHandler(handler)
1844 try:
1845 log.warning(message)
1846 finally:
1847 log.removeHandler(handler)
1848 handler.close()
1849 # check we wrote exactly those bytes, ignoring trailing \n etc
1850 s = stream.getvalue()
1851 #Compare against what the data should be when encoded in CP-1251
1852 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1853
1854
Georg Brandlf9734072008-12-07 15:30:06 +00001855class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001856
Georg Brandlf9734072008-12-07 15:30:06 +00001857 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001858 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001859 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001860 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001861 warnings.filterwarnings("always", category=UserWarning)
1862 stream = io.StringIO()
1863 h = logging.StreamHandler(stream)
1864 logger = logging.getLogger("py.warnings")
1865 logger.addHandler(h)
1866 warnings.warn("I'm warning you...")
1867 logger.removeHandler(h)
1868 s = stream.getvalue()
1869 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001870 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001871
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001872 #See if an explicit file uses the original implementation
1873 a_file = io.StringIO()
1874 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1875 a_file, "Dummy line")
1876 s = a_file.getvalue()
1877 a_file.close()
1878 self.assertEqual(s,
1879 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1880
1881 def test_warnings_no_handlers(self):
1882 with warnings.catch_warnings():
1883 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001884 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001885
1886 # confirm our assumption: no loggers are set
1887 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001888 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001889
1890 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001891 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001892 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001893
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001894
1895def formatFunc(format, datefmt=None):
1896 return logging.Formatter(format, datefmt)
1897
1898def handlerFunc():
1899 return logging.StreamHandler()
1900
1901class CustomHandler(logging.StreamHandler):
1902 pass
1903
1904class ConfigDictTest(BaseTest):
1905
1906 """Reading logging config from a dictionary."""
1907
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001908 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001909
1910 # config0 is a standard configuration.
1911 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001912 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001913 'formatters': {
1914 'form1' : {
1915 'format' : '%(levelname)s ++ %(message)s',
1916 },
1917 },
1918 'handlers' : {
1919 'hand1' : {
1920 'class' : 'logging.StreamHandler',
1921 'formatter' : 'form1',
1922 'level' : 'NOTSET',
1923 'stream' : 'ext://sys.stdout',
1924 },
1925 },
1926 'root' : {
1927 'level' : 'WARNING',
1928 'handlers' : ['hand1'],
1929 },
1930 }
1931
1932 # config1 adds a little to the standard configuration.
1933 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001934 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001935 'formatters': {
1936 'form1' : {
1937 'format' : '%(levelname)s ++ %(message)s',
1938 },
1939 },
1940 'handlers' : {
1941 'hand1' : {
1942 'class' : 'logging.StreamHandler',
1943 'formatter' : 'form1',
1944 'level' : 'NOTSET',
1945 'stream' : 'ext://sys.stdout',
1946 },
1947 },
1948 'loggers' : {
1949 'compiler.parser' : {
1950 'level' : 'DEBUG',
1951 'handlers' : ['hand1'],
1952 },
1953 },
1954 'root' : {
1955 'level' : 'WARNING',
1956 },
1957 }
1958
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001959 # config1a moves the handler to the root. Used with config8a
1960 config1a = {
1961 'version': 1,
1962 'formatters': {
1963 'form1' : {
1964 'format' : '%(levelname)s ++ %(message)s',
1965 },
1966 },
1967 'handlers' : {
1968 'hand1' : {
1969 'class' : 'logging.StreamHandler',
1970 'formatter' : 'form1',
1971 'level' : 'NOTSET',
1972 'stream' : 'ext://sys.stdout',
1973 },
1974 },
1975 'loggers' : {
1976 'compiler.parser' : {
1977 'level' : 'DEBUG',
1978 },
1979 },
1980 'root' : {
1981 'level' : 'WARNING',
1982 'handlers' : ['hand1'],
1983 },
1984 }
1985
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001986 # config2 has a subtle configuration error that should be reported
1987 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001988 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001989 'formatters': {
1990 'form1' : {
1991 'format' : '%(levelname)s ++ %(message)s',
1992 },
1993 },
1994 'handlers' : {
1995 'hand1' : {
1996 'class' : 'logging.StreamHandler',
1997 'formatter' : 'form1',
1998 'level' : 'NOTSET',
1999 'stream' : 'ext://sys.stdbout',
2000 },
2001 },
2002 'loggers' : {
2003 'compiler.parser' : {
2004 'level' : 'DEBUG',
2005 'handlers' : ['hand1'],
2006 },
2007 },
2008 'root' : {
2009 'level' : 'WARNING',
2010 },
2011 }
2012
2013 #As config1 but with a misspelt level on a handler
2014 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002015 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002016 'formatters': {
2017 'form1' : {
2018 'format' : '%(levelname)s ++ %(message)s',
2019 },
2020 },
2021 'handlers' : {
2022 'hand1' : {
2023 'class' : 'logging.StreamHandler',
2024 'formatter' : 'form1',
2025 'level' : 'NTOSET',
2026 'stream' : 'ext://sys.stdout',
2027 },
2028 },
2029 'loggers' : {
2030 'compiler.parser' : {
2031 'level' : 'DEBUG',
2032 'handlers' : ['hand1'],
2033 },
2034 },
2035 'root' : {
2036 'level' : 'WARNING',
2037 },
2038 }
2039
2040
2041 #As config1 but with a misspelt level on a logger
2042 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002043 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002044 'formatters': {
2045 'form1' : {
2046 'format' : '%(levelname)s ++ %(message)s',
2047 },
2048 },
2049 'handlers' : {
2050 'hand1' : {
2051 'class' : 'logging.StreamHandler',
2052 'formatter' : 'form1',
2053 'level' : 'NOTSET',
2054 'stream' : 'ext://sys.stdout',
2055 },
2056 },
2057 'loggers' : {
2058 'compiler.parser' : {
2059 'level' : 'DEBUG',
2060 'handlers' : ['hand1'],
2061 },
2062 },
2063 'root' : {
2064 'level' : 'WRANING',
2065 },
2066 }
2067
2068 # config3 has a less subtle configuration error
2069 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002070 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002071 'formatters': {
2072 'form1' : {
2073 'format' : '%(levelname)s ++ %(message)s',
2074 },
2075 },
2076 'handlers' : {
2077 'hand1' : {
2078 'class' : 'logging.StreamHandler',
2079 'formatter' : 'misspelled_name',
2080 'level' : 'NOTSET',
2081 'stream' : 'ext://sys.stdout',
2082 },
2083 },
2084 'loggers' : {
2085 'compiler.parser' : {
2086 'level' : 'DEBUG',
2087 'handlers' : ['hand1'],
2088 },
2089 },
2090 'root' : {
2091 'level' : 'WARNING',
2092 },
2093 }
2094
2095 # config4 specifies a custom formatter class to be loaded
2096 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002097 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002098 'formatters': {
2099 'form1' : {
2100 '()' : __name__ + '.ExceptionFormatter',
2101 'format' : '%(levelname)s:%(name)s:%(message)s',
2102 },
2103 },
2104 'handlers' : {
2105 'hand1' : {
2106 'class' : 'logging.StreamHandler',
2107 'formatter' : 'form1',
2108 'level' : 'NOTSET',
2109 'stream' : 'ext://sys.stdout',
2110 },
2111 },
2112 'root' : {
2113 'level' : 'NOTSET',
2114 'handlers' : ['hand1'],
2115 },
2116 }
2117
2118 # As config4 but using an actual callable rather than a string
2119 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002120 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002121 'formatters': {
2122 'form1' : {
2123 '()' : ExceptionFormatter,
2124 'format' : '%(levelname)s:%(name)s:%(message)s',
2125 },
2126 'form2' : {
2127 '()' : __name__ + '.formatFunc',
2128 'format' : '%(levelname)s:%(name)s:%(message)s',
2129 },
2130 'form3' : {
2131 '()' : formatFunc,
2132 'format' : '%(levelname)s:%(name)s:%(message)s',
2133 },
2134 },
2135 'handlers' : {
2136 'hand1' : {
2137 'class' : 'logging.StreamHandler',
2138 'formatter' : 'form1',
2139 'level' : 'NOTSET',
2140 'stream' : 'ext://sys.stdout',
2141 },
2142 'hand2' : {
2143 '()' : handlerFunc,
2144 },
2145 },
2146 'root' : {
2147 'level' : 'NOTSET',
2148 'handlers' : ['hand1'],
2149 },
2150 }
2151
2152 # config5 specifies a custom handler class to be loaded
2153 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002154 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002155 'formatters': {
2156 'form1' : {
2157 'format' : '%(levelname)s ++ %(message)s',
2158 },
2159 },
2160 'handlers' : {
2161 'hand1' : {
2162 'class' : __name__ + '.CustomHandler',
2163 'formatter' : 'form1',
2164 'level' : 'NOTSET',
2165 'stream' : 'ext://sys.stdout',
2166 },
2167 },
2168 'loggers' : {
2169 'compiler.parser' : {
2170 'level' : 'DEBUG',
2171 'handlers' : ['hand1'],
2172 },
2173 },
2174 'root' : {
2175 'level' : 'WARNING',
2176 },
2177 }
2178
2179 # config6 specifies a custom handler class to be loaded
2180 # but has bad arguments
2181 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002182 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002183 'formatters': {
2184 'form1' : {
2185 'format' : '%(levelname)s ++ %(message)s',
2186 },
2187 },
2188 'handlers' : {
2189 'hand1' : {
2190 'class' : __name__ + '.CustomHandler',
2191 'formatter' : 'form1',
2192 'level' : 'NOTSET',
2193 'stream' : 'ext://sys.stdout',
2194 '9' : 'invalid parameter name',
2195 },
2196 },
2197 'loggers' : {
2198 'compiler.parser' : {
2199 'level' : 'DEBUG',
2200 'handlers' : ['hand1'],
2201 },
2202 },
2203 'root' : {
2204 'level' : 'WARNING',
2205 },
2206 }
2207
2208 #config 7 does not define compiler.parser but defines compiler.lexer
2209 #so compiler.parser should be disabled after applying it
2210 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002211 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002212 'formatters': {
2213 'form1' : {
2214 'format' : '%(levelname)s ++ %(message)s',
2215 },
2216 },
2217 'handlers' : {
2218 'hand1' : {
2219 'class' : 'logging.StreamHandler',
2220 'formatter' : 'form1',
2221 'level' : 'NOTSET',
2222 'stream' : 'ext://sys.stdout',
2223 },
2224 },
2225 'loggers' : {
2226 'compiler.lexer' : {
2227 'level' : 'DEBUG',
2228 'handlers' : ['hand1'],
2229 },
2230 },
2231 'root' : {
2232 'level' : 'WARNING',
2233 },
2234 }
2235
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002236 # config8 defines both compiler and compiler.lexer
2237 # so compiler.parser should not be disabled (since
2238 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002239 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002240 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002241 'disable_existing_loggers' : False,
2242 'formatters': {
2243 'form1' : {
2244 'format' : '%(levelname)s ++ %(message)s',
2245 },
2246 },
2247 'handlers' : {
2248 'hand1' : {
2249 'class' : 'logging.StreamHandler',
2250 'formatter' : 'form1',
2251 'level' : 'NOTSET',
2252 'stream' : 'ext://sys.stdout',
2253 },
2254 },
2255 'loggers' : {
2256 'compiler' : {
2257 'level' : 'DEBUG',
2258 'handlers' : ['hand1'],
2259 },
2260 'compiler.lexer' : {
2261 },
2262 },
2263 'root' : {
2264 'level' : 'WARNING',
2265 },
2266 }
2267
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002268 # config8a disables existing loggers
2269 config8a = {
2270 'version': 1,
2271 'disable_existing_loggers' : True,
2272 'formatters': {
2273 'form1' : {
2274 'format' : '%(levelname)s ++ %(message)s',
2275 },
2276 },
2277 'handlers' : {
2278 'hand1' : {
2279 'class' : 'logging.StreamHandler',
2280 'formatter' : 'form1',
2281 'level' : 'NOTSET',
2282 'stream' : 'ext://sys.stdout',
2283 },
2284 },
2285 'loggers' : {
2286 'compiler' : {
2287 'level' : 'DEBUG',
2288 'handlers' : ['hand1'],
2289 },
2290 'compiler.lexer' : {
2291 },
2292 },
2293 'root' : {
2294 'level' : 'WARNING',
2295 },
2296 }
2297
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002298 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002299 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002300 'formatters': {
2301 'form1' : {
2302 'format' : '%(levelname)s ++ %(message)s',
2303 },
2304 },
2305 'handlers' : {
2306 'hand1' : {
2307 'class' : 'logging.StreamHandler',
2308 'formatter' : 'form1',
2309 'level' : 'WARNING',
2310 'stream' : 'ext://sys.stdout',
2311 },
2312 },
2313 'loggers' : {
2314 'compiler.parser' : {
2315 'level' : 'WARNING',
2316 'handlers' : ['hand1'],
2317 },
2318 },
2319 'root' : {
2320 'level' : 'NOTSET',
2321 },
2322 }
2323
2324 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002325 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002326 'incremental' : True,
2327 'handlers' : {
2328 'hand1' : {
2329 'level' : 'WARNING',
2330 },
2331 },
2332 'loggers' : {
2333 'compiler.parser' : {
2334 'level' : 'INFO',
2335 },
2336 },
2337 }
2338
2339 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002340 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002341 'incremental' : True,
2342 'handlers' : {
2343 'hand1' : {
2344 'level' : 'INFO',
2345 },
2346 },
2347 'loggers' : {
2348 'compiler.parser' : {
2349 'level' : 'INFO',
2350 },
2351 },
2352 }
2353
2354 #As config1 but with a filter added
2355 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002356 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002357 'formatters': {
2358 'form1' : {
2359 'format' : '%(levelname)s ++ %(message)s',
2360 },
2361 },
2362 'filters' : {
2363 'filt1' : {
2364 'name' : 'compiler.parser',
2365 },
2366 },
2367 'handlers' : {
2368 'hand1' : {
2369 'class' : 'logging.StreamHandler',
2370 'formatter' : 'form1',
2371 'level' : 'NOTSET',
2372 'stream' : 'ext://sys.stdout',
2373 'filters' : ['filt1'],
2374 },
2375 },
2376 'loggers' : {
2377 'compiler.parser' : {
2378 'level' : 'DEBUG',
2379 'filters' : ['filt1'],
2380 },
2381 },
2382 'root' : {
2383 'level' : 'WARNING',
2384 'handlers' : ['hand1'],
2385 },
2386 }
2387
2388 #As config1 but using cfg:// references
2389 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002390 'version': 1,
2391 'true_formatters': {
2392 'form1' : {
2393 'format' : '%(levelname)s ++ %(message)s',
2394 },
2395 },
2396 'handler_configs': {
2397 'hand1' : {
2398 'class' : 'logging.StreamHandler',
2399 'formatter' : 'form1',
2400 'level' : 'NOTSET',
2401 'stream' : 'ext://sys.stdout',
2402 },
2403 },
2404 'formatters' : 'cfg://true_formatters',
2405 'handlers' : {
2406 'hand1' : 'cfg://handler_configs[hand1]',
2407 },
2408 'loggers' : {
2409 'compiler.parser' : {
2410 'level' : 'DEBUG',
2411 'handlers' : ['hand1'],
2412 },
2413 },
2414 'root' : {
2415 'level' : 'WARNING',
2416 },
2417 }
2418
2419 #As config11 but missing the version key
2420 config12 = {
2421 'true_formatters': {
2422 'form1' : {
2423 'format' : '%(levelname)s ++ %(message)s',
2424 },
2425 },
2426 'handler_configs': {
2427 'hand1' : {
2428 'class' : 'logging.StreamHandler',
2429 'formatter' : 'form1',
2430 'level' : 'NOTSET',
2431 'stream' : 'ext://sys.stdout',
2432 },
2433 },
2434 'formatters' : 'cfg://true_formatters',
2435 'handlers' : {
2436 'hand1' : 'cfg://handler_configs[hand1]',
2437 },
2438 'loggers' : {
2439 'compiler.parser' : {
2440 'level' : 'DEBUG',
2441 'handlers' : ['hand1'],
2442 },
2443 },
2444 'root' : {
2445 'level' : 'WARNING',
2446 },
2447 }
2448
2449 #As config11 but using an unsupported version
2450 config13 = {
2451 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002452 'true_formatters': {
2453 'form1' : {
2454 'format' : '%(levelname)s ++ %(message)s',
2455 },
2456 },
2457 'handler_configs': {
2458 'hand1' : {
2459 'class' : 'logging.StreamHandler',
2460 'formatter' : 'form1',
2461 'level' : 'NOTSET',
2462 'stream' : 'ext://sys.stdout',
2463 },
2464 },
2465 'formatters' : 'cfg://true_formatters',
2466 'handlers' : {
2467 'hand1' : 'cfg://handler_configs[hand1]',
2468 },
2469 'loggers' : {
2470 'compiler.parser' : {
2471 'level' : 'DEBUG',
2472 'handlers' : ['hand1'],
2473 },
2474 },
2475 'root' : {
2476 'level' : 'WARNING',
2477 },
2478 }
2479
Vinay Sajip8d270232012-11-15 14:20:18 +00002480 # As config0, but with properties
2481 config14 = {
2482 'version': 1,
2483 'formatters': {
2484 'form1' : {
2485 'format' : '%(levelname)s ++ %(message)s',
2486 },
2487 },
2488 'handlers' : {
2489 'hand1' : {
2490 'class' : 'logging.StreamHandler',
2491 'formatter' : 'form1',
2492 'level' : 'NOTSET',
2493 'stream' : 'ext://sys.stdout',
2494 '.': {
2495 'foo': 'bar',
2496 'terminator': '!\n',
2497 }
2498 },
2499 },
2500 'root' : {
2501 'level' : 'WARNING',
2502 'handlers' : ['hand1'],
2503 },
2504 }
2505
Vinay Sajip3f885b52013-03-22 15:19:54 +00002506 out_of_order = {
2507 "version": 1,
2508 "formatters": {
2509 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002510 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2511 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002512 }
2513 },
2514 "handlers": {
2515 "fileGlobal": {
2516 "class": "logging.StreamHandler",
2517 "level": "DEBUG",
2518 "formatter": "mySimpleFormatter"
2519 },
2520 "bufferGlobal": {
2521 "class": "logging.handlers.MemoryHandler",
2522 "capacity": 5,
2523 "formatter": "mySimpleFormatter",
2524 "target": "fileGlobal",
2525 "level": "DEBUG"
2526 }
2527 },
2528 "loggers": {
2529 "mymodule": {
2530 "level": "DEBUG",
2531 "handlers": ["bufferGlobal"],
2532 "propagate": "true"
2533 }
2534 }
2535 }
2536
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002537 def apply_config(self, conf):
2538 logging.config.dictConfig(conf)
2539
2540 def test_config0_ok(self):
2541 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002542 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002543 self.apply_config(self.config0)
2544 logger = logging.getLogger()
2545 # Won't output anything
2546 logger.info(self.next_message())
2547 # Outputs a message
2548 logger.error(self.next_message())
2549 self.assert_log_lines([
2550 ('ERROR', '2'),
2551 ], stream=output)
2552 # Original logger output is empty.
2553 self.assert_log_lines([])
2554
2555 def test_config1_ok(self, config=config1):
2556 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002557 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002558 self.apply_config(config)
2559 logger = logging.getLogger("compiler.parser")
2560 # Both will output a message
2561 logger.info(self.next_message())
2562 logger.error(self.next_message())
2563 self.assert_log_lines([
2564 ('INFO', '1'),
2565 ('ERROR', '2'),
2566 ], stream=output)
2567 # Original logger output is empty.
2568 self.assert_log_lines([])
2569
2570 def test_config2_failure(self):
2571 # A simple config which overrides the default settings.
2572 self.assertRaises(Exception, self.apply_config, self.config2)
2573
2574 def test_config2a_failure(self):
2575 # A simple config which overrides the default settings.
2576 self.assertRaises(Exception, self.apply_config, self.config2a)
2577
2578 def test_config2b_failure(self):
2579 # A simple config which overrides the default settings.
2580 self.assertRaises(Exception, self.apply_config, self.config2b)
2581
2582 def test_config3_failure(self):
2583 # A simple config which overrides the default settings.
2584 self.assertRaises(Exception, self.apply_config, self.config3)
2585
2586 def test_config4_ok(self):
2587 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002588 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002589 self.apply_config(self.config4)
2590 #logger = logging.getLogger()
2591 try:
2592 raise RuntimeError()
2593 except RuntimeError:
2594 logging.exception("just testing")
2595 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002596 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002597 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2598 # Original logger output is empty
2599 self.assert_log_lines([])
2600
2601 def test_config4a_ok(self):
2602 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002603 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002604 self.apply_config(self.config4a)
2605 #logger = logging.getLogger()
2606 try:
2607 raise RuntimeError()
2608 except RuntimeError:
2609 logging.exception("just testing")
2610 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002611 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002612 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2613 # Original logger output is empty
2614 self.assert_log_lines([])
2615
2616 def test_config5_ok(self):
2617 self.test_config1_ok(config=self.config5)
2618
2619 def test_config6_failure(self):
2620 self.assertRaises(Exception, self.apply_config, self.config6)
2621
2622 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002623 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002624 self.apply_config(self.config1)
2625 logger = logging.getLogger("compiler.parser")
2626 # Both will output a message
2627 logger.info(self.next_message())
2628 logger.error(self.next_message())
2629 self.assert_log_lines([
2630 ('INFO', '1'),
2631 ('ERROR', '2'),
2632 ], stream=output)
2633 # Original logger output is empty.
2634 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002635 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002636 self.apply_config(self.config7)
2637 logger = logging.getLogger("compiler.parser")
2638 self.assertTrue(logger.disabled)
2639 logger = logging.getLogger("compiler.lexer")
2640 # Both will output a message
2641 logger.info(self.next_message())
2642 logger.error(self.next_message())
2643 self.assert_log_lines([
2644 ('INFO', '3'),
2645 ('ERROR', '4'),
2646 ], stream=output)
2647 # Original logger output is empty.
2648 self.assert_log_lines([])
2649
2650 #Same as test_config_7_ok but don't disable old loggers.
2651 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002652 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002653 self.apply_config(self.config1)
2654 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002655 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002656 logger.info(self.next_message())
2657 logger.error(self.next_message())
2658 self.assert_log_lines([
2659 ('INFO', '1'),
2660 ('ERROR', '2'),
2661 ], stream=output)
2662 # Original logger output is empty.
2663 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002664 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002665 self.apply_config(self.config8)
2666 logger = logging.getLogger("compiler.parser")
2667 self.assertFalse(logger.disabled)
2668 # Both will output a message
2669 logger.info(self.next_message())
2670 logger.error(self.next_message())
2671 logger = logging.getLogger("compiler.lexer")
2672 # Both will output a message
2673 logger.info(self.next_message())
2674 logger.error(self.next_message())
2675 self.assert_log_lines([
2676 ('INFO', '3'),
2677 ('ERROR', '4'),
2678 ('INFO', '5'),
2679 ('ERROR', '6'),
2680 ], stream=output)
2681 # Original logger output is empty.
2682 self.assert_log_lines([])
2683
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002684 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002685 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002686 self.apply_config(self.config1a)
2687 logger = logging.getLogger("compiler.parser")
2688 # See issue #11424. compiler-hyphenated sorts
2689 # between compiler and compiler.xyz and this
2690 # was preventing compiler.xyz from being included
2691 # in the child loggers of compiler because of an
2692 # overzealous loop termination condition.
2693 hyphenated = logging.getLogger('compiler-hyphenated')
2694 # All will output a message
2695 logger.info(self.next_message())
2696 logger.error(self.next_message())
2697 hyphenated.critical(self.next_message())
2698 self.assert_log_lines([
2699 ('INFO', '1'),
2700 ('ERROR', '2'),
2701 ('CRITICAL', '3'),
2702 ], stream=output)
2703 # Original logger output is empty.
2704 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002705 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002706 self.apply_config(self.config8a)
2707 logger = logging.getLogger("compiler.parser")
2708 self.assertFalse(logger.disabled)
2709 # Both will output a message
2710 logger.info(self.next_message())
2711 logger.error(self.next_message())
2712 logger = logging.getLogger("compiler.lexer")
2713 # Both will output a message
2714 logger.info(self.next_message())
2715 logger.error(self.next_message())
2716 # Will not appear
2717 hyphenated.critical(self.next_message())
2718 self.assert_log_lines([
2719 ('INFO', '4'),
2720 ('ERROR', '5'),
2721 ('INFO', '6'),
2722 ('ERROR', '7'),
2723 ], stream=output)
2724 # Original logger output is empty.
2725 self.assert_log_lines([])
2726
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002727 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002728 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002729 self.apply_config(self.config9)
2730 logger = logging.getLogger("compiler.parser")
2731 #Nothing will be output since both handler and logger are set to WARNING
2732 logger.info(self.next_message())
2733 self.assert_log_lines([], stream=output)
2734 self.apply_config(self.config9a)
2735 #Nothing will be output since both handler is still set to WARNING
2736 logger.info(self.next_message())
2737 self.assert_log_lines([], stream=output)
2738 self.apply_config(self.config9b)
2739 #Message should now be output
2740 logger.info(self.next_message())
2741 self.assert_log_lines([
2742 ('INFO', '3'),
2743 ], stream=output)
2744
2745 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002746 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002747 self.apply_config(self.config10)
2748 logger = logging.getLogger("compiler.parser")
2749 logger.warning(self.next_message())
2750 logger = logging.getLogger('compiler')
2751 #Not output, because filtered
2752 logger.warning(self.next_message())
2753 logger = logging.getLogger('compiler.lexer')
2754 #Not output, because filtered
2755 logger.warning(self.next_message())
2756 logger = logging.getLogger("compiler.parser.codegen")
2757 #Output, as not filtered
2758 logger.error(self.next_message())
2759 self.assert_log_lines([
2760 ('WARNING', '1'),
2761 ('ERROR', '4'),
2762 ], stream=output)
2763
2764 def test_config11_ok(self):
2765 self.test_config1_ok(self.config11)
2766
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002767 def test_config12_failure(self):
2768 self.assertRaises(Exception, self.apply_config, self.config12)
2769
2770 def test_config13_failure(self):
2771 self.assertRaises(Exception, self.apply_config, self.config13)
2772
Vinay Sajip8d270232012-11-15 14:20:18 +00002773 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002774 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002775 self.apply_config(self.config14)
2776 h = logging._handlers['hand1']
2777 self.assertEqual(h.foo, 'bar')
2778 self.assertEqual(h.terminator, '!\n')
2779 logging.warning('Exclamation')
2780 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2781
Victor Stinner45df8202010-04-28 22:31:17 +00002782 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002783 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002784 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002785 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002786 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002787 t.start()
2788 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002789 # Now get the port allocated
2790 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002791 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002792 try:
2793 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2794 sock.settimeout(2.0)
2795 sock.connect(('localhost', port))
2796
2797 slen = struct.pack('>L', len(text))
2798 s = slen + text
2799 sentsofar = 0
2800 left = len(s)
2801 while left > 0:
2802 sent = sock.send(s[sentsofar:])
2803 sentsofar += sent
2804 left -= sent
2805 sock.close()
2806 finally:
2807 t.ready.wait(2.0)
2808 logging.config.stopListening()
2809 t.join(2.0)
2810
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002811 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002812 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002813 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002814 self.setup_via_listener(json.dumps(self.config10))
2815 logger = logging.getLogger("compiler.parser")
2816 logger.warning(self.next_message())
2817 logger = logging.getLogger('compiler')
2818 #Not output, because filtered
2819 logger.warning(self.next_message())
2820 logger = logging.getLogger('compiler.lexer')
2821 #Not output, because filtered
2822 logger.warning(self.next_message())
2823 logger = logging.getLogger("compiler.parser.codegen")
2824 #Output, as not filtered
2825 logger.error(self.next_message())
2826 self.assert_log_lines([
2827 ('WARNING', '1'),
2828 ('ERROR', '4'),
2829 ], stream=output)
2830
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002831 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002832 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002833 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002834 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2835 logger = logging.getLogger("compiler.parser")
2836 # Both will output a message
2837 logger.info(self.next_message())
2838 logger.error(self.next_message())
2839 self.assert_log_lines([
2840 ('INFO', '1'),
2841 ('ERROR', '2'),
2842 ], stream=output)
2843 # Original logger output is empty.
2844 self.assert_log_lines([])
2845
Vinay Sajip4ded5512012-10-02 15:56:16 +01002846 @unittest.skipUnless(threading, 'Threading required for this test.')
2847 def test_listen_verify(self):
2848
2849 def verify_fail(stuff):
2850 return None
2851
2852 def verify_reverse(stuff):
2853 return stuff[::-1]
2854
2855 logger = logging.getLogger("compiler.parser")
2856 to_send = textwrap.dedent(ConfigFileTest.config1)
2857 # First, specify a verification function that will fail.
2858 # We expect to see no output, since our configuration
2859 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002860 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002861 self.setup_via_listener(to_send, verify_fail)
2862 # Both will output a message
2863 logger.info(self.next_message())
2864 logger.error(self.next_message())
2865 self.assert_log_lines([], stream=output)
2866 # Original logger output has the stuff we logged.
2867 self.assert_log_lines([
2868 ('INFO', '1'),
2869 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002870 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002871
2872 # Now, perform no verification. Our configuration
2873 # should take effect.
2874
Vinay Sajip1feedb42014-05-31 08:19:12 +01002875 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002876 self.setup_via_listener(to_send) # no verify callable specified
2877 logger = logging.getLogger("compiler.parser")
2878 # Both will output a message
2879 logger.info(self.next_message())
2880 logger.error(self.next_message())
2881 self.assert_log_lines([
2882 ('INFO', '3'),
2883 ('ERROR', '4'),
2884 ], stream=output)
2885 # Original logger output still has the stuff we logged before.
2886 self.assert_log_lines([
2887 ('INFO', '1'),
2888 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002889 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002890
2891 # Now, perform verification which transforms the bytes.
2892
Vinay Sajip1feedb42014-05-31 08:19:12 +01002893 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002894 self.setup_via_listener(to_send[::-1], verify_reverse)
2895 logger = logging.getLogger("compiler.parser")
2896 # Both will output a message
2897 logger.info(self.next_message())
2898 logger.error(self.next_message())
2899 self.assert_log_lines([
2900 ('INFO', '5'),
2901 ('ERROR', '6'),
2902 ], stream=output)
2903 # Original logger output still has the stuff we logged before.
2904 self.assert_log_lines([
2905 ('INFO', '1'),
2906 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002907 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002908
Vinay Sajip3f885b52013-03-22 15:19:54 +00002909 def test_out_of_order(self):
2910 self.apply_config(self.out_of_order)
2911 handler = logging.getLogger('mymodule').handlers[0]
2912 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002913 self.assertIsInstance(handler.formatter._style,
2914 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002915
Vinay Sajip373baef2011-04-26 20:05:24 +01002916 def test_baseconfig(self):
2917 d = {
2918 'atuple': (1, 2, 3),
2919 'alist': ['a', 'b', 'c'],
2920 'adict': {'d': 'e', 'f': 3 },
2921 'nest1': ('g', ('h', 'i'), 'j'),
2922 'nest2': ['k', ['l', 'm'], 'n'],
2923 'nest3': ['o', 'cfg://alist', 'p'],
2924 }
2925 bc = logging.config.BaseConfigurator(d)
2926 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2927 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2928 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2929 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2930 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2931 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2932 v = bc.convert('cfg://nest3')
2933 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2934 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2935 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2936 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002937
2938class ManagerTest(BaseTest):
2939 def test_manager_loggerclass(self):
2940 logged = []
2941
2942 class MyLogger(logging.Logger):
2943 def _log(self, level, msg, args, exc_info=None, extra=None):
2944 logged.append(msg)
2945
2946 man = logging.Manager(None)
2947 self.assertRaises(TypeError, man.setLoggerClass, int)
2948 man.setLoggerClass(MyLogger)
2949 logger = man.getLogger('test')
2950 logger.warning('should appear in logged')
2951 logging.warning('should not appear in logged')
2952
2953 self.assertEqual(logged, ['should appear in logged'])
2954
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002955 def test_set_log_record_factory(self):
2956 man = logging.Manager(None)
2957 expected = object()
2958 man.setLogRecordFactory(expected)
2959 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002960
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002961class ChildLoggerTest(BaseTest):
2962 def test_child_loggers(self):
2963 r = logging.getLogger()
2964 l1 = logging.getLogger('abc')
2965 l2 = logging.getLogger('def.ghi')
2966 c1 = r.getChild('xyz')
2967 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002968 self.assertIs(c1, logging.getLogger('xyz'))
2969 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002970 c1 = l1.getChild('def')
2971 c2 = c1.getChild('ghi')
2972 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002973 self.assertIs(c1, logging.getLogger('abc.def'))
2974 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2975 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002976
2977
Vinay Sajip6fac8172010-10-19 20:44:14 +00002978class DerivedLogRecord(logging.LogRecord):
2979 pass
2980
Vinay Sajip61561522010-12-03 11:50:38 +00002981class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002982
2983 def setUp(self):
2984 class CheckingFilter(logging.Filter):
2985 def __init__(self, cls):
2986 self.cls = cls
2987
2988 def filter(self, record):
2989 t = type(record)
2990 if t is not self.cls:
2991 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2992 self.cls)
2993 raise TypeError(msg)
2994 return True
2995
2996 BaseTest.setUp(self)
2997 self.filter = CheckingFilter(DerivedLogRecord)
2998 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002999 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003000
3001 def tearDown(self):
3002 self.root_logger.removeFilter(self.filter)
3003 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003004 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003005
3006 def test_logrecord_class(self):
3007 self.assertRaises(TypeError, self.root_logger.warning,
3008 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003009 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003010 self.root_logger.error(self.next_message())
3011 self.assert_log_lines([
3012 ('root', 'ERROR', '2'),
3013 ])
3014
3015
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003016class QueueHandlerTest(BaseTest):
3017 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003018 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003019
3020 def setUp(self):
3021 BaseTest.setUp(self)
3022 self.queue = queue.Queue(-1)
3023 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3024 self.que_logger = logging.getLogger('que')
3025 self.que_logger.propagate = False
3026 self.que_logger.setLevel(logging.WARNING)
3027 self.que_logger.addHandler(self.que_hdlr)
3028
3029 def tearDown(self):
3030 self.que_hdlr.close()
3031 BaseTest.tearDown(self)
3032
3033 def test_queue_handler(self):
3034 self.que_logger.debug(self.next_message())
3035 self.assertRaises(queue.Empty, self.queue.get_nowait)
3036 self.que_logger.info(self.next_message())
3037 self.assertRaises(queue.Empty, self.queue.get_nowait)
3038 msg = self.next_message()
3039 self.que_logger.warning(msg)
3040 data = self.queue.get_nowait()
3041 self.assertTrue(isinstance(data, logging.LogRecord))
3042 self.assertEqual(data.name, self.que_logger.name)
3043 self.assertEqual((data.msg, data.args), (msg, None))
3044
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003045 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3046 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003047 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003048 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003049 listener = logging.handlers.QueueListener(self.queue, handler)
3050 listener.start()
3051 try:
3052 self.que_logger.warning(self.next_message())
3053 self.que_logger.error(self.next_message())
3054 self.que_logger.critical(self.next_message())
3055 finally:
3056 listener.stop()
3057 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3058 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3059 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003060 handler.close()
3061
3062 # Now test with respect_handler_level set
3063
3064 handler = support.TestHandler(support.Matcher())
3065 handler.setLevel(logging.CRITICAL)
3066 listener = logging.handlers.QueueListener(self.queue, handler,
3067 respect_handler_level=True)
3068 listener.start()
3069 try:
3070 self.que_logger.warning(self.next_message())
3071 self.que_logger.error(self.next_message())
3072 self.que_logger.critical(self.next_message())
3073 finally:
3074 listener.stop()
3075 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3076 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3077 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3078
Vinay Sajipe723e962011-04-15 22:27:17 +01003079
Vinay Sajip37eb3382011-04-26 20:26:41 +01003080ZERO = datetime.timedelta(0)
3081
3082class UTC(datetime.tzinfo):
3083 def utcoffset(self, dt):
3084 return ZERO
3085
3086 dst = utcoffset
3087
3088 def tzname(self, dt):
3089 return 'UTC'
3090
3091utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003092
Vinay Sajipa39c5712010-10-25 13:57:39 +00003093class FormatterTest(unittest.TestCase):
3094 def setUp(self):
3095 self.common = {
3096 'name': 'formatter.test',
3097 'level': logging.DEBUG,
3098 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3099 'lineno': 42,
3100 'exc_info': None,
3101 'func': None,
3102 'msg': 'Message with %d %s',
3103 'args': (2, 'placeholders'),
3104 }
3105 self.variants = {
3106 }
3107
3108 def get_record(self, name=None):
3109 result = dict(self.common)
3110 if name is not None:
3111 result.update(self.variants[name])
3112 return logging.makeLogRecord(result)
3113
3114 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003115 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003116 r = self.get_record()
3117 f = logging.Formatter('${%(message)s}')
3118 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3119 f = logging.Formatter('%(random)s')
3120 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003121 self.assertFalse(f.usesTime())
3122 f = logging.Formatter('%(asctime)s')
3123 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003124 f = logging.Formatter('%(asctime)-15s')
3125 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003126 f = logging.Formatter('asctime')
3127 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003128
3129 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003130 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003131 r = self.get_record()
3132 f = logging.Formatter('$%{message}%$', style='{')
3133 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3134 f = logging.Formatter('{random}', style='{')
3135 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003136 self.assertFalse(f.usesTime())
3137 f = logging.Formatter('{asctime}', style='{')
3138 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003139 f = logging.Formatter('{asctime!s:15}', style='{')
3140 self.assertTrue(f.usesTime())
3141 f = logging.Formatter('{asctime:15}', style='{')
3142 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003143 f = logging.Formatter('asctime', style='{')
3144 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003145
3146 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003147 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003148 r = self.get_record()
3149 f = logging.Formatter('$message', style='$')
3150 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3151 f = logging.Formatter('$$%${message}%$$', style='$')
3152 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3153 f = logging.Formatter('${random}', style='$')
3154 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003155 self.assertFalse(f.usesTime())
3156 f = logging.Formatter('${asctime}', style='$')
3157 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003158 f = logging.Formatter('${asctime', style='$')
3159 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003160 f = logging.Formatter('$asctime', style='$')
3161 self.assertTrue(f.usesTime())
3162 f = logging.Formatter('asctime', style='$')
3163 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003164
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003165 def test_invalid_style(self):
3166 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3167
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003168 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003169 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003170 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3171 # We use None to indicate we want the local timezone
3172 # We're essentially converting a UTC time to local time
3173 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003174 r.msecs = 123
3175 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003176 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003177 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3178 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003179 f.format(r)
3180 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3181
3182class TestBufferingFormatter(logging.BufferingFormatter):
3183 def formatHeader(self, records):
3184 return '[(%d)' % len(records)
3185
3186 def formatFooter(self, records):
3187 return '(%d)]' % len(records)
3188
3189class BufferingFormatterTest(unittest.TestCase):
3190 def setUp(self):
3191 self.records = [
3192 logging.makeLogRecord({'msg': 'one'}),
3193 logging.makeLogRecord({'msg': 'two'}),
3194 ]
3195
3196 def test_default(self):
3197 f = logging.BufferingFormatter()
3198 self.assertEqual('', f.format([]))
3199 self.assertEqual('onetwo', f.format(self.records))
3200
3201 def test_custom(self):
3202 f = TestBufferingFormatter()
3203 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3204 lf = logging.Formatter('<%(message)s>')
3205 f = TestBufferingFormatter(lf)
3206 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003207
3208class ExceptionTest(BaseTest):
3209 def test_formatting(self):
3210 r = self.root_logger
3211 h = RecordingHandler()
3212 r.addHandler(h)
3213 try:
3214 raise RuntimeError('deliberate mistake')
3215 except:
3216 logging.exception('failed', stack_info=True)
3217 r.removeHandler(h)
3218 h.close()
3219 r = h.records[0]
3220 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3221 'call last):\n'))
3222 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3223 'deliberate mistake'))
3224 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3225 'call last):\n'))
3226 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3227 'stack_info=True)'))
3228
3229
Vinay Sajip5a27d402010-12-10 11:42:57 +00003230class LastResortTest(BaseTest):
3231 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003232 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003233 root = self.root_logger
3234 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003235 old_lastresort = logging.lastResort
3236 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003237
Vinay Sajip5a27d402010-12-10 11:42:57 +00003238 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003239 with support.captured_stderr() as stderr:
3240 root.debug('This should not appear')
3241 self.assertEqual(stderr.getvalue(), '')
3242 root.warning('Final chance!')
3243 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3244
3245 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003246 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003247 with support.captured_stderr() as stderr:
3248 root.warning('Final chance!')
3249 msg = 'No handlers could be found for logger "root"\n'
3250 self.assertEqual(stderr.getvalue(), msg)
3251
Vinay Sajip5a27d402010-12-10 11:42:57 +00003252 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003253 with support.captured_stderr() as stderr:
3254 root.warning('Final chance!')
3255 self.assertEqual(stderr.getvalue(), '')
3256
3257 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003258 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003259 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003260 with support.captured_stderr() as stderr:
3261 root.warning('Final chance!')
3262 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003263 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003264 root.addHandler(self.root_hdlr)
3265 logging.lastResort = old_lastresort
3266 logging.raiseExceptions = old_raise_exceptions
3267
3268
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003269class FakeHandler:
3270
3271 def __init__(self, identifier, called):
3272 for method in ('acquire', 'flush', 'close', 'release'):
3273 setattr(self, method, self.record_call(identifier, method, called))
3274
3275 def record_call(self, identifier, method_name, called):
3276 def inner():
3277 called.append('{} - {}'.format(identifier, method_name))
3278 return inner
3279
3280
3281class RecordingHandler(logging.NullHandler):
3282
3283 def __init__(self, *args, **kwargs):
3284 super(RecordingHandler, self).__init__(*args, **kwargs)
3285 self.records = []
3286
3287 def handle(self, record):
3288 """Keep track of all the emitted records."""
3289 self.records.append(record)
3290
3291
3292class ShutdownTest(BaseTest):
3293
Vinay Sajip5e66b162011-04-20 15:41:14 +01003294 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003295
3296 def setUp(self):
3297 super(ShutdownTest, self).setUp()
3298 self.called = []
3299
3300 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003301 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003302
3303 def raise_error(self, error):
3304 def inner():
3305 raise error()
3306 return inner
3307
3308 def test_no_failure(self):
3309 # create some fake handlers
3310 handler0 = FakeHandler(0, self.called)
3311 handler1 = FakeHandler(1, self.called)
3312 handler2 = FakeHandler(2, self.called)
3313
3314 # create live weakref to those handlers
3315 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3316
3317 logging.shutdown(handlerList=list(handlers))
3318
3319 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3320 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3321 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3322 self.assertEqual(expected, self.called)
3323
3324 def _test_with_failure_in_method(self, method, error):
3325 handler = FakeHandler(0, self.called)
3326 setattr(handler, method, self.raise_error(error))
3327 handlers = [logging.weakref.ref(handler)]
3328
3329 logging.shutdown(handlerList=list(handlers))
3330
3331 self.assertEqual('0 - release', self.called[-1])
3332
3333 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003334 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003335
3336 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003337 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003338
3339 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003340 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003341
3342 def test_with_valueerror_in_acquire(self):
3343 self._test_with_failure_in_method('acquire', ValueError)
3344
3345 def test_with_valueerror_in_flush(self):
3346 self._test_with_failure_in_method('flush', ValueError)
3347
3348 def test_with_valueerror_in_close(self):
3349 self._test_with_failure_in_method('close', ValueError)
3350
3351 def test_with_other_error_in_acquire_without_raise(self):
3352 logging.raiseExceptions = False
3353 self._test_with_failure_in_method('acquire', IndexError)
3354
3355 def test_with_other_error_in_flush_without_raise(self):
3356 logging.raiseExceptions = False
3357 self._test_with_failure_in_method('flush', IndexError)
3358
3359 def test_with_other_error_in_close_without_raise(self):
3360 logging.raiseExceptions = False
3361 self._test_with_failure_in_method('close', IndexError)
3362
3363 def test_with_other_error_in_acquire_with_raise(self):
3364 logging.raiseExceptions = True
3365 self.assertRaises(IndexError, self._test_with_failure_in_method,
3366 'acquire', IndexError)
3367
3368 def test_with_other_error_in_flush_with_raise(self):
3369 logging.raiseExceptions = True
3370 self.assertRaises(IndexError, self._test_with_failure_in_method,
3371 'flush', IndexError)
3372
3373 def test_with_other_error_in_close_with_raise(self):
3374 logging.raiseExceptions = True
3375 self.assertRaises(IndexError, self._test_with_failure_in_method,
3376 'close', IndexError)
3377
3378
3379class ModuleLevelMiscTest(BaseTest):
3380
Vinay Sajip5e66b162011-04-20 15:41:14 +01003381 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003382
3383 def test_disable(self):
3384 old_disable = logging.root.manager.disable
3385 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003386 self.assertEqual(old_disable, 0)
3387 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003388
3389 logging.disable(83)
3390 self.assertEqual(logging.root.manager.disable, 83)
3391
3392 def _test_log(self, method, level=None):
3393 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003394 support.patch(self, logging, 'basicConfig',
3395 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003396
3397 recording = RecordingHandler()
3398 logging.root.addHandler(recording)
3399
3400 log_method = getattr(logging, method)
3401 if level is not None:
3402 log_method(level, "test me: %r", recording)
3403 else:
3404 log_method("test me: %r", recording)
3405
3406 self.assertEqual(len(recording.records), 1)
3407 record = recording.records[0]
3408 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3409
3410 expected_level = level if level is not None else getattr(logging, method.upper())
3411 self.assertEqual(record.levelno, expected_level)
3412
3413 # basicConfig was not called!
3414 self.assertEqual(called, [])
3415
3416 def test_log(self):
3417 self._test_log('log', logging.ERROR)
3418
3419 def test_debug(self):
3420 self._test_log('debug')
3421
3422 def test_info(self):
3423 self._test_log('info')
3424
3425 def test_warning(self):
3426 self._test_log('warning')
3427
3428 def test_error(self):
3429 self._test_log('error')
3430
3431 def test_critical(self):
3432 self._test_log('critical')
3433
3434 def test_set_logger_class(self):
3435 self.assertRaises(TypeError, logging.setLoggerClass, object)
3436
3437 class MyLogger(logging.Logger):
3438 pass
3439
3440 logging.setLoggerClass(MyLogger)
3441 self.assertEqual(logging.getLoggerClass(), MyLogger)
3442
3443 logging.setLoggerClass(logging.Logger)
3444 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3445
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003446 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003447 def test_logging_at_shutdown(self):
3448 # Issue #20037
3449 code = """if 1:
3450 import logging
3451
3452 class A:
3453 def __del__(self):
3454 try:
3455 raise ValueError("some error")
3456 except Exception:
3457 logging.exception("exception in __del__")
3458
3459 a = A()"""
3460 rc, out, err = assert_python_ok("-c", code)
3461 err = err.decode()
3462 self.assertIn("exception in __del__", err)
3463 self.assertIn("ValueError: some error", err)
3464
3465
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003466class LogRecordTest(BaseTest):
3467 def test_str_rep(self):
3468 r = logging.makeLogRecord({})
3469 s = str(r)
3470 self.assertTrue(s.startswith('<LogRecord: '))
3471 self.assertTrue(s.endswith('>'))
3472
3473 def test_dict_arg(self):
3474 h = RecordingHandler()
3475 r = logging.getLogger()
3476 r.addHandler(h)
3477 d = {'less' : 'more' }
3478 logging.warning('less is %(less)s', d)
3479 self.assertIs(h.records[0].args, d)
3480 self.assertEqual(h.records[0].message, 'less is more')
3481 r.removeHandler(h)
3482 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003483
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003484 def test_multiprocessing(self):
3485 r = logging.makeLogRecord({})
3486 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003487 try:
3488 import multiprocessing as mp
3489 r = logging.makeLogRecord({})
3490 self.assertEqual(r.processName, mp.current_process().name)
3491 except ImportError:
3492 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003493
3494 def test_optional(self):
3495 r = logging.makeLogRecord({})
3496 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003497 if threading:
3498 NOT_NONE(r.thread)
3499 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003500 NOT_NONE(r.process)
3501 NOT_NONE(r.processName)
3502 log_threads = logging.logThreads
3503 log_processes = logging.logProcesses
3504 log_multiprocessing = logging.logMultiprocessing
3505 try:
3506 logging.logThreads = False
3507 logging.logProcesses = False
3508 logging.logMultiprocessing = False
3509 r = logging.makeLogRecord({})
3510 NONE = self.assertIsNone
3511 NONE(r.thread)
3512 NONE(r.threadName)
3513 NONE(r.process)
3514 NONE(r.processName)
3515 finally:
3516 logging.logThreads = log_threads
3517 logging.logProcesses = log_processes
3518 logging.logMultiprocessing = log_multiprocessing
3519
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003520class BasicConfigTest(unittest.TestCase):
3521
Vinay Sajip95bf5042011-04-20 11:50:56 +01003522 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003523
3524 def setUp(self):
3525 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003526 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003527 self.saved_handlers = logging._handlers.copy()
3528 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003529 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003530 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003531 logging.root.handlers = []
3532
3533 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003534 for h in logging.root.handlers[:]:
3535 logging.root.removeHandler(h)
3536 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003537 super(BasicConfigTest, self).tearDown()
3538
Vinay Sajip3def7e02011-04-20 10:58:06 +01003539 def cleanup(self):
3540 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003541 logging._handlers.clear()
3542 logging._handlers.update(self.saved_handlers)
3543 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003544 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003545
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003546 def test_no_kwargs(self):
3547 logging.basicConfig()
3548
3549 # handler defaults to a StreamHandler to sys.stderr
3550 self.assertEqual(len(logging.root.handlers), 1)
3551 handler = logging.root.handlers[0]
3552 self.assertIsInstance(handler, logging.StreamHandler)
3553 self.assertEqual(handler.stream, sys.stderr)
3554
3555 formatter = handler.formatter
3556 # format defaults to logging.BASIC_FORMAT
3557 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3558 # datefmt defaults to None
3559 self.assertIsNone(formatter.datefmt)
3560 # style defaults to %
3561 self.assertIsInstance(formatter._style, logging.PercentStyle)
3562
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003563 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003564 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003565
Vinay Sajip1fd12022014-01-13 21:59:56 +00003566 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003567 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003568 logging.basicConfig(stream=sys.stdout, style="{")
3569 logging.error("Log an error")
3570 sys.stdout.seek(0)
3571 self.assertEqual(output.getvalue().strip(),
3572 "ERROR:root:Log an error")
3573
3574 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003575 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003576 logging.basicConfig(stream=sys.stdout, style="$")
3577 logging.error("Log an error")
3578 sys.stdout.seek(0)
3579 self.assertEqual(output.getvalue().strip(),
3580 "ERROR:root:Log an error")
3581
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003582 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003583
3584 def cleanup(h1, h2, fn):
3585 h1.close()
3586 h2.close()
3587 os.remove(fn)
3588
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003589 logging.basicConfig(filename='test.log')
3590
3591 self.assertEqual(len(logging.root.handlers), 1)
3592 handler = logging.root.handlers[0]
3593 self.assertIsInstance(handler, logging.FileHandler)
3594
3595 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003596 self.assertEqual(handler.stream.mode, expected.stream.mode)
3597 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003598 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003599
3600 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003601
3602 def cleanup(h1, h2, fn):
3603 h1.close()
3604 h2.close()
3605 os.remove(fn)
3606
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003607 logging.basicConfig(filename='test.log', filemode='wb')
3608
3609 handler = logging.root.handlers[0]
3610 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003611 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003612 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003613
3614 def test_stream(self):
3615 stream = io.StringIO()
3616 self.addCleanup(stream.close)
3617 logging.basicConfig(stream=stream)
3618
3619 self.assertEqual(len(logging.root.handlers), 1)
3620 handler = logging.root.handlers[0]
3621 self.assertIsInstance(handler, logging.StreamHandler)
3622 self.assertEqual(handler.stream, stream)
3623
3624 def test_format(self):
3625 logging.basicConfig(format='foo')
3626
3627 formatter = logging.root.handlers[0].formatter
3628 self.assertEqual(formatter._style._fmt, 'foo')
3629
3630 def test_datefmt(self):
3631 logging.basicConfig(datefmt='bar')
3632
3633 formatter = logging.root.handlers[0].formatter
3634 self.assertEqual(formatter.datefmt, 'bar')
3635
3636 def test_style(self):
3637 logging.basicConfig(style='$')
3638
3639 formatter = logging.root.handlers[0].formatter
3640 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3641
3642 def test_level(self):
3643 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003644 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003645
3646 logging.basicConfig(level=57)
3647 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003648 # Test that second call has no effect
3649 logging.basicConfig(level=58)
3650 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003651
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003652 def test_incompatible(self):
3653 assertRaises = self.assertRaises
3654 handlers = [logging.StreamHandler()]
3655 stream = sys.stderr
3656 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3657 stream=stream)
3658 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3659 handlers=handlers)
3660 assertRaises(ValueError, logging.basicConfig, stream=stream,
3661 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003662 # Issue 23207: test for invalid kwargs
3663 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3664 # Should pop both filename and filemode even if filename is None
3665 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003666
3667 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003668 handlers = [
3669 logging.StreamHandler(),
3670 logging.StreamHandler(sys.stdout),
3671 logging.StreamHandler(),
3672 ]
3673 f = logging.Formatter()
3674 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003675 logging.basicConfig(handlers=handlers)
3676 self.assertIs(handlers[0], logging.root.handlers[0])
3677 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003678 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003679 self.assertIsNotNone(handlers[0].formatter)
3680 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003681 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003682 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3683
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003684 def _test_log(self, method, level=None):
3685 # logging.root has no handlers so basicConfig should be called
3686 called = []
3687
3688 old_basic_config = logging.basicConfig
3689 def my_basic_config(*a, **kw):
3690 old_basic_config()
3691 old_level = logging.root.level
3692 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003693 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003694 called.append((a, kw))
3695
Vinay Sajip1feedb42014-05-31 08:19:12 +01003696 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003697
3698 log_method = getattr(logging, method)
3699 if level is not None:
3700 log_method(level, "test me")
3701 else:
3702 log_method("test me")
3703
3704 # basicConfig was called with no arguments
3705 self.assertEqual(called, [((), {})])
3706
3707 def test_log(self):
3708 self._test_log('log', logging.WARNING)
3709
3710 def test_debug(self):
3711 self._test_log('debug')
3712
3713 def test_info(self):
3714 self._test_log('info')
3715
3716 def test_warning(self):
3717 self._test_log('warning')
3718
3719 def test_error(self):
3720 self._test_log('error')
3721
3722 def test_critical(self):
3723 self._test_log('critical')
3724
3725
3726class LoggerAdapterTest(unittest.TestCase):
3727
3728 def setUp(self):
3729 super(LoggerAdapterTest, self).setUp()
3730 old_handler_list = logging._handlerList[:]
3731
3732 self.recording = RecordingHandler()
3733 self.logger = logging.root
3734 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003735 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003736 self.addCleanup(self.recording.close)
3737
3738 def cleanup():
3739 logging._handlerList[:] = old_handler_list
3740
3741 self.addCleanup(cleanup)
3742 self.addCleanup(logging.shutdown)
3743 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3744
3745 def test_exception(self):
3746 msg = 'testing exception: %r'
3747 exc = None
3748 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003749 1 / 0
3750 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751 exc = e
3752 self.adapter.exception(msg, self.recording)
3753
3754 self.assertEqual(len(self.recording.records), 1)
3755 record = self.recording.records[0]
3756 self.assertEqual(record.levelno, logging.ERROR)
3757 self.assertEqual(record.msg, msg)
3758 self.assertEqual(record.args, (self.recording,))
3759 self.assertEqual(record.exc_info,
3760 (exc.__class__, exc, exc.__traceback__))
3761
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003762 def test_exception_excinfo(self):
3763 try:
3764 1 / 0
3765 except ZeroDivisionError as e:
3766 exc = e
3767
3768 self.adapter.exception('exc_info test', exc_info=exc)
3769
3770 self.assertEqual(len(self.recording.records), 1)
3771 record = self.recording.records[0]
3772 self.assertEqual(record.exc_info,
3773 (exc.__class__, exc, exc.__traceback__))
3774
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003775 def test_critical(self):
3776 msg = 'critical test! %r'
3777 self.adapter.critical(msg, self.recording)
3778
3779 self.assertEqual(len(self.recording.records), 1)
3780 record = self.recording.records[0]
3781 self.assertEqual(record.levelno, logging.CRITICAL)
3782 self.assertEqual(record.msg, msg)
3783 self.assertEqual(record.args, (self.recording,))
3784
3785 def test_is_enabled_for(self):
3786 old_disable = self.adapter.logger.manager.disable
3787 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003788 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3789 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003790 self.assertFalse(self.adapter.isEnabledFor(32))
3791
3792 def test_has_handlers(self):
3793 self.assertTrue(self.adapter.hasHandlers())
3794
3795 for handler in self.logger.handlers:
3796 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003797
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003798 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003799 self.assertFalse(self.adapter.hasHandlers())
3800
3801
3802class LoggerTest(BaseTest):
3803
3804 def setUp(self):
3805 super(LoggerTest, self).setUp()
3806 self.recording = RecordingHandler()
3807 self.logger = logging.Logger(name='blah')
3808 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003809 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003810 self.addCleanup(self.recording.close)
3811 self.addCleanup(logging.shutdown)
3812
3813 def test_set_invalid_level(self):
3814 self.assertRaises(TypeError, self.logger.setLevel, object())
3815
3816 def test_exception(self):
3817 msg = 'testing exception: %r'
3818 exc = None
3819 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003820 1 / 0
3821 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003822 exc = e
3823 self.logger.exception(msg, self.recording)
3824
3825 self.assertEqual(len(self.recording.records), 1)
3826 record = self.recording.records[0]
3827 self.assertEqual(record.levelno, logging.ERROR)
3828 self.assertEqual(record.msg, msg)
3829 self.assertEqual(record.args, (self.recording,))
3830 self.assertEqual(record.exc_info,
3831 (exc.__class__, exc, exc.__traceback__))
3832
3833 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003834 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003835 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003836
3837 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003838 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003839 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003840
3841 def test_find_caller_with_stack_info(self):
3842 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003843 support.patch(self, logging.traceback, 'print_stack',
3844 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003845
3846 self.logger.findCaller(stack_info=True)
3847
3848 self.assertEqual(len(called), 1)
3849 self.assertEqual('Stack (most recent call last):\n', called[0])
3850
3851 def test_make_record_with_extra_overwrite(self):
3852 name = 'my record'
3853 level = 13
3854 fn = lno = msg = args = exc_info = func = sinfo = None
3855 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3856 exc_info, func, sinfo)
3857
3858 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3859 extra = {key: 'some value'}
3860 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3861 fn, lno, msg, args, exc_info,
3862 extra=extra, sinfo=sinfo)
3863
3864 def test_make_record_with_extra_no_overwrite(self):
3865 name = 'my record'
3866 level = 13
3867 fn = lno = msg = args = exc_info = func = sinfo = None
3868 extra = {'valid_key': 'some value'}
3869 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3870 exc_info, extra=extra, sinfo=sinfo)
3871 self.assertIn('valid_key', result.__dict__)
3872
3873 def test_has_handlers(self):
3874 self.assertTrue(self.logger.hasHandlers())
3875
3876 for handler in self.logger.handlers:
3877 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003878 self.assertFalse(self.logger.hasHandlers())
3879
3880 def test_has_handlers_no_propagate(self):
3881 child_logger = logging.getLogger('blah.child')
3882 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003883 self.assertFalse(child_logger.hasHandlers())
3884
3885 def test_is_enabled_for(self):
3886 old_disable = self.logger.manager.disable
3887 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003888 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003889 self.assertFalse(self.logger.isEnabledFor(22))
3890
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003891 def test_root_logger_aliases(self):
3892 root = logging.getLogger()
3893 self.assertIs(root, logging.root)
3894 self.assertIs(root, logging.getLogger(None))
3895 self.assertIs(root, logging.getLogger(''))
3896 self.assertIs(root, logging.getLogger('foo').root)
3897 self.assertIs(root, logging.getLogger('foo.bar').root)
3898 self.assertIs(root, logging.getLogger('foo').parent)
3899
3900 self.assertIsNot(root, logging.getLogger('\0'))
3901 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3902
3903 def test_invalid_names(self):
3904 self.assertRaises(TypeError, logging.getLogger, any)
3905 self.assertRaises(TypeError, logging.getLogger, b'foo')
3906
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003907
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003908class BaseFileTest(BaseTest):
3909 "Base class for handler tests that write log files"
3910
3911 def setUp(self):
3912 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003913 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3914 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003915 self.rmfiles = []
3916
3917 def tearDown(self):
3918 for fn in self.rmfiles:
3919 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003920 if os.path.exists(self.fn):
3921 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003922 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003923
3924 def assertLogFile(self, filename):
3925 "Assert a log file is there and register it for deletion"
3926 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003927 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003928 self.rmfiles.append(filename)
3929
3930
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003931class FileHandlerTest(BaseFileTest):
3932 def test_delay(self):
3933 os.unlink(self.fn)
3934 fh = logging.FileHandler(self.fn, delay=True)
3935 self.assertIsNone(fh.stream)
3936 self.assertFalse(os.path.exists(self.fn))
3937 fh.handle(logging.makeLogRecord({}))
3938 self.assertIsNotNone(fh.stream)
3939 self.assertTrue(os.path.exists(self.fn))
3940 fh.close()
3941
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003942class RotatingFileHandlerTest(BaseFileTest):
3943 def next_rec(self):
3944 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3945 self.next_message(), None, None, None)
3946
3947 def test_should_not_rollover(self):
3948 # If maxbytes is zero rollover never occurs
3949 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3950 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003951 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003952
3953 def test_should_rollover(self):
3954 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3955 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003956 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003957
3958 def test_file_created(self):
3959 # checks that the file is created and assumes it was created
3960 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003961 rh = logging.handlers.RotatingFileHandler(self.fn)
3962 rh.emit(self.next_rec())
3963 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003964 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003965
3966 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003967 def namer(name):
3968 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003969 rh = logging.handlers.RotatingFileHandler(
3970 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003971 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003972 rh.emit(self.next_rec())
3973 self.assertLogFile(self.fn)
3974 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003975 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003976 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003977 self.assertLogFile(namer(self.fn + ".2"))
3978 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3979 rh.close()
3980
Vinay Sajip1feedb42014-05-31 08:19:12 +01003981 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003982 def test_rotator(self):
3983 def namer(name):
3984 return name + ".gz"
3985
3986 def rotator(source, dest):
3987 with open(source, "rb") as sf:
3988 data = sf.read()
3989 compressed = zlib.compress(data, 9)
3990 with open(dest, "wb") as df:
3991 df.write(compressed)
3992 os.remove(source)
3993
3994 rh = logging.handlers.RotatingFileHandler(
3995 self.fn, backupCount=2, maxBytes=1)
3996 rh.rotator = rotator
3997 rh.namer = namer
3998 m1 = self.next_rec()
3999 rh.emit(m1)
4000 self.assertLogFile(self.fn)
4001 m2 = self.next_rec()
4002 rh.emit(m2)
4003 fn = namer(self.fn + ".1")
4004 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004005 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004006 with open(fn, "rb") as f:
4007 compressed = f.read()
4008 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004009 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004010 rh.emit(self.next_rec())
4011 fn = namer(self.fn + ".2")
4012 self.assertLogFile(fn)
4013 with open(fn, "rb") as f:
4014 compressed = f.read()
4015 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004016 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004017 rh.emit(self.next_rec())
4018 fn = namer(self.fn + ".2")
4019 with open(fn, "rb") as f:
4020 compressed = f.read()
4021 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004022 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004023 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004024 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004025
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004026class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004027 # other test methods added below
4028 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004029 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4030 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004031 fmt = logging.Formatter('%(asctime)s %(message)s')
4032 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004033 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004034 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004035 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004036 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004037 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004038 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004039 fh.close()
4040 # At this point, we should have a recent rotated file which we
4041 # can test for the existence of. However, in practice, on some
4042 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004043 # in time to go to look for the log file. So, we go back a fair
4044 # bit, and stop as soon as we see a rotated file. In theory this
4045 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004046 found = False
4047 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004048 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004049 for secs in range(GO_BACK):
4050 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004051 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4052 found = os.path.exists(fn)
4053 if found:
4054 self.rmfiles.append(fn)
4055 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004056 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4057 if not found:
4058 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004059 dn, fn = os.path.split(self.fn)
4060 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004061 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4062 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004063 for f in files:
4064 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004065 path = os.path.join(dn, f)
4066 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004067 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004068 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004069
Vinay Sajip0372e102011-05-05 12:59:14 +01004070 def test_invalid(self):
4071 assertRaises = self.assertRaises
4072 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004073 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004074 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004075 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004076 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004077 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004078
Vinay Sajipa7130792013-04-12 17:04:23 +01004079 def test_compute_rollover_daily_attime(self):
4080 currentTime = 0
4081 atTime = datetime.time(12, 0, 0)
4082 rh = logging.handlers.TimedRotatingFileHandler(
4083 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4084 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004085 try:
4086 actual = rh.computeRollover(currentTime)
4087 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004088
Vinay Sajipd86ac962013-04-14 12:20:46 +01004089 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4090 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4091 finally:
4092 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004093
Vinay Sajip10e8c492013-05-18 10:19:54 -07004094 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004095 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004096 currentTime = int(time.time())
4097 today = currentTime - currentTime % 86400
4098
Vinay Sajipa7130792013-04-12 17:04:23 +01004099 atTime = datetime.time(12, 0, 0)
4100
Vinay Sajip10e8c492013-05-18 10:19:54 -07004101 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004102 for day in range(7):
4103 rh = logging.handlers.TimedRotatingFileHandler(
4104 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4105 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004106 try:
4107 if wday > day:
4108 # The rollover day has already passed this week, so we
4109 # go over into next week
4110 expected = (7 - wday + day)
4111 else:
4112 expected = (day - wday)
4113 # At this point expected is in days from now, convert to seconds
4114 expected *= 24 * 60 * 60
4115 # Add in the rollover time
4116 expected += 12 * 60 * 60
4117 # Add in adjustment for today
4118 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004119 actual = rh.computeRollover(today)
4120 if actual != expected:
4121 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004122 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004123 self.assertEqual(actual, expected)
4124 if day == wday:
4125 # goes into following week
4126 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004127 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004128 if actual != expected:
4129 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004130 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004131 self.assertEqual(actual, expected)
4132 finally:
4133 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004134
4135
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004136def secs(**kw):
4137 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4138
4139for when, exp in (('S', 1),
4140 ('M', 60),
4141 ('H', 60 * 60),
4142 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004143 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004144 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004145 ('W0', secs(days=4, hours=24)),
4146 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004147 def test_compute_rollover(self, when=when, exp=exp):
4148 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004149 self.fn, when=when, interval=1, backupCount=0, utc=True)
4150 currentTime = 0.0
4151 actual = rh.computeRollover(currentTime)
4152 if exp != actual:
4153 # Failures occur on some systems for MIDNIGHT and W0.
4154 # Print detailed calculation for MIDNIGHT so we can try to see
4155 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004156 if when == 'MIDNIGHT':
4157 try:
4158 if rh.utc:
4159 t = time.gmtime(currentTime)
4160 else:
4161 t = time.localtime(currentTime)
4162 currentHour = t[3]
4163 currentMinute = t[4]
4164 currentSecond = t[5]
4165 # r is the number of seconds left between now and midnight
4166 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4167 currentMinute) * 60 +
4168 currentSecond)
4169 result = currentTime + r
4170 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4171 print('currentHour: %s' % currentHour, file=sys.stderr)
4172 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4173 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4174 print('r: %s' % r, file=sys.stderr)
4175 print('result: %s' % result, file=sys.stderr)
4176 except Exception:
4177 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4178 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004179 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004180 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4181
Vinay Sajip60ccd822011-05-09 17:32:09 +01004182
Vinay Sajip223349c2015-10-01 20:37:54 +01004183@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004184class NTEventLogHandlerTest(BaseTest):
4185 def test_basic(self):
4186 logtype = 'Application'
4187 elh = win32evtlog.OpenEventLog(None, logtype)
4188 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004189
4190 try:
4191 h = logging.handlers.NTEventLogHandler('test_logging')
4192 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004193 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004194 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004195 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004196
Vinay Sajip60ccd822011-05-09 17:32:09 +01004197 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4198 h.handle(r)
4199 h.close()
4200 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004201 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004202 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4203 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4204 found = False
4205 GO_BACK = 100
4206 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4207 for e in events:
4208 if e.SourceName != 'test_logging':
4209 continue
4210 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4211 if msg != 'Test Log Message\r\n':
4212 continue
4213 found = True
4214 break
4215 msg = 'Record not found in event log, went back %d records' % GO_BACK
4216 self.assertTrue(found, msg=msg)
4217
Martin Panter19e69c52015-11-14 12:46:42 +00004218
4219class MiscTestCase(unittest.TestCase):
4220 def test__all__(self):
4221 blacklist = {'logThreads', 'logMultiprocessing',
4222 'logProcesses', 'currentframe',
4223 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4224 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
4225 'root'}
4226 support.check__all__(self, logging, blacklist=blacklist)
4227
4228
Christian Heimes180510d2008-03-03 19:15:45 +00004229# Set the locale to the platform-dependent default. I have no idea
4230# why the test does this, but in any case we save the current locale
4231# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004232@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004233def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004234 support.run_unittest(
4235 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4236 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4237 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4238 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4239 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4240 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4241 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4242 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4243 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4244 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Martin Panter19e69c52015-11-14 12:46:42 +00004245 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
4246 MiscTestCase)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004247
Christian Heimes180510d2008-03-03 19:15:45 +00004248if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004249 test_main()