blob: 85344de5735c4b4368cdc03aa6c9b0e675d0ab0b [file] [log] [blame]
Vinay Sajipd61910c2016-09-08 01:13:39 +01001# Copyright 2001-2016 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajipd61910c2016-09-08 01:13:39 +010019Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000029import pickle
30import io
31import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000032import json
Christian Heimes180510d2008-03-03 19:15:45 +000033import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000034import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010035import random
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Christian Heimes180510d2008-03-03 19:15:45 +000037import socket
Christian Heimes180510d2008-03-03 19:15:45 +000038import struct
39import sys
40import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030041from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010042from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000043import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010044import time
Christian Heimes180510d2008-03-03 19:15:45 +000045import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000046import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000047import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000048try:
49 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010050 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010051 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 from http.server import HTTPServer, BaseHTTPRequestHandler
54 import smtpd
55 from urllib.parse import urlparse, parse_qs
56 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010057 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000058except ImportError:
59 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010060try:
Vinay Sajip223349c2015-10-01 20:37:54 +010061 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010062except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010063 win32evtlog = win32evtlogutil = pywintypes = None
64
Eric V. Smith851cad72012-03-11 22:46:04 -070065try:
66 import zlib
67except ImportError:
68 pass
Christian Heimes18c66892008-02-17 13:31:39 +000069
Christian Heimes180510d2008-03-03 19:15:45 +000070class BaseTest(unittest.TestCase):
71
72 """Base class for logging tests."""
73
74 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030075 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000076 message_num = 0
77
78 def setUp(self):
79 """Setup the default logging stream to an internal StringIO instance,
80 so that we can examine log output as we want."""
81 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000082 logging._acquireLock()
83 try:
Christian Heimes180510d2008-03-03 19:15:45 +000084 self.saved_handlers = logging._handlers.copy()
85 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000086 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070087 self.saved_name_to_level = logging._nameToLevel.copy()
88 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.logger_states = logger_states = {}
90 for name in saved_loggers:
91 logger_states[name] = getattr(saved_loggers[name],
92 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000093 finally:
94 logging._releaseLock()
95
Florent Xicluna5252f9f2011-11-07 19:43:05 +010096 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000097 self.logger1 = logging.getLogger("\xab\xd7\xbb")
98 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +000099
Christian Heimes180510d2008-03-03 19:15:45 +0000100 self.root_logger = logging.getLogger("")
101 self.original_logging_level = self.root_logger.getEffectiveLevel()
102
103 self.stream = io.StringIO()
104 self.root_logger.setLevel(logging.DEBUG)
105 self.root_hdlr = logging.StreamHandler(self.stream)
106 self.root_formatter = logging.Formatter(self.log_format)
107 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000108 if self.logger1.hasHandlers():
109 hlist = self.logger1.handlers + self.root_logger.handlers
110 raise AssertionError('Unexpected handlers: %s' % hlist)
111 if self.logger2.hasHandlers():
112 hlist = self.logger2.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000114 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000115 self.assertTrue(self.logger1.hasHandlers())
116 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000117
118 def tearDown(self):
119 """Remove our logging stream, and restore the original logging
120 level."""
121 self.stream.close()
122 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000123 while self.root_logger.handlers:
124 h = self.root_logger.handlers[0]
125 self.root_logger.removeHandler(h)
126 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000127 self.root_logger.setLevel(self.original_logging_level)
128 logging._acquireLock()
129 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700130 logging._levelToName.clear()
131 logging._levelToName.update(self.saved_level_to_name)
132 logging._nameToLevel.clear()
133 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000134 logging._handlers.clear()
135 logging._handlers.update(self.saved_handlers)
136 logging._handlerList[:] = self.saved_handler_list
137 loggerDict = logging.getLogger().manager.loggerDict
138 loggerDict.clear()
139 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000140 logger_states = self.logger_states
141 for name in self.logger_states:
142 if logger_states[name] is not None:
143 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000144 finally:
145 logging._releaseLock()
146
Vinay Sajip4ded5512012-10-02 15:56:16 +0100147 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000148 """Match the collected log lines against the regular expression
149 self.expected_log_pat, and compare the extracted group values to
150 the expected_values list of tuples."""
151 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100152 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300153 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100154 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000155 for actual, expected in zip(actual_lines, expected_values):
156 match = pat.search(actual)
157 if not match:
158 self.fail("Log line does not match expected pattern:\n" +
159 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000160 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000161 s = stream.read()
162 if s:
163 self.fail("Remaining output at end of log stream:\n" + s)
164
165 def next_message(self):
166 """Generate a message consisting solely of an auto-incrementing
167 integer."""
168 self.message_num += 1
169 return "%d" % self.message_num
170
171
172class BuiltinLevelsTest(BaseTest):
173 """Test builtin levels and their inheritance."""
174
175 def test_flat(self):
176 #Logging levels in a flat logger namespace.
177 m = self.next_message
178
179 ERR = logging.getLogger("ERR")
180 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000181 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000182 INF.setLevel(logging.INFO)
183 DEB = logging.getLogger("DEB")
184 DEB.setLevel(logging.DEBUG)
185
186 # These should log.
187 ERR.log(logging.CRITICAL, m())
188 ERR.error(m())
189
190 INF.log(logging.CRITICAL, m())
191 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100192 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000193 INF.info(m())
194
195 DEB.log(logging.CRITICAL, m())
196 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100197 DEB.warning(m())
198 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000199 DEB.debug(m())
200
201 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 ERR.info(m())
204 ERR.debug(m())
205
206 INF.debug(m())
207
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000208 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000209 ('ERR', 'CRITICAL', '1'),
210 ('ERR', 'ERROR', '2'),
211 ('INF', 'CRITICAL', '3'),
212 ('INF', 'ERROR', '4'),
213 ('INF', 'WARNING', '5'),
214 ('INF', 'INFO', '6'),
215 ('DEB', 'CRITICAL', '7'),
216 ('DEB', 'ERROR', '8'),
217 ('DEB', 'WARNING', '9'),
218 ('DEB', 'INFO', '10'),
219 ('DEB', 'DEBUG', '11'),
220 ])
221
222 def test_nested_explicit(self):
223 # Logging levels in a nested namespace, all explicitly set.
224 m = self.next_message
225
226 INF = logging.getLogger("INF")
227 INF.setLevel(logging.INFO)
228 INF_ERR = logging.getLogger("INF.ERR")
229 INF_ERR.setLevel(logging.ERROR)
230
231 # These should log.
232 INF_ERR.log(logging.CRITICAL, m())
233 INF_ERR.error(m())
234
235 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100236 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000237 INF_ERR.info(m())
238 INF_ERR.debug(m())
239
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000240 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000241 ('INF.ERR', 'CRITICAL', '1'),
242 ('INF.ERR', 'ERROR', '2'),
243 ])
244
245 def test_nested_inherited(self):
246 #Logging levels in a nested namespace, inherited from parent loggers.
247 m = self.next_message
248
249 INF = logging.getLogger("INF")
250 INF.setLevel(logging.INFO)
251 INF_ERR = logging.getLogger("INF.ERR")
252 INF_ERR.setLevel(logging.ERROR)
253 INF_UNDEF = logging.getLogger("INF.UNDEF")
254 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
255 UNDEF = logging.getLogger("UNDEF")
256
257 # These should log.
258 INF_UNDEF.log(logging.CRITICAL, m())
259 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100260 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000261 INF_UNDEF.info(m())
262 INF_ERR_UNDEF.log(logging.CRITICAL, m())
263 INF_ERR_UNDEF.error(m())
264
265 # These should not log.
266 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100267 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000268 INF_ERR_UNDEF.info(m())
269 INF_ERR_UNDEF.debug(m())
270
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000271 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000272 ('INF.UNDEF', 'CRITICAL', '1'),
273 ('INF.UNDEF', 'ERROR', '2'),
274 ('INF.UNDEF', 'WARNING', '3'),
275 ('INF.UNDEF', 'INFO', '4'),
276 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
277 ('INF.ERR.UNDEF', 'ERROR', '6'),
278 ])
279
280 def test_nested_with_virtual_parent(self):
281 # Logging levels when some parent does not exist yet.
282 m = self.next_message
283
284 INF = logging.getLogger("INF")
285 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
286 CHILD = logging.getLogger("INF.BADPARENT")
287 INF.setLevel(logging.INFO)
288
289 # These should log.
290 GRANDCHILD.log(logging.FATAL, m())
291 GRANDCHILD.info(m())
292 CHILD.log(logging.FATAL, m())
293 CHILD.info(m())
294
295 # These should not log.
296 GRANDCHILD.debug(m())
297 CHILD.debug(m())
298
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000299 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000300 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
301 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
302 ('INF.BADPARENT', 'CRITICAL', '3'),
303 ('INF.BADPARENT', 'INFO', '4'),
304 ])
305
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100306 def test_regression_22386(self):
307 """See issue #22386 for more information."""
308 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
309 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000310
311class BasicFilterTest(BaseTest):
312
313 """Test the bundled Filter class."""
314
315 def test_filter(self):
316 # Only messages satisfying the specified criteria pass through the
317 # filter.
318 filter_ = logging.Filter("spam.eggs")
319 handler = self.root_logger.handlers[0]
320 try:
321 handler.addFilter(filter_)
322 spam = logging.getLogger("spam")
323 spam_eggs = logging.getLogger("spam.eggs")
324 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
325 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
326
327 spam.info(self.next_message())
328 spam_eggs.info(self.next_message()) # Good.
329 spam_eggs_fish.info(self.next_message()) # Good.
330 spam_bakedbeans.info(self.next_message())
331
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000332 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000333 ('spam.eggs', 'INFO', '2'),
334 ('spam.eggs.fish', 'INFO', '3'),
335 ])
336 finally:
337 handler.removeFilter(filter_)
338
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000339 def test_callable_filter(self):
340 # Only messages satisfying the specified criteria pass through the
341 # filter.
342
343 def filterfunc(record):
344 parts = record.name.split('.')
345 prefix = '.'.join(parts[:2])
346 return prefix == 'spam.eggs'
347
348 handler = self.root_logger.handlers[0]
349 try:
350 handler.addFilter(filterfunc)
351 spam = logging.getLogger("spam")
352 spam_eggs = logging.getLogger("spam.eggs")
353 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
354 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
355
356 spam.info(self.next_message())
357 spam_eggs.info(self.next_message()) # Good.
358 spam_eggs_fish.info(self.next_message()) # Good.
359 spam_bakedbeans.info(self.next_message())
360
361 self.assert_log_lines([
362 ('spam.eggs', 'INFO', '2'),
363 ('spam.eggs.fish', 'INFO', '3'),
364 ])
365 finally:
366 handler.removeFilter(filterfunc)
367
Vinay Sajip985ef872011-04-26 19:34:04 +0100368 def test_empty_filter(self):
369 f = logging.Filter()
370 r = logging.makeLogRecord({'name': 'spam.eggs'})
371 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000372
373#
374# First, we define our levels. There can be as many as you want - the only
375# limitations are that they should be integers, the lowest should be > 0 and
376# larger values mean less information being logged. If you need specific
377# level values which do not fit into these limitations, you can use a
378# mapping dictionary to convert between your application levels and the
379# logging system.
380#
381SILENT = 120
382TACITURN = 119
383TERSE = 118
384EFFUSIVE = 117
385SOCIABLE = 116
386VERBOSE = 115
387TALKATIVE = 114
388GARRULOUS = 113
389CHATTERBOX = 112
390BORING = 111
391
392LEVEL_RANGE = range(BORING, SILENT + 1)
393
394#
395# Next, we define names for our levels. You don't need to do this - in which
396# case the system will use "Level n" to denote the text for the level.
397#
398my_logging_levels = {
399 SILENT : 'Silent',
400 TACITURN : 'Taciturn',
401 TERSE : 'Terse',
402 EFFUSIVE : 'Effusive',
403 SOCIABLE : 'Sociable',
404 VERBOSE : 'Verbose',
405 TALKATIVE : 'Talkative',
406 GARRULOUS : 'Garrulous',
407 CHATTERBOX : 'Chatterbox',
408 BORING : 'Boring',
409}
410
411class GarrulousFilter(logging.Filter):
412
413 """A filter which blocks garrulous messages."""
414
415 def filter(self, record):
416 return record.levelno != GARRULOUS
417
418class VerySpecificFilter(logging.Filter):
419
420 """A filter which blocks sociable and taciturn messages."""
421
422 def filter(self, record):
423 return record.levelno not in [SOCIABLE, TACITURN]
424
425
426class CustomLevelsAndFiltersTest(BaseTest):
427
428 """Test various filtering possibilities with custom logging levels."""
429
430 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300431 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000432
433 def setUp(self):
434 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000435 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000436 logging.addLevelName(k, v)
437
438 def log_at_all_levels(self, logger):
439 for lvl in LEVEL_RANGE:
440 logger.log(lvl, self.next_message())
441
442 def test_logger_filter(self):
443 # Filter at logger level.
444 self.root_logger.setLevel(VERBOSE)
445 # Levels >= 'Verbose' are good.
446 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000447 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000448 ('Verbose', '5'),
449 ('Sociable', '6'),
450 ('Effusive', '7'),
451 ('Terse', '8'),
452 ('Taciturn', '9'),
453 ('Silent', '10'),
454 ])
455
456 def test_handler_filter(self):
457 # Filter at handler level.
458 self.root_logger.handlers[0].setLevel(SOCIABLE)
459 try:
460 # Levels >= 'Sociable' are good.
461 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000462 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000463 ('Sociable', '6'),
464 ('Effusive', '7'),
465 ('Terse', '8'),
466 ('Taciturn', '9'),
467 ('Silent', '10'),
468 ])
469 finally:
470 self.root_logger.handlers[0].setLevel(logging.NOTSET)
471
472 def test_specific_filters(self):
473 # Set a specific filter object on the handler, and then add another
474 # filter object on the logger itself.
475 handler = self.root_logger.handlers[0]
476 specific_filter = None
477 garr = GarrulousFilter()
478 handler.addFilter(garr)
479 try:
480 self.log_at_all_levels(self.root_logger)
481 first_lines = [
482 # Notice how 'Garrulous' is missing
483 ('Boring', '1'),
484 ('Chatterbox', '2'),
485 ('Talkative', '4'),
486 ('Verbose', '5'),
487 ('Sociable', '6'),
488 ('Effusive', '7'),
489 ('Terse', '8'),
490 ('Taciturn', '9'),
491 ('Silent', '10'),
492 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000493 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000494
495 specific_filter = VerySpecificFilter()
496 self.root_logger.addFilter(specific_filter)
497 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000498 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000499 # Not only 'Garrulous' is still missing, but also 'Sociable'
500 # and 'Taciturn'
501 ('Boring', '11'),
502 ('Chatterbox', '12'),
503 ('Talkative', '14'),
504 ('Verbose', '15'),
505 ('Effusive', '17'),
506 ('Terse', '18'),
507 ('Silent', '20'),
508 ])
509 finally:
510 if specific_filter:
511 self.root_logger.removeFilter(specific_filter)
512 handler.removeFilter(garr)
513
514
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100515class HandlerTest(BaseTest):
516 def test_name(self):
517 h = logging.Handler()
518 h.name = 'generic'
519 self.assertEqual(h.name, 'generic')
520 h.name = 'anothergeneric'
521 self.assertEqual(h.name, 'anothergeneric')
522 self.assertRaises(NotImplementedError, h.emit, None)
523
Vinay Sajip5a35b062011-04-27 11:31:14 +0100524 def test_builtin_handlers(self):
525 # We can't actually *use* too many handlers in the tests,
526 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200527 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100528 for existing in (True, False):
529 fd, fn = tempfile.mkstemp()
530 os.close(fd)
531 if not existing:
532 os.unlink(fn)
533 h = logging.handlers.WatchedFileHandler(fn, delay=True)
534 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100535 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100536 self.assertEqual(dev, -1)
537 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100538 r = logging.makeLogRecord({'msg': 'Test'})
539 h.handle(r)
540 # Now remove the file.
541 os.unlink(fn)
542 self.assertFalse(os.path.exists(fn))
543 # The next call should recreate the file.
544 h.handle(r)
545 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100546 else:
547 self.assertEqual(h.dev, -1)
548 self.assertEqual(h.ino, -1)
549 h.close()
550 if existing:
551 os.unlink(fn)
552 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100553 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100554 else:
555 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100556 try:
557 h = logging.handlers.SysLogHandler(sockname)
558 self.assertEqual(h.facility, h.LOG_USER)
559 self.assertTrue(h.unixsocket)
560 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200561 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100562 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100563 for method in ('GET', 'POST', 'PUT'):
564 if method == 'PUT':
565 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
566 'localhost', '/log', method)
567 else:
568 h = logging.handlers.HTTPHandler('localhost', '/log', method)
569 h.close()
570 h = logging.handlers.BufferingHandler(0)
571 r = logging.makeLogRecord({})
572 self.assertTrue(h.shouldFlush(r))
573 h.close()
574 h = logging.handlers.BufferingHandler(1)
575 self.assertFalse(h.shouldFlush(r))
576 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100577
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100578 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100579 @unittest.skipUnless(threading, 'Threading required for this test.')
580 def test_race(self):
581 # Issue #14632 refers.
582 def remove_loop(fname, tries):
583 for _ in range(tries):
584 try:
585 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000586 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100587 except OSError:
588 pass
589 time.sleep(0.004 * random.randint(0, 4))
590
Vinay Sajipc94871a2012-04-25 10:51:35 +0100591 del_count = 500
592 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100593
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000594 self.handle_time = None
595 self.deletion_time = None
596
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100598 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
599 os.close(fd)
600 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
601 remover.daemon = True
602 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100604 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
605 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100606 try:
607 for _ in range(log_count):
608 time.sleep(0.005)
609 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000610 try:
611 self.handle_time = time.time()
612 h.handle(r)
613 except Exception:
614 print('Deleted at %s, '
615 'opened at %s' % (self.deletion_time,
616 self.handle_time))
617 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100618 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100619 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100620 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100621 if os.path.exists(fn):
622 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623
624
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100625class BadStream(object):
626 def write(self, data):
627 raise RuntimeError('deliberate mistake')
628
629class TestStreamHandler(logging.StreamHandler):
630 def handleError(self, record):
631 self.error_record = record
632
633class StreamHandlerTest(BaseTest):
634 def test_error_handling(self):
635 h = TestStreamHandler(BadStream())
636 r = logging.makeLogRecord({})
637 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100638
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100639 try:
640 h.handle(r)
641 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100642
Vinay Sajip985ef872011-04-26 19:34:04 +0100643 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100644 with support.captured_stderr() as stderr:
645 h.handle(r)
646 msg = '\nRuntimeError: deliberate mistake\n'
647 self.assertIn(msg, stderr.getvalue())
648
Vinay Sajip985ef872011-04-26 19:34:04 +0100649 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100650 with support.captured_stderr() as stderr:
651 h.handle(r)
652 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100653 finally:
654 logging.raiseExceptions = old_raise
655
Vinay Sajip7367d082011-05-02 13:17:27 +0100656# -- The following section could be moved into a server_helper.py module
657# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100658
Vinay Sajipce7c9782011-05-17 07:15:53 +0100659if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100660 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100661 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100662 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100663
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 :param addr: A (host, port) tuple which the server listens on.
665 You can specify a port value of zero: the server's
666 *port* attribute will hold the actual port number
667 used, which can be used in client connections.
668 :param handler: A callable which will be called to process
669 incoming messages. The handler will be passed
670 the client address tuple, who the message is from,
671 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100672 :param poll_interval: The interval, in seconds, used in the underlying
673 :func:`select` or :func:`poll` call by
674 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100675 :param sockmap: A dictionary which will be used to hold
676 :class:`asyncore.dispatcher` instances used by
677 :func:`asyncore.loop`. This avoids changing the
678 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100679 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100680
681 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400682 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
683 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100684 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100685 self._handler = handler
686 self._thread = None
687 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100688
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 def process_message(self, peer, mailfrom, rcpttos, data):
690 """
691 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 Typically, this will be a test case method.
694 :param peer: The client (host, port) tuple.
695 :param mailfrom: The address of the sender.
696 :param rcpttos: The addresses of the recipients.
697 :param data: The message.
698 """
699 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701 def start(self):
702 """
703 Start the server running on a separate daemon thread.
704 """
705 self._thread = t = threading.Thread(target=self.serve_forever,
706 args=(self.poll_interval,))
707 t.setDaemon(True)
708 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100709
Vinay Sajipce7c9782011-05-17 07:15:53 +0100710 def serve_forever(self, poll_interval):
711 """
712 Run the :mod:`asyncore` loop until normal termination
713 conditions arise.
714 :param poll_interval: The interval, in seconds, used in the underlying
715 :func:`select` or :func:`poll` call by
716 :func:`asyncore.loop`.
717 """
718 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100719 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200720 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 # On FreeBSD 8, closing the server repeatably
722 # raises this error. We swallow it if the
723 # server has been closed.
724 if self.connected or self.accepting:
725 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100726
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 def stop(self, timeout=None):
728 """
729 Stop the thread by closing the server instance.
730 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100731
Vinay Sajipce7c9782011-05-17 07:15:53 +0100732 :param timeout: How long to wait for the server thread
733 to terminate.
734 """
735 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100736 self._thread.join(timeout)
737 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100738
Vinay Sajipce7c9782011-05-17 07:15:53 +0100739 class ControlMixin(object):
740 """
741 This mixin is used to start a server on a separate thread, and
742 shut it down programmatically. Request handling is simplified - instead
743 of needing to derive a suitable RequestHandler subclass, you just
744 provide a callable which will be passed each received request to be
745 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100746
Vinay Sajipce7c9782011-05-17 07:15:53 +0100747 :param handler: A handler callable which will be called with a
748 single parameter - the request - in order to
749 process the request. This handler is called on the
750 server thread, effectively meaning that requests are
751 processed serially. While not quite Web scale ;-),
752 this should be fine for testing applications.
753 :param poll_interval: The polling interval in seconds.
754 """
755 def __init__(self, handler, poll_interval):
756 self._thread = None
757 self.poll_interval = poll_interval
758 self._handler = handler
759 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100760
Vinay Sajipce7c9782011-05-17 07:15:53 +0100761 def start(self):
762 """
763 Create a daemon thread to run the server, and start it.
764 """
765 self._thread = t = threading.Thread(target=self.serve_forever,
766 args=(self.poll_interval,))
767 t.setDaemon(True)
768 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def serve_forever(self, poll_interval):
771 """
772 Run the server. Set the ready flag before entering the
773 service loop.
774 """
775 self.ready.set()
776 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100777
Vinay Sajipce7c9782011-05-17 07:15:53 +0100778 def stop(self, timeout=None):
779 """
780 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 :param timeout: How long to wait for the server thread
783 to terminate.
784 """
785 self.shutdown()
786 if self._thread is not None:
787 self._thread.join(timeout)
788 self._thread = None
789 self.server_close()
790 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100791
Vinay Sajipce7c9782011-05-17 07:15:53 +0100792 class TestHTTPServer(ControlMixin, HTTPServer):
793 """
794 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 :param addr: A tuple with the IP address and port to listen on.
797 :param handler: A handler callable which will be called with a
798 single parameter - the request - in order to
799 process the request.
800 :param poll_interval: The polling interval in seconds.
801 :param log: Pass ``True`` to enable log messages.
802 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100803 def __init__(self, addr, handler, poll_interval=0.5,
804 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
806 def __getattr__(self, name, default=None):
807 if name.startswith('do_'):
808 return self.process_request
809 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100810
Vinay Sajipce7c9782011-05-17 07:15:53 +0100811 def process_request(self):
812 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 def log_message(self, format, *args):
815 if log:
816 super(DelegatingHTTPRequestHandler,
817 self).log_message(format, *args)
818 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
819 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100820 self.sslctx = sslctx
821
822 def get_request(self):
823 try:
824 sock, addr = self.socket.accept()
825 if self.sslctx:
826 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200827 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100828 # socket errors are silenced by the caller, print them here
829 sys.stderr.write("Got an error:\n%s\n" % e)
830 raise
831 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100832
Vinay Sajipce7c9782011-05-17 07:15:53 +0100833 class TestTCPServer(ControlMixin, ThreadingTCPServer):
834 """
835 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 :param addr: A tuple with the IP address and port to listen on.
838 :param handler: A handler callable which will be called with a single
839 parameter - the request - in order to process the request.
840 :param poll_interval: The polling interval in seconds.
841 :bind_and_activate: If True (the default), binds the server and starts it
842 listening. If False, you need to call
843 :meth:`server_bind` and :meth:`server_activate` at
844 some later time before calling :meth:`start`, so that
845 the server will set up the socket and listen on it.
846 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100849
Vinay Sajipce7c9782011-05-17 07:15:53 +0100850 def __init__(self, addr, handler, poll_interval=0.5,
851 bind_and_activate=True):
852 class DelegatingTCPRequestHandler(StreamRequestHandler):
853
854 def handle(self):
855 self.server._handler(self)
856 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
857 bind_and_activate)
858 ControlMixin.__init__(self, handler, poll_interval)
859
860 def server_bind(self):
861 super(TestTCPServer, self).server_bind()
862 self.port = self.socket.getsockname()[1]
863
864 class TestUDPServer(ControlMixin, ThreadingUDPServer):
865 """
866 A UDP server which is controllable using :class:`ControlMixin`.
867
868 :param addr: A tuple with the IP address and port to listen on.
869 :param handler: A handler callable which will be called with a
870 single parameter - the request - in order to
871 process the request.
872 :param poll_interval: The polling interval for shutdown requests,
873 in seconds.
874 :bind_and_activate: If True (the default), binds the server and
875 starts it listening. If False, you need to
876 call :meth:`server_bind` and
877 :meth:`server_activate` at some later time
878 before calling :meth:`start`, so that the server will
879 set up the socket and listen on it.
880 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100881 def __init__(self, addr, handler, poll_interval=0.5,
882 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100883 class DelegatingUDPRequestHandler(DatagramRequestHandler):
884
885 def handle(self):
886 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100887
888 def finish(self):
889 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 if data:
891 try:
892 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200893 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if not self.server._closed:
895 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100896
Vinay Sajip3ef12292011-05-23 23:00:42 +0100897 ThreadingUDPServer.__init__(self, addr,
898 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100899 bind_and_activate)
900 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100901 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100902
903 def server_bind(self):
904 super(TestUDPServer, self).server_bind()
905 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100906
Vinay Sajipba980db2011-05-23 21:37:54 +0100907 def server_close(self):
908 super(TestUDPServer, self).server_close()
909 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Victor Stinnerec5a8602014-06-02 14:41:51 +0200911 if hasattr(socket, "AF_UNIX"):
912 class TestUnixStreamServer(TestTCPServer):
913 address_family = socket.AF_UNIX
914
915 class TestUnixDatagramServer(TestUDPServer):
916 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100917
Vinay Sajip7367d082011-05-02 13:17:27 +0100918# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100919
Vinay Sajipce7c9782011-05-17 07:15:53 +0100920@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100921class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000922 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100923 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100924 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800925 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100926 sockmap)
927 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800928 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000929 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
930 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 self.assertEqual(h.toaddrs, ['you'])
932 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100933 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100934 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000936 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000938 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 self.assertEqual(len(self.messages), 1)
940 peer, mailfrom, rcpttos, data = self.messages[0]
941 self.assertEqual(mailfrom, 'me')
942 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100943 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100944 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100945 h.close()
946
947 def process_message(self, *args):
948 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100949 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100950
Christian Heimes180510d2008-03-03 19:15:45 +0000951class MemoryHandlerTest(BaseTest):
952
953 """Tests for the MemoryHandler."""
954
955 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300956 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000957
958 def setUp(self):
959 BaseTest.setUp(self)
960 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
961 self.root_hdlr)
962 self.mem_logger = logging.getLogger('mem')
963 self.mem_logger.propagate = 0
964 self.mem_logger.addHandler(self.mem_hdlr)
965
966 def tearDown(self):
967 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000968 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000969
970 def test_flush(self):
971 # The memory handler flushes to its target handler based on specific
972 # criteria (message count and message level).
973 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000974 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000975 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000976 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000977 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100978 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000979 lines = [
980 ('DEBUG', '1'),
981 ('INFO', '2'),
982 ('WARNING', '3'),
983 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000984 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000985 for n in (4, 14):
986 for i in range(9):
987 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 # This will flush because it's the 10th message since the last
990 # flush.
991 self.mem_logger.debug(self.next_message())
992 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000993 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000994
995 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000996 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000997
998
999class ExceptionFormatter(logging.Formatter):
1000 """A special exception formatter."""
1001 def formatException(self, ei):
1002 return "Got a [%s]" % ei[0].__name__
1003
1004
1005class ConfigFileTest(BaseTest):
1006
1007 """Reading logging config from a .ini-style config file."""
1008
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001009 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001010
1011 # config0 is a standard configuration.
1012 config0 = """
1013 [loggers]
1014 keys=root
1015
1016 [handlers]
1017 keys=hand1
1018
1019 [formatters]
1020 keys=form1
1021
1022 [logger_root]
1023 level=WARNING
1024 handlers=hand1
1025
1026 [handler_hand1]
1027 class=StreamHandler
1028 level=NOTSET
1029 formatter=form1
1030 args=(sys.stdout,)
1031
1032 [formatter_form1]
1033 format=%(levelname)s ++ %(message)s
1034 datefmt=
1035 """
1036
1037 # config1 adds a little to the standard configuration.
1038 config1 = """
1039 [loggers]
1040 keys=root,parser
1041
1042 [handlers]
1043 keys=hand1
1044
1045 [formatters]
1046 keys=form1
1047
1048 [logger_root]
1049 level=WARNING
1050 handlers=
1051
1052 [logger_parser]
1053 level=DEBUG
1054 handlers=hand1
1055 propagate=1
1056 qualname=compiler.parser
1057
1058 [handler_hand1]
1059 class=StreamHandler
1060 level=NOTSET
1061 formatter=form1
1062 args=(sys.stdout,)
1063
1064 [formatter_form1]
1065 format=%(levelname)s ++ %(message)s
1066 datefmt=
1067 """
1068
Vinay Sajip3f84b072011-03-07 17:49:33 +00001069 # config1a moves the handler to the root.
1070 config1a = """
1071 [loggers]
1072 keys=root,parser
1073
1074 [handlers]
1075 keys=hand1
1076
1077 [formatters]
1078 keys=form1
1079
1080 [logger_root]
1081 level=WARNING
1082 handlers=hand1
1083
1084 [logger_parser]
1085 level=DEBUG
1086 handlers=
1087 propagate=1
1088 qualname=compiler.parser
1089
1090 [handler_hand1]
1091 class=StreamHandler
1092 level=NOTSET
1093 formatter=form1
1094 args=(sys.stdout,)
1095
1096 [formatter_form1]
1097 format=%(levelname)s ++ %(message)s
1098 datefmt=
1099 """
1100
Christian Heimes180510d2008-03-03 19:15:45 +00001101 # config2 has a subtle configuration error that should be reported
1102 config2 = config1.replace("sys.stdout", "sys.stbout")
1103
1104 # config3 has a less subtle configuration error
1105 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1106
1107 # config4 specifies a custom formatter class to be loaded
1108 config4 = """
1109 [loggers]
1110 keys=root
1111
1112 [handlers]
1113 keys=hand1
1114
1115 [formatters]
1116 keys=form1
1117
1118 [logger_root]
1119 level=NOTSET
1120 handlers=hand1
1121
1122 [handler_hand1]
1123 class=StreamHandler
1124 level=NOTSET
1125 formatter=form1
1126 args=(sys.stdout,)
1127
1128 [formatter_form1]
1129 class=""" + __name__ + """.ExceptionFormatter
1130 format=%(levelname)s:%(name)s:%(message)s
1131 datefmt=
1132 """
1133
Georg Brandl3dbca812008-07-23 16:10:53 +00001134 # config5 specifies a custom handler class to be loaded
1135 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1136
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001137 # config6 uses ', ' delimiters in the handlers and formatters sections
1138 config6 = """
1139 [loggers]
1140 keys=root,parser
1141
1142 [handlers]
1143 keys=hand1, hand2
1144
1145 [formatters]
1146 keys=form1, form2
1147
1148 [logger_root]
1149 level=WARNING
1150 handlers=
1151
1152 [logger_parser]
1153 level=DEBUG
1154 handlers=hand1
1155 propagate=1
1156 qualname=compiler.parser
1157
1158 [handler_hand1]
1159 class=StreamHandler
1160 level=NOTSET
1161 formatter=form1
1162 args=(sys.stdout,)
1163
1164 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001165 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001166 level=NOTSET
1167 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001168 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001169
1170 [formatter_form1]
1171 format=%(levelname)s ++ %(message)s
1172 datefmt=
1173
1174 [formatter_form2]
1175 format=%(message)s
1176 datefmt=
1177 """
1178
Vinay Sajip3f84b072011-03-07 17:49:33 +00001179 # config7 adds a compiler logger.
1180 config7 = """
1181 [loggers]
1182 keys=root,parser,compiler
1183
1184 [handlers]
1185 keys=hand1
1186
1187 [formatters]
1188 keys=form1
1189
1190 [logger_root]
1191 level=WARNING
1192 handlers=hand1
1193
1194 [logger_compiler]
1195 level=DEBUG
1196 handlers=
1197 propagate=1
1198 qualname=compiler
1199
1200 [logger_parser]
1201 level=DEBUG
1202 handlers=
1203 propagate=1
1204 qualname=compiler.parser
1205
1206 [handler_hand1]
1207 class=StreamHandler
1208 level=NOTSET
1209 formatter=form1
1210 args=(sys.stdout,)
1211
1212 [formatter_form1]
1213 format=%(levelname)s ++ %(message)s
1214 datefmt=
1215 """
1216
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001217 disable_test = """
1218 [loggers]
1219 keys=root
1220
1221 [handlers]
1222 keys=screen
1223
1224 [formatters]
1225 keys=
1226
1227 [logger_root]
1228 level=DEBUG
1229 handlers=screen
1230
1231 [handler_screen]
1232 level=DEBUG
1233 class=StreamHandler
1234 args=(sys.stdout,)
1235 formatter=
1236 """
1237
1238 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001239 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001240 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001241
1242 def test_config0_ok(self):
1243 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001244 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001245 self.apply_config(self.config0)
1246 logger = logging.getLogger()
1247 # Won't output anything
1248 logger.info(self.next_message())
1249 # Outputs a message
1250 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001251 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001252 ('ERROR', '2'),
1253 ], stream=output)
1254 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001255 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001256
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001257 def test_config0_using_cp_ok(self):
1258 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001259 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001260 file = io.StringIO(textwrap.dedent(self.config0))
1261 cp = configparser.ConfigParser()
1262 cp.read_file(file)
1263 logging.config.fileConfig(cp)
1264 logger = logging.getLogger()
1265 # Won't output anything
1266 logger.info(self.next_message())
1267 # Outputs a message
1268 logger.error(self.next_message())
1269 self.assert_log_lines([
1270 ('ERROR', '2'),
1271 ], stream=output)
1272 # Original logger output is empty.
1273 self.assert_log_lines([])
1274
Georg Brandl3dbca812008-07-23 16:10:53 +00001275 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001276 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001277 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001278 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001279 logger = logging.getLogger("compiler.parser")
1280 # Both will output a message
1281 logger.info(self.next_message())
1282 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001283 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001284 ('INFO', '1'),
1285 ('ERROR', '2'),
1286 ], stream=output)
1287 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001288 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001289
1290 def test_config2_failure(self):
1291 # A simple config file which overrides the default settings.
1292 self.assertRaises(Exception, self.apply_config, self.config2)
1293
1294 def test_config3_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config3)
1297
1298 def test_config4_ok(self):
1299 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001300 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001301 self.apply_config(self.config4)
1302 logger = logging.getLogger()
1303 try:
1304 raise RuntimeError()
1305 except RuntimeError:
1306 logging.exception("just testing")
1307 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001308 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001309 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1310 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001311 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001312
Georg Brandl3dbca812008-07-23 16:10:53 +00001313 def test_config5_ok(self):
1314 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001315
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001316 def test_config6_ok(self):
1317 self.test_config1_ok(config=self.config6)
1318
Vinay Sajip3f84b072011-03-07 17:49:33 +00001319 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001320 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001321 self.apply_config(self.config1a)
1322 logger = logging.getLogger("compiler.parser")
1323 # See issue #11424. compiler-hyphenated sorts
1324 # between compiler and compiler.xyz and this
1325 # was preventing compiler.xyz from being included
1326 # in the child loggers of compiler because of an
1327 # overzealous loop termination condition.
1328 hyphenated = logging.getLogger('compiler-hyphenated')
1329 # All will output a message
1330 logger.info(self.next_message())
1331 logger.error(self.next_message())
1332 hyphenated.critical(self.next_message())
1333 self.assert_log_lines([
1334 ('INFO', '1'),
1335 ('ERROR', '2'),
1336 ('CRITICAL', '3'),
1337 ], stream=output)
1338 # Original logger output is empty.
1339 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001340 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001341 self.apply_config(self.config7)
1342 logger = logging.getLogger("compiler.parser")
1343 self.assertFalse(logger.disabled)
1344 # Both will output a message
1345 logger.info(self.next_message())
1346 logger.error(self.next_message())
1347 logger = logging.getLogger("compiler.lexer")
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 # Will not appear
1352 hyphenated.critical(self.next_message())
1353 self.assert_log_lines([
1354 ('INFO', '4'),
1355 ('ERROR', '5'),
1356 ('INFO', '6'),
1357 ('ERROR', '7'),
1358 ], stream=output)
1359 # Original logger output is empty.
1360 self.assert_log_lines([])
1361
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001362 def test_logger_disabling(self):
1363 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001364 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001365 self.assertFalse(logger.disabled)
1366 self.apply_config(self.disable_test)
1367 self.assertTrue(logger.disabled)
1368 self.apply_config(self.disable_test, disable_existing_loggers=False)
1369 self.assertFalse(logger.disabled)
1370
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001371
Victor Stinner45df8202010-04-28 22:31:17 +00001372@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001373class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001374
Christian Heimes180510d2008-03-03 19:15:45 +00001375 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001376
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001377 if threading:
1378 server_class = TestTCPServer
1379 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001380
Christian Heimes180510d2008-03-03 19:15:45 +00001381 def setUp(self):
1382 """Set up a TCP server to receive log messages, and a SocketHandler
1383 pointing to that server's address and port."""
1384 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001385 self.server = server = self.server_class(self.address,
1386 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001387 server.start()
1388 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001389 hcls = logging.handlers.SocketHandler
1390 if isinstance(server.server_address, tuple):
1391 self.sock_hdlr = hcls('localhost', server.port)
1392 else:
1393 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001394 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001395 self.root_logger.removeHandler(self.root_logger.handlers[0])
1396 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001397 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001398
Christian Heimes180510d2008-03-03 19:15:45 +00001399 def tearDown(self):
1400 """Shutdown the TCP server."""
1401 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001402 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001403 self.root_logger.removeHandler(self.sock_hdlr)
1404 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001405 finally:
1406 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001407
Vinay Sajip7367d082011-05-02 13:17:27 +01001408 def handle_socket(self, request):
1409 conn = request.connection
1410 while True:
1411 chunk = conn.recv(4)
1412 if len(chunk) < 4:
1413 break
1414 slen = struct.unpack(">L", chunk)[0]
1415 chunk = conn.recv(slen)
1416 while len(chunk) < slen:
1417 chunk = chunk + conn.recv(slen - len(chunk))
1418 obj = pickle.loads(chunk)
1419 record = logging.makeLogRecord(obj)
1420 self.log_output += record.msg + '\n'
1421 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001422
Christian Heimes180510d2008-03-03 19:15:45 +00001423 def test_output(self):
1424 # The log message sent to the SocketHandler is properly received.
1425 logger = logging.getLogger("tcp")
1426 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001427 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001428 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001429 self.handled.acquire()
1430 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001431
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001432 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001433 # Avoid timing-related failures due to SocketHandler's own hard-wired
1434 # one-second timeout on socket.create_connection() (issue #16264).
1435 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001436 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001437 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001438 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001439 try:
1440 raise RuntimeError('Deliberate mistake')
1441 except RuntimeError:
1442 self.root_logger.exception('Never sent')
1443 self.root_logger.error('Never sent, either')
1444 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001445 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001446 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1447 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001448
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001449def _get_temp_domain_socket():
1450 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1451 os.close(fd)
1452 # just need a name - file can't be present, or we'll get an
1453 # 'address already in use' error.
1454 os.remove(fn)
1455 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001456
Victor Stinnerec5a8602014-06-02 14:41:51 +02001457@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001458@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001459class UnixSocketHandlerTest(SocketHandlerTest):
1460
1461 """Test for SocketHandler with unix sockets."""
1462
Victor Stinnerec5a8602014-06-02 14:41:51 +02001463 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001464 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001465
1466 def setUp(self):
1467 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001468 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001469 SocketHandlerTest.setUp(self)
1470
1471 def tearDown(self):
1472 SocketHandlerTest.tearDown(self)
1473 os.remove(self.address)
1474
1475@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001476class DatagramHandlerTest(BaseTest):
1477
1478 """Test for DatagramHandler."""
1479
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001480 if threading:
1481 server_class = TestUDPServer
1482 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001483
Vinay Sajip7367d082011-05-02 13:17:27 +01001484 def setUp(self):
1485 """Set up a UDP server to receive log messages, and a DatagramHandler
1486 pointing to that server's address and port."""
1487 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001488 self.server = server = self.server_class(self.address,
1489 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001490 server.start()
1491 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001492 hcls = logging.handlers.DatagramHandler
1493 if isinstance(server.server_address, tuple):
1494 self.sock_hdlr = hcls('localhost', server.port)
1495 else:
1496 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001497 self.log_output = ''
1498 self.root_logger.removeHandler(self.root_logger.handlers[0])
1499 self.root_logger.addHandler(self.sock_hdlr)
1500 self.handled = threading.Event()
1501
1502 def tearDown(self):
1503 """Shutdown the UDP server."""
1504 try:
1505 self.server.stop(2.0)
1506 self.root_logger.removeHandler(self.sock_hdlr)
1507 self.sock_hdlr.close()
1508 finally:
1509 BaseTest.tearDown(self)
1510
1511 def handle_datagram(self, request):
1512 slen = struct.pack('>L', 0) # length of prefix
1513 packet = request.packet[len(slen):]
1514 obj = pickle.loads(packet)
1515 record = logging.makeLogRecord(obj)
1516 self.log_output += record.msg + '\n'
1517 self.handled.set()
1518
1519 def test_output(self):
1520 # The log message sent to the DatagramHandler is properly received.
1521 logger = logging.getLogger("udp")
1522 logger.error("spam")
1523 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001524 self.handled.clear()
1525 logger.error("eggs")
1526 self.handled.wait()
1527 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001528
Victor Stinnerec5a8602014-06-02 14:41:51 +02001529@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001530@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001531class UnixDatagramHandlerTest(DatagramHandlerTest):
1532
1533 """Test for DatagramHandler using Unix sockets."""
1534
Victor Stinnerec5a8602014-06-02 14:41:51 +02001535 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001536 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001537
1538 def setUp(self):
1539 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001540 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001541 DatagramHandlerTest.setUp(self)
1542
1543 def tearDown(self):
1544 DatagramHandlerTest.tearDown(self)
1545 os.remove(self.address)
1546
1547@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001548class SysLogHandlerTest(BaseTest):
1549
1550 """Test for SysLogHandler using UDP."""
1551
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001552 if threading:
1553 server_class = TestUDPServer
1554 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001555
Vinay Sajip7367d082011-05-02 13:17:27 +01001556 def setUp(self):
1557 """Set up a UDP server to receive log messages, and a SysLogHandler
1558 pointing to that server's address and port."""
1559 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001560 self.server = server = self.server_class(self.address,
1561 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001562 server.start()
1563 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 hcls = logging.handlers.SysLogHandler
1565 if isinstance(server.server_address, tuple):
1566 self.sl_hdlr = hcls(('localhost', server.port))
1567 else:
1568 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001569 self.log_output = ''
1570 self.root_logger.removeHandler(self.root_logger.handlers[0])
1571 self.root_logger.addHandler(self.sl_hdlr)
1572 self.handled = threading.Event()
1573
1574 def tearDown(self):
1575 """Shutdown the UDP server."""
1576 try:
1577 self.server.stop(2.0)
1578 self.root_logger.removeHandler(self.sl_hdlr)
1579 self.sl_hdlr.close()
1580 finally:
1581 BaseTest.tearDown(self)
1582
1583 def handle_datagram(self, request):
1584 self.log_output = request.packet
1585 self.handled.set()
1586
1587 def test_output(self):
1588 # The log message sent to the SysLogHandler is properly received.
1589 logger = logging.getLogger("slh")
1590 logger.error("sp\xe4m")
1591 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001592 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001593 self.handled.clear()
1594 self.sl_hdlr.append_nul = False
1595 logger.error("sp\xe4m")
1596 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001597 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001598 self.handled.clear()
1599 self.sl_hdlr.ident = "h\xe4m-"
1600 logger.error("sp\xe4m")
1601 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001602 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001603
Victor Stinnerec5a8602014-06-02 14:41:51 +02001604@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001605@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001606class UnixSysLogHandlerTest(SysLogHandlerTest):
1607
1608 """Test for SysLogHandler with Unix sockets."""
1609
Victor Stinnerec5a8602014-06-02 14:41:51 +02001610 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001611 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001612
1613 def setUp(self):
1614 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001615 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001616 SysLogHandlerTest.setUp(self)
1617
1618 def tearDown(self):
1619 SysLogHandlerTest.tearDown(self)
1620 os.remove(self.address)
1621
Vinay Sajip5421f352013-09-27 18:18:28 +01001622@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001623class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001624 """Test for HTTPHandler."""
1625
1626 def setUp(self):
1627 """Set up an HTTP server to receive log messages, and a HTTPHandler
1628 pointing to that server's address and port."""
1629 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001630 self.handled = threading.Event()
1631
Vinay Sajip7367d082011-05-02 13:17:27 +01001632 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001633 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001634 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001635 if self.command == 'POST':
1636 try:
1637 rlen = int(request.headers['Content-Length'])
1638 self.post_data = request.rfile.read(rlen)
1639 except:
1640 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001641 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001642 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001643 self.handled.set()
1644
1645 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001646 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001647 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001648 root_logger = self.root_logger
1649 root_logger.removeHandler(self.root_logger.handlers[0])
1650 for secure in (False, True):
1651 addr = ('localhost', 0)
1652 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001653 try:
1654 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001655 except ImportError:
1656 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001657 else:
1658 here = os.path.dirname(__file__)
1659 localhost_cert = os.path.join(here, "keycert.pem")
1660 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1661 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001662
1663 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001664 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001665 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001666 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001667 self.server = server = TestHTTPServer(addr, self.handle_request,
1668 0.01, sslctx=sslctx)
1669 server.start()
1670 server.ready.wait()
1671 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001672 secure_client = secure and sslctx
1673 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001674 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001675 context=context,
1676 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001677 self.log_data = None
1678 root_logger.addHandler(self.h_hdlr)
1679
1680 for method in ('GET', 'POST'):
1681 self.h_hdlr.method = method
1682 self.handled.clear()
1683 msg = "sp\xe4m"
1684 logger.error(msg)
1685 self.handled.wait()
1686 self.assertEqual(self.log_data.path, '/frob')
1687 self.assertEqual(self.command, method)
1688 if method == 'GET':
1689 d = parse_qs(self.log_data.query)
1690 else:
1691 d = parse_qs(self.post_data.decode('utf-8'))
1692 self.assertEqual(d['name'], ['http'])
1693 self.assertEqual(d['funcName'], ['test_output'])
1694 self.assertEqual(d['msg'], [msg])
1695
1696 self.server.stop(2.0)
1697 self.root_logger.removeHandler(self.h_hdlr)
1698 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001699
Christian Heimes180510d2008-03-03 19:15:45 +00001700class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001701
Christian Heimes180510d2008-03-03 19:15:45 +00001702 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001703
Christian Heimes180510d2008-03-03 19:15:45 +00001704 def setUp(self):
1705 """Create a dict to remember potentially destroyed objects."""
1706 BaseTest.setUp(self)
1707 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001708
Christian Heimes180510d2008-03-03 19:15:45 +00001709 def _watch_for_survival(self, *args):
1710 """Watch the given objects for survival, by creating weakrefs to
1711 them."""
1712 for obj in args:
1713 key = id(obj), repr(obj)
1714 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001715
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001716 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001717 """Assert that all objects watched for survival have survived."""
1718 # Trigger cycle breaking.
1719 gc.collect()
1720 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001721 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001722 if ref() is None:
1723 dead.append(repr_)
1724 if dead:
1725 self.fail("%d objects should have survived "
1726 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001727
Christian Heimes180510d2008-03-03 19:15:45 +00001728 def test_persistent_loggers(self):
1729 # Logger objects are persistent and retain their configuration, even
1730 # if visible references are destroyed.
1731 self.root_logger.setLevel(logging.INFO)
1732 foo = logging.getLogger("foo")
1733 self._watch_for_survival(foo)
1734 foo.setLevel(logging.DEBUG)
1735 self.root_logger.debug(self.next_message())
1736 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001737 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001738 ('foo', 'DEBUG', '2'),
1739 ])
1740 del foo
1741 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001742 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001743 # foo has retained its settings.
1744 bar = logging.getLogger("foo")
1745 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001746 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001747 ('foo', 'DEBUG', '2'),
1748 ('foo', 'DEBUG', '3'),
1749 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001750
Benjamin Petersonf91df042009-02-13 02:50:59 +00001751
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001752class EncodingTest(BaseTest):
1753 def test_encoding_plain_file(self):
1754 # In Python 2.x, a plain file object is treated as having no encoding.
1755 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001756 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1757 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001758 # the non-ascii data we write to the log.
1759 data = "foo\x80"
1760 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001761 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001762 log.addHandler(handler)
1763 try:
1764 # write non-ascii data to the log.
1765 log.warning(data)
1766 finally:
1767 log.removeHandler(handler)
1768 handler.close()
1769 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001770 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001771 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001772 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001773 finally:
1774 f.close()
1775 finally:
1776 if os.path.isfile(fn):
1777 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001778
Benjamin Petersonf91df042009-02-13 02:50:59 +00001779 def test_encoding_cyrillic_unicode(self):
1780 log = logging.getLogger("test")
1781 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1782 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1783 #Ensure it's written in a Cyrillic encoding
1784 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001785 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001786 stream = io.BytesIO()
1787 writer = writer_class(stream, 'strict')
1788 handler = logging.StreamHandler(writer)
1789 log.addHandler(handler)
1790 try:
1791 log.warning(message)
1792 finally:
1793 log.removeHandler(handler)
1794 handler.close()
1795 # check we wrote exactly those bytes, ignoring trailing \n etc
1796 s = stream.getvalue()
1797 #Compare against what the data should be when encoded in CP-1251
1798 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1799
1800
Georg Brandlf9734072008-12-07 15:30:06 +00001801class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001802
Georg Brandlf9734072008-12-07 15:30:06 +00001803 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001804 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001805 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001806 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001807 warnings.filterwarnings("always", category=UserWarning)
1808 stream = io.StringIO()
1809 h = logging.StreamHandler(stream)
1810 logger = logging.getLogger("py.warnings")
1811 logger.addHandler(h)
1812 warnings.warn("I'm warning you...")
1813 logger.removeHandler(h)
1814 s = stream.getvalue()
1815 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001816 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001817
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001818 #See if an explicit file uses the original implementation
1819 a_file = io.StringIO()
1820 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1821 a_file, "Dummy line")
1822 s = a_file.getvalue()
1823 a_file.close()
1824 self.assertEqual(s,
1825 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1826
1827 def test_warnings_no_handlers(self):
1828 with warnings.catch_warnings():
1829 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001830 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001831
1832 # confirm our assumption: no loggers are set
1833 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001834 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001835
1836 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001839
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001840
1841def formatFunc(format, datefmt=None):
1842 return logging.Formatter(format, datefmt)
1843
1844def handlerFunc():
1845 return logging.StreamHandler()
1846
1847class CustomHandler(logging.StreamHandler):
1848 pass
1849
1850class ConfigDictTest(BaseTest):
1851
1852 """Reading logging config from a dictionary."""
1853
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001854 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001855
1856 # config0 is a standard configuration.
1857 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001858 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001859 'formatters': {
1860 'form1' : {
1861 'format' : '%(levelname)s ++ %(message)s',
1862 },
1863 },
1864 'handlers' : {
1865 'hand1' : {
1866 'class' : 'logging.StreamHandler',
1867 'formatter' : 'form1',
1868 'level' : 'NOTSET',
1869 'stream' : 'ext://sys.stdout',
1870 },
1871 },
1872 'root' : {
1873 'level' : 'WARNING',
1874 'handlers' : ['hand1'],
1875 },
1876 }
1877
1878 # config1 adds a little to the standard configuration.
1879 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001880 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001881 'formatters': {
1882 'form1' : {
1883 'format' : '%(levelname)s ++ %(message)s',
1884 },
1885 },
1886 'handlers' : {
1887 'hand1' : {
1888 'class' : 'logging.StreamHandler',
1889 'formatter' : 'form1',
1890 'level' : 'NOTSET',
1891 'stream' : 'ext://sys.stdout',
1892 },
1893 },
1894 'loggers' : {
1895 'compiler.parser' : {
1896 'level' : 'DEBUG',
1897 'handlers' : ['hand1'],
1898 },
1899 },
1900 'root' : {
1901 'level' : 'WARNING',
1902 },
1903 }
1904
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001905 # config1a moves the handler to the root. Used with config8a
1906 config1a = {
1907 'version': 1,
1908 'formatters': {
1909 'form1' : {
1910 'format' : '%(levelname)s ++ %(message)s',
1911 },
1912 },
1913 'handlers' : {
1914 'hand1' : {
1915 'class' : 'logging.StreamHandler',
1916 'formatter' : 'form1',
1917 'level' : 'NOTSET',
1918 'stream' : 'ext://sys.stdout',
1919 },
1920 },
1921 'loggers' : {
1922 'compiler.parser' : {
1923 'level' : 'DEBUG',
1924 },
1925 },
1926 'root' : {
1927 'level' : 'WARNING',
1928 'handlers' : ['hand1'],
1929 },
1930 }
1931
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001932 # config2 has a subtle configuration error that should be reported
1933 config2 = {
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.stdbout',
1946 },
1947 },
1948 'loggers' : {
1949 'compiler.parser' : {
1950 'level' : 'DEBUG',
1951 'handlers' : ['hand1'],
1952 },
1953 },
1954 'root' : {
1955 'level' : 'WARNING',
1956 },
1957 }
1958
1959 #As config1 but with a misspelt level on a handler
1960 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001961 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001962 'formatters': {
1963 'form1' : {
1964 'format' : '%(levelname)s ++ %(message)s',
1965 },
1966 },
1967 'handlers' : {
1968 'hand1' : {
1969 'class' : 'logging.StreamHandler',
1970 'formatter' : 'form1',
1971 'level' : 'NTOSET',
1972 'stream' : 'ext://sys.stdout',
1973 },
1974 },
1975 'loggers' : {
1976 'compiler.parser' : {
1977 'level' : 'DEBUG',
1978 'handlers' : ['hand1'],
1979 },
1980 },
1981 'root' : {
1982 'level' : 'WARNING',
1983 },
1984 }
1985
1986
1987 #As config1 but with a misspelt level on a logger
1988 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001989 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001990 'formatters': {
1991 'form1' : {
1992 'format' : '%(levelname)s ++ %(message)s',
1993 },
1994 },
1995 'handlers' : {
1996 'hand1' : {
1997 'class' : 'logging.StreamHandler',
1998 'formatter' : 'form1',
1999 'level' : 'NOTSET',
2000 'stream' : 'ext://sys.stdout',
2001 },
2002 },
2003 'loggers' : {
2004 'compiler.parser' : {
2005 'level' : 'DEBUG',
2006 'handlers' : ['hand1'],
2007 },
2008 },
2009 'root' : {
2010 'level' : 'WRANING',
2011 },
2012 }
2013
2014 # config3 has a less subtle configuration error
2015 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002016 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002017 'formatters': {
2018 'form1' : {
2019 'format' : '%(levelname)s ++ %(message)s',
2020 },
2021 },
2022 'handlers' : {
2023 'hand1' : {
2024 'class' : 'logging.StreamHandler',
2025 'formatter' : 'misspelled_name',
2026 'level' : 'NOTSET',
2027 'stream' : 'ext://sys.stdout',
2028 },
2029 },
2030 'loggers' : {
2031 'compiler.parser' : {
2032 'level' : 'DEBUG',
2033 'handlers' : ['hand1'],
2034 },
2035 },
2036 'root' : {
2037 'level' : 'WARNING',
2038 },
2039 }
2040
2041 # config4 specifies a custom formatter class to be loaded
2042 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002043 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002044 'formatters': {
2045 'form1' : {
2046 '()' : __name__ + '.ExceptionFormatter',
2047 'format' : '%(levelname)s:%(name)s:%(message)s',
2048 },
2049 },
2050 'handlers' : {
2051 'hand1' : {
2052 'class' : 'logging.StreamHandler',
2053 'formatter' : 'form1',
2054 'level' : 'NOTSET',
2055 'stream' : 'ext://sys.stdout',
2056 },
2057 },
2058 'root' : {
2059 'level' : 'NOTSET',
2060 'handlers' : ['hand1'],
2061 },
2062 }
2063
2064 # As config4 but using an actual callable rather than a string
2065 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002066 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002067 'formatters': {
2068 'form1' : {
2069 '()' : ExceptionFormatter,
2070 'format' : '%(levelname)s:%(name)s:%(message)s',
2071 },
2072 'form2' : {
2073 '()' : __name__ + '.formatFunc',
2074 'format' : '%(levelname)s:%(name)s:%(message)s',
2075 },
2076 'form3' : {
2077 '()' : formatFunc,
2078 'format' : '%(levelname)s:%(name)s:%(message)s',
2079 },
2080 },
2081 'handlers' : {
2082 'hand1' : {
2083 'class' : 'logging.StreamHandler',
2084 'formatter' : 'form1',
2085 'level' : 'NOTSET',
2086 'stream' : 'ext://sys.stdout',
2087 },
2088 'hand2' : {
2089 '()' : handlerFunc,
2090 },
2091 },
2092 'root' : {
2093 'level' : 'NOTSET',
2094 'handlers' : ['hand1'],
2095 },
2096 }
2097
2098 # config5 specifies a custom handler class to be loaded
2099 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002100 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002101 'formatters': {
2102 'form1' : {
2103 'format' : '%(levelname)s ++ %(message)s',
2104 },
2105 },
2106 'handlers' : {
2107 'hand1' : {
2108 'class' : __name__ + '.CustomHandler',
2109 'formatter' : 'form1',
2110 'level' : 'NOTSET',
2111 'stream' : 'ext://sys.stdout',
2112 },
2113 },
2114 'loggers' : {
2115 'compiler.parser' : {
2116 'level' : 'DEBUG',
2117 'handlers' : ['hand1'],
2118 },
2119 },
2120 'root' : {
2121 'level' : 'WARNING',
2122 },
2123 }
2124
2125 # config6 specifies a custom handler class to be loaded
2126 # but has bad arguments
2127 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002128 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002129 'formatters': {
2130 'form1' : {
2131 'format' : '%(levelname)s ++ %(message)s',
2132 },
2133 },
2134 'handlers' : {
2135 'hand1' : {
2136 'class' : __name__ + '.CustomHandler',
2137 'formatter' : 'form1',
2138 'level' : 'NOTSET',
2139 'stream' : 'ext://sys.stdout',
2140 '9' : 'invalid parameter name',
2141 },
2142 },
2143 'loggers' : {
2144 'compiler.parser' : {
2145 'level' : 'DEBUG',
2146 'handlers' : ['hand1'],
2147 },
2148 },
2149 'root' : {
2150 'level' : 'WARNING',
2151 },
2152 }
2153
2154 #config 7 does not define compiler.parser but defines compiler.lexer
2155 #so compiler.parser should be disabled after applying it
2156 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002157 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002158 'formatters': {
2159 'form1' : {
2160 'format' : '%(levelname)s ++ %(message)s',
2161 },
2162 },
2163 'handlers' : {
2164 'hand1' : {
2165 'class' : 'logging.StreamHandler',
2166 'formatter' : 'form1',
2167 'level' : 'NOTSET',
2168 'stream' : 'ext://sys.stdout',
2169 },
2170 },
2171 'loggers' : {
2172 'compiler.lexer' : {
2173 'level' : 'DEBUG',
2174 'handlers' : ['hand1'],
2175 },
2176 },
2177 'root' : {
2178 'level' : 'WARNING',
2179 },
2180 }
2181
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002182 # config8 defines both compiler and compiler.lexer
2183 # so compiler.parser should not be disabled (since
2184 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002185 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002186 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002187 'disable_existing_loggers' : False,
2188 'formatters': {
2189 'form1' : {
2190 'format' : '%(levelname)s ++ %(message)s',
2191 },
2192 },
2193 'handlers' : {
2194 'hand1' : {
2195 'class' : 'logging.StreamHandler',
2196 'formatter' : 'form1',
2197 'level' : 'NOTSET',
2198 'stream' : 'ext://sys.stdout',
2199 },
2200 },
2201 'loggers' : {
2202 'compiler' : {
2203 'level' : 'DEBUG',
2204 'handlers' : ['hand1'],
2205 },
2206 'compiler.lexer' : {
2207 },
2208 },
2209 'root' : {
2210 'level' : 'WARNING',
2211 },
2212 }
2213
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002214 # config8a disables existing loggers
2215 config8a = {
2216 'version': 1,
2217 'disable_existing_loggers' : True,
2218 'formatters': {
2219 'form1' : {
2220 'format' : '%(levelname)s ++ %(message)s',
2221 },
2222 },
2223 'handlers' : {
2224 'hand1' : {
2225 'class' : 'logging.StreamHandler',
2226 'formatter' : 'form1',
2227 'level' : 'NOTSET',
2228 'stream' : 'ext://sys.stdout',
2229 },
2230 },
2231 'loggers' : {
2232 'compiler' : {
2233 'level' : 'DEBUG',
2234 'handlers' : ['hand1'],
2235 },
2236 'compiler.lexer' : {
2237 },
2238 },
2239 'root' : {
2240 'level' : 'WARNING',
2241 },
2242 }
2243
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002244 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002245 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002246 'formatters': {
2247 'form1' : {
2248 'format' : '%(levelname)s ++ %(message)s',
2249 },
2250 },
2251 'handlers' : {
2252 'hand1' : {
2253 'class' : 'logging.StreamHandler',
2254 'formatter' : 'form1',
2255 'level' : 'WARNING',
2256 'stream' : 'ext://sys.stdout',
2257 },
2258 },
2259 'loggers' : {
2260 'compiler.parser' : {
2261 'level' : 'WARNING',
2262 'handlers' : ['hand1'],
2263 },
2264 },
2265 'root' : {
2266 'level' : 'NOTSET',
2267 },
2268 }
2269
2270 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002271 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002272 'incremental' : True,
2273 'handlers' : {
2274 'hand1' : {
2275 'level' : 'WARNING',
2276 },
2277 },
2278 'loggers' : {
2279 'compiler.parser' : {
2280 'level' : 'INFO',
2281 },
2282 },
2283 }
2284
2285 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002286 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002287 'incremental' : True,
2288 'handlers' : {
2289 'hand1' : {
2290 'level' : 'INFO',
2291 },
2292 },
2293 'loggers' : {
2294 'compiler.parser' : {
2295 'level' : 'INFO',
2296 },
2297 },
2298 }
2299
2300 #As config1 but with a filter added
2301 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002302 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002303 'formatters': {
2304 'form1' : {
2305 'format' : '%(levelname)s ++ %(message)s',
2306 },
2307 },
2308 'filters' : {
2309 'filt1' : {
2310 'name' : 'compiler.parser',
2311 },
2312 },
2313 'handlers' : {
2314 'hand1' : {
2315 'class' : 'logging.StreamHandler',
2316 'formatter' : 'form1',
2317 'level' : 'NOTSET',
2318 'stream' : 'ext://sys.stdout',
2319 'filters' : ['filt1'],
2320 },
2321 },
2322 'loggers' : {
2323 'compiler.parser' : {
2324 'level' : 'DEBUG',
2325 'filters' : ['filt1'],
2326 },
2327 },
2328 'root' : {
2329 'level' : 'WARNING',
2330 'handlers' : ['hand1'],
2331 },
2332 }
2333
2334 #As config1 but using cfg:// references
2335 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002336 'version': 1,
2337 'true_formatters': {
2338 'form1' : {
2339 'format' : '%(levelname)s ++ %(message)s',
2340 },
2341 },
2342 'handler_configs': {
2343 'hand1' : {
2344 'class' : 'logging.StreamHandler',
2345 'formatter' : 'form1',
2346 'level' : 'NOTSET',
2347 'stream' : 'ext://sys.stdout',
2348 },
2349 },
2350 'formatters' : 'cfg://true_formatters',
2351 'handlers' : {
2352 'hand1' : 'cfg://handler_configs[hand1]',
2353 },
2354 'loggers' : {
2355 'compiler.parser' : {
2356 'level' : 'DEBUG',
2357 'handlers' : ['hand1'],
2358 },
2359 },
2360 'root' : {
2361 'level' : 'WARNING',
2362 },
2363 }
2364
2365 #As config11 but missing the version key
2366 config12 = {
2367 'true_formatters': {
2368 'form1' : {
2369 'format' : '%(levelname)s ++ %(message)s',
2370 },
2371 },
2372 'handler_configs': {
2373 'hand1' : {
2374 'class' : 'logging.StreamHandler',
2375 'formatter' : 'form1',
2376 'level' : 'NOTSET',
2377 'stream' : 'ext://sys.stdout',
2378 },
2379 },
2380 'formatters' : 'cfg://true_formatters',
2381 'handlers' : {
2382 'hand1' : 'cfg://handler_configs[hand1]',
2383 },
2384 'loggers' : {
2385 'compiler.parser' : {
2386 'level' : 'DEBUG',
2387 'handlers' : ['hand1'],
2388 },
2389 },
2390 'root' : {
2391 'level' : 'WARNING',
2392 },
2393 }
2394
2395 #As config11 but using an unsupported version
2396 config13 = {
2397 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002398 'true_formatters': {
2399 'form1' : {
2400 'format' : '%(levelname)s ++ %(message)s',
2401 },
2402 },
2403 'handler_configs': {
2404 'hand1' : {
2405 'class' : 'logging.StreamHandler',
2406 'formatter' : 'form1',
2407 'level' : 'NOTSET',
2408 'stream' : 'ext://sys.stdout',
2409 },
2410 },
2411 'formatters' : 'cfg://true_formatters',
2412 'handlers' : {
2413 'hand1' : 'cfg://handler_configs[hand1]',
2414 },
2415 'loggers' : {
2416 'compiler.parser' : {
2417 'level' : 'DEBUG',
2418 'handlers' : ['hand1'],
2419 },
2420 },
2421 'root' : {
2422 'level' : 'WARNING',
2423 },
2424 }
2425
Vinay Sajip8d270232012-11-15 14:20:18 +00002426 # As config0, but with properties
2427 config14 = {
2428 'version': 1,
2429 'formatters': {
2430 'form1' : {
2431 'format' : '%(levelname)s ++ %(message)s',
2432 },
2433 },
2434 'handlers' : {
2435 'hand1' : {
2436 'class' : 'logging.StreamHandler',
2437 'formatter' : 'form1',
2438 'level' : 'NOTSET',
2439 'stream' : 'ext://sys.stdout',
2440 '.': {
2441 'foo': 'bar',
2442 'terminator': '!\n',
2443 }
2444 },
2445 },
2446 'root' : {
2447 'level' : 'WARNING',
2448 'handlers' : ['hand1'],
2449 },
2450 }
2451
Vinay Sajip3f885b52013-03-22 15:19:54 +00002452 out_of_order = {
2453 "version": 1,
2454 "formatters": {
2455 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002456 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2457 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002458 }
2459 },
2460 "handlers": {
2461 "fileGlobal": {
2462 "class": "logging.StreamHandler",
2463 "level": "DEBUG",
2464 "formatter": "mySimpleFormatter"
2465 },
2466 "bufferGlobal": {
2467 "class": "logging.handlers.MemoryHandler",
2468 "capacity": 5,
2469 "formatter": "mySimpleFormatter",
2470 "target": "fileGlobal",
2471 "level": "DEBUG"
2472 }
2473 },
2474 "loggers": {
2475 "mymodule": {
2476 "level": "DEBUG",
2477 "handlers": ["bufferGlobal"],
2478 "propagate": "true"
2479 }
2480 }
2481 }
2482
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002483 def apply_config(self, conf):
2484 logging.config.dictConfig(conf)
2485
2486 def test_config0_ok(self):
2487 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002488 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002489 self.apply_config(self.config0)
2490 logger = logging.getLogger()
2491 # Won't output anything
2492 logger.info(self.next_message())
2493 # Outputs a message
2494 logger.error(self.next_message())
2495 self.assert_log_lines([
2496 ('ERROR', '2'),
2497 ], stream=output)
2498 # Original logger output is empty.
2499 self.assert_log_lines([])
2500
2501 def test_config1_ok(self, config=config1):
2502 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002503 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002504 self.apply_config(config)
2505 logger = logging.getLogger("compiler.parser")
2506 # Both will output a message
2507 logger.info(self.next_message())
2508 logger.error(self.next_message())
2509 self.assert_log_lines([
2510 ('INFO', '1'),
2511 ('ERROR', '2'),
2512 ], stream=output)
2513 # Original logger output is empty.
2514 self.assert_log_lines([])
2515
2516 def test_config2_failure(self):
2517 # A simple config which overrides the default settings.
2518 self.assertRaises(Exception, self.apply_config, self.config2)
2519
2520 def test_config2a_failure(self):
2521 # A simple config which overrides the default settings.
2522 self.assertRaises(Exception, self.apply_config, self.config2a)
2523
2524 def test_config2b_failure(self):
2525 # A simple config which overrides the default settings.
2526 self.assertRaises(Exception, self.apply_config, self.config2b)
2527
2528 def test_config3_failure(self):
2529 # A simple config which overrides the default settings.
2530 self.assertRaises(Exception, self.apply_config, self.config3)
2531
2532 def test_config4_ok(self):
2533 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002534 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002535 self.apply_config(self.config4)
2536 #logger = logging.getLogger()
2537 try:
2538 raise RuntimeError()
2539 except RuntimeError:
2540 logging.exception("just testing")
2541 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002542 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002543 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2544 # Original logger output is empty
2545 self.assert_log_lines([])
2546
2547 def test_config4a_ok(self):
2548 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002549 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002550 self.apply_config(self.config4a)
2551 #logger = logging.getLogger()
2552 try:
2553 raise RuntimeError()
2554 except RuntimeError:
2555 logging.exception("just testing")
2556 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002557 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002558 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2559 # Original logger output is empty
2560 self.assert_log_lines([])
2561
2562 def test_config5_ok(self):
2563 self.test_config1_ok(config=self.config5)
2564
2565 def test_config6_failure(self):
2566 self.assertRaises(Exception, self.apply_config, self.config6)
2567
2568 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002569 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002570 self.apply_config(self.config1)
2571 logger = logging.getLogger("compiler.parser")
2572 # Both will output a message
2573 logger.info(self.next_message())
2574 logger.error(self.next_message())
2575 self.assert_log_lines([
2576 ('INFO', '1'),
2577 ('ERROR', '2'),
2578 ], stream=output)
2579 # Original logger output is empty.
2580 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002581 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002582 self.apply_config(self.config7)
2583 logger = logging.getLogger("compiler.parser")
2584 self.assertTrue(logger.disabled)
2585 logger = logging.getLogger("compiler.lexer")
2586 # Both will output a message
2587 logger.info(self.next_message())
2588 logger.error(self.next_message())
2589 self.assert_log_lines([
2590 ('INFO', '3'),
2591 ('ERROR', '4'),
2592 ], stream=output)
2593 # Original logger output is empty.
2594 self.assert_log_lines([])
2595
2596 #Same as test_config_7_ok but don't disable old loggers.
2597 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002598 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002599 self.apply_config(self.config1)
2600 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002601 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002602 logger.info(self.next_message())
2603 logger.error(self.next_message())
2604 self.assert_log_lines([
2605 ('INFO', '1'),
2606 ('ERROR', '2'),
2607 ], stream=output)
2608 # Original logger output is empty.
2609 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002610 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002611 self.apply_config(self.config8)
2612 logger = logging.getLogger("compiler.parser")
2613 self.assertFalse(logger.disabled)
2614 # Both will output a message
2615 logger.info(self.next_message())
2616 logger.error(self.next_message())
2617 logger = logging.getLogger("compiler.lexer")
2618 # Both will output a message
2619 logger.info(self.next_message())
2620 logger.error(self.next_message())
2621 self.assert_log_lines([
2622 ('INFO', '3'),
2623 ('ERROR', '4'),
2624 ('INFO', '5'),
2625 ('ERROR', '6'),
2626 ], stream=output)
2627 # Original logger output is empty.
2628 self.assert_log_lines([])
2629
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002630 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002631 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002632 self.apply_config(self.config1a)
2633 logger = logging.getLogger("compiler.parser")
2634 # See issue #11424. compiler-hyphenated sorts
2635 # between compiler and compiler.xyz and this
2636 # was preventing compiler.xyz from being included
2637 # in the child loggers of compiler because of an
2638 # overzealous loop termination condition.
2639 hyphenated = logging.getLogger('compiler-hyphenated')
2640 # All will output a message
2641 logger.info(self.next_message())
2642 logger.error(self.next_message())
2643 hyphenated.critical(self.next_message())
2644 self.assert_log_lines([
2645 ('INFO', '1'),
2646 ('ERROR', '2'),
2647 ('CRITICAL', '3'),
2648 ], stream=output)
2649 # Original logger output is empty.
2650 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002651 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002652 self.apply_config(self.config8a)
2653 logger = logging.getLogger("compiler.parser")
2654 self.assertFalse(logger.disabled)
2655 # Both will output a message
2656 logger.info(self.next_message())
2657 logger.error(self.next_message())
2658 logger = logging.getLogger("compiler.lexer")
2659 # Both will output a message
2660 logger.info(self.next_message())
2661 logger.error(self.next_message())
2662 # Will not appear
2663 hyphenated.critical(self.next_message())
2664 self.assert_log_lines([
2665 ('INFO', '4'),
2666 ('ERROR', '5'),
2667 ('INFO', '6'),
2668 ('ERROR', '7'),
2669 ], stream=output)
2670 # Original logger output is empty.
2671 self.assert_log_lines([])
2672
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002673 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002674 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002675 self.apply_config(self.config9)
2676 logger = logging.getLogger("compiler.parser")
2677 #Nothing will be output since both handler and logger are set to WARNING
2678 logger.info(self.next_message())
2679 self.assert_log_lines([], stream=output)
2680 self.apply_config(self.config9a)
2681 #Nothing will be output since both handler is still set to WARNING
2682 logger.info(self.next_message())
2683 self.assert_log_lines([], stream=output)
2684 self.apply_config(self.config9b)
2685 #Message should now be output
2686 logger.info(self.next_message())
2687 self.assert_log_lines([
2688 ('INFO', '3'),
2689 ], stream=output)
2690
2691 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002692 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002693 self.apply_config(self.config10)
2694 logger = logging.getLogger("compiler.parser")
2695 logger.warning(self.next_message())
2696 logger = logging.getLogger('compiler')
2697 #Not output, because filtered
2698 logger.warning(self.next_message())
2699 logger = logging.getLogger('compiler.lexer')
2700 #Not output, because filtered
2701 logger.warning(self.next_message())
2702 logger = logging.getLogger("compiler.parser.codegen")
2703 #Output, as not filtered
2704 logger.error(self.next_message())
2705 self.assert_log_lines([
2706 ('WARNING', '1'),
2707 ('ERROR', '4'),
2708 ], stream=output)
2709
2710 def test_config11_ok(self):
2711 self.test_config1_ok(self.config11)
2712
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002713 def test_config12_failure(self):
2714 self.assertRaises(Exception, self.apply_config, self.config12)
2715
2716 def test_config13_failure(self):
2717 self.assertRaises(Exception, self.apply_config, self.config13)
2718
Vinay Sajip8d270232012-11-15 14:20:18 +00002719 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002720 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002721 self.apply_config(self.config14)
2722 h = logging._handlers['hand1']
2723 self.assertEqual(h.foo, 'bar')
2724 self.assertEqual(h.terminator, '!\n')
2725 logging.warning('Exclamation')
2726 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2727
Victor Stinner45df8202010-04-28 22:31:17 +00002728 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002729 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002730 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002731 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002732 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002733 t.start()
2734 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002735 # Now get the port allocated
2736 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002737 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002738 try:
2739 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2740 sock.settimeout(2.0)
2741 sock.connect(('localhost', port))
2742
2743 slen = struct.pack('>L', len(text))
2744 s = slen + text
2745 sentsofar = 0
2746 left = len(s)
2747 while left > 0:
2748 sent = sock.send(s[sentsofar:])
2749 sentsofar += sent
2750 left -= sent
2751 sock.close()
2752 finally:
2753 t.ready.wait(2.0)
2754 logging.config.stopListening()
2755 t.join(2.0)
2756
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002757 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002758 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002759 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002760 self.setup_via_listener(json.dumps(self.config10))
2761 logger = logging.getLogger("compiler.parser")
2762 logger.warning(self.next_message())
2763 logger = logging.getLogger('compiler')
2764 #Not output, because filtered
2765 logger.warning(self.next_message())
2766 logger = logging.getLogger('compiler.lexer')
2767 #Not output, because filtered
2768 logger.warning(self.next_message())
2769 logger = logging.getLogger("compiler.parser.codegen")
2770 #Output, as not filtered
2771 logger.error(self.next_message())
2772 self.assert_log_lines([
2773 ('WARNING', '1'),
2774 ('ERROR', '4'),
2775 ], stream=output)
2776
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002777 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002778 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002779 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002780 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2781 logger = logging.getLogger("compiler.parser")
2782 # Both will output a message
2783 logger.info(self.next_message())
2784 logger.error(self.next_message())
2785 self.assert_log_lines([
2786 ('INFO', '1'),
2787 ('ERROR', '2'),
2788 ], stream=output)
2789 # Original logger output is empty.
2790 self.assert_log_lines([])
2791
Vinay Sajip4ded5512012-10-02 15:56:16 +01002792 @unittest.skipUnless(threading, 'Threading required for this test.')
2793 def test_listen_verify(self):
2794
2795 def verify_fail(stuff):
2796 return None
2797
2798 def verify_reverse(stuff):
2799 return stuff[::-1]
2800
2801 logger = logging.getLogger("compiler.parser")
2802 to_send = textwrap.dedent(ConfigFileTest.config1)
2803 # First, specify a verification function that will fail.
2804 # We expect to see no output, since our configuration
2805 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002806 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002807 self.setup_via_listener(to_send, verify_fail)
2808 # Both will output a message
2809 logger.info(self.next_message())
2810 logger.error(self.next_message())
2811 self.assert_log_lines([], stream=output)
2812 # Original logger output has the stuff we logged.
2813 self.assert_log_lines([
2814 ('INFO', '1'),
2815 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002816 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002817
2818 # Now, perform no verification. Our configuration
2819 # should take effect.
2820
Vinay Sajip1feedb42014-05-31 08:19:12 +01002821 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002822 self.setup_via_listener(to_send) # no verify callable specified
2823 logger = logging.getLogger("compiler.parser")
2824 # Both will output a message
2825 logger.info(self.next_message())
2826 logger.error(self.next_message())
2827 self.assert_log_lines([
2828 ('INFO', '3'),
2829 ('ERROR', '4'),
2830 ], stream=output)
2831 # Original logger output still has the stuff we logged before.
2832 self.assert_log_lines([
2833 ('INFO', '1'),
2834 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002835 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002836
2837 # Now, perform verification which transforms the bytes.
2838
Vinay Sajip1feedb42014-05-31 08:19:12 +01002839 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002840 self.setup_via_listener(to_send[::-1], verify_reverse)
2841 logger = logging.getLogger("compiler.parser")
2842 # Both will output a message
2843 logger.info(self.next_message())
2844 logger.error(self.next_message())
2845 self.assert_log_lines([
2846 ('INFO', '5'),
2847 ('ERROR', '6'),
2848 ], stream=output)
2849 # Original logger output still has the stuff we logged before.
2850 self.assert_log_lines([
2851 ('INFO', '1'),
2852 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002853 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002854
Vinay Sajip3f885b52013-03-22 15:19:54 +00002855 def test_out_of_order(self):
2856 self.apply_config(self.out_of_order)
2857 handler = logging.getLogger('mymodule').handlers[0]
2858 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002859 self.assertIsInstance(handler.formatter._style,
2860 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002861
Vinay Sajip373baef2011-04-26 20:05:24 +01002862 def test_baseconfig(self):
2863 d = {
2864 'atuple': (1, 2, 3),
2865 'alist': ['a', 'b', 'c'],
2866 'adict': {'d': 'e', 'f': 3 },
2867 'nest1': ('g', ('h', 'i'), 'j'),
2868 'nest2': ['k', ['l', 'm'], 'n'],
2869 'nest3': ['o', 'cfg://alist', 'p'],
2870 }
2871 bc = logging.config.BaseConfigurator(d)
2872 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2873 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2874 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2875 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2876 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2877 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2878 v = bc.convert('cfg://nest3')
2879 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2880 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2881 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2882 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002883
2884class ManagerTest(BaseTest):
2885 def test_manager_loggerclass(self):
2886 logged = []
2887
2888 class MyLogger(logging.Logger):
2889 def _log(self, level, msg, args, exc_info=None, extra=None):
2890 logged.append(msg)
2891
2892 man = logging.Manager(None)
2893 self.assertRaises(TypeError, man.setLoggerClass, int)
2894 man.setLoggerClass(MyLogger)
2895 logger = man.getLogger('test')
2896 logger.warning('should appear in logged')
2897 logging.warning('should not appear in logged')
2898
2899 self.assertEqual(logged, ['should appear in logged'])
2900
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002901 def test_set_log_record_factory(self):
2902 man = logging.Manager(None)
2903 expected = object()
2904 man.setLogRecordFactory(expected)
2905 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002906
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002907class ChildLoggerTest(BaseTest):
2908 def test_child_loggers(self):
2909 r = logging.getLogger()
2910 l1 = logging.getLogger('abc')
2911 l2 = logging.getLogger('def.ghi')
2912 c1 = r.getChild('xyz')
2913 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002914 self.assertIs(c1, logging.getLogger('xyz'))
2915 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002916 c1 = l1.getChild('def')
2917 c2 = c1.getChild('ghi')
2918 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002919 self.assertIs(c1, logging.getLogger('abc.def'))
2920 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2921 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002922
2923
Vinay Sajip6fac8172010-10-19 20:44:14 +00002924class DerivedLogRecord(logging.LogRecord):
2925 pass
2926
Vinay Sajip61561522010-12-03 11:50:38 +00002927class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002928
2929 def setUp(self):
2930 class CheckingFilter(logging.Filter):
2931 def __init__(self, cls):
2932 self.cls = cls
2933
2934 def filter(self, record):
2935 t = type(record)
2936 if t is not self.cls:
2937 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2938 self.cls)
2939 raise TypeError(msg)
2940 return True
2941
2942 BaseTest.setUp(self)
2943 self.filter = CheckingFilter(DerivedLogRecord)
2944 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002945 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002946
2947 def tearDown(self):
2948 self.root_logger.removeFilter(self.filter)
2949 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002950 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002951
2952 def test_logrecord_class(self):
2953 self.assertRaises(TypeError, self.root_logger.warning,
2954 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002955 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002956 self.root_logger.error(self.next_message())
2957 self.assert_log_lines([
2958 ('root', 'ERROR', '2'),
2959 ])
2960
2961
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002962class QueueHandlerTest(BaseTest):
2963 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002964 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002965
2966 def setUp(self):
2967 BaseTest.setUp(self)
2968 self.queue = queue.Queue(-1)
2969 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2970 self.que_logger = logging.getLogger('que')
2971 self.que_logger.propagate = False
2972 self.que_logger.setLevel(logging.WARNING)
2973 self.que_logger.addHandler(self.que_hdlr)
2974
2975 def tearDown(self):
2976 self.que_hdlr.close()
2977 BaseTest.tearDown(self)
2978
2979 def test_queue_handler(self):
2980 self.que_logger.debug(self.next_message())
2981 self.assertRaises(queue.Empty, self.queue.get_nowait)
2982 self.que_logger.info(self.next_message())
2983 self.assertRaises(queue.Empty, self.queue.get_nowait)
2984 msg = self.next_message()
2985 self.que_logger.warning(msg)
2986 data = self.queue.get_nowait()
2987 self.assertTrue(isinstance(data, logging.LogRecord))
2988 self.assertEqual(data.name, self.que_logger.name)
2989 self.assertEqual((data.msg, data.args), (msg, None))
2990
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002991 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2992 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002993 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002994 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01002995 listener = logging.handlers.QueueListener(self.queue, handler)
2996 listener.start()
2997 try:
2998 self.que_logger.warning(self.next_message())
2999 self.que_logger.error(self.next_message())
3000 self.que_logger.critical(self.next_message())
3001 finally:
3002 listener.stop()
3003 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3004 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3005 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003006 handler.close()
3007
3008 # Now test with respect_handler_level set
3009
3010 handler = support.TestHandler(support.Matcher())
3011 handler.setLevel(logging.CRITICAL)
3012 listener = logging.handlers.QueueListener(self.queue, handler,
3013 respect_handler_level=True)
3014 listener.start()
3015 try:
3016 self.que_logger.warning(self.next_message())
3017 self.que_logger.error(self.next_message())
3018 self.que_logger.critical(self.next_message())
3019 finally:
3020 listener.stop()
3021 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3022 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3023 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3024
Vinay Sajipd61910c2016-09-08 01:13:39 +01003025if hasattr(logging.handlers, 'QueueListener'):
3026 import multiprocessing
3027 from unittest.mock import patch
3028
3029 class QueueListenerTest(BaseTest):
3030 """
3031 Tests based on patch submitted for issue #27930. Ensure that
3032 QueueListener handles all log messages.
3033 """
3034
3035 repeat = 20
3036
3037 @staticmethod
3038 def setup_and_log(log_queue, ident):
3039 """
3040 Creates a logger with a QueueHandler that logs to a queue read by a
3041 QueueListener. Starts the listener, logs five messages, and stops
3042 the listener.
3043 """
3044 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3045 logger.setLevel(logging.DEBUG)
3046 handler = logging.handlers.QueueHandler(log_queue)
3047 logger.addHandler(handler)
3048 listener = logging.handlers.QueueListener(log_queue)
3049 listener.start()
3050
3051 logger.info('one')
3052 logger.info('two')
3053 logger.info('three')
3054 logger.info('four')
3055 logger.info('five')
3056
3057 listener.stop()
3058 logger.removeHandler(handler)
3059 handler.close()
3060
3061 @patch.object(logging.handlers.QueueListener, 'handle')
3062 def test_handle_called_with_queue_queue(self, mock_handle):
3063 for i in range(self.repeat):
3064 log_queue = queue.Queue()
3065 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3066 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3067 'correct number of handled log messages')
3068
3069 @patch.object(logging.handlers.QueueListener, 'handle')
3070 def test_handle_called_with_mp_queue(self, mock_handle):
3071 for i in range(self.repeat):
3072 log_queue = multiprocessing.Queue()
3073 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3074 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3075 'correct number of handled log messages')
3076
3077 @staticmethod
3078 def get_all_from_queue(log_queue):
3079 try:
3080 while True:
3081 yield log_queue.get_nowait()
3082 except queue.Empty:
3083 return []
3084
3085 def test_no_messages_in_queue_after_stop(self):
3086 """
3087 Five messages are logged then the QueueListener is stopped. This
3088 test then gets everything off the queue. Failure of this test
3089 indicates that messages were not registered on the queue until
3090 _after_ the QueueListener stopped.
3091 """
3092 for i in range(self.repeat):
3093 queue = multiprocessing.Queue()
3094 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3095 # time.sleep(1)
3096 items = list(self.get_all_from_queue(queue))
3097 expected = [[], [logging.handlers.QueueListener._sentinel]]
3098 self.assertIn(items, expected,
3099 'Found unexpected messages in queue: %s' % (
3100 [m.msg if isinstance(m, logging.LogRecord)
3101 else m for m in items]))
3102
Vinay Sajipe723e962011-04-15 22:27:17 +01003103
Vinay Sajip37eb3382011-04-26 20:26:41 +01003104ZERO = datetime.timedelta(0)
3105
3106class UTC(datetime.tzinfo):
3107 def utcoffset(self, dt):
3108 return ZERO
3109
3110 dst = utcoffset
3111
3112 def tzname(self, dt):
3113 return 'UTC'
3114
3115utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003116
Vinay Sajipa39c5712010-10-25 13:57:39 +00003117class FormatterTest(unittest.TestCase):
3118 def setUp(self):
3119 self.common = {
3120 'name': 'formatter.test',
3121 'level': logging.DEBUG,
3122 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3123 'lineno': 42,
3124 'exc_info': None,
3125 'func': None,
3126 'msg': 'Message with %d %s',
3127 'args': (2, 'placeholders'),
3128 }
3129 self.variants = {
3130 }
3131
3132 def get_record(self, name=None):
3133 result = dict(self.common)
3134 if name is not None:
3135 result.update(self.variants[name])
3136 return logging.makeLogRecord(result)
3137
3138 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003139 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003140 r = self.get_record()
3141 f = logging.Formatter('${%(message)s}')
3142 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3143 f = logging.Formatter('%(random)s')
3144 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003145 self.assertFalse(f.usesTime())
3146 f = logging.Formatter('%(asctime)s')
3147 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003148 f = logging.Formatter('%(asctime)-15s')
3149 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003150 f = logging.Formatter('asctime')
3151 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003152
3153 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003154 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003155 r = self.get_record()
3156 f = logging.Formatter('$%{message}%$', style='{')
3157 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3158 f = logging.Formatter('{random}', style='{')
3159 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003160 self.assertFalse(f.usesTime())
3161 f = logging.Formatter('{asctime}', style='{')
3162 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003163 f = logging.Formatter('{asctime!s:15}', style='{')
3164 self.assertTrue(f.usesTime())
3165 f = logging.Formatter('{asctime:15}', style='{')
3166 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003167 f = logging.Formatter('asctime', style='{')
3168 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003169
3170 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003171 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003172 r = self.get_record()
3173 f = logging.Formatter('$message', style='$')
3174 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3175 f = logging.Formatter('$$%${message}%$$', style='$')
3176 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3177 f = logging.Formatter('${random}', style='$')
3178 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003179 self.assertFalse(f.usesTime())
3180 f = logging.Formatter('${asctime}', style='$')
3181 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003182 f = logging.Formatter('${asctime', style='$')
3183 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003184 f = logging.Formatter('$asctime', style='$')
3185 self.assertTrue(f.usesTime())
3186 f = logging.Formatter('asctime', style='$')
3187 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003188
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003189 def test_invalid_style(self):
3190 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3191
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003192 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003193 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003194 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3195 # We use None to indicate we want the local timezone
3196 # We're essentially converting a UTC time to local time
3197 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003198 r.msecs = 123
3199 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003200 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003201 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3202 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003203 f.format(r)
3204 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3205
3206class TestBufferingFormatter(logging.BufferingFormatter):
3207 def formatHeader(self, records):
3208 return '[(%d)' % len(records)
3209
3210 def formatFooter(self, records):
3211 return '(%d)]' % len(records)
3212
3213class BufferingFormatterTest(unittest.TestCase):
3214 def setUp(self):
3215 self.records = [
3216 logging.makeLogRecord({'msg': 'one'}),
3217 logging.makeLogRecord({'msg': 'two'}),
3218 ]
3219
3220 def test_default(self):
3221 f = logging.BufferingFormatter()
3222 self.assertEqual('', f.format([]))
3223 self.assertEqual('onetwo', f.format(self.records))
3224
3225 def test_custom(self):
3226 f = TestBufferingFormatter()
3227 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3228 lf = logging.Formatter('<%(message)s>')
3229 f = TestBufferingFormatter(lf)
3230 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003231
3232class ExceptionTest(BaseTest):
3233 def test_formatting(self):
3234 r = self.root_logger
3235 h = RecordingHandler()
3236 r.addHandler(h)
3237 try:
3238 raise RuntimeError('deliberate mistake')
3239 except:
3240 logging.exception('failed', stack_info=True)
3241 r.removeHandler(h)
3242 h.close()
3243 r = h.records[0]
3244 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3245 'call last):\n'))
3246 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3247 'deliberate mistake'))
3248 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3249 'call last):\n'))
3250 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3251 'stack_info=True)'))
3252
3253
Vinay Sajip5a27d402010-12-10 11:42:57 +00003254class LastResortTest(BaseTest):
3255 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003256 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003257 root = self.root_logger
3258 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003259 old_lastresort = logging.lastResort
3260 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003261
Vinay Sajip5a27d402010-12-10 11:42:57 +00003262 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003263 with support.captured_stderr() as stderr:
3264 root.debug('This should not appear')
3265 self.assertEqual(stderr.getvalue(), '')
3266 root.warning('Final chance!')
3267 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3268
3269 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003270 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003271 with support.captured_stderr() as stderr:
3272 root.warning('Final chance!')
3273 msg = 'No handlers could be found for logger "root"\n'
3274 self.assertEqual(stderr.getvalue(), msg)
3275
Vinay Sajip5a27d402010-12-10 11:42:57 +00003276 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003277 with support.captured_stderr() as stderr:
3278 root.warning('Final chance!')
3279 self.assertEqual(stderr.getvalue(), '')
3280
3281 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003282 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003283 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003284 with support.captured_stderr() as stderr:
3285 root.warning('Final chance!')
3286 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003287 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003288 root.addHandler(self.root_hdlr)
3289 logging.lastResort = old_lastresort
3290 logging.raiseExceptions = old_raise_exceptions
3291
3292
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003293class FakeHandler:
3294
3295 def __init__(self, identifier, called):
3296 for method in ('acquire', 'flush', 'close', 'release'):
3297 setattr(self, method, self.record_call(identifier, method, called))
3298
3299 def record_call(self, identifier, method_name, called):
3300 def inner():
3301 called.append('{} - {}'.format(identifier, method_name))
3302 return inner
3303
3304
3305class RecordingHandler(logging.NullHandler):
3306
3307 def __init__(self, *args, **kwargs):
3308 super(RecordingHandler, self).__init__(*args, **kwargs)
3309 self.records = []
3310
3311 def handle(self, record):
3312 """Keep track of all the emitted records."""
3313 self.records.append(record)
3314
3315
3316class ShutdownTest(BaseTest):
3317
Vinay Sajip5e66b162011-04-20 15:41:14 +01003318 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003319
3320 def setUp(self):
3321 super(ShutdownTest, self).setUp()
3322 self.called = []
3323
3324 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003325 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003326
3327 def raise_error(self, error):
3328 def inner():
3329 raise error()
3330 return inner
3331
3332 def test_no_failure(self):
3333 # create some fake handlers
3334 handler0 = FakeHandler(0, self.called)
3335 handler1 = FakeHandler(1, self.called)
3336 handler2 = FakeHandler(2, self.called)
3337
3338 # create live weakref to those handlers
3339 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3340
3341 logging.shutdown(handlerList=list(handlers))
3342
3343 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3344 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3345 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3346 self.assertEqual(expected, self.called)
3347
3348 def _test_with_failure_in_method(self, method, error):
3349 handler = FakeHandler(0, self.called)
3350 setattr(handler, method, self.raise_error(error))
3351 handlers = [logging.weakref.ref(handler)]
3352
3353 logging.shutdown(handlerList=list(handlers))
3354
3355 self.assertEqual('0 - release', self.called[-1])
3356
3357 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003358 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003359
3360 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003361 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003362
3363 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003364 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003365
3366 def test_with_valueerror_in_acquire(self):
3367 self._test_with_failure_in_method('acquire', ValueError)
3368
3369 def test_with_valueerror_in_flush(self):
3370 self._test_with_failure_in_method('flush', ValueError)
3371
3372 def test_with_valueerror_in_close(self):
3373 self._test_with_failure_in_method('close', ValueError)
3374
3375 def test_with_other_error_in_acquire_without_raise(self):
3376 logging.raiseExceptions = False
3377 self._test_with_failure_in_method('acquire', IndexError)
3378
3379 def test_with_other_error_in_flush_without_raise(self):
3380 logging.raiseExceptions = False
3381 self._test_with_failure_in_method('flush', IndexError)
3382
3383 def test_with_other_error_in_close_without_raise(self):
3384 logging.raiseExceptions = False
3385 self._test_with_failure_in_method('close', IndexError)
3386
3387 def test_with_other_error_in_acquire_with_raise(self):
3388 logging.raiseExceptions = True
3389 self.assertRaises(IndexError, self._test_with_failure_in_method,
3390 'acquire', IndexError)
3391
3392 def test_with_other_error_in_flush_with_raise(self):
3393 logging.raiseExceptions = True
3394 self.assertRaises(IndexError, self._test_with_failure_in_method,
3395 'flush', IndexError)
3396
3397 def test_with_other_error_in_close_with_raise(self):
3398 logging.raiseExceptions = True
3399 self.assertRaises(IndexError, self._test_with_failure_in_method,
3400 'close', IndexError)
3401
3402
3403class ModuleLevelMiscTest(BaseTest):
3404
Vinay Sajip5e66b162011-04-20 15:41:14 +01003405 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003406
3407 def test_disable(self):
3408 old_disable = logging.root.manager.disable
3409 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003410 self.assertEqual(old_disable, 0)
3411 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003412
3413 logging.disable(83)
3414 self.assertEqual(logging.root.manager.disable, 83)
3415
3416 def _test_log(self, method, level=None):
3417 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003418 support.patch(self, logging, 'basicConfig',
3419 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003420
3421 recording = RecordingHandler()
3422 logging.root.addHandler(recording)
3423
3424 log_method = getattr(logging, method)
3425 if level is not None:
3426 log_method(level, "test me: %r", recording)
3427 else:
3428 log_method("test me: %r", recording)
3429
3430 self.assertEqual(len(recording.records), 1)
3431 record = recording.records[0]
3432 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3433
3434 expected_level = level if level is not None else getattr(logging, method.upper())
3435 self.assertEqual(record.levelno, expected_level)
3436
3437 # basicConfig was not called!
3438 self.assertEqual(called, [])
3439
3440 def test_log(self):
3441 self._test_log('log', logging.ERROR)
3442
3443 def test_debug(self):
3444 self._test_log('debug')
3445
3446 def test_info(self):
3447 self._test_log('info')
3448
3449 def test_warning(self):
3450 self._test_log('warning')
3451
3452 def test_error(self):
3453 self._test_log('error')
3454
3455 def test_critical(self):
3456 self._test_log('critical')
3457
3458 def test_set_logger_class(self):
3459 self.assertRaises(TypeError, logging.setLoggerClass, object)
3460
3461 class MyLogger(logging.Logger):
3462 pass
3463
3464 logging.setLoggerClass(MyLogger)
3465 self.assertEqual(logging.getLoggerClass(), MyLogger)
3466
3467 logging.setLoggerClass(logging.Logger)
3468 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3469
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003470 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003471 def test_logging_at_shutdown(self):
3472 # Issue #20037
3473 code = """if 1:
3474 import logging
3475
3476 class A:
3477 def __del__(self):
3478 try:
3479 raise ValueError("some error")
3480 except Exception:
3481 logging.exception("exception in __del__")
3482
3483 a = A()"""
3484 rc, out, err = assert_python_ok("-c", code)
3485 err = err.decode()
3486 self.assertIn("exception in __del__", err)
3487 self.assertIn("ValueError: some error", err)
3488
3489
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003490class LogRecordTest(BaseTest):
3491 def test_str_rep(self):
3492 r = logging.makeLogRecord({})
3493 s = str(r)
3494 self.assertTrue(s.startswith('<LogRecord: '))
3495 self.assertTrue(s.endswith('>'))
3496
3497 def test_dict_arg(self):
3498 h = RecordingHandler()
3499 r = logging.getLogger()
3500 r.addHandler(h)
3501 d = {'less' : 'more' }
3502 logging.warning('less is %(less)s', d)
3503 self.assertIs(h.records[0].args, d)
3504 self.assertEqual(h.records[0].message, 'less is more')
3505 r.removeHandler(h)
3506 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003507
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003508 def test_multiprocessing(self):
3509 r = logging.makeLogRecord({})
3510 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003511 try:
3512 import multiprocessing as mp
3513 r = logging.makeLogRecord({})
3514 self.assertEqual(r.processName, mp.current_process().name)
3515 except ImportError:
3516 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003517
3518 def test_optional(self):
3519 r = logging.makeLogRecord({})
3520 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003521 if threading:
3522 NOT_NONE(r.thread)
3523 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003524 NOT_NONE(r.process)
3525 NOT_NONE(r.processName)
3526 log_threads = logging.logThreads
3527 log_processes = logging.logProcesses
3528 log_multiprocessing = logging.logMultiprocessing
3529 try:
3530 logging.logThreads = False
3531 logging.logProcesses = False
3532 logging.logMultiprocessing = False
3533 r = logging.makeLogRecord({})
3534 NONE = self.assertIsNone
3535 NONE(r.thread)
3536 NONE(r.threadName)
3537 NONE(r.process)
3538 NONE(r.processName)
3539 finally:
3540 logging.logThreads = log_threads
3541 logging.logProcesses = log_processes
3542 logging.logMultiprocessing = log_multiprocessing
3543
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003544class BasicConfigTest(unittest.TestCase):
3545
Vinay Sajip95bf5042011-04-20 11:50:56 +01003546 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547
3548 def setUp(self):
3549 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003550 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003551 self.saved_handlers = logging._handlers.copy()
3552 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003553 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003554 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003555 logging.root.handlers = []
3556
3557 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003558 for h in logging.root.handlers[:]:
3559 logging.root.removeHandler(h)
3560 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561 super(BasicConfigTest, self).tearDown()
3562
Vinay Sajip3def7e02011-04-20 10:58:06 +01003563 def cleanup(self):
3564 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003565 logging._handlers.clear()
3566 logging._handlers.update(self.saved_handlers)
3567 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003568 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003569
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003570 def test_no_kwargs(self):
3571 logging.basicConfig()
3572
3573 # handler defaults to a StreamHandler to sys.stderr
3574 self.assertEqual(len(logging.root.handlers), 1)
3575 handler = logging.root.handlers[0]
3576 self.assertIsInstance(handler, logging.StreamHandler)
3577 self.assertEqual(handler.stream, sys.stderr)
3578
3579 formatter = handler.formatter
3580 # format defaults to logging.BASIC_FORMAT
3581 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3582 # datefmt defaults to None
3583 self.assertIsNone(formatter.datefmt)
3584 # style defaults to %
3585 self.assertIsInstance(formatter._style, logging.PercentStyle)
3586
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003587 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003588 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003589
Vinay Sajip1fd12022014-01-13 21:59:56 +00003590 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003591 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003592 logging.basicConfig(stream=sys.stdout, style="{")
3593 logging.error("Log an error")
3594 sys.stdout.seek(0)
3595 self.assertEqual(output.getvalue().strip(),
3596 "ERROR:root:Log an error")
3597
3598 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003599 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003600 logging.basicConfig(stream=sys.stdout, style="$")
3601 logging.error("Log an error")
3602 sys.stdout.seek(0)
3603 self.assertEqual(output.getvalue().strip(),
3604 "ERROR:root:Log an error")
3605
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003606 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003607
3608 def cleanup(h1, h2, fn):
3609 h1.close()
3610 h2.close()
3611 os.remove(fn)
3612
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003613 logging.basicConfig(filename='test.log')
3614
3615 self.assertEqual(len(logging.root.handlers), 1)
3616 handler = logging.root.handlers[0]
3617 self.assertIsInstance(handler, logging.FileHandler)
3618
3619 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003620 self.assertEqual(handler.stream.mode, expected.stream.mode)
3621 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003622 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003623
3624 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003625
3626 def cleanup(h1, h2, fn):
3627 h1.close()
3628 h2.close()
3629 os.remove(fn)
3630
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003631 logging.basicConfig(filename='test.log', filemode='wb')
3632
3633 handler = logging.root.handlers[0]
3634 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003635 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003636 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003637
3638 def test_stream(self):
3639 stream = io.StringIO()
3640 self.addCleanup(stream.close)
3641 logging.basicConfig(stream=stream)
3642
3643 self.assertEqual(len(logging.root.handlers), 1)
3644 handler = logging.root.handlers[0]
3645 self.assertIsInstance(handler, logging.StreamHandler)
3646 self.assertEqual(handler.stream, stream)
3647
3648 def test_format(self):
3649 logging.basicConfig(format='foo')
3650
3651 formatter = logging.root.handlers[0].formatter
3652 self.assertEqual(formatter._style._fmt, 'foo')
3653
3654 def test_datefmt(self):
3655 logging.basicConfig(datefmt='bar')
3656
3657 formatter = logging.root.handlers[0].formatter
3658 self.assertEqual(formatter.datefmt, 'bar')
3659
3660 def test_style(self):
3661 logging.basicConfig(style='$')
3662
3663 formatter = logging.root.handlers[0].formatter
3664 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3665
3666 def test_level(self):
3667 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003668 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003669
3670 logging.basicConfig(level=57)
3671 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003672 # Test that second call has no effect
3673 logging.basicConfig(level=58)
3674 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003675
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003676 def test_incompatible(self):
3677 assertRaises = self.assertRaises
3678 handlers = [logging.StreamHandler()]
3679 stream = sys.stderr
3680 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3681 stream=stream)
3682 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3683 handlers=handlers)
3684 assertRaises(ValueError, logging.basicConfig, stream=stream,
3685 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003686 # Issue 23207: test for invalid kwargs
3687 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3688 # Should pop both filename and filemode even if filename is None
3689 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003690
3691 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003692 handlers = [
3693 logging.StreamHandler(),
3694 logging.StreamHandler(sys.stdout),
3695 logging.StreamHandler(),
3696 ]
3697 f = logging.Formatter()
3698 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003699 logging.basicConfig(handlers=handlers)
3700 self.assertIs(handlers[0], logging.root.handlers[0])
3701 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003702 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003703 self.assertIsNotNone(handlers[0].formatter)
3704 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003705 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003706 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3707
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003708 def _test_log(self, method, level=None):
3709 # logging.root has no handlers so basicConfig should be called
3710 called = []
3711
3712 old_basic_config = logging.basicConfig
3713 def my_basic_config(*a, **kw):
3714 old_basic_config()
3715 old_level = logging.root.level
3716 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003717 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003718 called.append((a, kw))
3719
Vinay Sajip1feedb42014-05-31 08:19:12 +01003720 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003721
3722 log_method = getattr(logging, method)
3723 if level is not None:
3724 log_method(level, "test me")
3725 else:
3726 log_method("test me")
3727
3728 # basicConfig was called with no arguments
3729 self.assertEqual(called, [((), {})])
3730
3731 def test_log(self):
3732 self._test_log('log', logging.WARNING)
3733
3734 def test_debug(self):
3735 self._test_log('debug')
3736
3737 def test_info(self):
3738 self._test_log('info')
3739
3740 def test_warning(self):
3741 self._test_log('warning')
3742
3743 def test_error(self):
3744 self._test_log('error')
3745
3746 def test_critical(self):
3747 self._test_log('critical')
3748
3749
3750class LoggerAdapterTest(unittest.TestCase):
3751
3752 def setUp(self):
3753 super(LoggerAdapterTest, self).setUp()
3754 old_handler_list = logging._handlerList[:]
3755
3756 self.recording = RecordingHandler()
3757 self.logger = logging.root
3758 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003759 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003760 self.addCleanup(self.recording.close)
3761
3762 def cleanup():
3763 logging._handlerList[:] = old_handler_list
3764
3765 self.addCleanup(cleanup)
3766 self.addCleanup(logging.shutdown)
3767 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3768
3769 def test_exception(self):
3770 msg = 'testing exception: %r'
3771 exc = None
3772 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003773 1 / 0
3774 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003775 exc = e
3776 self.adapter.exception(msg, self.recording)
3777
3778 self.assertEqual(len(self.recording.records), 1)
3779 record = self.recording.records[0]
3780 self.assertEqual(record.levelno, logging.ERROR)
3781 self.assertEqual(record.msg, msg)
3782 self.assertEqual(record.args, (self.recording,))
3783 self.assertEqual(record.exc_info,
3784 (exc.__class__, exc, exc.__traceback__))
3785
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003786 def test_exception_excinfo(self):
3787 try:
3788 1 / 0
3789 except ZeroDivisionError as e:
3790 exc = e
3791
3792 self.adapter.exception('exc_info test', exc_info=exc)
3793
3794 self.assertEqual(len(self.recording.records), 1)
3795 record = self.recording.records[0]
3796 self.assertEqual(record.exc_info,
3797 (exc.__class__, exc, exc.__traceback__))
3798
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003799 def test_critical(self):
3800 msg = 'critical test! %r'
3801 self.adapter.critical(msg, self.recording)
3802
3803 self.assertEqual(len(self.recording.records), 1)
3804 record = self.recording.records[0]
3805 self.assertEqual(record.levelno, logging.CRITICAL)
3806 self.assertEqual(record.msg, msg)
3807 self.assertEqual(record.args, (self.recording,))
3808
3809 def test_is_enabled_for(self):
3810 old_disable = self.adapter.logger.manager.disable
3811 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003812 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3813 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003814 self.assertFalse(self.adapter.isEnabledFor(32))
3815
3816 def test_has_handlers(self):
3817 self.assertTrue(self.adapter.hasHandlers())
3818
3819 for handler in self.logger.handlers:
3820 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003821
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003822 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003823 self.assertFalse(self.adapter.hasHandlers())
3824
3825
3826class LoggerTest(BaseTest):
3827
3828 def setUp(self):
3829 super(LoggerTest, self).setUp()
3830 self.recording = RecordingHandler()
3831 self.logger = logging.Logger(name='blah')
3832 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003833 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003834 self.addCleanup(self.recording.close)
3835 self.addCleanup(logging.shutdown)
3836
3837 def test_set_invalid_level(self):
3838 self.assertRaises(TypeError, self.logger.setLevel, object())
3839
3840 def test_exception(self):
3841 msg = 'testing exception: %r'
3842 exc = None
3843 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003844 1 / 0
3845 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003846 exc = e
3847 self.logger.exception(msg, self.recording)
3848
3849 self.assertEqual(len(self.recording.records), 1)
3850 record = self.recording.records[0]
3851 self.assertEqual(record.levelno, logging.ERROR)
3852 self.assertEqual(record.msg, msg)
3853 self.assertEqual(record.args, (self.recording,))
3854 self.assertEqual(record.exc_info,
3855 (exc.__class__, exc, exc.__traceback__))
3856
3857 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003858 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003859 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003860
3861 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003862 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003863 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003864
3865 def test_find_caller_with_stack_info(self):
3866 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003867 support.patch(self, logging.traceback, 'print_stack',
3868 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003869
3870 self.logger.findCaller(stack_info=True)
3871
3872 self.assertEqual(len(called), 1)
3873 self.assertEqual('Stack (most recent call last):\n', called[0])
3874
3875 def test_make_record_with_extra_overwrite(self):
3876 name = 'my record'
3877 level = 13
3878 fn = lno = msg = args = exc_info = func = sinfo = None
3879 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3880 exc_info, func, sinfo)
3881
3882 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3883 extra = {key: 'some value'}
3884 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3885 fn, lno, msg, args, exc_info,
3886 extra=extra, sinfo=sinfo)
3887
3888 def test_make_record_with_extra_no_overwrite(self):
3889 name = 'my record'
3890 level = 13
3891 fn = lno = msg = args = exc_info = func = sinfo = None
3892 extra = {'valid_key': 'some value'}
3893 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3894 exc_info, extra=extra, sinfo=sinfo)
3895 self.assertIn('valid_key', result.__dict__)
3896
3897 def test_has_handlers(self):
3898 self.assertTrue(self.logger.hasHandlers())
3899
3900 for handler in self.logger.handlers:
3901 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003902 self.assertFalse(self.logger.hasHandlers())
3903
3904 def test_has_handlers_no_propagate(self):
3905 child_logger = logging.getLogger('blah.child')
3906 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003907 self.assertFalse(child_logger.hasHandlers())
3908
3909 def test_is_enabled_for(self):
3910 old_disable = self.logger.manager.disable
3911 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003912 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003913 self.assertFalse(self.logger.isEnabledFor(22))
3914
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003915 def test_root_logger_aliases(self):
3916 root = logging.getLogger()
3917 self.assertIs(root, logging.root)
3918 self.assertIs(root, logging.getLogger(None))
3919 self.assertIs(root, logging.getLogger(''))
3920 self.assertIs(root, logging.getLogger('foo').root)
3921 self.assertIs(root, logging.getLogger('foo.bar').root)
3922 self.assertIs(root, logging.getLogger('foo').parent)
3923
3924 self.assertIsNot(root, logging.getLogger('\0'))
3925 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3926
3927 def test_invalid_names(self):
3928 self.assertRaises(TypeError, logging.getLogger, any)
3929 self.assertRaises(TypeError, logging.getLogger, b'foo')
3930
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003931
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003932class BaseFileTest(BaseTest):
3933 "Base class for handler tests that write log files"
3934
3935 def setUp(self):
3936 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003937 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3938 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003939 self.rmfiles = []
3940
3941 def tearDown(self):
3942 for fn in self.rmfiles:
3943 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003944 if os.path.exists(self.fn):
3945 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003946 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003947
3948 def assertLogFile(self, filename):
3949 "Assert a log file is there and register it for deletion"
3950 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003951 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003952 self.rmfiles.append(filename)
3953
3954
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003955class FileHandlerTest(BaseFileTest):
3956 def test_delay(self):
3957 os.unlink(self.fn)
3958 fh = logging.FileHandler(self.fn, delay=True)
3959 self.assertIsNone(fh.stream)
3960 self.assertFalse(os.path.exists(self.fn))
3961 fh.handle(logging.makeLogRecord({}))
3962 self.assertIsNotNone(fh.stream)
3963 self.assertTrue(os.path.exists(self.fn))
3964 fh.close()
3965
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003966class RotatingFileHandlerTest(BaseFileTest):
3967 def next_rec(self):
3968 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3969 self.next_message(), None, None, None)
3970
3971 def test_should_not_rollover(self):
3972 # If maxbytes is zero rollover never occurs
3973 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3974 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003975 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003976
3977 def test_should_rollover(self):
3978 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3979 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003980 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003981
3982 def test_file_created(self):
3983 # checks that the file is created and assumes it was created
3984 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003985 rh = logging.handlers.RotatingFileHandler(self.fn)
3986 rh.emit(self.next_rec())
3987 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003988 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003989
3990 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003991 def namer(name):
3992 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003993 rh = logging.handlers.RotatingFileHandler(
3994 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003995 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003996 rh.emit(self.next_rec())
3997 self.assertLogFile(self.fn)
3998 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003999 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004000 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004001 self.assertLogFile(namer(self.fn + ".2"))
4002 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4003 rh.close()
4004
Vinay Sajip1feedb42014-05-31 08:19:12 +01004005 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004006 def test_rotator(self):
4007 def namer(name):
4008 return name + ".gz"
4009
4010 def rotator(source, dest):
4011 with open(source, "rb") as sf:
4012 data = sf.read()
4013 compressed = zlib.compress(data, 9)
4014 with open(dest, "wb") as df:
4015 df.write(compressed)
4016 os.remove(source)
4017
4018 rh = logging.handlers.RotatingFileHandler(
4019 self.fn, backupCount=2, maxBytes=1)
4020 rh.rotator = rotator
4021 rh.namer = namer
4022 m1 = self.next_rec()
4023 rh.emit(m1)
4024 self.assertLogFile(self.fn)
4025 m2 = self.next_rec()
4026 rh.emit(m2)
4027 fn = namer(self.fn + ".1")
4028 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004029 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004030 with open(fn, "rb") as f:
4031 compressed = f.read()
4032 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004033 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004034 rh.emit(self.next_rec())
4035 fn = namer(self.fn + ".2")
4036 self.assertLogFile(fn)
4037 with open(fn, "rb") as f:
4038 compressed = f.read()
4039 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004040 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004041 rh.emit(self.next_rec())
4042 fn = namer(self.fn + ".2")
4043 with open(fn, "rb") as f:
4044 compressed = f.read()
4045 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004046 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004047 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004048 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004049
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004050class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004051 # other test methods added below
4052 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004053 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4054 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004055 fmt = logging.Formatter('%(asctime)s %(message)s')
4056 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004057 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004058 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004059 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004060 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004061 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004062 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004063 fh.close()
4064 # At this point, we should have a recent rotated file which we
4065 # can test for the existence of. However, in practice, on some
4066 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004067 # in time to go to look for the log file. So, we go back a fair
4068 # bit, and stop as soon as we see a rotated file. In theory this
4069 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004070 found = False
4071 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004072 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004073 for secs in range(GO_BACK):
4074 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004075 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4076 found = os.path.exists(fn)
4077 if found:
4078 self.rmfiles.append(fn)
4079 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004080 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4081 if not found:
4082 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004083 dn, fn = os.path.split(self.fn)
4084 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004085 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4086 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004087 for f in files:
4088 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004089 path = os.path.join(dn, f)
4090 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004091 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004092 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004093
Vinay Sajip0372e102011-05-05 12:59:14 +01004094 def test_invalid(self):
4095 assertRaises = self.assertRaises
4096 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004097 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004098 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004099 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004100 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004101 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004102
Vinay Sajipa7130792013-04-12 17:04:23 +01004103 def test_compute_rollover_daily_attime(self):
4104 currentTime = 0
4105 atTime = datetime.time(12, 0, 0)
4106 rh = logging.handlers.TimedRotatingFileHandler(
4107 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4108 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004109 try:
4110 actual = rh.computeRollover(currentTime)
4111 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004112
Vinay Sajipd86ac962013-04-14 12:20:46 +01004113 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4114 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4115 finally:
4116 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004117
Vinay Sajip10e8c492013-05-18 10:19:54 -07004118 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004119 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004120 currentTime = int(time.time())
4121 today = currentTime - currentTime % 86400
4122
Vinay Sajipa7130792013-04-12 17:04:23 +01004123 atTime = datetime.time(12, 0, 0)
4124
Vinay Sajip10e8c492013-05-18 10:19:54 -07004125 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004126 for day in range(7):
4127 rh = logging.handlers.TimedRotatingFileHandler(
4128 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4129 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004130 try:
4131 if wday > day:
4132 # The rollover day has already passed this week, so we
4133 # go over into next week
4134 expected = (7 - wday + day)
4135 else:
4136 expected = (day - wday)
4137 # At this point expected is in days from now, convert to seconds
4138 expected *= 24 * 60 * 60
4139 # Add in the rollover time
4140 expected += 12 * 60 * 60
4141 # Add in adjustment for today
4142 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004143 actual = rh.computeRollover(today)
4144 if actual != expected:
4145 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004146 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004147 self.assertEqual(actual, expected)
4148 if day == wday:
4149 # goes into following week
4150 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004151 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004152 if actual != expected:
4153 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004154 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004155 self.assertEqual(actual, expected)
4156 finally:
4157 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004158
4159
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004160def secs(**kw):
4161 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4162
4163for when, exp in (('S', 1),
4164 ('M', 60),
4165 ('H', 60 * 60),
4166 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004167 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004168 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004169 ('W0', secs(days=4, hours=24)),
4170 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004171 def test_compute_rollover(self, when=when, exp=exp):
4172 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004173 self.fn, when=when, interval=1, backupCount=0, utc=True)
4174 currentTime = 0.0
4175 actual = rh.computeRollover(currentTime)
4176 if exp != actual:
4177 # Failures occur on some systems for MIDNIGHT and W0.
4178 # Print detailed calculation for MIDNIGHT so we can try to see
4179 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004180 if when == 'MIDNIGHT':
4181 try:
4182 if rh.utc:
4183 t = time.gmtime(currentTime)
4184 else:
4185 t = time.localtime(currentTime)
4186 currentHour = t[3]
4187 currentMinute = t[4]
4188 currentSecond = t[5]
4189 # r is the number of seconds left between now and midnight
4190 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4191 currentMinute) * 60 +
4192 currentSecond)
4193 result = currentTime + r
4194 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4195 print('currentHour: %s' % currentHour, file=sys.stderr)
4196 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4197 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4198 print('r: %s' % r, file=sys.stderr)
4199 print('result: %s' % result, file=sys.stderr)
4200 except Exception:
4201 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4202 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004203 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004204 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4205
Vinay Sajip60ccd822011-05-09 17:32:09 +01004206
Vinay Sajip223349c2015-10-01 20:37:54 +01004207@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004208class NTEventLogHandlerTest(BaseTest):
4209 def test_basic(self):
4210 logtype = 'Application'
4211 elh = win32evtlog.OpenEventLog(None, logtype)
4212 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004213
4214 try:
4215 h = logging.handlers.NTEventLogHandler('test_logging')
4216 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004217 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004218 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004219 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004220
Vinay Sajip60ccd822011-05-09 17:32:09 +01004221 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4222 h.handle(r)
4223 h.close()
4224 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004225 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004226 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4227 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4228 found = False
4229 GO_BACK = 100
4230 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4231 for e in events:
4232 if e.SourceName != 'test_logging':
4233 continue
4234 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4235 if msg != 'Test Log Message\r\n':
4236 continue
4237 found = True
4238 break
4239 msg = 'Record not found in event log, went back %d records' % GO_BACK
4240 self.assertTrue(found, msg=msg)
4241
Christian Heimes180510d2008-03-03 19:15:45 +00004242# Set the locale to the platform-dependent default. I have no idea
4243# why the test does this, but in any case we save the current locale
4244# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004245@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004246def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004247 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004248 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4249 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4250 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4251 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4252 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4253 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4254 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4255 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4256 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4257 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004258 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
4259 ]
4260 if hasattr(logging.handlers, 'QueueListener'):
4261 tests.append(QueueListenerTest)
4262 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004263
Christian Heimes180510d2008-03-03 19:15:45 +00004264if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004265 test_main()