blob: c323a59deabf14e7bea06f65caf4590af6858f00 [file] [log] [blame]
Vinay Sajip1feedb42014-05-31 08:19:12 +01001# Copyright 2001-2014 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip1feedb42014-05-31 08:19:12 +010019Copyright (C) 2001-2014 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
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
Antoine Pitrou712cb732013-12-21 15:51:54 +010041from test.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:
61 import win32evtlog
62except ImportError:
63 win32evtlog = None
64try:
65 import win32evtlogutil
66except ImportError:
67 win32evtlogutil = None
68 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070069try:
70 import zlib
71except ImportError:
72 pass
Christian Heimes18c66892008-02-17 13:31:39 +000073
Christian Heimes180510d2008-03-03 19:15:45 +000074class BaseTest(unittest.TestCase):
75
76 """Base class for logging tests."""
77
78 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030079 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000080 message_num = 0
81
82 def setUp(self):
83 """Setup the default logging stream to an internal StringIO instance,
84 so that we can examine log output as we want."""
85 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000086 logging._acquireLock()
87 try:
Christian Heimes180510d2008-03-03 19:15:45 +000088 self.saved_handlers = logging._handlers.copy()
89 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000090 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070091 self.saved_name_to_level = logging._nameToLevel.copy()
92 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000093 self.logger_states = logger_states = {}
94 for name in saved_loggers:
95 logger_states[name] = getattr(saved_loggers[name],
96 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000097 finally:
98 logging._releaseLock()
99
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100100 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000101 self.logger1 = logging.getLogger("\xab\xd7\xbb")
102 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000103
Christian Heimes180510d2008-03-03 19:15:45 +0000104 self.root_logger = logging.getLogger("")
105 self.original_logging_level = self.root_logger.getEffectiveLevel()
106
107 self.stream = io.StringIO()
108 self.root_logger.setLevel(logging.DEBUG)
109 self.root_hdlr = logging.StreamHandler(self.stream)
110 self.root_formatter = logging.Formatter(self.log_format)
111 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000112 if self.logger1.hasHandlers():
113 hlist = self.logger1.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
115 if self.logger2.hasHandlers():
116 hlist = self.logger2.handlers + self.root_logger.handlers
117 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000118 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000119 self.assertTrue(self.logger1.hasHandlers())
120 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000121
122 def tearDown(self):
123 """Remove our logging stream, and restore the original logging
124 level."""
125 self.stream.close()
126 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000127 while self.root_logger.handlers:
128 h = self.root_logger.handlers[0]
129 self.root_logger.removeHandler(h)
130 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000131 self.root_logger.setLevel(self.original_logging_level)
132 logging._acquireLock()
133 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700134 logging._levelToName.clear()
135 logging._levelToName.update(self.saved_level_to_name)
136 logging._nameToLevel.clear()
137 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000138 logging._handlers.clear()
139 logging._handlers.update(self.saved_handlers)
140 logging._handlerList[:] = self.saved_handler_list
141 loggerDict = logging.getLogger().manager.loggerDict
142 loggerDict.clear()
143 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000144 logger_states = self.logger_states
145 for name in self.logger_states:
146 if logger_states[name] is not None:
147 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000148 finally:
149 logging._releaseLock()
150
Vinay Sajip4ded5512012-10-02 15:56:16 +0100151 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000152 """Match the collected log lines against the regular expression
153 self.expected_log_pat, and compare the extracted group values to
154 the expected_values list of tuples."""
155 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100156 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300157 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100158 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000159 for actual, expected in zip(actual_lines, expected_values):
160 match = pat.search(actual)
161 if not match:
162 self.fail("Log line does not match expected pattern:\n" +
163 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000164 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000165 s = stream.read()
166 if s:
167 self.fail("Remaining output at end of log stream:\n" + s)
168
169 def next_message(self):
170 """Generate a message consisting solely of an auto-incrementing
171 integer."""
172 self.message_num += 1
173 return "%d" % self.message_num
174
175
176class BuiltinLevelsTest(BaseTest):
177 """Test builtin levels and their inheritance."""
178
179 def test_flat(self):
180 #Logging levels in a flat logger namespace.
181 m = self.next_message
182
183 ERR = logging.getLogger("ERR")
184 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000185 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000186 INF.setLevel(logging.INFO)
187 DEB = logging.getLogger("DEB")
188 DEB.setLevel(logging.DEBUG)
189
190 # These should log.
191 ERR.log(logging.CRITICAL, m())
192 ERR.error(m())
193
194 INF.log(logging.CRITICAL, m())
195 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100196 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000197 INF.info(m())
198
199 DEB.log(logging.CRITICAL, m())
200 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100201 DEB.warning(m())
202 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 DEB.debug(m())
204
205 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100206 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000207 ERR.info(m())
208 ERR.debug(m())
209
210 INF.debug(m())
211
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000212 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000213 ('ERR', 'CRITICAL', '1'),
214 ('ERR', 'ERROR', '2'),
215 ('INF', 'CRITICAL', '3'),
216 ('INF', 'ERROR', '4'),
217 ('INF', 'WARNING', '5'),
218 ('INF', 'INFO', '6'),
219 ('DEB', 'CRITICAL', '7'),
220 ('DEB', 'ERROR', '8'),
221 ('DEB', 'WARNING', '9'),
222 ('DEB', 'INFO', '10'),
223 ('DEB', 'DEBUG', '11'),
224 ])
225
226 def test_nested_explicit(self):
227 # Logging levels in a nested namespace, all explicitly set.
228 m = self.next_message
229
230 INF = logging.getLogger("INF")
231 INF.setLevel(logging.INFO)
232 INF_ERR = logging.getLogger("INF.ERR")
233 INF_ERR.setLevel(logging.ERROR)
234
235 # These should log.
236 INF_ERR.log(logging.CRITICAL, m())
237 INF_ERR.error(m())
238
239 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100240 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000241 INF_ERR.info(m())
242 INF_ERR.debug(m())
243
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000244 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000245 ('INF.ERR', 'CRITICAL', '1'),
246 ('INF.ERR', 'ERROR', '2'),
247 ])
248
249 def test_nested_inherited(self):
250 #Logging levels in a nested namespace, inherited from parent loggers.
251 m = self.next_message
252
253 INF = logging.getLogger("INF")
254 INF.setLevel(logging.INFO)
255 INF_ERR = logging.getLogger("INF.ERR")
256 INF_ERR.setLevel(logging.ERROR)
257 INF_UNDEF = logging.getLogger("INF.UNDEF")
258 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
259 UNDEF = logging.getLogger("UNDEF")
260
261 # These should log.
262 INF_UNDEF.log(logging.CRITICAL, m())
263 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100264 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000265 INF_UNDEF.info(m())
266 INF_ERR_UNDEF.log(logging.CRITICAL, m())
267 INF_ERR_UNDEF.error(m())
268
269 # These should not log.
270 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100271 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000272 INF_ERR_UNDEF.info(m())
273 INF_ERR_UNDEF.debug(m())
274
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000275 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000276 ('INF.UNDEF', 'CRITICAL', '1'),
277 ('INF.UNDEF', 'ERROR', '2'),
278 ('INF.UNDEF', 'WARNING', '3'),
279 ('INF.UNDEF', 'INFO', '4'),
280 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
281 ('INF.ERR.UNDEF', 'ERROR', '6'),
282 ])
283
284 def test_nested_with_virtual_parent(self):
285 # Logging levels when some parent does not exist yet.
286 m = self.next_message
287
288 INF = logging.getLogger("INF")
289 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
290 CHILD = logging.getLogger("INF.BADPARENT")
291 INF.setLevel(logging.INFO)
292
293 # These should log.
294 GRANDCHILD.log(logging.FATAL, m())
295 GRANDCHILD.info(m())
296 CHILD.log(logging.FATAL, m())
297 CHILD.info(m())
298
299 # These should not log.
300 GRANDCHILD.debug(m())
301 CHILD.debug(m())
302
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000303 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000304 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
305 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
306 ('INF.BADPARENT', 'CRITICAL', '3'),
307 ('INF.BADPARENT', 'INFO', '4'),
308 ])
309
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100310 def test_regression_22386(self):
311 """See issue #22386 for more information."""
312 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
313 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000314
315class BasicFilterTest(BaseTest):
316
317 """Test the bundled Filter class."""
318
319 def test_filter(self):
320 # Only messages satisfying the specified criteria pass through the
321 # filter.
322 filter_ = logging.Filter("spam.eggs")
323 handler = self.root_logger.handlers[0]
324 try:
325 handler.addFilter(filter_)
326 spam = logging.getLogger("spam")
327 spam_eggs = logging.getLogger("spam.eggs")
328 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
329 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
330
331 spam.info(self.next_message())
332 spam_eggs.info(self.next_message()) # Good.
333 spam_eggs_fish.info(self.next_message()) # Good.
334 spam_bakedbeans.info(self.next_message())
335
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000336 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000337 ('spam.eggs', 'INFO', '2'),
338 ('spam.eggs.fish', 'INFO', '3'),
339 ])
340 finally:
341 handler.removeFilter(filter_)
342
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000343 def test_callable_filter(self):
344 # Only messages satisfying the specified criteria pass through the
345 # filter.
346
347 def filterfunc(record):
348 parts = record.name.split('.')
349 prefix = '.'.join(parts[:2])
350 return prefix == 'spam.eggs'
351
352 handler = self.root_logger.handlers[0]
353 try:
354 handler.addFilter(filterfunc)
355 spam = logging.getLogger("spam")
356 spam_eggs = logging.getLogger("spam.eggs")
357 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
358 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
359
360 spam.info(self.next_message())
361 spam_eggs.info(self.next_message()) # Good.
362 spam_eggs_fish.info(self.next_message()) # Good.
363 spam_bakedbeans.info(self.next_message())
364
365 self.assert_log_lines([
366 ('spam.eggs', 'INFO', '2'),
367 ('spam.eggs.fish', 'INFO', '3'),
368 ])
369 finally:
370 handler.removeFilter(filterfunc)
371
Vinay Sajip985ef872011-04-26 19:34:04 +0100372 def test_empty_filter(self):
373 f = logging.Filter()
374 r = logging.makeLogRecord({'name': 'spam.eggs'})
375 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000376
377#
378# First, we define our levels. There can be as many as you want - the only
379# limitations are that they should be integers, the lowest should be > 0 and
380# larger values mean less information being logged. If you need specific
381# level values which do not fit into these limitations, you can use a
382# mapping dictionary to convert between your application levels and the
383# logging system.
384#
385SILENT = 120
386TACITURN = 119
387TERSE = 118
388EFFUSIVE = 117
389SOCIABLE = 116
390VERBOSE = 115
391TALKATIVE = 114
392GARRULOUS = 113
393CHATTERBOX = 112
394BORING = 111
395
396LEVEL_RANGE = range(BORING, SILENT + 1)
397
398#
399# Next, we define names for our levels. You don't need to do this - in which
400# case the system will use "Level n" to denote the text for the level.
401#
402my_logging_levels = {
403 SILENT : 'Silent',
404 TACITURN : 'Taciturn',
405 TERSE : 'Terse',
406 EFFUSIVE : 'Effusive',
407 SOCIABLE : 'Sociable',
408 VERBOSE : 'Verbose',
409 TALKATIVE : 'Talkative',
410 GARRULOUS : 'Garrulous',
411 CHATTERBOX : 'Chatterbox',
412 BORING : 'Boring',
413}
414
415class GarrulousFilter(logging.Filter):
416
417 """A filter which blocks garrulous messages."""
418
419 def filter(self, record):
420 return record.levelno != GARRULOUS
421
422class VerySpecificFilter(logging.Filter):
423
424 """A filter which blocks sociable and taciturn messages."""
425
426 def filter(self, record):
427 return record.levelno not in [SOCIABLE, TACITURN]
428
429
430class CustomLevelsAndFiltersTest(BaseTest):
431
432 """Test various filtering possibilities with custom logging levels."""
433
434 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300435 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000436
437 def setUp(self):
438 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000439 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000440 logging.addLevelName(k, v)
441
442 def log_at_all_levels(self, logger):
443 for lvl in LEVEL_RANGE:
444 logger.log(lvl, self.next_message())
445
446 def test_logger_filter(self):
447 # Filter at logger level.
448 self.root_logger.setLevel(VERBOSE)
449 # Levels >= 'Verbose' are good.
450 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000451 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000452 ('Verbose', '5'),
453 ('Sociable', '6'),
454 ('Effusive', '7'),
455 ('Terse', '8'),
456 ('Taciturn', '9'),
457 ('Silent', '10'),
458 ])
459
460 def test_handler_filter(self):
461 # Filter at handler level.
462 self.root_logger.handlers[0].setLevel(SOCIABLE)
463 try:
464 # Levels >= 'Sociable' are good.
465 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000466 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000467 ('Sociable', '6'),
468 ('Effusive', '7'),
469 ('Terse', '8'),
470 ('Taciturn', '9'),
471 ('Silent', '10'),
472 ])
473 finally:
474 self.root_logger.handlers[0].setLevel(logging.NOTSET)
475
476 def test_specific_filters(self):
477 # Set a specific filter object on the handler, and then add another
478 # filter object on the logger itself.
479 handler = self.root_logger.handlers[0]
480 specific_filter = None
481 garr = GarrulousFilter()
482 handler.addFilter(garr)
483 try:
484 self.log_at_all_levels(self.root_logger)
485 first_lines = [
486 # Notice how 'Garrulous' is missing
487 ('Boring', '1'),
488 ('Chatterbox', '2'),
489 ('Talkative', '4'),
490 ('Verbose', '5'),
491 ('Sociable', '6'),
492 ('Effusive', '7'),
493 ('Terse', '8'),
494 ('Taciturn', '9'),
495 ('Silent', '10'),
496 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000497 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000498
499 specific_filter = VerySpecificFilter()
500 self.root_logger.addFilter(specific_filter)
501 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000502 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000503 # Not only 'Garrulous' is still missing, but also 'Sociable'
504 # and 'Taciturn'
505 ('Boring', '11'),
506 ('Chatterbox', '12'),
507 ('Talkative', '14'),
508 ('Verbose', '15'),
509 ('Effusive', '17'),
510 ('Terse', '18'),
511 ('Silent', '20'),
512 ])
513 finally:
514 if specific_filter:
515 self.root_logger.removeFilter(specific_filter)
516 handler.removeFilter(garr)
517
518
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100519class HandlerTest(BaseTest):
520 def test_name(self):
521 h = logging.Handler()
522 h.name = 'generic'
523 self.assertEqual(h.name, 'generic')
524 h.name = 'anothergeneric'
525 self.assertEqual(h.name, 'anothergeneric')
526 self.assertRaises(NotImplementedError, h.emit, None)
527
Vinay Sajip5a35b062011-04-27 11:31:14 +0100528 def test_builtin_handlers(self):
529 # We can't actually *use* too many handlers in the tests,
530 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200531 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100532 for existing in (True, False):
533 fd, fn = tempfile.mkstemp()
534 os.close(fd)
535 if not existing:
536 os.unlink(fn)
537 h = logging.handlers.WatchedFileHandler(fn, delay=True)
538 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100539 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100540 self.assertEqual(dev, -1)
541 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100542 r = logging.makeLogRecord({'msg': 'Test'})
543 h.handle(r)
544 # Now remove the file.
545 os.unlink(fn)
546 self.assertFalse(os.path.exists(fn))
547 # The next call should recreate the file.
548 h.handle(r)
549 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100550 else:
551 self.assertEqual(h.dev, -1)
552 self.assertEqual(h.ino, -1)
553 h.close()
554 if existing:
555 os.unlink(fn)
556 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100557 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100558 else:
559 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100560 try:
561 h = logging.handlers.SysLogHandler(sockname)
562 self.assertEqual(h.facility, h.LOG_USER)
563 self.assertTrue(h.unixsocket)
564 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200565 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100566 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100567 for method in ('GET', 'POST', 'PUT'):
568 if method == 'PUT':
569 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
570 'localhost', '/log', method)
571 else:
572 h = logging.handlers.HTTPHandler('localhost', '/log', method)
573 h.close()
574 h = logging.handlers.BufferingHandler(0)
575 r = logging.makeLogRecord({})
576 self.assertTrue(h.shouldFlush(r))
577 h.close()
578 h = logging.handlers.BufferingHandler(1)
579 self.assertFalse(h.shouldFlush(r))
580 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100581
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100582 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100583 @unittest.skipUnless(threading, 'Threading required for this test.')
584 def test_race(self):
585 # Issue #14632 refers.
586 def remove_loop(fname, tries):
587 for _ in range(tries):
588 try:
589 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000590 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100591 except OSError:
592 pass
593 time.sleep(0.004 * random.randint(0, 4))
594
Vinay Sajipc94871a2012-04-25 10:51:35 +0100595 del_count = 500
596 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000598 self.handle_time = None
599 self.deletion_time = None
600
Vinay Sajipa5798de2012-04-24 23:33:33 +0100601 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100602 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
603 os.close(fd)
604 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
605 remover.daemon = True
606 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100607 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100608 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
609 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100610 try:
611 for _ in range(log_count):
612 time.sleep(0.005)
613 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000614 try:
615 self.handle_time = time.time()
616 h.handle(r)
617 except Exception:
618 print('Deleted at %s, '
619 'opened at %s' % (self.deletion_time,
620 self.handle_time))
621 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100622 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100623 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100624 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100625 if os.path.exists(fn):
626 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100627
628
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100629class BadStream(object):
630 def write(self, data):
631 raise RuntimeError('deliberate mistake')
632
633class TestStreamHandler(logging.StreamHandler):
634 def handleError(self, record):
635 self.error_record = record
636
637class StreamHandlerTest(BaseTest):
638 def test_error_handling(self):
639 h = TestStreamHandler(BadStream())
640 r = logging.makeLogRecord({})
641 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100642
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100643 try:
644 h.handle(r)
645 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100646
Vinay Sajip985ef872011-04-26 19:34:04 +0100647 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100648 with support.captured_stderr() as stderr:
649 h.handle(r)
650 msg = '\nRuntimeError: deliberate mistake\n'
651 self.assertIn(msg, stderr.getvalue())
652
Vinay Sajip985ef872011-04-26 19:34:04 +0100653 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100654 with support.captured_stderr() as stderr:
655 h.handle(r)
656 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100657 finally:
658 logging.raiseExceptions = old_raise
659
Vinay Sajip7367d082011-05-02 13:17:27 +0100660# -- The following section could be moved into a server_helper.py module
661# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100662
Vinay Sajipce7c9782011-05-17 07:15:53 +0100663if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100665 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100666 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100667
Vinay Sajipce7c9782011-05-17 07:15:53 +0100668 :param addr: A (host, port) tuple which the server listens on.
669 You can specify a port value of zero: the server's
670 *port* attribute will hold the actual port number
671 used, which can be used in client connections.
672 :param handler: A callable which will be called to process
673 incoming messages. The handler will be passed
674 the client address tuple, who the message is from,
675 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100676 :param poll_interval: The interval, in seconds, used in the underlying
677 :func:`select` or :func:`poll` call by
678 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100679 :param sockmap: A dictionary which will be used to hold
680 :class:`asyncore.dispatcher` instances used by
681 :func:`asyncore.loop`. This avoids changing the
682 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100683 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100684
685 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400686 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
687 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100688 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 self._handler = handler
690 self._thread = None
691 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 def process_message(self, peer, mailfrom, rcpttos, data):
694 """
695 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100696
Vinay Sajipce7c9782011-05-17 07:15:53 +0100697 Typically, this will be a test case method.
698 :param peer: The client (host, port) tuple.
699 :param mailfrom: The address of the sender.
700 :param rcpttos: The addresses of the recipients.
701 :param data: The message.
702 """
703 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100704
Vinay Sajipce7c9782011-05-17 07:15:53 +0100705 def start(self):
706 """
707 Start the server running on a separate daemon thread.
708 """
709 self._thread = t = threading.Thread(target=self.serve_forever,
710 args=(self.poll_interval,))
711 t.setDaemon(True)
712 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100713
Vinay Sajipce7c9782011-05-17 07:15:53 +0100714 def serve_forever(self, poll_interval):
715 """
716 Run the :mod:`asyncore` loop until normal termination
717 conditions arise.
718 :param poll_interval: The interval, in seconds, used in the underlying
719 :func:`select` or :func:`poll` call by
720 :func:`asyncore.loop`.
721 """
722 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100723 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200724 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 # On FreeBSD 8, closing the server repeatably
726 # raises this error. We swallow it if the
727 # server has been closed.
728 if self.connected or self.accepting:
729 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100730
Vinay Sajipce7c9782011-05-17 07:15:53 +0100731 def stop(self, timeout=None):
732 """
733 Stop the thread by closing the server instance.
734 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 :param timeout: How long to wait for the server thread
737 to terminate.
738 """
739 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100740 self._thread.join(timeout)
741 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100742
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743 class ControlMixin(object):
744 """
745 This mixin is used to start a server on a separate thread, and
746 shut it down programmatically. Request handling is simplified - instead
747 of needing to derive a suitable RequestHandler subclass, you just
748 provide a callable which will be passed each received request to be
749 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100750
Vinay Sajipce7c9782011-05-17 07:15:53 +0100751 :param handler: A handler callable which will be called with a
752 single parameter - the request - in order to
753 process the request. This handler is called on the
754 server thread, effectively meaning that requests are
755 processed serially. While not quite Web scale ;-),
756 this should be fine for testing applications.
757 :param poll_interval: The polling interval in seconds.
758 """
759 def __init__(self, handler, poll_interval):
760 self._thread = None
761 self.poll_interval = poll_interval
762 self._handler = handler
763 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100764
Vinay Sajipce7c9782011-05-17 07:15:53 +0100765 def start(self):
766 """
767 Create a daemon thread to run the server, and start it.
768 """
769 self._thread = t = threading.Thread(target=self.serve_forever,
770 args=(self.poll_interval,))
771 t.setDaemon(True)
772 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100773
Vinay Sajipce7c9782011-05-17 07:15:53 +0100774 def serve_forever(self, poll_interval):
775 """
776 Run the server. Set the ready flag before entering the
777 service loop.
778 """
779 self.ready.set()
780 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 def stop(self, timeout=None):
783 """
784 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 :param timeout: How long to wait for the server thread
787 to terminate.
788 """
789 self.shutdown()
790 if self._thread is not None:
791 self._thread.join(timeout)
792 self._thread = None
793 self.server_close()
794 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 class TestHTTPServer(ControlMixin, HTTPServer):
797 """
798 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Vinay Sajipce7c9782011-05-17 07:15:53 +0100800 :param addr: A tuple with the IP address and port to listen on.
801 :param handler: A handler callable which will be called with a
802 single parameter - the request - in order to
803 process the request.
804 :param poll_interval: The polling interval in seconds.
805 :param log: Pass ``True`` to enable log messages.
806 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100807 def __init__(self, addr, handler, poll_interval=0.5,
808 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100809 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
810 def __getattr__(self, name, default=None):
811 if name.startswith('do_'):
812 return self.process_request
813 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100814
Vinay Sajipce7c9782011-05-17 07:15:53 +0100815 def process_request(self):
816 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100817
Vinay Sajipce7c9782011-05-17 07:15:53 +0100818 def log_message(self, format, *args):
819 if log:
820 super(DelegatingHTTPRequestHandler,
821 self).log_message(format, *args)
822 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
823 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100824 self.sslctx = sslctx
825
826 def get_request(self):
827 try:
828 sock, addr = self.socket.accept()
829 if self.sslctx:
830 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200831 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100832 # socket errors are silenced by the caller, print them here
833 sys.stderr.write("Got an error:\n%s\n" % e)
834 raise
835 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 class TestTCPServer(ControlMixin, ThreadingTCPServer):
838 """
839 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 :param addr: A tuple with the IP address and port to listen on.
842 :param handler: A handler callable which will be called with a single
843 parameter - the request - in order to process the request.
844 :param poll_interval: The polling interval in seconds.
845 :bind_and_activate: If True (the default), binds the server and starts it
846 listening. If False, you need to call
847 :meth:`server_bind` and :meth:`server_activate` at
848 some later time before calling :meth:`start`, so that
849 the server will set up the socket and listen on it.
850 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Vinay Sajipce7c9782011-05-17 07:15:53 +0100852 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100853
Vinay Sajipce7c9782011-05-17 07:15:53 +0100854 def __init__(self, addr, handler, poll_interval=0.5,
855 bind_and_activate=True):
856 class DelegatingTCPRequestHandler(StreamRequestHandler):
857
858 def handle(self):
859 self.server._handler(self)
860 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
861 bind_and_activate)
862 ControlMixin.__init__(self, handler, poll_interval)
863
864 def server_bind(self):
865 super(TestTCPServer, self).server_bind()
866 self.port = self.socket.getsockname()[1]
867
868 class TestUDPServer(ControlMixin, ThreadingUDPServer):
869 """
870 A UDP server which is controllable using :class:`ControlMixin`.
871
872 :param addr: A tuple with the IP address and port to listen on.
873 :param handler: A handler callable which will be called with a
874 single parameter - the request - in order to
875 process the request.
876 :param poll_interval: The polling interval for shutdown requests,
877 in seconds.
878 :bind_and_activate: If True (the default), binds the server and
879 starts it listening. If False, you need to
880 call :meth:`server_bind` and
881 :meth:`server_activate` at some later time
882 before calling :meth:`start`, so that the server will
883 set up the socket and listen on it.
884 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100885 def __init__(self, addr, handler, poll_interval=0.5,
886 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100887 class DelegatingUDPRequestHandler(DatagramRequestHandler):
888
889 def handle(self):
890 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100891
892 def finish(self):
893 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if data:
895 try:
896 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200897 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 if not self.server._closed:
899 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100900
Vinay Sajip3ef12292011-05-23 23:00:42 +0100901 ThreadingUDPServer.__init__(self, addr,
902 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100903 bind_and_activate)
904 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100905 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906
907 def server_bind(self):
908 super(TestUDPServer, self).server_bind()
909 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Vinay Sajipba980db2011-05-23 21:37:54 +0100911 def server_close(self):
912 super(TestUDPServer, self).server_close()
913 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Victor Stinnerec5a8602014-06-02 14:41:51 +0200915 if hasattr(socket, "AF_UNIX"):
916 class TestUnixStreamServer(TestTCPServer):
917 address_family = socket.AF_UNIX
918
919 class TestUnixDatagramServer(TestUDPServer):
920 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100921
Vinay Sajip7367d082011-05-02 13:17:27 +0100922# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100923
Vinay Sajipce7c9782011-05-17 07:15:53 +0100924@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100925class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000926 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100927 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100928 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800929 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100930 sockmap)
931 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800932 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000933 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
934 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 self.assertEqual(h.toaddrs, ['you'])
936 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100938 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000940 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100941 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000942 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100943 self.assertEqual(len(self.messages), 1)
944 peer, mailfrom, rcpttos, data = self.messages[0]
945 self.assertEqual(mailfrom, 'me')
946 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100947 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100948 self.assertTrue(data.endswith('\n\nHello'))
949 h.close()
950
951 def process_message(self, *args):
952 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100953 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100954
Christian Heimes180510d2008-03-03 19:15:45 +0000955class MemoryHandlerTest(BaseTest):
956
957 """Tests for the MemoryHandler."""
958
959 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300960 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000961
962 def setUp(self):
963 BaseTest.setUp(self)
964 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
965 self.root_hdlr)
966 self.mem_logger = logging.getLogger('mem')
967 self.mem_logger.propagate = 0
968 self.mem_logger.addHandler(self.mem_hdlr)
969
970 def tearDown(self):
971 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000972 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000973
974 def test_flush(self):
975 # The memory handler flushes to its target handler based on specific
976 # criteria (message count and message level).
977 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000978 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000979 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000980 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000981 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100982 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000983 lines = [
984 ('DEBUG', '1'),
985 ('INFO', '2'),
986 ('WARNING', '3'),
987 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 for n in (4, 14):
990 for i in range(9):
991 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000992 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000993 # This will flush because it's the 10th message since the last
994 # flush.
995 self.mem_logger.debug(self.next_message())
996 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000997 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000998
999 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001000 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001001
1002
1003class ExceptionFormatter(logging.Formatter):
1004 """A special exception formatter."""
1005 def formatException(self, ei):
1006 return "Got a [%s]" % ei[0].__name__
1007
1008
1009class ConfigFileTest(BaseTest):
1010
1011 """Reading logging config from a .ini-style config file."""
1012
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001013 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001014
1015 # config0 is a standard configuration.
1016 config0 = """
1017 [loggers]
1018 keys=root
1019
1020 [handlers]
1021 keys=hand1
1022
1023 [formatters]
1024 keys=form1
1025
1026 [logger_root]
1027 level=WARNING
1028 handlers=hand1
1029
1030 [handler_hand1]
1031 class=StreamHandler
1032 level=NOTSET
1033 formatter=form1
1034 args=(sys.stdout,)
1035
1036 [formatter_form1]
1037 format=%(levelname)s ++ %(message)s
1038 datefmt=
1039 """
1040
1041 # config1 adds a little to the standard configuration.
1042 config1 = """
1043 [loggers]
1044 keys=root,parser
1045
1046 [handlers]
1047 keys=hand1
1048
1049 [formatters]
1050 keys=form1
1051
1052 [logger_root]
1053 level=WARNING
1054 handlers=
1055
1056 [logger_parser]
1057 level=DEBUG
1058 handlers=hand1
1059 propagate=1
1060 qualname=compiler.parser
1061
1062 [handler_hand1]
1063 class=StreamHandler
1064 level=NOTSET
1065 formatter=form1
1066 args=(sys.stdout,)
1067
1068 [formatter_form1]
1069 format=%(levelname)s ++ %(message)s
1070 datefmt=
1071 """
1072
Vinay Sajip3f84b072011-03-07 17:49:33 +00001073 # config1a moves the handler to the root.
1074 config1a = """
1075 [loggers]
1076 keys=root,parser
1077
1078 [handlers]
1079 keys=hand1
1080
1081 [formatters]
1082 keys=form1
1083
1084 [logger_root]
1085 level=WARNING
1086 handlers=hand1
1087
1088 [logger_parser]
1089 level=DEBUG
1090 handlers=
1091 propagate=1
1092 qualname=compiler.parser
1093
1094 [handler_hand1]
1095 class=StreamHandler
1096 level=NOTSET
1097 formatter=form1
1098 args=(sys.stdout,)
1099
1100 [formatter_form1]
1101 format=%(levelname)s ++ %(message)s
1102 datefmt=
1103 """
1104
Christian Heimes180510d2008-03-03 19:15:45 +00001105 # config2 has a subtle configuration error that should be reported
1106 config2 = config1.replace("sys.stdout", "sys.stbout")
1107
1108 # config3 has a less subtle configuration error
1109 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1110
1111 # config4 specifies a custom formatter class to be loaded
1112 config4 = """
1113 [loggers]
1114 keys=root
1115
1116 [handlers]
1117 keys=hand1
1118
1119 [formatters]
1120 keys=form1
1121
1122 [logger_root]
1123 level=NOTSET
1124 handlers=hand1
1125
1126 [handler_hand1]
1127 class=StreamHandler
1128 level=NOTSET
1129 formatter=form1
1130 args=(sys.stdout,)
1131
1132 [formatter_form1]
1133 class=""" + __name__ + """.ExceptionFormatter
1134 format=%(levelname)s:%(name)s:%(message)s
1135 datefmt=
1136 """
1137
Georg Brandl3dbca812008-07-23 16:10:53 +00001138 # config5 specifies a custom handler class to be loaded
1139 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1140
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001141 # config6 uses ', ' delimiters in the handlers and formatters sections
1142 config6 = """
1143 [loggers]
1144 keys=root,parser
1145
1146 [handlers]
1147 keys=hand1, hand2
1148
1149 [formatters]
1150 keys=form1, form2
1151
1152 [logger_root]
1153 level=WARNING
1154 handlers=
1155
1156 [logger_parser]
1157 level=DEBUG
1158 handlers=hand1
1159 propagate=1
1160 qualname=compiler.parser
1161
1162 [handler_hand1]
1163 class=StreamHandler
1164 level=NOTSET
1165 formatter=form1
1166 args=(sys.stdout,)
1167
1168 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001169 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001170 level=NOTSET
1171 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001172 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001173
1174 [formatter_form1]
1175 format=%(levelname)s ++ %(message)s
1176 datefmt=
1177
1178 [formatter_form2]
1179 format=%(message)s
1180 datefmt=
1181 """
1182
Vinay Sajip3f84b072011-03-07 17:49:33 +00001183 # config7 adds a compiler logger.
1184 config7 = """
1185 [loggers]
1186 keys=root,parser,compiler
1187
1188 [handlers]
1189 keys=hand1
1190
1191 [formatters]
1192 keys=form1
1193
1194 [logger_root]
1195 level=WARNING
1196 handlers=hand1
1197
1198 [logger_compiler]
1199 level=DEBUG
1200 handlers=
1201 propagate=1
1202 qualname=compiler
1203
1204 [logger_parser]
1205 level=DEBUG
1206 handlers=
1207 propagate=1
1208 qualname=compiler.parser
1209
1210 [handler_hand1]
1211 class=StreamHandler
1212 level=NOTSET
1213 formatter=form1
1214 args=(sys.stdout,)
1215
1216 [formatter_form1]
1217 format=%(levelname)s ++ %(message)s
1218 datefmt=
1219 """
1220
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001221 disable_test = """
1222 [loggers]
1223 keys=root
1224
1225 [handlers]
1226 keys=screen
1227
1228 [formatters]
1229 keys=
1230
1231 [logger_root]
1232 level=DEBUG
1233 handlers=screen
1234
1235 [handler_screen]
1236 level=DEBUG
1237 class=StreamHandler
1238 args=(sys.stdout,)
1239 formatter=
1240 """
1241
1242 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001243 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001244 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001245
1246 def test_config0_ok(self):
1247 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001248 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001249 self.apply_config(self.config0)
1250 logger = logging.getLogger()
1251 # Won't output anything
1252 logger.info(self.next_message())
1253 # Outputs a message
1254 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001255 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001256 ('ERROR', '2'),
1257 ], stream=output)
1258 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001259 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001260
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001261 def test_config0_using_cp_ok(self):
1262 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001263 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001264 file = io.StringIO(textwrap.dedent(self.config0))
1265 cp = configparser.ConfigParser()
1266 cp.read_file(file)
1267 logging.config.fileConfig(cp)
1268 logger = logging.getLogger()
1269 # Won't output anything
1270 logger.info(self.next_message())
1271 # Outputs a message
1272 logger.error(self.next_message())
1273 self.assert_log_lines([
1274 ('ERROR', '2'),
1275 ], stream=output)
1276 # Original logger output is empty.
1277 self.assert_log_lines([])
1278
Georg Brandl3dbca812008-07-23 16:10:53 +00001279 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001280 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001281 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001282 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001283 logger = logging.getLogger("compiler.parser")
1284 # Both will output a message
1285 logger.info(self.next_message())
1286 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001287 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001288 ('INFO', '1'),
1289 ('ERROR', '2'),
1290 ], stream=output)
1291 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001292 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001293
1294 def test_config2_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config2)
1297
1298 def test_config3_failure(self):
1299 # A simple config file which overrides the default settings.
1300 self.assertRaises(Exception, self.apply_config, self.config3)
1301
1302 def test_config4_ok(self):
1303 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001304 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001305 self.apply_config(self.config4)
1306 logger = logging.getLogger()
1307 try:
1308 raise RuntimeError()
1309 except RuntimeError:
1310 logging.exception("just testing")
1311 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001312 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001313 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1314 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001315 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001316
Georg Brandl3dbca812008-07-23 16:10:53 +00001317 def test_config5_ok(self):
1318 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001319
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001320 def test_config6_ok(self):
1321 self.test_config1_ok(config=self.config6)
1322
Vinay Sajip3f84b072011-03-07 17:49:33 +00001323 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001324 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001325 self.apply_config(self.config1a)
1326 logger = logging.getLogger("compiler.parser")
1327 # See issue #11424. compiler-hyphenated sorts
1328 # between compiler and compiler.xyz and this
1329 # was preventing compiler.xyz from being included
1330 # in the child loggers of compiler because of an
1331 # overzealous loop termination condition.
1332 hyphenated = logging.getLogger('compiler-hyphenated')
1333 # All will output a message
1334 logger.info(self.next_message())
1335 logger.error(self.next_message())
1336 hyphenated.critical(self.next_message())
1337 self.assert_log_lines([
1338 ('INFO', '1'),
1339 ('ERROR', '2'),
1340 ('CRITICAL', '3'),
1341 ], stream=output)
1342 # Original logger output is empty.
1343 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001344 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001345 self.apply_config(self.config7)
1346 logger = logging.getLogger("compiler.parser")
1347 self.assertFalse(logger.disabled)
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 logger = logging.getLogger("compiler.lexer")
1352 # Both will output a message
1353 logger.info(self.next_message())
1354 logger.error(self.next_message())
1355 # Will not appear
1356 hyphenated.critical(self.next_message())
1357 self.assert_log_lines([
1358 ('INFO', '4'),
1359 ('ERROR', '5'),
1360 ('INFO', '6'),
1361 ('ERROR', '7'),
1362 ], stream=output)
1363 # Original logger output is empty.
1364 self.assert_log_lines([])
1365
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001366 def test_logger_disabling(self):
1367 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001368 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001369 self.assertFalse(logger.disabled)
1370 self.apply_config(self.disable_test)
1371 self.assertTrue(logger.disabled)
1372 self.apply_config(self.disable_test, disable_existing_loggers=False)
1373 self.assertFalse(logger.disabled)
1374
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001375
Victor Stinner45df8202010-04-28 22:31:17 +00001376@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001377class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001378
Christian Heimes180510d2008-03-03 19:15:45 +00001379 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001380
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001381 if threading:
1382 server_class = TestTCPServer
1383 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001384
Christian Heimes180510d2008-03-03 19:15:45 +00001385 def setUp(self):
1386 """Set up a TCP server to receive log messages, and a SocketHandler
1387 pointing to that server's address and port."""
1388 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001389 self.server = server = self.server_class(self.address,
1390 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001391 server.start()
1392 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001393 hcls = logging.handlers.SocketHandler
1394 if isinstance(server.server_address, tuple):
1395 self.sock_hdlr = hcls('localhost', server.port)
1396 else:
1397 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001398 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001399 self.root_logger.removeHandler(self.root_logger.handlers[0])
1400 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001401 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001402
Christian Heimes180510d2008-03-03 19:15:45 +00001403 def tearDown(self):
1404 """Shutdown the TCP server."""
1405 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001406 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001407 self.root_logger.removeHandler(self.sock_hdlr)
1408 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001409 finally:
1410 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001411
Vinay Sajip7367d082011-05-02 13:17:27 +01001412 def handle_socket(self, request):
1413 conn = request.connection
1414 while True:
1415 chunk = conn.recv(4)
1416 if len(chunk) < 4:
1417 break
1418 slen = struct.unpack(">L", chunk)[0]
1419 chunk = conn.recv(slen)
1420 while len(chunk) < slen:
1421 chunk = chunk + conn.recv(slen - len(chunk))
1422 obj = pickle.loads(chunk)
1423 record = logging.makeLogRecord(obj)
1424 self.log_output += record.msg + '\n'
1425 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001426
Christian Heimes180510d2008-03-03 19:15:45 +00001427 def test_output(self):
1428 # The log message sent to the SocketHandler is properly received.
1429 logger = logging.getLogger("tcp")
1430 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001431 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001432 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001433 self.handled.acquire()
1434 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001435
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001436 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001437 # Avoid timing-related failures due to SocketHandler's own hard-wired
1438 # one-second timeout on socket.create_connection() (issue #16264).
1439 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001440 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001441 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001442 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001443 try:
1444 raise RuntimeError('Deliberate mistake')
1445 except RuntimeError:
1446 self.root_logger.exception('Never sent')
1447 self.root_logger.error('Never sent, either')
1448 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001449 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001450 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1451 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001452
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001453def _get_temp_domain_socket():
1454 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1455 os.close(fd)
1456 # just need a name - file can't be present, or we'll get an
1457 # 'address already in use' error.
1458 os.remove(fn)
1459 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001460
Victor Stinnerec5a8602014-06-02 14:41:51 +02001461@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001462@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001463class UnixSocketHandlerTest(SocketHandlerTest):
1464
1465 """Test for SocketHandler with unix sockets."""
1466
Victor Stinnerec5a8602014-06-02 14:41:51 +02001467 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001468 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001469
1470 def setUp(self):
1471 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001472 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001473 SocketHandlerTest.setUp(self)
1474
1475 def tearDown(self):
1476 SocketHandlerTest.tearDown(self)
1477 os.remove(self.address)
1478
1479@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001480class DatagramHandlerTest(BaseTest):
1481
1482 """Test for DatagramHandler."""
1483
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001484 if threading:
1485 server_class = TestUDPServer
1486 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001487
Vinay Sajip7367d082011-05-02 13:17:27 +01001488 def setUp(self):
1489 """Set up a UDP server to receive log messages, and a DatagramHandler
1490 pointing to that server's address and port."""
1491 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001492 self.server = server = self.server_class(self.address,
1493 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001494 server.start()
1495 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001496 hcls = logging.handlers.DatagramHandler
1497 if isinstance(server.server_address, tuple):
1498 self.sock_hdlr = hcls('localhost', server.port)
1499 else:
1500 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001501 self.log_output = ''
1502 self.root_logger.removeHandler(self.root_logger.handlers[0])
1503 self.root_logger.addHandler(self.sock_hdlr)
1504 self.handled = threading.Event()
1505
1506 def tearDown(self):
1507 """Shutdown the UDP server."""
1508 try:
1509 self.server.stop(2.0)
1510 self.root_logger.removeHandler(self.sock_hdlr)
1511 self.sock_hdlr.close()
1512 finally:
1513 BaseTest.tearDown(self)
1514
1515 def handle_datagram(self, request):
1516 slen = struct.pack('>L', 0) # length of prefix
1517 packet = request.packet[len(slen):]
1518 obj = pickle.loads(packet)
1519 record = logging.makeLogRecord(obj)
1520 self.log_output += record.msg + '\n'
1521 self.handled.set()
1522
1523 def test_output(self):
1524 # The log message sent to the DatagramHandler is properly received.
1525 logger = logging.getLogger("udp")
1526 logger.error("spam")
1527 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001528 self.handled.clear()
1529 logger.error("eggs")
1530 self.handled.wait()
1531 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001532
Victor Stinnerec5a8602014-06-02 14:41:51 +02001533@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001534@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001535class UnixDatagramHandlerTest(DatagramHandlerTest):
1536
1537 """Test for DatagramHandler using Unix sockets."""
1538
Victor Stinnerec5a8602014-06-02 14:41:51 +02001539 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001540 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001541
1542 def setUp(self):
1543 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001544 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001545 DatagramHandlerTest.setUp(self)
1546
1547 def tearDown(self):
1548 DatagramHandlerTest.tearDown(self)
1549 os.remove(self.address)
1550
1551@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001552class SysLogHandlerTest(BaseTest):
1553
1554 """Test for SysLogHandler using UDP."""
1555
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001556 if threading:
1557 server_class = TestUDPServer
1558 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001559
Vinay Sajip7367d082011-05-02 13:17:27 +01001560 def setUp(self):
1561 """Set up a UDP server to receive log messages, and a SysLogHandler
1562 pointing to that server's address and port."""
1563 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 self.server = server = self.server_class(self.address,
1565 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 server.start()
1567 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001568 hcls = logging.handlers.SysLogHandler
1569 if isinstance(server.server_address, tuple):
1570 self.sl_hdlr = hcls(('localhost', server.port))
1571 else:
1572 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001573 self.log_output = ''
1574 self.root_logger.removeHandler(self.root_logger.handlers[0])
1575 self.root_logger.addHandler(self.sl_hdlr)
1576 self.handled = threading.Event()
1577
1578 def tearDown(self):
1579 """Shutdown the UDP server."""
1580 try:
1581 self.server.stop(2.0)
1582 self.root_logger.removeHandler(self.sl_hdlr)
1583 self.sl_hdlr.close()
1584 finally:
1585 BaseTest.tearDown(self)
1586
1587 def handle_datagram(self, request):
1588 self.log_output = request.packet
1589 self.handled.set()
1590
1591 def test_output(self):
1592 # The log message sent to the SysLogHandler is properly received.
1593 logger = logging.getLogger("slh")
1594 logger.error("sp\xe4m")
1595 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001596 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001597 self.handled.clear()
1598 self.sl_hdlr.append_nul = False
1599 logger.error("sp\xe4m")
1600 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001601 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001602 self.handled.clear()
1603 self.sl_hdlr.ident = "h\xe4m-"
1604 logger.error("sp\xe4m")
1605 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001606 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001607
Victor Stinnerec5a8602014-06-02 14:41:51 +02001608@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001609@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001610class UnixSysLogHandlerTest(SysLogHandlerTest):
1611
1612 """Test for SysLogHandler with Unix sockets."""
1613
Victor Stinnerec5a8602014-06-02 14:41:51 +02001614 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001615 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001616
1617 def setUp(self):
1618 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001619 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001620 SysLogHandlerTest.setUp(self)
1621
1622 def tearDown(self):
1623 SysLogHandlerTest.tearDown(self)
1624 os.remove(self.address)
1625
Vinay Sajip5421f352013-09-27 18:18:28 +01001626@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001627class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001628 """Test for HTTPHandler."""
1629
1630 def setUp(self):
1631 """Set up an HTTP server to receive log messages, and a HTTPHandler
1632 pointing to that server's address and port."""
1633 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001634 self.handled = threading.Event()
1635
Vinay Sajip7367d082011-05-02 13:17:27 +01001636 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001637 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001638 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001639 if self.command == 'POST':
1640 try:
1641 rlen = int(request.headers['Content-Length'])
1642 self.post_data = request.rfile.read(rlen)
1643 except:
1644 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001645 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001646 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001647 self.handled.set()
1648
1649 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001650 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001651 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001652 root_logger = self.root_logger
1653 root_logger.removeHandler(self.root_logger.handlers[0])
1654 for secure in (False, True):
1655 addr = ('localhost', 0)
1656 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001657 try:
1658 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001659 except ImportError:
1660 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001661 else:
1662 here = os.path.dirname(__file__)
1663 localhost_cert = os.path.join(here, "keycert.pem")
1664 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1665 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001666
1667 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001668 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001669 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001670 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001671 self.server = server = TestHTTPServer(addr, self.handle_request,
1672 0.01, sslctx=sslctx)
1673 server.start()
1674 server.ready.wait()
1675 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001676 secure_client = secure and sslctx
1677 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001678 secure=secure_client,
1679 context=context)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001680 self.log_data = None
1681 root_logger.addHandler(self.h_hdlr)
1682
1683 for method in ('GET', 'POST'):
1684 self.h_hdlr.method = method
1685 self.handled.clear()
1686 msg = "sp\xe4m"
1687 logger.error(msg)
1688 self.handled.wait()
1689 self.assertEqual(self.log_data.path, '/frob')
1690 self.assertEqual(self.command, method)
1691 if method == 'GET':
1692 d = parse_qs(self.log_data.query)
1693 else:
1694 d = parse_qs(self.post_data.decode('utf-8'))
1695 self.assertEqual(d['name'], ['http'])
1696 self.assertEqual(d['funcName'], ['test_output'])
1697 self.assertEqual(d['msg'], [msg])
1698
1699 self.server.stop(2.0)
1700 self.root_logger.removeHandler(self.h_hdlr)
1701 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001702
Christian Heimes180510d2008-03-03 19:15:45 +00001703class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001704
Christian Heimes180510d2008-03-03 19:15:45 +00001705 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001706
Christian Heimes180510d2008-03-03 19:15:45 +00001707 def setUp(self):
1708 """Create a dict to remember potentially destroyed objects."""
1709 BaseTest.setUp(self)
1710 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001711
Christian Heimes180510d2008-03-03 19:15:45 +00001712 def _watch_for_survival(self, *args):
1713 """Watch the given objects for survival, by creating weakrefs to
1714 them."""
1715 for obj in args:
1716 key = id(obj), repr(obj)
1717 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001718
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001719 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001720 """Assert that all objects watched for survival have survived."""
1721 # Trigger cycle breaking.
1722 gc.collect()
1723 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001724 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001725 if ref() is None:
1726 dead.append(repr_)
1727 if dead:
1728 self.fail("%d objects should have survived "
1729 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731 def test_persistent_loggers(self):
1732 # Logger objects are persistent and retain their configuration, even
1733 # if visible references are destroyed.
1734 self.root_logger.setLevel(logging.INFO)
1735 foo = logging.getLogger("foo")
1736 self._watch_for_survival(foo)
1737 foo.setLevel(logging.DEBUG)
1738 self.root_logger.debug(self.next_message())
1739 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001740 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001741 ('foo', 'DEBUG', '2'),
1742 ])
1743 del foo
1744 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001745 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001746 # foo has retained its settings.
1747 bar = logging.getLogger("foo")
1748 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001749 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001750 ('foo', 'DEBUG', '2'),
1751 ('foo', 'DEBUG', '3'),
1752 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001753
Benjamin Petersonf91df042009-02-13 02:50:59 +00001754
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001755class EncodingTest(BaseTest):
1756 def test_encoding_plain_file(self):
1757 # In Python 2.x, a plain file object is treated as having no encoding.
1758 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001759 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1760 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001761 # the non-ascii data we write to the log.
1762 data = "foo\x80"
1763 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001764 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001765 log.addHandler(handler)
1766 try:
1767 # write non-ascii data to the log.
1768 log.warning(data)
1769 finally:
1770 log.removeHandler(handler)
1771 handler.close()
1772 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001773 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001774 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001775 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001776 finally:
1777 f.close()
1778 finally:
1779 if os.path.isfile(fn):
1780 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001781
Benjamin Petersonf91df042009-02-13 02:50:59 +00001782 def test_encoding_cyrillic_unicode(self):
1783 log = logging.getLogger("test")
1784 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1785 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1786 #Ensure it's written in a Cyrillic encoding
1787 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001788 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001789 stream = io.BytesIO()
1790 writer = writer_class(stream, 'strict')
1791 handler = logging.StreamHandler(writer)
1792 log.addHandler(handler)
1793 try:
1794 log.warning(message)
1795 finally:
1796 log.removeHandler(handler)
1797 handler.close()
1798 # check we wrote exactly those bytes, ignoring trailing \n etc
1799 s = stream.getvalue()
1800 #Compare against what the data should be when encoded in CP-1251
1801 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1802
1803
Georg Brandlf9734072008-12-07 15:30:06 +00001804class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001805
Georg Brandlf9734072008-12-07 15:30:06 +00001806 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001807 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001808 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001809 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001810 warnings.filterwarnings("always", category=UserWarning)
1811 stream = io.StringIO()
1812 h = logging.StreamHandler(stream)
1813 logger = logging.getLogger("py.warnings")
1814 logger.addHandler(h)
1815 warnings.warn("I'm warning you...")
1816 logger.removeHandler(h)
1817 s = stream.getvalue()
1818 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001819 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001820
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001821 #See if an explicit file uses the original implementation
1822 a_file = io.StringIO()
1823 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1824 a_file, "Dummy line")
1825 s = a_file.getvalue()
1826 a_file.close()
1827 self.assertEqual(s,
1828 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1829
1830 def test_warnings_no_handlers(self):
1831 with warnings.catch_warnings():
1832 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001833 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001834
1835 # confirm our assumption: no loggers are set
1836 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838
1839 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001840 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001841 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001842
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001843
1844def formatFunc(format, datefmt=None):
1845 return logging.Formatter(format, datefmt)
1846
1847def handlerFunc():
1848 return logging.StreamHandler()
1849
1850class CustomHandler(logging.StreamHandler):
1851 pass
1852
1853class ConfigDictTest(BaseTest):
1854
1855 """Reading logging config from a dictionary."""
1856
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001857 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001858
1859 # config0 is a standard configuration.
1860 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001861 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001862 'formatters': {
1863 'form1' : {
1864 'format' : '%(levelname)s ++ %(message)s',
1865 },
1866 },
1867 'handlers' : {
1868 'hand1' : {
1869 'class' : 'logging.StreamHandler',
1870 'formatter' : 'form1',
1871 'level' : 'NOTSET',
1872 'stream' : 'ext://sys.stdout',
1873 },
1874 },
1875 'root' : {
1876 'level' : 'WARNING',
1877 'handlers' : ['hand1'],
1878 },
1879 }
1880
1881 # config1 adds a little to the standard configuration.
1882 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001883 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001884 'formatters': {
1885 'form1' : {
1886 'format' : '%(levelname)s ++ %(message)s',
1887 },
1888 },
1889 'handlers' : {
1890 'hand1' : {
1891 'class' : 'logging.StreamHandler',
1892 'formatter' : 'form1',
1893 'level' : 'NOTSET',
1894 'stream' : 'ext://sys.stdout',
1895 },
1896 },
1897 'loggers' : {
1898 'compiler.parser' : {
1899 'level' : 'DEBUG',
1900 'handlers' : ['hand1'],
1901 },
1902 },
1903 'root' : {
1904 'level' : 'WARNING',
1905 },
1906 }
1907
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001908 # config1a moves the handler to the root. Used with config8a
1909 config1a = {
1910 'version': 1,
1911 'formatters': {
1912 'form1' : {
1913 'format' : '%(levelname)s ++ %(message)s',
1914 },
1915 },
1916 'handlers' : {
1917 'hand1' : {
1918 'class' : 'logging.StreamHandler',
1919 'formatter' : 'form1',
1920 'level' : 'NOTSET',
1921 'stream' : 'ext://sys.stdout',
1922 },
1923 },
1924 'loggers' : {
1925 'compiler.parser' : {
1926 'level' : 'DEBUG',
1927 },
1928 },
1929 'root' : {
1930 'level' : 'WARNING',
1931 'handlers' : ['hand1'],
1932 },
1933 }
1934
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001935 # config2 has a subtle configuration error that should be reported
1936 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001937 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001938 'formatters': {
1939 'form1' : {
1940 'format' : '%(levelname)s ++ %(message)s',
1941 },
1942 },
1943 'handlers' : {
1944 'hand1' : {
1945 'class' : 'logging.StreamHandler',
1946 'formatter' : 'form1',
1947 'level' : 'NOTSET',
1948 'stream' : 'ext://sys.stdbout',
1949 },
1950 },
1951 'loggers' : {
1952 'compiler.parser' : {
1953 'level' : 'DEBUG',
1954 'handlers' : ['hand1'],
1955 },
1956 },
1957 'root' : {
1958 'level' : 'WARNING',
1959 },
1960 }
1961
1962 #As config1 but with a misspelt level on a handler
1963 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001964 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001965 'formatters': {
1966 'form1' : {
1967 'format' : '%(levelname)s ++ %(message)s',
1968 },
1969 },
1970 'handlers' : {
1971 'hand1' : {
1972 'class' : 'logging.StreamHandler',
1973 'formatter' : 'form1',
1974 'level' : 'NTOSET',
1975 'stream' : 'ext://sys.stdout',
1976 },
1977 },
1978 'loggers' : {
1979 'compiler.parser' : {
1980 'level' : 'DEBUG',
1981 'handlers' : ['hand1'],
1982 },
1983 },
1984 'root' : {
1985 'level' : 'WARNING',
1986 },
1987 }
1988
1989
1990 #As config1 but with a misspelt level on a logger
1991 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001992 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001993 'formatters': {
1994 'form1' : {
1995 'format' : '%(levelname)s ++ %(message)s',
1996 },
1997 },
1998 'handlers' : {
1999 'hand1' : {
2000 'class' : 'logging.StreamHandler',
2001 'formatter' : 'form1',
2002 'level' : 'NOTSET',
2003 'stream' : 'ext://sys.stdout',
2004 },
2005 },
2006 'loggers' : {
2007 'compiler.parser' : {
2008 'level' : 'DEBUG',
2009 'handlers' : ['hand1'],
2010 },
2011 },
2012 'root' : {
2013 'level' : 'WRANING',
2014 },
2015 }
2016
2017 # config3 has a less subtle configuration error
2018 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002019 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002020 'formatters': {
2021 'form1' : {
2022 'format' : '%(levelname)s ++ %(message)s',
2023 },
2024 },
2025 'handlers' : {
2026 'hand1' : {
2027 'class' : 'logging.StreamHandler',
2028 'formatter' : 'misspelled_name',
2029 'level' : 'NOTSET',
2030 'stream' : 'ext://sys.stdout',
2031 },
2032 },
2033 'loggers' : {
2034 'compiler.parser' : {
2035 'level' : 'DEBUG',
2036 'handlers' : ['hand1'],
2037 },
2038 },
2039 'root' : {
2040 'level' : 'WARNING',
2041 },
2042 }
2043
2044 # config4 specifies a custom formatter class to be loaded
2045 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002046 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002047 'formatters': {
2048 'form1' : {
2049 '()' : __name__ + '.ExceptionFormatter',
2050 'format' : '%(levelname)s:%(name)s:%(message)s',
2051 },
2052 },
2053 'handlers' : {
2054 'hand1' : {
2055 'class' : 'logging.StreamHandler',
2056 'formatter' : 'form1',
2057 'level' : 'NOTSET',
2058 'stream' : 'ext://sys.stdout',
2059 },
2060 },
2061 'root' : {
2062 'level' : 'NOTSET',
2063 'handlers' : ['hand1'],
2064 },
2065 }
2066
2067 # As config4 but using an actual callable rather than a string
2068 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002069 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002070 'formatters': {
2071 'form1' : {
2072 '()' : ExceptionFormatter,
2073 'format' : '%(levelname)s:%(name)s:%(message)s',
2074 },
2075 'form2' : {
2076 '()' : __name__ + '.formatFunc',
2077 'format' : '%(levelname)s:%(name)s:%(message)s',
2078 },
2079 'form3' : {
2080 '()' : formatFunc,
2081 'format' : '%(levelname)s:%(name)s:%(message)s',
2082 },
2083 },
2084 'handlers' : {
2085 'hand1' : {
2086 'class' : 'logging.StreamHandler',
2087 'formatter' : 'form1',
2088 'level' : 'NOTSET',
2089 'stream' : 'ext://sys.stdout',
2090 },
2091 'hand2' : {
2092 '()' : handlerFunc,
2093 },
2094 },
2095 'root' : {
2096 'level' : 'NOTSET',
2097 'handlers' : ['hand1'],
2098 },
2099 }
2100
2101 # config5 specifies a custom handler class to be loaded
2102 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002103 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002104 'formatters': {
2105 'form1' : {
2106 'format' : '%(levelname)s ++ %(message)s',
2107 },
2108 },
2109 'handlers' : {
2110 'hand1' : {
2111 'class' : __name__ + '.CustomHandler',
2112 'formatter' : 'form1',
2113 'level' : 'NOTSET',
2114 'stream' : 'ext://sys.stdout',
2115 },
2116 },
2117 'loggers' : {
2118 'compiler.parser' : {
2119 'level' : 'DEBUG',
2120 'handlers' : ['hand1'],
2121 },
2122 },
2123 'root' : {
2124 'level' : 'WARNING',
2125 },
2126 }
2127
2128 # config6 specifies a custom handler class to be loaded
2129 # but has bad arguments
2130 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002131 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002132 'formatters': {
2133 'form1' : {
2134 'format' : '%(levelname)s ++ %(message)s',
2135 },
2136 },
2137 'handlers' : {
2138 'hand1' : {
2139 'class' : __name__ + '.CustomHandler',
2140 'formatter' : 'form1',
2141 'level' : 'NOTSET',
2142 'stream' : 'ext://sys.stdout',
2143 '9' : 'invalid parameter name',
2144 },
2145 },
2146 'loggers' : {
2147 'compiler.parser' : {
2148 'level' : 'DEBUG',
2149 'handlers' : ['hand1'],
2150 },
2151 },
2152 'root' : {
2153 'level' : 'WARNING',
2154 },
2155 }
2156
2157 #config 7 does not define compiler.parser but defines compiler.lexer
2158 #so compiler.parser should be disabled after applying it
2159 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002160 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002161 'formatters': {
2162 'form1' : {
2163 'format' : '%(levelname)s ++ %(message)s',
2164 },
2165 },
2166 'handlers' : {
2167 'hand1' : {
2168 'class' : 'logging.StreamHandler',
2169 'formatter' : 'form1',
2170 'level' : 'NOTSET',
2171 'stream' : 'ext://sys.stdout',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.lexer' : {
2176 'level' : 'DEBUG',
2177 'handlers' : ['hand1'],
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WARNING',
2182 },
2183 }
2184
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002185 # config8 defines both compiler and compiler.lexer
2186 # so compiler.parser should not be disabled (since
2187 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002188 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002189 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002190 'disable_existing_loggers' : False,
2191 'formatters': {
2192 'form1' : {
2193 'format' : '%(levelname)s ++ %(message)s',
2194 },
2195 },
2196 'handlers' : {
2197 'hand1' : {
2198 'class' : 'logging.StreamHandler',
2199 'formatter' : 'form1',
2200 'level' : 'NOTSET',
2201 'stream' : 'ext://sys.stdout',
2202 },
2203 },
2204 'loggers' : {
2205 'compiler' : {
2206 'level' : 'DEBUG',
2207 'handlers' : ['hand1'],
2208 },
2209 'compiler.lexer' : {
2210 },
2211 },
2212 'root' : {
2213 'level' : 'WARNING',
2214 },
2215 }
2216
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002217 # config8a disables existing loggers
2218 config8a = {
2219 'version': 1,
2220 'disable_existing_loggers' : True,
2221 'formatters': {
2222 'form1' : {
2223 'format' : '%(levelname)s ++ %(message)s',
2224 },
2225 },
2226 'handlers' : {
2227 'hand1' : {
2228 'class' : 'logging.StreamHandler',
2229 'formatter' : 'form1',
2230 'level' : 'NOTSET',
2231 'stream' : 'ext://sys.stdout',
2232 },
2233 },
2234 'loggers' : {
2235 'compiler' : {
2236 'level' : 'DEBUG',
2237 'handlers' : ['hand1'],
2238 },
2239 'compiler.lexer' : {
2240 },
2241 },
2242 'root' : {
2243 'level' : 'WARNING',
2244 },
2245 }
2246
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002247 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002248 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002249 'formatters': {
2250 'form1' : {
2251 'format' : '%(levelname)s ++ %(message)s',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : 'logging.StreamHandler',
2257 'formatter' : 'form1',
2258 'level' : 'WARNING',
2259 'stream' : 'ext://sys.stdout',
2260 },
2261 },
2262 'loggers' : {
2263 'compiler.parser' : {
2264 'level' : 'WARNING',
2265 'handlers' : ['hand1'],
2266 },
2267 },
2268 'root' : {
2269 'level' : 'NOTSET',
2270 },
2271 }
2272
2273 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002274 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 'incremental' : True,
2276 'handlers' : {
2277 'hand1' : {
2278 'level' : 'WARNING',
2279 },
2280 },
2281 'loggers' : {
2282 'compiler.parser' : {
2283 'level' : 'INFO',
2284 },
2285 },
2286 }
2287
2288 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002289 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002290 'incremental' : True,
2291 'handlers' : {
2292 'hand1' : {
2293 'level' : 'INFO',
2294 },
2295 },
2296 'loggers' : {
2297 'compiler.parser' : {
2298 'level' : 'INFO',
2299 },
2300 },
2301 }
2302
2303 #As config1 but with a filter added
2304 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002305 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002306 'formatters': {
2307 'form1' : {
2308 'format' : '%(levelname)s ++ %(message)s',
2309 },
2310 },
2311 'filters' : {
2312 'filt1' : {
2313 'name' : 'compiler.parser',
2314 },
2315 },
2316 'handlers' : {
2317 'hand1' : {
2318 'class' : 'logging.StreamHandler',
2319 'formatter' : 'form1',
2320 'level' : 'NOTSET',
2321 'stream' : 'ext://sys.stdout',
2322 'filters' : ['filt1'],
2323 },
2324 },
2325 'loggers' : {
2326 'compiler.parser' : {
2327 'level' : 'DEBUG',
2328 'filters' : ['filt1'],
2329 },
2330 },
2331 'root' : {
2332 'level' : 'WARNING',
2333 'handlers' : ['hand1'],
2334 },
2335 }
2336
2337 #As config1 but using cfg:// references
2338 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002339 'version': 1,
2340 'true_formatters': {
2341 'form1' : {
2342 'format' : '%(levelname)s ++ %(message)s',
2343 },
2344 },
2345 'handler_configs': {
2346 'hand1' : {
2347 'class' : 'logging.StreamHandler',
2348 'formatter' : 'form1',
2349 'level' : 'NOTSET',
2350 'stream' : 'ext://sys.stdout',
2351 },
2352 },
2353 'formatters' : 'cfg://true_formatters',
2354 'handlers' : {
2355 'hand1' : 'cfg://handler_configs[hand1]',
2356 },
2357 'loggers' : {
2358 'compiler.parser' : {
2359 'level' : 'DEBUG',
2360 'handlers' : ['hand1'],
2361 },
2362 },
2363 'root' : {
2364 'level' : 'WARNING',
2365 },
2366 }
2367
2368 #As config11 but missing the version key
2369 config12 = {
2370 'true_formatters': {
2371 'form1' : {
2372 'format' : '%(levelname)s ++ %(message)s',
2373 },
2374 },
2375 'handler_configs': {
2376 'hand1' : {
2377 'class' : 'logging.StreamHandler',
2378 'formatter' : 'form1',
2379 'level' : 'NOTSET',
2380 'stream' : 'ext://sys.stdout',
2381 },
2382 },
2383 'formatters' : 'cfg://true_formatters',
2384 'handlers' : {
2385 'hand1' : 'cfg://handler_configs[hand1]',
2386 },
2387 'loggers' : {
2388 'compiler.parser' : {
2389 'level' : 'DEBUG',
2390 'handlers' : ['hand1'],
2391 },
2392 },
2393 'root' : {
2394 'level' : 'WARNING',
2395 },
2396 }
2397
2398 #As config11 but using an unsupported version
2399 config13 = {
2400 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002401 'true_formatters': {
2402 'form1' : {
2403 'format' : '%(levelname)s ++ %(message)s',
2404 },
2405 },
2406 'handler_configs': {
2407 'hand1' : {
2408 'class' : 'logging.StreamHandler',
2409 'formatter' : 'form1',
2410 'level' : 'NOTSET',
2411 'stream' : 'ext://sys.stdout',
2412 },
2413 },
2414 'formatters' : 'cfg://true_formatters',
2415 'handlers' : {
2416 'hand1' : 'cfg://handler_configs[hand1]',
2417 },
2418 'loggers' : {
2419 'compiler.parser' : {
2420 'level' : 'DEBUG',
2421 'handlers' : ['hand1'],
2422 },
2423 },
2424 'root' : {
2425 'level' : 'WARNING',
2426 },
2427 }
2428
Vinay Sajip8d270232012-11-15 14:20:18 +00002429 # As config0, but with properties
2430 config14 = {
2431 'version': 1,
2432 'formatters': {
2433 'form1' : {
2434 'format' : '%(levelname)s ++ %(message)s',
2435 },
2436 },
2437 'handlers' : {
2438 'hand1' : {
2439 'class' : 'logging.StreamHandler',
2440 'formatter' : 'form1',
2441 'level' : 'NOTSET',
2442 'stream' : 'ext://sys.stdout',
2443 '.': {
2444 'foo': 'bar',
2445 'terminator': '!\n',
2446 }
2447 },
2448 },
2449 'root' : {
2450 'level' : 'WARNING',
2451 'handlers' : ['hand1'],
2452 },
2453 }
2454
Vinay Sajip3f885b52013-03-22 15:19:54 +00002455 out_of_order = {
2456 "version": 1,
2457 "formatters": {
2458 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002459 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2460 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002461 }
2462 },
2463 "handlers": {
2464 "fileGlobal": {
2465 "class": "logging.StreamHandler",
2466 "level": "DEBUG",
2467 "formatter": "mySimpleFormatter"
2468 },
2469 "bufferGlobal": {
2470 "class": "logging.handlers.MemoryHandler",
2471 "capacity": 5,
2472 "formatter": "mySimpleFormatter",
2473 "target": "fileGlobal",
2474 "level": "DEBUG"
2475 }
2476 },
2477 "loggers": {
2478 "mymodule": {
2479 "level": "DEBUG",
2480 "handlers": ["bufferGlobal"],
2481 "propagate": "true"
2482 }
2483 }
2484 }
2485
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002486 def apply_config(self, conf):
2487 logging.config.dictConfig(conf)
2488
2489 def test_config0_ok(self):
2490 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002491 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002492 self.apply_config(self.config0)
2493 logger = logging.getLogger()
2494 # Won't output anything
2495 logger.info(self.next_message())
2496 # Outputs a message
2497 logger.error(self.next_message())
2498 self.assert_log_lines([
2499 ('ERROR', '2'),
2500 ], stream=output)
2501 # Original logger output is empty.
2502 self.assert_log_lines([])
2503
2504 def test_config1_ok(self, config=config1):
2505 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002506 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002507 self.apply_config(config)
2508 logger = logging.getLogger("compiler.parser")
2509 # Both will output a message
2510 logger.info(self.next_message())
2511 logger.error(self.next_message())
2512 self.assert_log_lines([
2513 ('INFO', '1'),
2514 ('ERROR', '2'),
2515 ], stream=output)
2516 # Original logger output is empty.
2517 self.assert_log_lines([])
2518
2519 def test_config2_failure(self):
2520 # A simple config which overrides the default settings.
2521 self.assertRaises(Exception, self.apply_config, self.config2)
2522
2523 def test_config2a_failure(self):
2524 # A simple config which overrides the default settings.
2525 self.assertRaises(Exception, self.apply_config, self.config2a)
2526
2527 def test_config2b_failure(self):
2528 # A simple config which overrides the default settings.
2529 self.assertRaises(Exception, self.apply_config, self.config2b)
2530
2531 def test_config3_failure(self):
2532 # A simple config which overrides the default settings.
2533 self.assertRaises(Exception, self.apply_config, self.config3)
2534
2535 def test_config4_ok(self):
2536 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002537 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002538 self.apply_config(self.config4)
2539 #logger = logging.getLogger()
2540 try:
2541 raise RuntimeError()
2542 except RuntimeError:
2543 logging.exception("just testing")
2544 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002545 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002546 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2547 # Original logger output is empty
2548 self.assert_log_lines([])
2549
2550 def test_config4a_ok(self):
2551 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002552 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002553 self.apply_config(self.config4a)
2554 #logger = logging.getLogger()
2555 try:
2556 raise RuntimeError()
2557 except RuntimeError:
2558 logging.exception("just testing")
2559 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002560 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002561 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2562 # Original logger output is empty
2563 self.assert_log_lines([])
2564
2565 def test_config5_ok(self):
2566 self.test_config1_ok(config=self.config5)
2567
2568 def test_config6_failure(self):
2569 self.assertRaises(Exception, self.apply_config, self.config6)
2570
2571 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002572 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002573 self.apply_config(self.config1)
2574 logger = logging.getLogger("compiler.parser")
2575 # Both will output a message
2576 logger.info(self.next_message())
2577 logger.error(self.next_message())
2578 self.assert_log_lines([
2579 ('INFO', '1'),
2580 ('ERROR', '2'),
2581 ], stream=output)
2582 # Original logger output is empty.
2583 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002584 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002585 self.apply_config(self.config7)
2586 logger = logging.getLogger("compiler.parser")
2587 self.assertTrue(logger.disabled)
2588 logger = logging.getLogger("compiler.lexer")
2589 # Both will output a message
2590 logger.info(self.next_message())
2591 logger.error(self.next_message())
2592 self.assert_log_lines([
2593 ('INFO', '3'),
2594 ('ERROR', '4'),
2595 ], stream=output)
2596 # Original logger output is empty.
2597 self.assert_log_lines([])
2598
2599 #Same as test_config_7_ok but don't disable old loggers.
2600 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002601 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002602 self.apply_config(self.config1)
2603 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002604 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002605 logger.info(self.next_message())
2606 logger.error(self.next_message())
2607 self.assert_log_lines([
2608 ('INFO', '1'),
2609 ('ERROR', '2'),
2610 ], stream=output)
2611 # Original logger output is empty.
2612 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002613 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002614 self.apply_config(self.config8)
2615 logger = logging.getLogger("compiler.parser")
2616 self.assertFalse(logger.disabled)
2617 # Both will output a message
2618 logger.info(self.next_message())
2619 logger.error(self.next_message())
2620 logger = logging.getLogger("compiler.lexer")
2621 # Both will output a message
2622 logger.info(self.next_message())
2623 logger.error(self.next_message())
2624 self.assert_log_lines([
2625 ('INFO', '3'),
2626 ('ERROR', '4'),
2627 ('INFO', '5'),
2628 ('ERROR', '6'),
2629 ], stream=output)
2630 # Original logger output is empty.
2631 self.assert_log_lines([])
2632
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002633 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002634 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002635 self.apply_config(self.config1a)
2636 logger = logging.getLogger("compiler.parser")
2637 # See issue #11424. compiler-hyphenated sorts
2638 # between compiler and compiler.xyz and this
2639 # was preventing compiler.xyz from being included
2640 # in the child loggers of compiler because of an
2641 # overzealous loop termination condition.
2642 hyphenated = logging.getLogger('compiler-hyphenated')
2643 # All will output a message
2644 logger.info(self.next_message())
2645 logger.error(self.next_message())
2646 hyphenated.critical(self.next_message())
2647 self.assert_log_lines([
2648 ('INFO', '1'),
2649 ('ERROR', '2'),
2650 ('CRITICAL', '3'),
2651 ], stream=output)
2652 # Original logger output is empty.
2653 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002654 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002655 self.apply_config(self.config8a)
2656 logger = logging.getLogger("compiler.parser")
2657 self.assertFalse(logger.disabled)
2658 # Both will output a message
2659 logger.info(self.next_message())
2660 logger.error(self.next_message())
2661 logger = logging.getLogger("compiler.lexer")
2662 # Both will output a message
2663 logger.info(self.next_message())
2664 logger.error(self.next_message())
2665 # Will not appear
2666 hyphenated.critical(self.next_message())
2667 self.assert_log_lines([
2668 ('INFO', '4'),
2669 ('ERROR', '5'),
2670 ('INFO', '6'),
2671 ('ERROR', '7'),
2672 ], stream=output)
2673 # Original logger output is empty.
2674 self.assert_log_lines([])
2675
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002676 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002677 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 self.apply_config(self.config9)
2679 logger = logging.getLogger("compiler.parser")
2680 #Nothing will be output since both handler and logger are set to WARNING
2681 logger.info(self.next_message())
2682 self.assert_log_lines([], stream=output)
2683 self.apply_config(self.config9a)
2684 #Nothing will be output since both handler is still set to WARNING
2685 logger.info(self.next_message())
2686 self.assert_log_lines([], stream=output)
2687 self.apply_config(self.config9b)
2688 #Message should now be output
2689 logger.info(self.next_message())
2690 self.assert_log_lines([
2691 ('INFO', '3'),
2692 ], stream=output)
2693
2694 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002695 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002696 self.apply_config(self.config10)
2697 logger = logging.getLogger("compiler.parser")
2698 logger.warning(self.next_message())
2699 logger = logging.getLogger('compiler')
2700 #Not output, because filtered
2701 logger.warning(self.next_message())
2702 logger = logging.getLogger('compiler.lexer')
2703 #Not output, because filtered
2704 logger.warning(self.next_message())
2705 logger = logging.getLogger("compiler.parser.codegen")
2706 #Output, as not filtered
2707 logger.error(self.next_message())
2708 self.assert_log_lines([
2709 ('WARNING', '1'),
2710 ('ERROR', '4'),
2711 ], stream=output)
2712
2713 def test_config11_ok(self):
2714 self.test_config1_ok(self.config11)
2715
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002716 def test_config12_failure(self):
2717 self.assertRaises(Exception, self.apply_config, self.config12)
2718
2719 def test_config13_failure(self):
2720 self.assertRaises(Exception, self.apply_config, self.config13)
2721
Vinay Sajip8d270232012-11-15 14:20:18 +00002722 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002723 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002724 self.apply_config(self.config14)
2725 h = logging._handlers['hand1']
2726 self.assertEqual(h.foo, 'bar')
2727 self.assertEqual(h.terminator, '!\n')
2728 logging.warning('Exclamation')
2729 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2730
Victor Stinner45df8202010-04-28 22:31:17 +00002731 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002732 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002733 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002734 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002735 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002736 t.start()
2737 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002738 # Now get the port allocated
2739 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002740 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002741 try:
2742 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2743 sock.settimeout(2.0)
2744 sock.connect(('localhost', port))
2745
2746 slen = struct.pack('>L', len(text))
2747 s = slen + text
2748 sentsofar = 0
2749 left = len(s)
2750 while left > 0:
2751 sent = sock.send(s[sentsofar:])
2752 sentsofar += sent
2753 left -= sent
2754 sock.close()
2755 finally:
2756 t.ready.wait(2.0)
2757 logging.config.stopListening()
2758 t.join(2.0)
2759
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002760 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002761 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002762 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002763 self.setup_via_listener(json.dumps(self.config10))
2764 logger = logging.getLogger("compiler.parser")
2765 logger.warning(self.next_message())
2766 logger = logging.getLogger('compiler')
2767 #Not output, because filtered
2768 logger.warning(self.next_message())
2769 logger = logging.getLogger('compiler.lexer')
2770 #Not output, because filtered
2771 logger.warning(self.next_message())
2772 logger = logging.getLogger("compiler.parser.codegen")
2773 #Output, as not filtered
2774 logger.error(self.next_message())
2775 self.assert_log_lines([
2776 ('WARNING', '1'),
2777 ('ERROR', '4'),
2778 ], stream=output)
2779
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002780 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002781 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002782 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002783 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2784 logger = logging.getLogger("compiler.parser")
2785 # Both will output a message
2786 logger.info(self.next_message())
2787 logger.error(self.next_message())
2788 self.assert_log_lines([
2789 ('INFO', '1'),
2790 ('ERROR', '2'),
2791 ], stream=output)
2792 # Original logger output is empty.
2793 self.assert_log_lines([])
2794
Vinay Sajip4ded5512012-10-02 15:56:16 +01002795 @unittest.skipUnless(threading, 'Threading required for this test.')
2796 def test_listen_verify(self):
2797
2798 def verify_fail(stuff):
2799 return None
2800
2801 def verify_reverse(stuff):
2802 return stuff[::-1]
2803
2804 logger = logging.getLogger("compiler.parser")
2805 to_send = textwrap.dedent(ConfigFileTest.config1)
2806 # First, specify a verification function that will fail.
2807 # We expect to see no output, since our configuration
2808 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002809 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002810 self.setup_via_listener(to_send, verify_fail)
2811 # Both will output a message
2812 logger.info(self.next_message())
2813 logger.error(self.next_message())
2814 self.assert_log_lines([], stream=output)
2815 # Original logger output has the stuff we logged.
2816 self.assert_log_lines([
2817 ('INFO', '1'),
2818 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002819 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002820
2821 # Now, perform no verification. Our configuration
2822 # should take effect.
2823
Vinay Sajip1feedb42014-05-31 08:19:12 +01002824 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002825 self.setup_via_listener(to_send) # no verify callable specified
2826 logger = logging.getLogger("compiler.parser")
2827 # Both will output a message
2828 logger.info(self.next_message())
2829 logger.error(self.next_message())
2830 self.assert_log_lines([
2831 ('INFO', '3'),
2832 ('ERROR', '4'),
2833 ], stream=output)
2834 # Original logger output still has the stuff we logged before.
2835 self.assert_log_lines([
2836 ('INFO', '1'),
2837 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002838 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002839
2840 # Now, perform verification which transforms the bytes.
2841
Vinay Sajip1feedb42014-05-31 08:19:12 +01002842 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002843 self.setup_via_listener(to_send[::-1], verify_reverse)
2844 logger = logging.getLogger("compiler.parser")
2845 # Both will output a message
2846 logger.info(self.next_message())
2847 logger.error(self.next_message())
2848 self.assert_log_lines([
2849 ('INFO', '5'),
2850 ('ERROR', '6'),
2851 ], stream=output)
2852 # Original logger output still has the stuff we logged before.
2853 self.assert_log_lines([
2854 ('INFO', '1'),
2855 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002856 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002857
Vinay Sajip3f885b52013-03-22 15:19:54 +00002858 def test_out_of_order(self):
2859 self.apply_config(self.out_of_order)
2860 handler = logging.getLogger('mymodule').handlers[0]
2861 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002862 self.assertIsInstance(handler.formatter._style,
2863 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002864
Vinay Sajip373baef2011-04-26 20:05:24 +01002865 def test_baseconfig(self):
2866 d = {
2867 'atuple': (1, 2, 3),
2868 'alist': ['a', 'b', 'c'],
2869 'adict': {'d': 'e', 'f': 3 },
2870 'nest1': ('g', ('h', 'i'), 'j'),
2871 'nest2': ['k', ['l', 'm'], 'n'],
2872 'nest3': ['o', 'cfg://alist', 'p'],
2873 }
2874 bc = logging.config.BaseConfigurator(d)
2875 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2876 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2877 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2878 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2879 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2880 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2881 v = bc.convert('cfg://nest3')
2882 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2883 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2884 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2885 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002886
2887class ManagerTest(BaseTest):
2888 def test_manager_loggerclass(self):
2889 logged = []
2890
2891 class MyLogger(logging.Logger):
2892 def _log(self, level, msg, args, exc_info=None, extra=None):
2893 logged.append(msg)
2894
2895 man = logging.Manager(None)
2896 self.assertRaises(TypeError, man.setLoggerClass, int)
2897 man.setLoggerClass(MyLogger)
2898 logger = man.getLogger('test')
2899 logger.warning('should appear in logged')
2900 logging.warning('should not appear in logged')
2901
2902 self.assertEqual(logged, ['should appear in logged'])
2903
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002904 def test_set_log_record_factory(self):
2905 man = logging.Manager(None)
2906 expected = object()
2907 man.setLogRecordFactory(expected)
2908 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002909
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002910class ChildLoggerTest(BaseTest):
2911 def test_child_loggers(self):
2912 r = logging.getLogger()
2913 l1 = logging.getLogger('abc')
2914 l2 = logging.getLogger('def.ghi')
2915 c1 = r.getChild('xyz')
2916 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002917 self.assertIs(c1, logging.getLogger('xyz'))
2918 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002919 c1 = l1.getChild('def')
2920 c2 = c1.getChild('ghi')
2921 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002922 self.assertIs(c1, logging.getLogger('abc.def'))
2923 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2924 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002925
2926
Vinay Sajip6fac8172010-10-19 20:44:14 +00002927class DerivedLogRecord(logging.LogRecord):
2928 pass
2929
Vinay Sajip61561522010-12-03 11:50:38 +00002930class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002931
2932 def setUp(self):
2933 class CheckingFilter(logging.Filter):
2934 def __init__(self, cls):
2935 self.cls = cls
2936
2937 def filter(self, record):
2938 t = type(record)
2939 if t is not self.cls:
2940 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2941 self.cls)
2942 raise TypeError(msg)
2943 return True
2944
2945 BaseTest.setUp(self)
2946 self.filter = CheckingFilter(DerivedLogRecord)
2947 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002948 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002949
2950 def tearDown(self):
2951 self.root_logger.removeFilter(self.filter)
2952 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002953 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002954
2955 def test_logrecord_class(self):
2956 self.assertRaises(TypeError, self.root_logger.warning,
2957 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002958 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959 self.root_logger.error(self.next_message())
2960 self.assert_log_lines([
2961 ('root', 'ERROR', '2'),
2962 ])
2963
2964
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002965class QueueHandlerTest(BaseTest):
2966 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002967 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002968
2969 def setUp(self):
2970 BaseTest.setUp(self)
2971 self.queue = queue.Queue(-1)
2972 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2973 self.que_logger = logging.getLogger('que')
2974 self.que_logger.propagate = False
2975 self.que_logger.setLevel(logging.WARNING)
2976 self.que_logger.addHandler(self.que_hdlr)
2977
2978 def tearDown(self):
2979 self.que_hdlr.close()
2980 BaseTest.tearDown(self)
2981
2982 def test_queue_handler(self):
2983 self.que_logger.debug(self.next_message())
2984 self.assertRaises(queue.Empty, self.queue.get_nowait)
2985 self.que_logger.info(self.next_message())
2986 self.assertRaises(queue.Empty, self.queue.get_nowait)
2987 msg = self.next_message()
2988 self.que_logger.warning(msg)
2989 data = self.queue.get_nowait()
2990 self.assertTrue(isinstance(data, logging.LogRecord))
2991 self.assertEqual(data.name, self.que_logger.name)
2992 self.assertEqual((data.msg, data.args), (msg, None))
2993
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002994 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2995 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002996 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002997 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01002998 listener = logging.handlers.QueueListener(self.queue, handler)
2999 listener.start()
3000 try:
3001 self.que_logger.warning(self.next_message())
3002 self.que_logger.error(self.next_message())
3003 self.que_logger.critical(self.next_message())
3004 finally:
3005 listener.stop()
3006 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3007 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3008 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003009 handler.close()
3010
3011 # Now test with respect_handler_level set
3012
3013 handler = support.TestHandler(support.Matcher())
3014 handler.setLevel(logging.CRITICAL)
3015 listener = logging.handlers.QueueListener(self.queue, handler,
3016 respect_handler_level=True)
3017 listener.start()
3018 try:
3019 self.que_logger.warning(self.next_message())
3020 self.que_logger.error(self.next_message())
3021 self.que_logger.critical(self.next_message())
3022 finally:
3023 listener.stop()
3024 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3025 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3026 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3027
Vinay Sajipe723e962011-04-15 22:27:17 +01003028
Vinay Sajip37eb3382011-04-26 20:26:41 +01003029ZERO = datetime.timedelta(0)
3030
3031class UTC(datetime.tzinfo):
3032 def utcoffset(self, dt):
3033 return ZERO
3034
3035 dst = utcoffset
3036
3037 def tzname(self, dt):
3038 return 'UTC'
3039
3040utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003041
Vinay Sajipa39c5712010-10-25 13:57:39 +00003042class FormatterTest(unittest.TestCase):
3043 def setUp(self):
3044 self.common = {
3045 'name': 'formatter.test',
3046 'level': logging.DEBUG,
3047 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3048 'lineno': 42,
3049 'exc_info': None,
3050 'func': None,
3051 'msg': 'Message with %d %s',
3052 'args': (2, 'placeholders'),
3053 }
3054 self.variants = {
3055 }
3056
3057 def get_record(self, name=None):
3058 result = dict(self.common)
3059 if name is not None:
3060 result.update(self.variants[name])
3061 return logging.makeLogRecord(result)
3062
3063 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003064 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003065 r = self.get_record()
3066 f = logging.Formatter('${%(message)s}')
3067 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3068 f = logging.Formatter('%(random)s')
3069 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003070 self.assertFalse(f.usesTime())
3071 f = logging.Formatter('%(asctime)s')
3072 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003073 f = logging.Formatter('%(asctime)-15s')
3074 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003075 f = logging.Formatter('asctime')
3076 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003077
3078 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003079 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003080 r = self.get_record()
3081 f = logging.Formatter('$%{message}%$', style='{')
3082 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3083 f = logging.Formatter('{random}', style='{')
3084 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003085 self.assertFalse(f.usesTime())
3086 f = logging.Formatter('{asctime}', style='{')
3087 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003088 f = logging.Formatter('{asctime!s:15}', style='{')
3089 self.assertTrue(f.usesTime())
3090 f = logging.Formatter('{asctime:15}', style='{')
3091 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003092 f = logging.Formatter('asctime', style='{')
3093 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003094
3095 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003096 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003097 r = self.get_record()
3098 f = logging.Formatter('$message', style='$')
3099 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3100 f = logging.Formatter('$$%${message}%$$', style='$')
3101 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3102 f = logging.Formatter('${random}', style='$')
3103 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003104 self.assertFalse(f.usesTime())
3105 f = logging.Formatter('${asctime}', style='$')
3106 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003107 f = logging.Formatter('${asctime', style='$')
3108 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003109 f = logging.Formatter('$asctime', style='$')
3110 self.assertTrue(f.usesTime())
3111 f = logging.Formatter('asctime', style='$')
3112 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003113
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003114 def test_invalid_style(self):
3115 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3116
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003117 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003118 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003119 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3120 # We use None to indicate we want the local timezone
3121 # We're essentially converting a UTC time to local time
3122 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003123 r.msecs = 123
3124 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003125 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003126 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3127 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003128 f.format(r)
3129 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3130
3131class TestBufferingFormatter(logging.BufferingFormatter):
3132 def formatHeader(self, records):
3133 return '[(%d)' % len(records)
3134
3135 def formatFooter(self, records):
3136 return '(%d)]' % len(records)
3137
3138class BufferingFormatterTest(unittest.TestCase):
3139 def setUp(self):
3140 self.records = [
3141 logging.makeLogRecord({'msg': 'one'}),
3142 logging.makeLogRecord({'msg': 'two'}),
3143 ]
3144
3145 def test_default(self):
3146 f = logging.BufferingFormatter()
3147 self.assertEqual('', f.format([]))
3148 self.assertEqual('onetwo', f.format(self.records))
3149
3150 def test_custom(self):
3151 f = TestBufferingFormatter()
3152 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3153 lf = logging.Formatter('<%(message)s>')
3154 f = TestBufferingFormatter(lf)
3155 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003156
3157class ExceptionTest(BaseTest):
3158 def test_formatting(self):
3159 r = self.root_logger
3160 h = RecordingHandler()
3161 r.addHandler(h)
3162 try:
3163 raise RuntimeError('deliberate mistake')
3164 except:
3165 logging.exception('failed', stack_info=True)
3166 r.removeHandler(h)
3167 h.close()
3168 r = h.records[0]
3169 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3170 'call last):\n'))
3171 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3172 'deliberate mistake'))
3173 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3174 'call last):\n'))
3175 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3176 'stack_info=True)'))
3177
3178
Vinay Sajip5a27d402010-12-10 11:42:57 +00003179class LastResortTest(BaseTest):
3180 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003181 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003182 root = self.root_logger
3183 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003184 old_lastresort = logging.lastResort
3185 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003186
Vinay Sajip5a27d402010-12-10 11:42:57 +00003187 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003188 with support.captured_stderr() as stderr:
3189 root.debug('This should not appear')
3190 self.assertEqual(stderr.getvalue(), '')
3191 root.warning('Final chance!')
3192 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3193
3194 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003195 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003196 with support.captured_stderr() as stderr:
3197 root.warning('Final chance!')
3198 msg = 'No handlers could be found for logger "root"\n'
3199 self.assertEqual(stderr.getvalue(), msg)
3200
Vinay Sajip5a27d402010-12-10 11:42:57 +00003201 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003202 with support.captured_stderr() as stderr:
3203 root.warning('Final chance!')
3204 self.assertEqual(stderr.getvalue(), '')
3205
3206 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003207 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003208 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003209 with support.captured_stderr() as stderr:
3210 root.warning('Final chance!')
3211 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003212 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003213 root.addHandler(self.root_hdlr)
3214 logging.lastResort = old_lastresort
3215 logging.raiseExceptions = old_raise_exceptions
3216
3217
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003218class FakeHandler:
3219
3220 def __init__(self, identifier, called):
3221 for method in ('acquire', 'flush', 'close', 'release'):
3222 setattr(self, method, self.record_call(identifier, method, called))
3223
3224 def record_call(self, identifier, method_name, called):
3225 def inner():
3226 called.append('{} - {}'.format(identifier, method_name))
3227 return inner
3228
3229
3230class RecordingHandler(logging.NullHandler):
3231
3232 def __init__(self, *args, **kwargs):
3233 super(RecordingHandler, self).__init__(*args, **kwargs)
3234 self.records = []
3235
3236 def handle(self, record):
3237 """Keep track of all the emitted records."""
3238 self.records.append(record)
3239
3240
3241class ShutdownTest(BaseTest):
3242
Vinay Sajip5e66b162011-04-20 15:41:14 +01003243 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003244
3245 def setUp(self):
3246 super(ShutdownTest, self).setUp()
3247 self.called = []
3248
3249 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003250 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003251
3252 def raise_error(self, error):
3253 def inner():
3254 raise error()
3255 return inner
3256
3257 def test_no_failure(self):
3258 # create some fake handlers
3259 handler0 = FakeHandler(0, self.called)
3260 handler1 = FakeHandler(1, self.called)
3261 handler2 = FakeHandler(2, self.called)
3262
3263 # create live weakref to those handlers
3264 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3265
3266 logging.shutdown(handlerList=list(handlers))
3267
3268 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3269 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3270 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3271 self.assertEqual(expected, self.called)
3272
3273 def _test_with_failure_in_method(self, method, error):
3274 handler = FakeHandler(0, self.called)
3275 setattr(handler, method, self.raise_error(error))
3276 handlers = [logging.weakref.ref(handler)]
3277
3278 logging.shutdown(handlerList=list(handlers))
3279
3280 self.assertEqual('0 - release', self.called[-1])
3281
3282 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003283 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003284
3285 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003286 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003287
3288 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003289 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003290
3291 def test_with_valueerror_in_acquire(self):
3292 self._test_with_failure_in_method('acquire', ValueError)
3293
3294 def test_with_valueerror_in_flush(self):
3295 self._test_with_failure_in_method('flush', ValueError)
3296
3297 def test_with_valueerror_in_close(self):
3298 self._test_with_failure_in_method('close', ValueError)
3299
3300 def test_with_other_error_in_acquire_without_raise(self):
3301 logging.raiseExceptions = False
3302 self._test_with_failure_in_method('acquire', IndexError)
3303
3304 def test_with_other_error_in_flush_without_raise(self):
3305 logging.raiseExceptions = False
3306 self._test_with_failure_in_method('flush', IndexError)
3307
3308 def test_with_other_error_in_close_without_raise(self):
3309 logging.raiseExceptions = False
3310 self._test_with_failure_in_method('close', IndexError)
3311
3312 def test_with_other_error_in_acquire_with_raise(self):
3313 logging.raiseExceptions = True
3314 self.assertRaises(IndexError, self._test_with_failure_in_method,
3315 'acquire', IndexError)
3316
3317 def test_with_other_error_in_flush_with_raise(self):
3318 logging.raiseExceptions = True
3319 self.assertRaises(IndexError, self._test_with_failure_in_method,
3320 'flush', IndexError)
3321
3322 def test_with_other_error_in_close_with_raise(self):
3323 logging.raiseExceptions = True
3324 self.assertRaises(IndexError, self._test_with_failure_in_method,
3325 'close', IndexError)
3326
3327
3328class ModuleLevelMiscTest(BaseTest):
3329
Vinay Sajip5e66b162011-04-20 15:41:14 +01003330 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003331
3332 def test_disable(self):
3333 old_disable = logging.root.manager.disable
3334 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003335 self.assertEqual(old_disable, 0)
3336 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003337
3338 logging.disable(83)
3339 self.assertEqual(logging.root.manager.disable, 83)
3340
3341 def _test_log(self, method, level=None):
3342 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003343 support.patch(self, logging, 'basicConfig',
3344 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003345
3346 recording = RecordingHandler()
3347 logging.root.addHandler(recording)
3348
3349 log_method = getattr(logging, method)
3350 if level is not None:
3351 log_method(level, "test me: %r", recording)
3352 else:
3353 log_method("test me: %r", recording)
3354
3355 self.assertEqual(len(recording.records), 1)
3356 record = recording.records[0]
3357 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3358
3359 expected_level = level if level is not None else getattr(logging, method.upper())
3360 self.assertEqual(record.levelno, expected_level)
3361
3362 # basicConfig was not called!
3363 self.assertEqual(called, [])
3364
3365 def test_log(self):
3366 self._test_log('log', logging.ERROR)
3367
3368 def test_debug(self):
3369 self._test_log('debug')
3370
3371 def test_info(self):
3372 self._test_log('info')
3373
3374 def test_warning(self):
3375 self._test_log('warning')
3376
3377 def test_error(self):
3378 self._test_log('error')
3379
3380 def test_critical(self):
3381 self._test_log('critical')
3382
3383 def test_set_logger_class(self):
3384 self.assertRaises(TypeError, logging.setLoggerClass, object)
3385
3386 class MyLogger(logging.Logger):
3387 pass
3388
3389 logging.setLoggerClass(MyLogger)
3390 self.assertEqual(logging.getLoggerClass(), MyLogger)
3391
3392 logging.setLoggerClass(logging.Logger)
3393 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3394
Antoine Pitrou712cb732013-12-21 15:51:54 +01003395 def test_logging_at_shutdown(self):
3396 # Issue #20037
3397 code = """if 1:
3398 import logging
3399
3400 class A:
3401 def __del__(self):
3402 try:
3403 raise ValueError("some error")
3404 except Exception:
3405 logging.exception("exception in __del__")
3406
3407 a = A()"""
3408 rc, out, err = assert_python_ok("-c", code)
3409 err = err.decode()
3410 self.assertIn("exception in __del__", err)
3411 self.assertIn("ValueError: some error", err)
3412
3413
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003414class LogRecordTest(BaseTest):
3415 def test_str_rep(self):
3416 r = logging.makeLogRecord({})
3417 s = str(r)
3418 self.assertTrue(s.startswith('<LogRecord: '))
3419 self.assertTrue(s.endswith('>'))
3420
3421 def test_dict_arg(self):
3422 h = RecordingHandler()
3423 r = logging.getLogger()
3424 r.addHandler(h)
3425 d = {'less' : 'more' }
3426 logging.warning('less is %(less)s', d)
3427 self.assertIs(h.records[0].args, d)
3428 self.assertEqual(h.records[0].message, 'less is more')
3429 r.removeHandler(h)
3430 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003431
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003432 def test_multiprocessing(self):
3433 r = logging.makeLogRecord({})
3434 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003435 try:
3436 import multiprocessing as mp
3437 r = logging.makeLogRecord({})
3438 self.assertEqual(r.processName, mp.current_process().name)
3439 except ImportError:
3440 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003441
3442 def test_optional(self):
3443 r = logging.makeLogRecord({})
3444 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003445 if threading:
3446 NOT_NONE(r.thread)
3447 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003448 NOT_NONE(r.process)
3449 NOT_NONE(r.processName)
3450 log_threads = logging.logThreads
3451 log_processes = logging.logProcesses
3452 log_multiprocessing = logging.logMultiprocessing
3453 try:
3454 logging.logThreads = False
3455 logging.logProcesses = False
3456 logging.logMultiprocessing = False
3457 r = logging.makeLogRecord({})
3458 NONE = self.assertIsNone
3459 NONE(r.thread)
3460 NONE(r.threadName)
3461 NONE(r.process)
3462 NONE(r.processName)
3463 finally:
3464 logging.logThreads = log_threads
3465 logging.logProcesses = log_processes
3466 logging.logMultiprocessing = log_multiprocessing
3467
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003468class BasicConfigTest(unittest.TestCase):
3469
Vinay Sajip95bf5042011-04-20 11:50:56 +01003470 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003471
3472 def setUp(self):
3473 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003474 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003475 self.saved_handlers = logging._handlers.copy()
3476 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003477 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003478 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003479 logging.root.handlers = []
3480
3481 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003482 for h in logging.root.handlers[:]:
3483 logging.root.removeHandler(h)
3484 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003485 super(BasicConfigTest, self).tearDown()
3486
Vinay Sajip3def7e02011-04-20 10:58:06 +01003487 def cleanup(self):
3488 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003489 logging._handlers.clear()
3490 logging._handlers.update(self.saved_handlers)
3491 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003492 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003493
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494 def test_no_kwargs(self):
3495 logging.basicConfig()
3496
3497 # handler defaults to a StreamHandler to sys.stderr
3498 self.assertEqual(len(logging.root.handlers), 1)
3499 handler = logging.root.handlers[0]
3500 self.assertIsInstance(handler, logging.StreamHandler)
3501 self.assertEqual(handler.stream, sys.stderr)
3502
3503 formatter = handler.formatter
3504 # format defaults to logging.BASIC_FORMAT
3505 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3506 # datefmt defaults to None
3507 self.assertIsNone(formatter.datefmt)
3508 # style defaults to %
3509 self.assertIsInstance(formatter._style, logging.PercentStyle)
3510
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003511 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003512 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003513
Vinay Sajip1fd12022014-01-13 21:59:56 +00003514 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003515 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003516 logging.basicConfig(stream=sys.stdout, style="{")
3517 logging.error("Log an error")
3518 sys.stdout.seek(0)
3519 self.assertEqual(output.getvalue().strip(),
3520 "ERROR:root:Log an error")
3521
3522 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003523 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003524 logging.basicConfig(stream=sys.stdout, style="$")
3525 logging.error("Log an error")
3526 sys.stdout.seek(0)
3527 self.assertEqual(output.getvalue().strip(),
3528 "ERROR:root:Log an error")
3529
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003530 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003531
3532 def cleanup(h1, h2, fn):
3533 h1.close()
3534 h2.close()
3535 os.remove(fn)
3536
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003537 logging.basicConfig(filename='test.log')
3538
3539 self.assertEqual(len(logging.root.handlers), 1)
3540 handler = logging.root.handlers[0]
3541 self.assertIsInstance(handler, logging.FileHandler)
3542
3543 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003544 self.assertEqual(handler.stream.mode, expected.stream.mode)
3545 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003546 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547
3548 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003549
3550 def cleanup(h1, h2, fn):
3551 h1.close()
3552 h2.close()
3553 os.remove(fn)
3554
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003555 logging.basicConfig(filename='test.log', filemode='wb')
3556
3557 handler = logging.root.handlers[0]
3558 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003559 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003560 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561
3562 def test_stream(self):
3563 stream = io.StringIO()
3564 self.addCleanup(stream.close)
3565 logging.basicConfig(stream=stream)
3566
3567 self.assertEqual(len(logging.root.handlers), 1)
3568 handler = logging.root.handlers[0]
3569 self.assertIsInstance(handler, logging.StreamHandler)
3570 self.assertEqual(handler.stream, stream)
3571
3572 def test_format(self):
3573 logging.basicConfig(format='foo')
3574
3575 formatter = logging.root.handlers[0].formatter
3576 self.assertEqual(formatter._style._fmt, 'foo')
3577
3578 def test_datefmt(self):
3579 logging.basicConfig(datefmt='bar')
3580
3581 formatter = logging.root.handlers[0].formatter
3582 self.assertEqual(formatter.datefmt, 'bar')
3583
3584 def test_style(self):
3585 logging.basicConfig(style='$')
3586
3587 formatter = logging.root.handlers[0].formatter
3588 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3589
3590 def test_level(self):
3591 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003592 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003593
3594 logging.basicConfig(level=57)
3595 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003596 # Test that second call has no effect
3597 logging.basicConfig(level=58)
3598 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003599
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003600 def test_incompatible(self):
3601 assertRaises = self.assertRaises
3602 handlers = [logging.StreamHandler()]
3603 stream = sys.stderr
3604 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3605 stream=stream)
3606 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3607 handlers=handlers)
3608 assertRaises(ValueError, logging.basicConfig, stream=stream,
3609 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003610 # Issue 23207: test for invalid kwargs
3611 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3612 # Should pop both filename and filemode even if filename is None
3613 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003614
3615 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003616 handlers = [
3617 logging.StreamHandler(),
3618 logging.StreamHandler(sys.stdout),
3619 logging.StreamHandler(),
3620 ]
3621 f = logging.Formatter()
3622 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003623 logging.basicConfig(handlers=handlers)
3624 self.assertIs(handlers[0], logging.root.handlers[0])
3625 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003626 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003627 self.assertIsNotNone(handlers[0].formatter)
3628 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003629 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003630 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3631
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003632 def _test_log(self, method, level=None):
3633 # logging.root has no handlers so basicConfig should be called
3634 called = []
3635
3636 old_basic_config = logging.basicConfig
3637 def my_basic_config(*a, **kw):
3638 old_basic_config()
3639 old_level = logging.root.level
3640 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003641 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003642 called.append((a, kw))
3643
Vinay Sajip1feedb42014-05-31 08:19:12 +01003644 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003645
3646 log_method = getattr(logging, method)
3647 if level is not None:
3648 log_method(level, "test me")
3649 else:
3650 log_method("test me")
3651
3652 # basicConfig was called with no arguments
3653 self.assertEqual(called, [((), {})])
3654
3655 def test_log(self):
3656 self._test_log('log', logging.WARNING)
3657
3658 def test_debug(self):
3659 self._test_log('debug')
3660
3661 def test_info(self):
3662 self._test_log('info')
3663
3664 def test_warning(self):
3665 self._test_log('warning')
3666
3667 def test_error(self):
3668 self._test_log('error')
3669
3670 def test_critical(self):
3671 self._test_log('critical')
3672
3673
3674class LoggerAdapterTest(unittest.TestCase):
3675
3676 def setUp(self):
3677 super(LoggerAdapterTest, self).setUp()
3678 old_handler_list = logging._handlerList[:]
3679
3680 self.recording = RecordingHandler()
3681 self.logger = logging.root
3682 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003683 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003684 self.addCleanup(self.recording.close)
3685
3686 def cleanup():
3687 logging._handlerList[:] = old_handler_list
3688
3689 self.addCleanup(cleanup)
3690 self.addCleanup(logging.shutdown)
3691 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3692
3693 def test_exception(self):
3694 msg = 'testing exception: %r'
3695 exc = None
3696 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003697 1 / 0
3698 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003699 exc = e
3700 self.adapter.exception(msg, self.recording)
3701
3702 self.assertEqual(len(self.recording.records), 1)
3703 record = self.recording.records[0]
3704 self.assertEqual(record.levelno, logging.ERROR)
3705 self.assertEqual(record.msg, msg)
3706 self.assertEqual(record.args, (self.recording,))
3707 self.assertEqual(record.exc_info,
3708 (exc.__class__, exc, exc.__traceback__))
3709
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003710 def test_exception_excinfo(self):
3711 try:
3712 1 / 0
3713 except ZeroDivisionError as e:
3714 exc = e
3715
3716 self.adapter.exception('exc_info test', exc_info=exc)
3717
3718 self.assertEqual(len(self.recording.records), 1)
3719 record = self.recording.records[0]
3720 self.assertEqual(record.exc_info,
3721 (exc.__class__, exc, exc.__traceback__))
3722
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003723 def test_critical(self):
3724 msg = 'critical test! %r'
3725 self.adapter.critical(msg, self.recording)
3726
3727 self.assertEqual(len(self.recording.records), 1)
3728 record = self.recording.records[0]
3729 self.assertEqual(record.levelno, logging.CRITICAL)
3730 self.assertEqual(record.msg, msg)
3731 self.assertEqual(record.args, (self.recording,))
3732
3733 def test_is_enabled_for(self):
3734 old_disable = self.adapter.logger.manager.disable
3735 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003736 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3737 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003738 self.assertFalse(self.adapter.isEnabledFor(32))
3739
3740 def test_has_handlers(self):
3741 self.assertTrue(self.adapter.hasHandlers())
3742
3743 for handler in self.logger.handlers:
3744 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003745
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003746 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003747 self.assertFalse(self.adapter.hasHandlers())
3748
3749
3750class LoggerTest(BaseTest):
3751
3752 def setUp(self):
3753 super(LoggerTest, self).setUp()
3754 self.recording = RecordingHandler()
3755 self.logger = logging.Logger(name='blah')
3756 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003757 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003758 self.addCleanup(self.recording.close)
3759 self.addCleanup(logging.shutdown)
3760
3761 def test_set_invalid_level(self):
3762 self.assertRaises(TypeError, self.logger.setLevel, object())
3763
3764 def test_exception(self):
3765 msg = 'testing exception: %r'
3766 exc = None
3767 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003768 1 / 0
3769 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003770 exc = e
3771 self.logger.exception(msg, self.recording)
3772
3773 self.assertEqual(len(self.recording.records), 1)
3774 record = self.recording.records[0]
3775 self.assertEqual(record.levelno, logging.ERROR)
3776 self.assertEqual(record.msg, msg)
3777 self.assertEqual(record.args, (self.recording,))
3778 self.assertEqual(record.exc_info,
3779 (exc.__class__, exc, exc.__traceback__))
3780
3781 def test_log_invalid_level_with_raise(self):
3782 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003783 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003784
3785 logging.raiseExceptions = True
3786 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3787
3788 def test_log_invalid_level_no_raise(self):
3789 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003790 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003791
3792 logging.raiseExceptions = False
3793 self.logger.log('10', 'test message') # no exception happens
3794
3795 def test_find_caller_with_stack_info(self):
3796 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003797 support.patch(self, logging.traceback, 'print_stack',
3798 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003799
3800 self.logger.findCaller(stack_info=True)
3801
3802 self.assertEqual(len(called), 1)
3803 self.assertEqual('Stack (most recent call last):\n', called[0])
3804
3805 def test_make_record_with_extra_overwrite(self):
3806 name = 'my record'
3807 level = 13
3808 fn = lno = msg = args = exc_info = func = sinfo = None
3809 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3810 exc_info, func, sinfo)
3811
3812 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3813 extra = {key: 'some value'}
3814 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3815 fn, lno, msg, args, exc_info,
3816 extra=extra, sinfo=sinfo)
3817
3818 def test_make_record_with_extra_no_overwrite(self):
3819 name = 'my record'
3820 level = 13
3821 fn = lno = msg = args = exc_info = func = sinfo = None
3822 extra = {'valid_key': 'some value'}
3823 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3824 exc_info, extra=extra, sinfo=sinfo)
3825 self.assertIn('valid_key', result.__dict__)
3826
3827 def test_has_handlers(self):
3828 self.assertTrue(self.logger.hasHandlers())
3829
3830 for handler in self.logger.handlers:
3831 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003832 self.assertFalse(self.logger.hasHandlers())
3833
3834 def test_has_handlers_no_propagate(self):
3835 child_logger = logging.getLogger('blah.child')
3836 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003837 self.assertFalse(child_logger.hasHandlers())
3838
3839 def test_is_enabled_for(self):
3840 old_disable = self.logger.manager.disable
3841 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003842 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003843 self.assertFalse(self.logger.isEnabledFor(22))
3844
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003845 def test_root_logger_aliases(self):
3846 root = logging.getLogger()
3847 self.assertIs(root, logging.root)
3848 self.assertIs(root, logging.getLogger(None))
3849 self.assertIs(root, logging.getLogger(''))
3850 self.assertIs(root, logging.getLogger('foo').root)
3851 self.assertIs(root, logging.getLogger('foo.bar').root)
3852 self.assertIs(root, logging.getLogger('foo').parent)
3853
3854 self.assertIsNot(root, logging.getLogger('\0'))
3855 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3856
3857 def test_invalid_names(self):
3858 self.assertRaises(TypeError, logging.getLogger, any)
3859 self.assertRaises(TypeError, logging.getLogger, b'foo')
3860
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003861
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003862class BaseFileTest(BaseTest):
3863 "Base class for handler tests that write log files"
3864
3865 def setUp(self):
3866 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003867 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3868 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003869 self.rmfiles = []
3870
3871 def tearDown(self):
3872 for fn in self.rmfiles:
3873 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003874 if os.path.exists(self.fn):
3875 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003876 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003877
3878 def assertLogFile(self, filename):
3879 "Assert a log file is there and register it for deletion"
3880 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003881 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003882 self.rmfiles.append(filename)
3883
3884
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003885class FileHandlerTest(BaseFileTest):
3886 def test_delay(self):
3887 os.unlink(self.fn)
3888 fh = logging.FileHandler(self.fn, delay=True)
3889 self.assertIsNone(fh.stream)
3890 self.assertFalse(os.path.exists(self.fn))
3891 fh.handle(logging.makeLogRecord({}))
3892 self.assertIsNotNone(fh.stream)
3893 self.assertTrue(os.path.exists(self.fn))
3894 fh.close()
3895
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003896class RotatingFileHandlerTest(BaseFileTest):
3897 def next_rec(self):
3898 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3899 self.next_message(), None, None, None)
3900
3901 def test_should_not_rollover(self):
3902 # If maxbytes is zero rollover never occurs
3903 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3904 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003905 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003906
3907 def test_should_rollover(self):
3908 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3909 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003910 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003911
3912 def test_file_created(self):
3913 # checks that the file is created and assumes it was created
3914 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003915 rh = logging.handlers.RotatingFileHandler(self.fn)
3916 rh.emit(self.next_rec())
3917 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003918 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003919
3920 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003921 def namer(name):
3922 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003923 rh = logging.handlers.RotatingFileHandler(
3924 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003925 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003926 rh.emit(self.next_rec())
3927 self.assertLogFile(self.fn)
3928 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003929 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003930 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003931 self.assertLogFile(namer(self.fn + ".2"))
3932 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3933 rh.close()
3934
Vinay Sajip1feedb42014-05-31 08:19:12 +01003935 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003936 def test_rotator(self):
3937 def namer(name):
3938 return name + ".gz"
3939
3940 def rotator(source, dest):
3941 with open(source, "rb") as sf:
3942 data = sf.read()
3943 compressed = zlib.compress(data, 9)
3944 with open(dest, "wb") as df:
3945 df.write(compressed)
3946 os.remove(source)
3947
3948 rh = logging.handlers.RotatingFileHandler(
3949 self.fn, backupCount=2, maxBytes=1)
3950 rh.rotator = rotator
3951 rh.namer = namer
3952 m1 = self.next_rec()
3953 rh.emit(m1)
3954 self.assertLogFile(self.fn)
3955 m2 = self.next_rec()
3956 rh.emit(m2)
3957 fn = namer(self.fn + ".1")
3958 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003959 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003960 with open(fn, "rb") as f:
3961 compressed = f.read()
3962 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003963 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003964 rh.emit(self.next_rec())
3965 fn = namer(self.fn + ".2")
3966 self.assertLogFile(fn)
3967 with open(fn, "rb") as f:
3968 compressed = f.read()
3969 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003970 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003971 rh.emit(self.next_rec())
3972 fn = namer(self.fn + ".2")
3973 with open(fn, "rb") as f:
3974 compressed = f.read()
3975 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003976 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003977 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003978 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003979
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003980class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003981 # other test methods added below
3982 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003983 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3984 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003985 fmt = logging.Formatter('%(asctime)s %(message)s')
3986 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003987 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003988 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003989 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003990 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003991 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003992 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003993 fh.close()
3994 # At this point, we should have a recent rotated file which we
3995 # can test for the existence of. However, in practice, on some
3996 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003997 # in time to go to look for the log file. So, we go back a fair
3998 # bit, and stop as soon as we see a rotated file. In theory this
3999 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004000 found = False
4001 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004002 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004003 for secs in range(GO_BACK):
4004 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004005 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4006 found = os.path.exists(fn)
4007 if found:
4008 self.rmfiles.append(fn)
4009 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004010 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4011 if not found:
4012 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004013 dn, fn = os.path.split(self.fn)
4014 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004015 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4016 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004017 for f in files:
4018 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004019 path = os.path.join(dn, f)
4020 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004021 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004022 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004023
Vinay Sajip0372e102011-05-05 12:59:14 +01004024 def test_invalid(self):
4025 assertRaises = self.assertRaises
4026 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004027 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004028 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004029 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004030 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004031 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004032
Vinay Sajipa7130792013-04-12 17:04:23 +01004033 def test_compute_rollover_daily_attime(self):
4034 currentTime = 0
4035 atTime = datetime.time(12, 0, 0)
4036 rh = logging.handlers.TimedRotatingFileHandler(
4037 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4038 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004039 try:
4040 actual = rh.computeRollover(currentTime)
4041 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004042
Vinay Sajipd86ac962013-04-14 12:20:46 +01004043 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4044 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4045 finally:
4046 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004047
Vinay Sajip10e8c492013-05-18 10:19:54 -07004048 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004049 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004050 currentTime = int(time.time())
4051 today = currentTime - currentTime % 86400
4052
Vinay Sajipa7130792013-04-12 17:04:23 +01004053 atTime = datetime.time(12, 0, 0)
4054
Vinay Sajip10e8c492013-05-18 10:19:54 -07004055 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004056 for day in range(7):
4057 rh = logging.handlers.TimedRotatingFileHandler(
4058 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4059 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004060 try:
4061 if wday > day:
4062 # The rollover day has already passed this week, so we
4063 # go over into next week
4064 expected = (7 - wday + day)
4065 else:
4066 expected = (day - wday)
4067 # At this point expected is in days from now, convert to seconds
4068 expected *= 24 * 60 * 60
4069 # Add in the rollover time
4070 expected += 12 * 60 * 60
4071 # Add in adjustment for today
4072 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004073 actual = rh.computeRollover(today)
4074 if actual != expected:
4075 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004076 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004077 self.assertEqual(actual, expected)
4078 if day == wday:
4079 # goes into following week
4080 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004081 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004082 if actual != expected:
4083 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004084 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004085 self.assertEqual(actual, expected)
4086 finally:
4087 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004088
4089
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004090def secs(**kw):
4091 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4092
4093for when, exp in (('S', 1),
4094 ('M', 60),
4095 ('H', 60 * 60),
4096 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004097 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004098 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004099 ('W0', secs(days=4, hours=24)),
4100 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004101 def test_compute_rollover(self, when=when, exp=exp):
4102 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004103 self.fn, when=when, interval=1, backupCount=0, utc=True)
4104 currentTime = 0.0
4105 actual = rh.computeRollover(currentTime)
4106 if exp != actual:
4107 # Failures occur on some systems for MIDNIGHT and W0.
4108 # Print detailed calculation for MIDNIGHT so we can try to see
4109 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004110 if when == 'MIDNIGHT':
4111 try:
4112 if rh.utc:
4113 t = time.gmtime(currentTime)
4114 else:
4115 t = time.localtime(currentTime)
4116 currentHour = t[3]
4117 currentMinute = t[4]
4118 currentSecond = t[5]
4119 # r is the number of seconds left between now and midnight
4120 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4121 currentMinute) * 60 +
4122 currentSecond)
4123 result = currentTime + r
4124 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4125 print('currentHour: %s' % currentHour, file=sys.stderr)
4126 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4127 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4128 print('r: %s' % r, file=sys.stderr)
4129 print('result: %s' % result, file=sys.stderr)
4130 except Exception:
4131 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4132 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004133 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004134 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4135
Vinay Sajip60ccd822011-05-09 17:32:09 +01004136
4137@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4138class NTEventLogHandlerTest(BaseTest):
4139 def test_basic(self):
4140 logtype = 'Application'
4141 elh = win32evtlog.OpenEventLog(None, logtype)
4142 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4143 h = logging.handlers.NTEventLogHandler('test_logging')
4144 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4145 h.handle(r)
4146 h.close()
4147 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004148 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004149 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4150 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4151 found = False
4152 GO_BACK = 100
4153 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4154 for e in events:
4155 if e.SourceName != 'test_logging':
4156 continue
4157 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4158 if msg != 'Test Log Message\r\n':
4159 continue
4160 found = True
4161 break
4162 msg = 'Record not found in event log, went back %d records' % GO_BACK
4163 self.assertTrue(found, msg=msg)
4164
Christian Heimes180510d2008-03-03 19:15:45 +00004165# Set the locale to the platform-dependent default. I have no idea
4166# why the test does this, but in any case we save the current locale
4167# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004168@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004169def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004170 support.run_unittest(
4171 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4172 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4173 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4174 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4175 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4176 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4177 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4178 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4179 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4180 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
4181 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004182
Christian Heimes180510d2008-03-03 19:15:45 +00004183if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004184 test_main()