blob: 52412d1217862c759a022130e321e0d87f0c4975 [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
310
311class BasicFilterTest(BaseTest):
312
313 """Test the bundled Filter class."""
314
315 def test_filter(self):
316 # Only messages satisfying the specified criteria pass through the
317 # filter.
318 filter_ = logging.Filter("spam.eggs")
319 handler = self.root_logger.handlers[0]
320 try:
321 handler.addFilter(filter_)
322 spam = logging.getLogger("spam")
323 spam_eggs = logging.getLogger("spam.eggs")
324 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
325 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
326
327 spam.info(self.next_message())
328 spam_eggs.info(self.next_message()) # Good.
329 spam_eggs_fish.info(self.next_message()) # Good.
330 spam_bakedbeans.info(self.next_message())
331
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000332 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000333 ('spam.eggs', 'INFO', '2'),
334 ('spam.eggs.fish', 'INFO', '3'),
335 ])
336 finally:
337 handler.removeFilter(filter_)
338
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000339 def test_callable_filter(self):
340 # Only messages satisfying the specified criteria pass through the
341 # filter.
342
343 def filterfunc(record):
344 parts = record.name.split('.')
345 prefix = '.'.join(parts[:2])
346 return prefix == 'spam.eggs'
347
348 handler = self.root_logger.handlers[0]
349 try:
350 handler.addFilter(filterfunc)
351 spam = logging.getLogger("spam")
352 spam_eggs = logging.getLogger("spam.eggs")
353 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
354 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
355
356 spam.info(self.next_message())
357 spam_eggs.info(self.next_message()) # Good.
358 spam_eggs_fish.info(self.next_message()) # Good.
359 spam_bakedbeans.info(self.next_message())
360
361 self.assert_log_lines([
362 ('spam.eggs', 'INFO', '2'),
363 ('spam.eggs.fish', 'INFO', '3'),
364 ])
365 finally:
366 handler.removeFilter(filterfunc)
367
Vinay Sajip985ef872011-04-26 19:34:04 +0100368 def test_empty_filter(self):
369 f = logging.Filter()
370 r = logging.makeLogRecord({'name': 'spam.eggs'})
371 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000372
373#
374# First, we define our levels. There can be as many as you want - the only
375# limitations are that they should be integers, the lowest should be > 0 and
376# larger values mean less information being logged. If you need specific
377# level values which do not fit into these limitations, you can use a
378# mapping dictionary to convert between your application levels and the
379# logging system.
380#
381SILENT = 120
382TACITURN = 119
383TERSE = 118
384EFFUSIVE = 117
385SOCIABLE = 116
386VERBOSE = 115
387TALKATIVE = 114
388GARRULOUS = 113
389CHATTERBOX = 112
390BORING = 111
391
392LEVEL_RANGE = range(BORING, SILENT + 1)
393
394#
395# Next, we define names for our levels. You don't need to do this - in which
396# case the system will use "Level n" to denote the text for the level.
397#
398my_logging_levels = {
399 SILENT : 'Silent',
400 TACITURN : 'Taciturn',
401 TERSE : 'Terse',
402 EFFUSIVE : 'Effusive',
403 SOCIABLE : 'Sociable',
404 VERBOSE : 'Verbose',
405 TALKATIVE : 'Talkative',
406 GARRULOUS : 'Garrulous',
407 CHATTERBOX : 'Chatterbox',
408 BORING : 'Boring',
409}
410
411class GarrulousFilter(logging.Filter):
412
413 """A filter which blocks garrulous messages."""
414
415 def filter(self, record):
416 return record.levelno != GARRULOUS
417
418class VerySpecificFilter(logging.Filter):
419
420 """A filter which blocks sociable and taciturn messages."""
421
422 def filter(self, record):
423 return record.levelno not in [SOCIABLE, TACITURN]
424
425
426class CustomLevelsAndFiltersTest(BaseTest):
427
428 """Test various filtering possibilities with custom logging levels."""
429
430 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300431 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000432
433 def setUp(self):
434 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000435 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000436 logging.addLevelName(k, v)
437
438 def log_at_all_levels(self, logger):
439 for lvl in LEVEL_RANGE:
440 logger.log(lvl, self.next_message())
441
442 def test_logger_filter(self):
443 # Filter at logger level.
444 self.root_logger.setLevel(VERBOSE)
445 # Levels >= 'Verbose' are good.
446 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000447 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000448 ('Verbose', '5'),
449 ('Sociable', '6'),
450 ('Effusive', '7'),
451 ('Terse', '8'),
452 ('Taciturn', '9'),
453 ('Silent', '10'),
454 ])
455
456 def test_handler_filter(self):
457 # Filter at handler level.
458 self.root_logger.handlers[0].setLevel(SOCIABLE)
459 try:
460 # Levels >= 'Sociable' are good.
461 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000462 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000463 ('Sociable', '6'),
464 ('Effusive', '7'),
465 ('Terse', '8'),
466 ('Taciturn', '9'),
467 ('Silent', '10'),
468 ])
469 finally:
470 self.root_logger.handlers[0].setLevel(logging.NOTSET)
471
472 def test_specific_filters(self):
473 # Set a specific filter object on the handler, and then add another
474 # filter object on the logger itself.
475 handler = self.root_logger.handlers[0]
476 specific_filter = None
477 garr = GarrulousFilter()
478 handler.addFilter(garr)
479 try:
480 self.log_at_all_levels(self.root_logger)
481 first_lines = [
482 # Notice how 'Garrulous' is missing
483 ('Boring', '1'),
484 ('Chatterbox', '2'),
485 ('Talkative', '4'),
486 ('Verbose', '5'),
487 ('Sociable', '6'),
488 ('Effusive', '7'),
489 ('Terse', '8'),
490 ('Taciturn', '9'),
491 ('Silent', '10'),
492 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000493 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000494
495 specific_filter = VerySpecificFilter()
496 self.root_logger.addFilter(specific_filter)
497 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000498 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000499 # Not only 'Garrulous' is still missing, but also 'Sociable'
500 # and 'Taciturn'
501 ('Boring', '11'),
502 ('Chatterbox', '12'),
503 ('Talkative', '14'),
504 ('Verbose', '15'),
505 ('Effusive', '17'),
506 ('Terse', '18'),
507 ('Silent', '20'),
508 ])
509 finally:
510 if specific_filter:
511 self.root_logger.removeFilter(specific_filter)
512 handler.removeFilter(garr)
513
514
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100515class HandlerTest(BaseTest):
516 def test_name(self):
517 h = logging.Handler()
518 h.name = 'generic'
519 self.assertEqual(h.name, 'generic')
520 h.name = 'anothergeneric'
521 self.assertEqual(h.name, 'anothergeneric')
522 self.assertRaises(NotImplementedError, h.emit, None)
523
Vinay Sajip5a35b062011-04-27 11:31:14 +0100524 def test_builtin_handlers(self):
525 # We can't actually *use* too many handlers in the tests,
526 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200527 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100528 for existing in (True, False):
529 fd, fn = tempfile.mkstemp()
530 os.close(fd)
531 if not existing:
532 os.unlink(fn)
533 h = logging.handlers.WatchedFileHandler(fn, delay=True)
534 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100535 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100536 self.assertEqual(dev, -1)
537 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100538 r = logging.makeLogRecord({'msg': 'Test'})
539 h.handle(r)
540 # Now remove the file.
541 os.unlink(fn)
542 self.assertFalse(os.path.exists(fn))
543 # The next call should recreate the file.
544 h.handle(r)
545 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100546 else:
547 self.assertEqual(h.dev, -1)
548 self.assertEqual(h.ino, -1)
549 h.close()
550 if existing:
551 os.unlink(fn)
552 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100553 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100554 else:
555 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100556 try:
557 h = logging.handlers.SysLogHandler(sockname)
558 self.assertEqual(h.facility, h.LOG_USER)
559 self.assertTrue(h.unixsocket)
560 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200561 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100562 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100563 for method in ('GET', 'POST', 'PUT'):
564 if method == 'PUT':
565 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
566 'localhost', '/log', method)
567 else:
568 h = logging.handlers.HTTPHandler('localhost', '/log', method)
569 h.close()
570 h = logging.handlers.BufferingHandler(0)
571 r = logging.makeLogRecord({})
572 self.assertTrue(h.shouldFlush(r))
573 h.close()
574 h = logging.handlers.BufferingHandler(1)
575 self.assertFalse(h.shouldFlush(r))
576 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100577
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100578 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100579 @unittest.skipUnless(threading, 'Threading required for this test.')
580 def test_race(self):
581 # Issue #14632 refers.
582 def remove_loop(fname, tries):
583 for _ in range(tries):
584 try:
585 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000586 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100587 except OSError:
588 pass
589 time.sleep(0.004 * random.randint(0, 4))
590
Vinay Sajipc94871a2012-04-25 10:51:35 +0100591 del_count = 500
592 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100593
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000594 self.handle_time = None
595 self.deletion_time = None
596
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100598 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
599 os.close(fd)
600 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
601 remover.daemon = True
602 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100604 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
605 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100606 try:
607 for _ in range(log_count):
608 time.sleep(0.005)
609 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000610 try:
611 self.handle_time = time.time()
612 h.handle(r)
613 except Exception:
614 print('Deleted at %s, '
615 'opened at %s' % (self.deletion_time,
616 self.handle_time))
617 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100618 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100619 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100620 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100621 if os.path.exists(fn):
622 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623
624
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100625class BadStream(object):
626 def write(self, data):
627 raise RuntimeError('deliberate mistake')
628
629class TestStreamHandler(logging.StreamHandler):
630 def handleError(self, record):
631 self.error_record = record
632
633class StreamHandlerTest(BaseTest):
634 def test_error_handling(self):
635 h = TestStreamHandler(BadStream())
636 r = logging.makeLogRecord({})
637 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100638
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100639 try:
640 h.handle(r)
641 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100642
Vinay Sajip985ef872011-04-26 19:34:04 +0100643 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100644 with support.captured_stderr() as stderr:
645 h.handle(r)
646 msg = '\nRuntimeError: deliberate mistake\n'
647 self.assertIn(msg, stderr.getvalue())
648
Vinay Sajip985ef872011-04-26 19:34:04 +0100649 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100650 with support.captured_stderr() as stderr:
651 h.handle(r)
652 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100653 finally:
654 logging.raiseExceptions = old_raise
655
Vinay Sajip7367d082011-05-02 13:17:27 +0100656# -- The following section could be moved into a server_helper.py module
657# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100658
Vinay Sajipce7c9782011-05-17 07:15:53 +0100659if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100660 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100661 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100662 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100663
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 :param addr: A (host, port) tuple which the server listens on.
665 You can specify a port value of zero: the server's
666 *port* attribute will hold the actual port number
667 used, which can be used in client connections.
668 :param handler: A callable which will be called to process
669 incoming messages. The handler will be passed
670 the client address tuple, who the message is from,
671 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100672 :param poll_interval: The interval, in seconds, used in the underlying
673 :func:`select` or :func:`poll` call by
674 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100675 :param sockmap: A dictionary which will be used to hold
676 :class:`asyncore.dispatcher` instances used by
677 :func:`asyncore.loop`. This avoids changing the
678 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100679 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100680
681 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400682 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
683 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100684 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100685 self._handler = handler
686 self._thread = None
687 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100688
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 def process_message(self, peer, mailfrom, rcpttos, data):
690 """
691 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 Typically, this will be a test case method.
694 :param peer: The client (host, port) tuple.
695 :param mailfrom: The address of the sender.
696 :param rcpttos: The addresses of the recipients.
697 :param data: The message.
698 """
699 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701 def start(self):
702 """
703 Start the server running on a separate daemon thread.
704 """
705 self._thread = t = threading.Thread(target=self.serve_forever,
706 args=(self.poll_interval,))
707 t.setDaemon(True)
708 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100709
Vinay Sajipce7c9782011-05-17 07:15:53 +0100710 def serve_forever(self, poll_interval):
711 """
712 Run the :mod:`asyncore` loop until normal termination
713 conditions arise.
714 :param poll_interval: The interval, in seconds, used in the underlying
715 :func:`select` or :func:`poll` call by
716 :func:`asyncore.loop`.
717 """
718 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100719 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200720 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 # On FreeBSD 8, closing the server repeatably
722 # raises this error. We swallow it if the
723 # server has been closed.
724 if self.connected or self.accepting:
725 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100726
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 def stop(self, timeout=None):
728 """
729 Stop the thread by closing the server instance.
730 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100731
Vinay Sajipce7c9782011-05-17 07:15:53 +0100732 :param timeout: How long to wait for the server thread
733 to terminate.
734 """
735 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100736 self._thread.join(timeout)
737 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100738
Vinay Sajipce7c9782011-05-17 07:15:53 +0100739 class ControlMixin(object):
740 """
741 This mixin is used to start a server on a separate thread, and
742 shut it down programmatically. Request handling is simplified - instead
743 of needing to derive a suitable RequestHandler subclass, you just
744 provide a callable which will be passed each received request to be
745 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100746
Vinay Sajipce7c9782011-05-17 07:15:53 +0100747 :param handler: A handler callable which will be called with a
748 single parameter - the request - in order to
749 process the request. This handler is called on the
750 server thread, effectively meaning that requests are
751 processed serially. While not quite Web scale ;-),
752 this should be fine for testing applications.
753 :param poll_interval: The polling interval in seconds.
754 """
755 def __init__(self, handler, poll_interval):
756 self._thread = None
757 self.poll_interval = poll_interval
758 self._handler = handler
759 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100760
Vinay Sajipce7c9782011-05-17 07:15:53 +0100761 def start(self):
762 """
763 Create a daemon thread to run the server, and start it.
764 """
765 self._thread = t = threading.Thread(target=self.serve_forever,
766 args=(self.poll_interval,))
767 t.setDaemon(True)
768 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def serve_forever(self, poll_interval):
771 """
772 Run the server. Set the ready flag before entering the
773 service loop.
774 """
775 self.ready.set()
776 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100777
Vinay Sajipce7c9782011-05-17 07:15:53 +0100778 def stop(self, timeout=None):
779 """
780 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 :param timeout: How long to wait for the server thread
783 to terminate.
784 """
785 self.shutdown()
786 if self._thread is not None:
787 self._thread.join(timeout)
788 self._thread = None
789 self.server_close()
790 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100791
Vinay Sajipce7c9782011-05-17 07:15:53 +0100792 class TestHTTPServer(ControlMixin, HTTPServer):
793 """
794 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 :param addr: A tuple with the IP address and port to listen on.
797 :param handler: A handler callable which will be called with a
798 single parameter - the request - in order to
799 process the request.
800 :param poll_interval: The polling interval in seconds.
801 :param log: Pass ``True`` to enable log messages.
802 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100803 def __init__(self, addr, handler, poll_interval=0.5,
804 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
806 def __getattr__(self, name, default=None):
807 if name.startswith('do_'):
808 return self.process_request
809 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100810
Vinay Sajipce7c9782011-05-17 07:15:53 +0100811 def process_request(self):
812 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 def log_message(self, format, *args):
815 if log:
816 super(DelegatingHTTPRequestHandler,
817 self).log_message(format, *args)
818 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
819 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100820 self.sslctx = sslctx
821
822 def get_request(self):
823 try:
824 sock, addr = self.socket.accept()
825 if self.sslctx:
826 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200827 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100828 # socket errors are silenced by the caller, print them here
829 sys.stderr.write("Got an error:\n%s\n" % e)
830 raise
831 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100832
Vinay Sajipce7c9782011-05-17 07:15:53 +0100833 class TestTCPServer(ControlMixin, ThreadingTCPServer):
834 """
835 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 :param addr: A tuple with the IP address and port to listen on.
838 :param handler: A handler callable which will be called with a single
839 parameter - the request - in order to process the request.
840 :param poll_interval: The polling interval in seconds.
841 :bind_and_activate: If True (the default), binds the server and starts it
842 listening. If False, you need to call
843 :meth:`server_bind` and :meth:`server_activate` at
844 some later time before calling :meth:`start`, so that
845 the server will set up the socket and listen on it.
846 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100849
Vinay Sajipce7c9782011-05-17 07:15:53 +0100850 def __init__(self, addr, handler, poll_interval=0.5,
851 bind_and_activate=True):
852 class DelegatingTCPRequestHandler(StreamRequestHandler):
853
854 def handle(self):
855 self.server._handler(self)
856 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
857 bind_and_activate)
858 ControlMixin.__init__(self, handler, poll_interval)
859
860 def server_bind(self):
861 super(TestTCPServer, self).server_bind()
862 self.port = self.socket.getsockname()[1]
863
864 class TestUDPServer(ControlMixin, ThreadingUDPServer):
865 """
866 A UDP server which is controllable using :class:`ControlMixin`.
867
868 :param addr: A tuple with the IP address and port to listen on.
869 :param handler: A handler callable which will be called with a
870 single parameter - the request - in order to
871 process the request.
872 :param poll_interval: The polling interval for shutdown requests,
873 in seconds.
874 :bind_and_activate: If True (the default), binds the server and
875 starts it listening. If False, you need to
876 call :meth:`server_bind` and
877 :meth:`server_activate` at some later time
878 before calling :meth:`start`, so that the server will
879 set up the socket and listen on it.
880 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100881 def __init__(self, addr, handler, poll_interval=0.5,
882 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100883 class DelegatingUDPRequestHandler(DatagramRequestHandler):
884
885 def handle(self):
886 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100887
888 def finish(self):
889 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 if data:
891 try:
892 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200893 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if not self.server._closed:
895 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100896
Vinay Sajip3ef12292011-05-23 23:00:42 +0100897 ThreadingUDPServer.__init__(self, addr,
898 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100899 bind_and_activate)
900 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100901 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100902
903 def server_bind(self):
904 super(TestUDPServer, self).server_bind()
905 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100906
Vinay Sajipba980db2011-05-23 21:37:54 +0100907 def server_close(self):
908 super(TestUDPServer, self).server_close()
909 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Victor Stinnerec5a8602014-06-02 14:41:51 +0200911 if hasattr(socket, "AF_UNIX"):
912 class TestUnixStreamServer(TestTCPServer):
913 address_family = socket.AF_UNIX
914
915 class TestUnixDatagramServer(TestUDPServer):
916 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100917
Vinay Sajip7367d082011-05-02 13:17:27 +0100918# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100919
Vinay Sajipce7c9782011-05-17 07:15:53 +0100920@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100921class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000922 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100923 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100924 sockmap = {}
925 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
926 sockmap)
927 server.start()
928 addr = ('localhost', server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000929 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
930 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 self.assertEqual(h.toaddrs, ['you'])
932 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100933 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100934 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000936 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000938 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 self.assertEqual(len(self.messages), 1)
940 peer, mailfrom, rcpttos, data = self.messages[0]
941 self.assertEqual(mailfrom, 'me')
942 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100943 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100944 self.assertTrue(data.endswith('\n\nHello'))
945 h.close()
946
947 def process_message(self, *args):
948 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100949 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100950
Christian Heimes180510d2008-03-03 19:15:45 +0000951class MemoryHandlerTest(BaseTest):
952
953 """Tests for the MemoryHandler."""
954
955 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300956 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000957
958 def setUp(self):
959 BaseTest.setUp(self)
960 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
961 self.root_hdlr)
962 self.mem_logger = logging.getLogger('mem')
963 self.mem_logger.propagate = 0
964 self.mem_logger.addHandler(self.mem_hdlr)
965
966 def tearDown(self):
967 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000968 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000969
970 def test_flush(self):
971 # The memory handler flushes to its target handler based on specific
972 # criteria (message count and message level).
973 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000974 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000975 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000976 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000977 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100978 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000979 lines = [
980 ('DEBUG', '1'),
981 ('INFO', '2'),
982 ('WARNING', '3'),
983 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000984 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000985 for n in (4, 14):
986 for i in range(9):
987 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 # This will flush because it's the 10th message since the last
990 # flush.
991 self.mem_logger.debug(self.next_message())
992 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000993 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000994
995 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000996 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000997
998
999class ExceptionFormatter(logging.Formatter):
1000 """A special exception formatter."""
1001 def formatException(self, ei):
1002 return "Got a [%s]" % ei[0].__name__
1003
1004
1005class ConfigFileTest(BaseTest):
1006
1007 """Reading logging config from a .ini-style config file."""
1008
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001009 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001010
1011 # config0 is a standard configuration.
1012 config0 = """
1013 [loggers]
1014 keys=root
1015
1016 [handlers]
1017 keys=hand1
1018
1019 [formatters]
1020 keys=form1
1021
1022 [logger_root]
1023 level=WARNING
1024 handlers=hand1
1025
1026 [handler_hand1]
1027 class=StreamHandler
1028 level=NOTSET
1029 formatter=form1
1030 args=(sys.stdout,)
1031
1032 [formatter_form1]
1033 format=%(levelname)s ++ %(message)s
1034 datefmt=
1035 """
1036
1037 # config1 adds a little to the standard configuration.
1038 config1 = """
1039 [loggers]
1040 keys=root,parser
1041
1042 [handlers]
1043 keys=hand1
1044
1045 [formatters]
1046 keys=form1
1047
1048 [logger_root]
1049 level=WARNING
1050 handlers=
1051
1052 [logger_parser]
1053 level=DEBUG
1054 handlers=hand1
1055 propagate=1
1056 qualname=compiler.parser
1057
1058 [handler_hand1]
1059 class=StreamHandler
1060 level=NOTSET
1061 formatter=form1
1062 args=(sys.stdout,)
1063
1064 [formatter_form1]
1065 format=%(levelname)s ++ %(message)s
1066 datefmt=
1067 """
1068
Vinay Sajip3f84b072011-03-07 17:49:33 +00001069 # config1a moves the handler to the root.
1070 config1a = """
1071 [loggers]
1072 keys=root,parser
1073
1074 [handlers]
1075 keys=hand1
1076
1077 [formatters]
1078 keys=form1
1079
1080 [logger_root]
1081 level=WARNING
1082 handlers=hand1
1083
1084 [logger_parser]
1085 level=DEBUG
1086 handlers=
1087 propagate=1
1088 qualname=compiler.parser
1089
1090 [handler_hand1]
1091 class=StreamHandler
1092 level=NOTSET
1093 formatter=form1
1094 args=(sys.stdout,)
1095
1096 [formatter_form1]
1097 format=%(levelname)s ++ %(message)s
1098 datefmt=
1099 """
1100
Christian Heimes180510d2008-03-03 19:15:45 +00001101 # config2 has a subtle configuration error that should be reported
1102 config2 = config1.replace("sys.stdout", "sys.stbout")
1103
1104 # config3 has a less subtle configuration error
1105 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1106
1107 # config4 specifies a custom formatter class to be loaded
1108 config4 = """
1109 [loggers]
1110 keys=root
1111
1112 [handlers]
1113 keys=hand1
1114
1115 [formatters]
1116 keys=form1
1117
1118 [logger_root]
1119 level=NOTSET
1120 handlers=hand1
1121
1122 [handler_hand1]
1123 class=StreamHandler
1124 level=NOTSET
1125 formatter=form1
1126 args=(sys.stdout,)
1127
1128 [formatter_form1]
1129 class=""" + __name__ + """.ExceptionFormatter
1130 format=%(levelname)s:%(name)s:%(message)s
1131 datefmt=
1132 """
1133
Georg Brandl3dbca812008-07-23 16:10:53 +00001134 # config5 specifies a custom handler class to be loaded
1135 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1136
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001137 # config6 uses ', ' delimiters in the handlers and formatters sections
1138 config6 = """
1139 [loggers]
1140 keys=root,parser
1141
1142 [handlers]
1143 keys=hand1, hand2
1144
1145 [formatters]
1146 keys=form1, form2
1147
1148 [logger_root]
1149 level=WARNING
1150 handlers=
1151
1152 [logger_parser]
1153 level=DEBUG
1154 handlers=hand1
1155 propagate=1
1156 qualname=compiler.parser
1157
1158 [handler_hand1]
1159 class=StreamHandler
1160 level=NOTSET
1161 formatter=form1
1162 args=(sys.stdout,)
1163
1164 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001165 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001166 level=NOTSET
1167 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001168 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001169
1170 [formatter_form1]
1171 format=%(levelname)s ++ %(message)s
1172 datefmt=
1173
1174 [formatter_form2]
1175 format=%(message)s
1176 datefmt=
1177 """
1178
Vinay Sajip3f84b072011-03-07 17:49:33 +00001179 # config7 adds a compiler logger.
1180 config7 = """
1181 [loggers]
1182 keys=root,parser,compiler
1183
1184 [handlers]
1185 keys=hand1
1186
1187 [formatters]
1188 keys=form1
1189
1190 [logger_root]
1191 level=WARNING
1192 handlers=hand1
1193
1194 [logger_compiler]
1195 level=DEBUG
1196 handlers=
1197 propagate=1
1198 qualname=compiler
1199
1200 [logger_parser]
1201 level=DEBUG
1202 handlers=
1203 propagate=1
1204 qualname=compiler.parser
1205
1206 [handler_hand1]
1207 class=StreamHandler
1208 level=NOTSET
1209 formatter=form1
1210 args=(sys.stdout,)
1211
1212 [formatter_form1]
1213 format=%(levelname)s ++ %(message)s
1214 datefmt=
1215 """
1216
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001217 disable_test = """
1218 [loggers]
1219 keys=root
1220
1221 [handlers]
1222 keys=screen
1223
1224 [formatters]
1225 keys=
1226
1227 [logger_root]
1228 level=DEBUG
1229 handlers=screen
1230
1231 [handler_screen]
1232 level=DEBUG
1233 class=StreamHandler
1234 args=(sys.stdout,)
1235 formatter=
1236 """
1237
1238 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001239 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001240 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001241
1242 def test_config0_ok(self):
1243 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001244 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001245 self.apply_config(self.config0)
1246 logger = logging.getLogger()
1247 # Won't output anything
1248 logger.info(self.next_message())
1249 # Outputs a message
1250 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001251 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001252 ('ERROR', '2'),
1253 ], stream=output)
1254 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001255 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001256
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001257 def test_config0_using_cp_ok(self):
1258 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001259 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001260 file = io.StringIO(textwrap.dedent(self.config0))
1261 cp = configparser.ConfigParser()
1262 cp.read_file(file)
1263 logging.config.fileConfig(cp)
1264 logger = logging.getLogger()
1265 # Won't output anything
1266 logger.info(self.next_message())
1267 # Outputs a message
1268 logger.error(self.next_message())
1269 self.assert_log_lines([
1270 ('ERROR', '2'),
1271 ], stream=output)
1272 # Original logger output is empty.
1273 self.assert_log_lines([])
1274
Georg Brandl3dbca812008-07-23 16:10:53 +00001275 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001276 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001277 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001278 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001279 logger = logging.getLogger("compiler.parser")
1280 # Both will output a message
1281 logger.info(self.next_message())
1282 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001283 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001284 ('INFO', '1'),
1285 ('ERROR', '2'),
1286 ], stream=output)
1287 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001288 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001289
1290 def test_config2_failure(self):
1291 # A simple config file which overrides the default settings.
1292 self.assertRaises(Exception, self.apply_config, self.config2)
1293
1294 def test_config3_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config3)
1297
1298 def test_config4_ok(self):
1299 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001300 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001301 self.apply_config(self.config4)
1302 logger = logging.getLogger()
1303 try:
1304 raise RuntimeError()
1305 except RuntimeError:
1306 logging.exception("just testing")
1307 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001308 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001309 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1310 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001311 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001312
Georg Brandl3dbca812008-07-23 16:10:53 +00001313 def test_config5_ok(self):
1314 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001315
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001316 def test_config6_ok(self):
1317 self.test_config1_ok(config=self.config6)
1318
Vinay Sajip3f84b072011-03-07 17:49:33 +00001319 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001320 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001321 self.apply_config(self.config1a)
1322 logger = logging.getLogger("compiler.parser")
1323 # See issue #11424. compiler-hyphenated sorts
1324 # between compiler and compiler.xyz and this
1325 # was preventing compiler.xyz from being included
1326 # in the child loggers of compiler because of an
1327 # overzealous loop termination condition.
1328 hyphenated = logging.getLogger('compiler-hyphenated')
1329 # All will output a message
1330 logger.info(self.next_message())
1331 logger.error(self.next_message())
1332 hyphenated.critical(self.next_message())
1333 self.assert_log_lines([
1334 ('INFO', '1'),
1335 ('ERROR', '2'),
1336 ('CRITICAL', '3'),
1337 ], stream=output)
1338 # Original logger output is empty.
1339 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001340 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001341 self.apply_config(self.config7)
1342 logger = logging.getLogger("compiler.parser")
1343 self.assertFalse(logger.disabled)
1344 # Both will output a message
1345 logger.info(self.next_message())
1346 logger.error(self.next_message())
1347 logger = logging.getLogger("compiler.lexer")
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 # Will not appear
1352 hyphenated.critical(self.next_message())
1353 self.assert_log_lines([
1354 ('INFO', '4'),
1355 ('ERROR', '5'),
1356 ('INFO', '6'),
1357 ('ERROR', '7'),
1358 ], stream=output)
1359 # Original logger output is empty.
1360 self.assert_log_lines([])
1361
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001362 def test_logger_disabling(self):
1363 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001364 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001365 self.assertFalse(logger.disabled)
1366 self.apply_config(self.disable_test)
1367 self.assertTrue(logger.disabled)
1368 self.apply_config(self.disable_test, disable_existing_loggers=False)
1369 self.assertFalse(logger.disabled)
1370
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001371
Victor Stinner45df8202010-04-28 22:31:17 +00001372@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001373class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001374
Christian Heimes180510d2008-03-03 19:15:45 +00001375 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001376
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001377 if threading:
1378 server_class = TestTCPServer
1379 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001380
Christian Heimes180510d2008-03-03 19:15:45 +00001381 def setUp(self):
1382 """Set up a TCP server to receive log messages, and a SocketHandler
1383 pointing to that server's address and port."""
1384 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001385 self.server = server = self.server_class(self.address,
1386 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001387 server.start()
1388 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001389 hcls = logging.handlers.SocketHandler
1390 if isinstance(server.server_address, tuple):
1391 self.sock_hdlr = hcls('localhost', server.port)
1392 else:
1393 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001394 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001395 self.root_logger.removeHandler(self.root_logger.handlers[0])
1396 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001397 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001398
Christian Heimes180510d2008-03-03 19:15:45 +00001399 def tearDown(self):
1400 """Shutdown the TCP server."""
1401 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001402 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001403 self.root_logger.removeHandler(self.sock_hdlr)
1404 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001405 finally:
1406 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001407
Vinay Sajip7367d082011-05-02 13:17:27 +01001408 def handle_socket(self, request):
1409 conn = request.connection
1410 while True:
1411 chunk = conn.recv(4)
1412 if len(chunk) < 4:
1413 break
1414 slen = struct.unpack(">L", chunk)[0]
1415 chunk = conn.recv(slen)
1416 while len(chunk) < slen:
1417 chunk = chunk + conn.recv(slen - len(chunk))
1418 obj = pickle.loads(chunk)
1419 record = logging.makeLogRecord(obj)
1420 self.log_output += record.msg + '\n'
1421 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001422
Christian Heimes180510d2008-03-03 19:15:45 +00001423 def test_output(self):
1424 # The log message sent to the SocketHandler is properly received.
1425 logger = logging.getLogger("tcp")
1426 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001427 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001428 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001429 self.handled.acquire()
1430 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001431
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001432 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001433 # Avoid timing-related failures due to SocketHandler's own hard-wired
1434 # one-second timeout on socket.create_connection() (issue #16264).
1435 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001436 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001437 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001438 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001439 try:
1440 raise RuntimeError('Deliberate mistake')
1441 except RuntimeError:
1442 self.root_logger.exception('Never sent')
1443 self.root_logger.error('Never sent, either')
1444 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001445 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001446 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1447 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001448
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001449def _get_temp_domain_socket():
1450 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1451 os.close(fd)
1452 # just need a name - file can't be present, or we'll get an
1453 # 'address already in use' error.
1454 os.remove(fn)
1455 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001456
Victor Stinnerec5a8602014-06-02 14:41:51 +02001457@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001458@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001459class UnixSocketHandlerTest(SocketHandlerTest):
1460
1461 """Test for SocketHandler with unix sockets."""
1462
Victor Stinnerec5a8602014-06-02 14:41:51 +02001463 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001464 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001465
1466 def setUp(self):
1467 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001468 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001469 SocketHandlerTest.setUp(self)
1470
1471 def tearDown(self):
1472 SocketHandlerTest.tearDown(self)
1473 os.remove(self.address)
1474
1475@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001476class DatagramHandlerTest(BaseTest):
1477
1478 """Test for DatagramHandler."""
1479
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001480 if threading:
1481 server_class = TestUDPServer
1482 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001483
Vinay Sajip7367d082011-05-02 13:17:27 +01001484 def setUp(self):
1485 """Set up a UDP server to receive log messages, and a DatagramHandler
1486 pointing to that server's address and port."""
1487 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001488 self.server = server = self.server_class(self.address,
1489 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001490 server.start()
1491 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001492 hcls = logging.handlers.DatagramHandler
1493 if isinstance(server.server_address, tuple):
1494 self.sock_hdlr = hcls('localhost', server.port)
1495 else:
1496 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001497 self.log_output = ''
1498 self.root_logger.removeHandler(self.root_logger.handlers[0])
1499 self.root_logger.addHandler(self.sock_hdlr)
1500 self.handled = threading.Event()
1501
1502 def tearDown(self):
1503 """Shutdown the UDP server."""
1504 try:
1505 self.server.stop(2.0)
1506 self.root_logger.removeHandler(self.sock_hdlr)
1507 self.sock_hdlr.close()
1508 finally:
1509 BaseTest.tearDown(self)
1510
1511 def handle_datagram(self, request):
1512 slen = struct.pack('>L', 0) # length of prefix
1513 packet = request.packet[len(slen):]
1514 obj = pickle.loads(packet)
1515 record = logging.makeLogRecord(obj)
1516 self.log_output += record.msg + '\n'
1517 self.handled.set()
1518
1519 def test_output(self):
1520 # The log message sent to the DatagramHandler is properly received.
1521 logger = logging.getLogger("udp")
1522 logger.error("spam")
1523 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001524 self.handled.clear()
1525 logger.error("eggs")
1526 self.handled.wait()
1527 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001528
Victor Stinnerec5a8602014-06-02 14:41:51 +02001529@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001530@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001531class UnixDatagramHandlerTest(DatagramHandlerTest):
1532
1533 """Test for DatagramHandler using Unix sockets."""
1534
Victor Stinnerec5a8602014-06-02 14:41:51 +02001535 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001536 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001537
1538 def setUp(self):
1539 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001540 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001541 DatagramHandlerTest.setUp(self)
1542
1543 def tearDown(self):
1544 DatagramHandlerTest.tearDown(self)
1545 os.remove(self.address)
1546
1547@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001548class SysLogHandlerTest(BaseTest):
1549
1550 """Test for SysLogHandler using UDP."""
1551
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001552 if threading:
1553 server_class = TestUDPServer
1554 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001555
Vinay Sajip7367d082011-05-02 13:17:27 +01001556 def setUp(self):
1557 """Set up a UDP server to receive log messages, and a SysLogHandler
1558 pointing to that server's address and port."""
1559 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001560 self.server = server = self.server_class(self.address,
1561 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001562 server.start()
1563 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 hcls = logging.handlers.SysLogHandler
1565 if isinstance(server.server_address, tuple):
1566 self.sl_hdlr = hcls(('localhost', server.port))
1567 else:
1568 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001569 self.log_output = ''
1570 self.root_logger.removeHandler(self.root_logger.handlers[0])
1571 self.root_logger.addHandler(self.sl_hdlr)
1572 self.handled = threading.Event()
1573
1574 def tearDown(self):
1575 """Shutdown the UDP server."""
1576 try:
1577 self.server.stop(2.0)
1578 self.root_logger.removeHandler(self.sl_hdlr)
1579 self.sl_hdlr.close()
1580 finally:
1581 BaseTest.tearDown(self)
1582
1583 def handle_datagram(self, request):
1584 self.log_output = request.packet
1585 self.handled.set()
1586
1587 def test_output(self):
1588 # The log message sent to the SysLogHandler is properly received.
1589 logger = logging.getLogger("slh")
1590 logger.error("sp\xe4m")
1591 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001592 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001593 self.handled.clear()
1594 self.sl_hdlr.append_nul = False
1595 logger.error("sp\xe4m")
1596 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001597 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001598 self.handled.clear()
1599 self.sl_hdlr.ident = "h\xe4m-"
1600 logger.error("sp\xe4m")
1601 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001602 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001603
Victor Stinnerec5a8602014-06-02 14:41:51 +02001604@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001605@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001606class UnixSysLogHandlerTest(SysLogHandlerTest):
1607
1608 """Test for SysLogHandler with Unix sockets."""
1609
Victor Stinnerec5a8602014-06-02 14:41:51 +02001610 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001611 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001612
1613 def setUp(self):
1614 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001615 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001616 SysLogHandlerTest.setUp(self)
1617
1618 def tearDown(self):
1619 SysLogHandlerTest.tearDown(self)
1620 os.remove(self.address)
1621
Vinay Sajip5421f352013-09-27 18:18:28 +01001622@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001623class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001624 """Test for HTTPHandler."""
1625
Vinay Sajip9ba87612011-05-21 11:32:15 +01001626 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1627MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1628zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1629aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1630AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16310tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16325LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1633piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16342z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1635i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1636PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1637E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1638rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1639/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1640-----END RSA PRIVATE KEY-----
1641-----BEGIN CERTIFICATE-----
1642MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1643BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1644EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1645xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1646l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1647vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1648BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1649S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1650BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16514f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16521c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1653IRbTpvlHWPjsSvHz0ZOH
1654-----END CERTIFICATE-----"""
1655
Vinay Sajip7367d082011-05-02 13:17:27 +01001656 def setUp(self):
1657 """Set up an HTTP server to receive log messages, and a HTTPHandler
1658 pointing to that server's address and port."""
1659 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001660 self.handled = threading.Event()
1661
Vinay Sajip7367d082011-05-02 13:17:27 +01001662 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001663 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001665 if self.command == 'POST':
1666 try:
1667 rlen = int(request.headers['Content-Length'])
1668 self.post_data = request.rfile.read(rlen)
1669 except:
1670 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001671 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001672 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001673 self.handled.set()
1674
1675 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001676 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001677 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001678 root_logger = self.root_logger
1679 root_logger.removeHandler(self.root_logger.handlers[0])
1680 for secure in (False, True):
1681 addr = ('localhost', 0)
1682 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001683 try:
1684 import ssl
1685 fd, fn = tempfile.mkstemp()
1686 os.close(fd)
1687 with open(fn, 'w') as f:
1688 f.write(self.PEMFILE)
1689 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1690 sslctx.load_cert_chain(fn)
1691 os.unlink(fn)
1692 except ImportError:
1693 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001694 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001695 sslctx = None
1696 self.server = server = TestHTTPServer(addr, self.handle_request,
1697 0.01, sslctx=sslctx)
1698 server.start()
1699 server.ready.wait()
1700 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001701 secure_client = secure and sslctx
1702 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1703 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001704 self.log_data = None
1705 root_logger.addHandler(self.h_hdlr)
1706
1707 for method in ('GET', 'POST'):
1708 self.h_hdlr.method = method
1709 self.handled.clear()
1710 msg = "sp\xe4m"
1711 logger.error(msg)
1712 self.handled.wait()
1713 self.assertEqual(self.log_data.path, '/frob')
1714 self.assertEqual(self.command, method)
1715 if method == 'GET':
1716 d = parse_qs(self.log_data.query)
1717 else:
1718 d = parse_qs(self.post_data.decode('utf-8'))
1719 self.assertEqual(d['name'], ['http'])
1720 self.assertEqual(d['funcName'], ['test_output'])
1721 self.assertEqual(d['msg'], [msg])
1722
1723 self.server.stop(2.0)
1724 self.root_logger.removeHandler(self.h_hdlr)
1725 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001726
Christian Heimes180510d2008-03-03 19:15:45 +00001727class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001728
Christian Heimes180510d2008-03-03 19:15:45 +00001729 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731 def setUp(self):
1732 """Create a dict to remember potentially destroyed objects."""
1733 BaseTest.setUp(self)
1734 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001735
Christian Heimes180510d2008-03-03 19:15:45 +00001736 def _watch_for_survival(self, *args):
1737 """Watch the given objects for survival, by creating weakrefs to
1738 them."""
1739 for obj in args:
1740 key = id(obj), repr(obj)
1741 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001742
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001743 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001744 """Assert that all objects watched for survival have survived."""
1745 # Trigger cycle breaking.
1746 gc.collect()
1747 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001748 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001749 if ref() is None:
1750 dead.append(repr_)
1751 if dead:
1752 self.fail("%d objects should have survived "
1753 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001754
Christian Heimes180510d2008-03-03 19:15:45 +00001755 def test_persistent_loggers(self):
1756 # Logger objects are persistent and retain their configuration, even
1757 # if visible references are destroyed.
1758 self.root_logger.setLevel(logging.INFO)
1759 foo = logging.getLogger("foo")
1760 self._watch_for_survival(foo)
1761 foo.setLevel(logging.DEBUG)
1762 self.root_logger.debug(self.next_message())
1763 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001764 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001765 ('foo', 'DEBUG', '2'),
1766 ])
1767 del foo
1768 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001769 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001770 # foo has retained its settings.
1771 bar = logging.getLogger("foo")
1772 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001773 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001774 ('foo', 'DEBUG', '2'),
1775 ('foo', 'DEBUG', '3'),
1776 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001777
Benjamin Petersonf91df042009-02-13 02:50:59 +00001778
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001779class EncodingTest(BaseTest):
1780 def test_encoding_plain_file(self):
1781 # In Python 2.x, a plain file object is treated as having no encoding.
1782 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001783 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1784 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001785 # the non-ascii data we write to the log.
1786 data = "foo\x80"
1787 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001788 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001789 log.addHandler(handler)
1790 try:
1791 # write non-ascii data to the log.
1792 log.warning(data)
1793 finally:
1794 log.removeHandler(handler)
1795 handler.close()
1796 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001797 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001798 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001799 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001800 finally:
1801 f.close()
1802 finally:
1803 if os.path.isfile(fn):
1804 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001805
Benjamin Petersonf91df042009-02-13 02:50:59 +00001806 def test_encoding_cyrillic_unicode(self):
1807 log = logging.getLogger("test")
1808 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1809 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1810 #Ensure it's written in a Cyrillic encoding
1811 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001812 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001813 stream = io.BytesIO()
1814 writer = writer_class(stream, 'strict')
1815 handler = logging.StreamHandler(writer)
1816 log.addHandler(handler)
1817 try:
1818 log.warning(message)
1819 finally:
1820 log.removeHandler(handler)
1821 handler.close()
1822 # check we wrote exactly those bytes, ignoring trailing \n etc
1823 s = stream.getvalue()
1824 #Compare against what the data should be when encoded in CP-1251
1825 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1826
1827
Georg Brandlf9734072008-12-07 15:30:06 +00001828class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001829
Georg Brandlf9734072008-12-07 15:30:06 +00001830 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001831 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001832 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001833 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001834 warnings.filterwarnings("always", category=UserWarning)
1835 stream = io.StringIO()
1836 h = logging.StreamHandler(stream)
1837 logger = logging.getLogger("py.warnings")
1838 logger.addHandler(h)
1839 warnings.warn("I'm warning you...")
1840 logger.removeHandler(h)
1841 s = stream.getvalue()
1842 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001843 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001844
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001845 #See if an explicit file uses the original implementation
1846 a_file = io.StringIO()
1847 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1848 a_file, "Dummy line")
1849 s = a_file.getvalue()
1850 a_file.close()
1851 self.assertEqual(s,
1852 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1853
1854 def test_warnings_no_handlers(self):
1855 with warnings.catch_warnings():
1856 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001857 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001858
1859 # confirm our assumption: no loggers are set
1860 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001861 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001862
1863 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001864 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001865 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001866
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001867
1868def formatFunc(format, datefmt=None):
1869 return logging.Formatter(format, datefmt)
1870
1871def handlerFunc():
1872 return logging.StreamHandler()
1873
1874class CustomHandler(logging.StreamHandler):
1875 pass
1876
1877class ConfigDictTest(BaseTest):
1878
1879 """Reading logging config from a dictionary."""
1880
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001881 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001882
1883 # config0 is a standard configuration.
1884 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001885 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001886 'formatters': {
1887 'form1' : {
1888 'format' : '%(levelname)s ++ %(message)s',
1889 },
1890 },
1891 'handlers' : {
1892 'hand1' : {
1893 'class' : 'logging.StreamHandler',
1894 'formatter' : 'form1',
1895 'level' : 'NOTSET',
1896 'stream' : 'ext://sys.stdout',
1897 },
1898 },
1899 'root' : {
1900 'level' : 'WARNING',
1901 'handlers' : ['hand1'],
1902 },
1903 }
1904
1905 # config1 adds a little to the standard configuration.
1906 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001907 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001908 'formatters': {
1909 'form1' : {
1910 'format' : '%(levelname)s ++ %(message)s',
1911 },
1912 },
1913 'handlers' : {
1914 'hand1' : {
1915 'class' : 'logging.StreamHandler',
1916 'formatter' : 'form1',
1917 'level' : 'NOTSET',
1918 'stream' : 'ext://sys.stdout',
1919 },
1920 },
1921 'loggers' : {
1922 'compiler.parser' : {
1923 'level' : 'DEBUG',
1924 'handlers' : ['hand1'],
1925 },
1926 },
1927 'root' : {
1928 'level' : 'WARNING',
1929 },
1930 }
1931
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001932 # config1a moves the handler to the root. Used with config8a
1933 config1a = {
1934 'version': 1,
1935 'formatters': {
1936 'form1' : {
1937 'format' : '%(levelname)s ++ %(message)s',
1938 },
1939 },
1940 'handlers' : {
1941 'hand1' : {
1942 'class' : 'logging.StreamHandler',
1943 'formatter' : 'form1',
1944 'level' : 'NOTSET',
1945 'stream' : 'ext://sys.stdout',
1946 },
1947 },
1948 'loggers' : {
1949 'compiler.parser' : {
1950 'level' : 'DEBUG',
1951 },
1952 },
1953 'root' : {
1954 'level' : 'WARNING',
1955 'handlers' : ['hand1'],
1956 },
1957 }
1958
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001959 # config2 has a subtle configuration error that should be reported
1960 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001961 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001962 'formatters': {
1963 'form1' : {
1964 'format' : '%(levelname)s ++ %(message)s',
1965 },
1966 },
1967 'handlers' : {
1968 'hand1' : {
1969 'class' : 'logging.StreamHandler',
1970 'formatter' : 'form1',
1971 'level' : 'NOTSET',
1972 'stream' : 'ext://sys.stdbout',
1973 },
1974 },
1975 'loggers' : {
1976 'compiler.parser' : {
1977 'level' : 'DEBUG',
1978 'handlers' : ['hand1'],
1979 },
1980 },
1981 'root' : {
1982 'level' : 'WARNING',
1983 },
1984 }
1985
1986 #As config1 but with a misspelt level on a handler
1987 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001988 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001989 'formatters': {
1990 'form1' : {
1991 'format' : '%(levelname)s ++ %(message)s',
1992 },
1993 },
1994 'handlers' : {
1995 'hand1' : {
1996 'class' : 'logging.StreamHandler',
1997 'formatter' : 'form1',
1998 'level' : 'NTOSET',
1999 'stream' : 'ext://sys.stdout',
2000 },
2001 },
2002 'loggers' : {
2003 'compiler.parser' : {
2004 'level' : 'DEBUG',
2005 'handlers' : ['hand1'],
2006 },
2007 },
2008 'root' : {
2009 'level' : 'WARNING',
2010 },
2011 }
2012
2013
2014 #As config1 but with a misspelt level on a logger
2015 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002016 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002017 'formatters': {
2018 'form1' : {
2019 'format' : '%(levelname)s ++ %(message)s',
2020 },
2021 },
2022 'handlers' : {
2023 'hand1' : {
2024 'class' : 'logging.StreamHandler',
2025 'formatter' : 'form1',
2026 'level' : 'NOTSET',
2027 'stream' : 'ext://sys.stdout',
2028 },
2029 },
2030 'loggers' : {
2031 'compiler.parser' : {
2032 'level' : 'DEBUG',
2033 'handlers' : ['hand1'],
2034 },
2035 },
2036 'root' : {
2037 'level' : 'WRANING',
2038 },
2039 }
2040
2041 # config3 has a less subtle configuration error
2042 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002043 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002044 'formatters': {
2045 'form1' : {
2046 'format' : '%(levelname)s ++ %(message)s',
2047 },
2048 },
2049 'handlers' : {
2050 'hand1' : {
2051 'class' : 'logging.StreamHandler',
2052 'formatter' : 'misspelled_name',
2053 'level' : 'NOTSET',
2054 'stream' : 'ext://sys.stdout',
2055 },
2056 },
2057 'loggers' : {
2058 'compiler.parser' : {
2059 'level' : 'DEBUG',
2060 'handlers' : ['hand1'],
2061 },
2062 },
2063 'root' : {
2064 'level' : 'WARNING',
2065 },
2066 }
2067
2068 # config4 specifies a custom formatter class to be loaded
2069 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002070 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002071 'formatters': {
2072 'form1' : {
2073 '()' : __name__ + '.ExceptionFormatter',
2074 'format' : '%(levelname)s:%(name)s:%(message)s',
2075 },
2076 },
2077 'handlers' : {
2078 'hand1' : {
2079 'class' : 'logging.StreamHandler',
2080 'formatter' : 'form1',
2081 'level' : 'NOTSET',
2082 'stream' : 'ext://sys.stdout',
2083 },
2084 },
2085 'root' : {
2086 'level' : 'NOTSET',
2087 'handlers' : ['hand1'],
2088 },
2089 }
2090
2091 # As config4 but using an actual callable rather than a string
2092 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002093 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002094 'formatters': {
2095 'form1' : {
2096 '()' : ExceptionFormatter,
2097 'format' : '%(levelname)s:%(name)s:%(message)s',
2098 },
2099 'form2' : {
2100 '()' : __name__ + '.formatFunc',
2101 'format' : '%(levelname)s:%(name)s:%(message)s',
2102 },
2103 'form3' : {
2104 '()' : formatFunc,
2105 'format' : '%(levelname)s:%(name)s:%(message)s',
2106 },
2107 },
2108 'handlers' : {
2109 'hand1' : {
2110 'class' : 'logging.StreamHandler',
2111 'formatter' : 'form1',
2112 'level' : 'NOTSET',
2113 'stream' : 'ext://sys.stdout',
2114 },
2115 'hand2' : {
2116 '()' : handlerFunc,
2117 },
2118 },
2119 'root' : {
2120 'level' : 'NOTSET',
2121 'handlers' : ['hand1'],
2122 },
2123 }
2124
2125 # config5 specifies a custom handler class to be loaded
2126 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002127 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002128 'formatters': {
2129 'form1' : {
2130 'format' : '%(levelname)s ++ %(message)s',
2131 },
2132 },
2133 'handlers' : {
2134 'hand1' : {
2135 'class' : __name__ + '.CustomHandler',
2136 'formatter' : 'form1',
2137 'level' : 'NOTSET',
2138 'stream' : 'ext://sys.stdout',
2139 },
2140 },
2141 'loggers' : {
2142 'compiler.parser' : {
2143 'level' : 'DEBUG',
2144 'handlers' : ['hand1'],
2145 },
2146 },
2147 'root' : {
2148 'level' : 'WARNING',
2149 },
2150 }
2151
2152 # config6 specifies a custom handler class to be loaded
2153 # but has bad arguments
2154 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002155 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002156 'formatters': {
2157 'form1' : {
2158 'format' : '%(levelname)s ++ %(message)s',
2159 },
2160 },
2161 'handlers' : {
2162 'hand1' : {
2163 'class' : __name__ + '.CustomHandler',
2164 'formatter' : 'form1',
2165 'level' : 'NOTSET',
2166 'stream' : 'ext://sys.stdout',
2167 '9' : 'invalid parameter name',
2168 },
2169 },
2170 'loggers' : {
2171 'compiler.parser' : {
2172 'level' : 'DEBUG',
2173 'handlers' : ['hand1'],
2174 },
2175 },
2176 'root' : {
2177 'level' : 'WARNING',
2178 },
2179 }
2180
2181 #config 7 does not define compiler.parser but defines compiler.lexer
2182 #so compiler.parser should be disabled after applying it
2183 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002184 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002185 'formatters': {
2186 'form1' : {
2187 'format' : '%(levelname)s ++ %(message)s',
2188 },
2189 },
2190 'handlers' : {
2191 'hand1' : {
2192 'class' : 'logging.StreamHandler',
2193 'formatter' : 'form1',
2194 'level' : 'NOTSET',
2195 'stream' : 'ext://sys.stdout',
2196 },
2197 },
2198 'loggers' : {
2199 'compiler.lexer' : {
2200 'level' : 'DEBUG',
2201 'handlers' : ['hand1'],
2202 },
2203 },
2204 'root' : {
2205 'level' : 'WARNING',
2206 },
2207 }
2208
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002209 # config8 defines both compiler and compiler.lexer
2210 # so compiler.parser should not be disabled (since
2211 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002212 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002213 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002214 'disable_existing_loggers' : False,
2215 'formatters': {
2216 'form1' : {
2217 'format' : '%(levelname)s ++ %(message)s',
2218 },
2219 },
2220 'handlers' : {
2221 'hand1' : {
2222 'class' : 'logging.StreamHandler',
2223 'formatter' : 'form1',
2224 'level' : 'NOTSET',
2225 'stream' : 'ext://sys.stdout',
2226 },
2227 },
2228 'loggers' : {
2229 'compiler' : {
2230 'level' : 'DEBUG',
2231 'handlers' : ['hand1'],
2232 },
2233 'compiler.lexer' : {
2234 },
2235 },
2236 'root' : {
2237 'level' : 'WARNING',
2238 },
2239 }
2240
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002241 # config8a disables existing loggers
2242 config8a = {
2243 'version': 1,
2244 'disable_existing_loggers' : True,
2245 'formatters': {
2246 'form1' : {
2247 'format' : '%(levelname)s ++ %(message)s',
2248 },
2249 },
2250 'handlers' : {
2251 'hand1' : {
2252 'class' : 'logging.StreamHandler',
2253 'formatter' : 'form1',
2254 'level' : 'NOTSET',
2255 'stream' : 'ext://sys.stdout',
2256 },
2257 },
2258 'loggers' : {
2259 'compiler' : {
2260 'level' : 'DEBUG',
2261 'handlers' : ['hand1'],
2262 },
2263 'compiler.lexer' : {
2264 },
2265 },
2266 'root' : {
2267 'level' : 'WARNING',
2268 },
2269 }
2270
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002271 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002272 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002273 'formatters': {
2274 'form1' : {
2275 'format' : '%(levelname)s ++ %(message)s',
2276 },
2277 },
2278 'handlers' : {
2279 'hand1' : {
2280 'class' : 'logging.StreamHandler',
2281 'formatter' : 'form1',
2282 'level' : 'WARNING',
2283 'stream' : 'ext://sys.stdout',
2284 },
2285 },
2286 'loggers' : {
2287 'compiler.parser' : {
2288 'level' : 'WARNING',
2289 'handlers' : ['hand1'],
2290 },
2291 },
2292 'root' : {
2293 'level' : 'NOTSET',
2294 },
2295 }
2296
2297 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002298 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002299 'incremental' : True,
2300 'handlers' : {
2301 'hand1' : {
2302 'level' : 'WARNING',
2303 },
2304 },
2305 'loggers' : {
2306 'compiler.parser' : {
2307 'level' : 'INFO',
2308 },
2309 },
2310 }
2311
2312 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002313 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002314 'incremental' : True,
2315 'handlers' : {
2316 'hand1' : {
2317 'level' : 'INFO',
2318 },
2319 },
2320 'loggers' : {
2321 'compiler.parser' : {
2322 'level' : 'INFO',
2323 },
2324 },
2325 }
2326
2327 #As config1 but with a filter added
2328 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002329 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002330 'formatters': {
2331 'form1' : {
2332 'format' : '%(levelname)s ++ %(message)s',
2333 },
2334 },
2335 'filters' : {
2336 'filt1' : {
2337 'name' : 'compiler.parser',
2338 },
2339 },
2340 'handlers' : {
2341 'hand1' : {
2342 'class' : 'logging.StreamHandler',
2343 'formatter' : 'form1',
2344 'level' : 'NOTSET',
2345 'stream' : 'ext://sys.stdout',
2346 'filters' : ['filt1'],
2347 },
2348 },
2349 'loggers' : {
2350 'compiler.parser' : {
2351 'level' : 'DEBUG',
2352 'filters' : ['filt1'],
2353 },
2354 },
2355 'root' : {
2356 'level' : 'WARNING',
2357 'handlers' : ['hand1'],
2358 },
2359 }
2360
2361 #As config1 but using cfg:// references
2362 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002363 'version': 1,
2364 'true_formatters': {
2365 'form1' : {
2366 'format' : '%(levelname)s ++ %(message)s',
2367 },
2368 },
2369 'handler_configs': {
2370 'hand1' : {
2371 'class' : 'logging.StreamHandler',
2372 'formatter' : 'form1',
2373 'level' : 'NOTSET',
2374 'stream' : 'ext://sys.stdout',
2375 },
2376 },
2377 'formatters' : 'cfg://true_formatters',
2378 'handlers' : {
2379 'hand1' : 'cfg://handler_configs[hand1]',
2380 },
2381 'loggers' : {
2382 'compiler.parser' : {
2383 'level' : 'DEBUG',
2384 'handlers' : ['hand1'],
2385 },
2386 },
2387 'root' : {
2388 'level' : 'WARNING',
2389 },
2390 }
2391
2392 #As config11 but missing the version key
2393 config12 = {
2394 'true_formatters': {
2395 'form1' : {
2396 'format' : '%(levelname)s ++ %(message)s',
2397 },
2398 },
2399 'handler_configs': {
2400 'hand1' : {
2401 'class' : 'logging.StreamHandler',
2402 'formatter' : 'form1',
2403 'level' : 'NOTSET',
2404 'stream' : 'ext://sys.stdout',
2405 },
2406 },
2407 'formatters' : 'cfg://true_formatters',
2408 'handlers' : {
2409 'hand1' : 'cfg://handler_configs[hand1]',
2410 },
2411 'loggers' : {
2412 'compiler.parser' : {
2413 'level' : 'DEBUG',
2414 'handlers' : ['hand1'],
2415 },
2416 },
2417 'root' : {
2418 'level' : 'WARNING',
2419 },
2420 }
2421
2422 #As config11 but using an unsupported version
2423 config13 = {
2424 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002425 'true_formatters': {
2426 'form1' : {
2427 'format' : '%(levelname)s ++ %(message)s',
2428 },
2429 },
2430 'handler_configs': {
2431 'hand1' : {
2432 'class' : 'logging.StreamHandler',
2433 'formatter' : 'form1',
2434 'level' : 'NOTSET',
2435 'stream' : 'ext://sys.stdout',
2436 },
2437 },
2438 'formatters' : 'cfg://true_formatters',
2439 'handlers' : {
2440 'hand1' : 'cfg://handler_configs[hand1]',
2441 },
2442 'loggers' : {
2443 'compiler.parser' : {
2444 'level' : 'DEBUG',
2445 'handlers' : ['hand1'],
2446 },
2447 },
2448 'root' : {
2449 'level' : 'WARNING',
2450 },
2451 }
2452
Vinay Sajip8d270232012-11-15 14:20:18 +00002453 # As config0, but with properties
2454 config14 = {
2455 'version': 1,
2456 'formatters': {
2457 'form1' : {
2458 'format' : '%(levelname)s ++ %(message)s',
2459 },
2460 },
2461 'handlers' : {
2462 'hand1' : {
2463 'class' : 'logging.StreamHandler',
2464 'formatter' : 'form1',
2465 'level' : 'NOTSET',
2466 'stream' : 'ext://sys.stdout',
2467 '.': {
2468 'foo': 'bar',
2469 'terminator': '!\n',
2470 }
2471 },
2472 },
2473 'root' : {
2474 'level' : 'WARNING',
2475 'handlers' : ['hand1'],
2476 },
2477 }
2478
Vinay Sajip3f885b52013-03-22 15:19:54 +00002479 out_of_order = {
2480 "version": 1,
2481 "formatters": {
2482 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002483 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2484 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002485 }
2486 },
2487 "handlers": {
2488 "fileGlobal": {
2489 "class": "logging.StreamHandler",
2490 "level": "DEBUG",
2491 "formatter": "mySimpleFormatter"
2492 },
2493 "bufferGlobal": {
2494 "class": "logging.handlers.MemoryHandler",
2495 "capacity": 5,
2496 "formatter": "mySimpleFormatter",
2497 "target": "fileGlobal",
2498 "level": "DEBUG"
2499 }
2500 },
2501 "loggers": {
2502 "mymodule": {
2503 "level": "DEBUG",
2504 "handlers": ["bufferGlobal"],
2505 "propagate": "true"
2506 }
2507 }
2508 }
2509
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002510 def apply_config(self, conf):
2511 logging.config.dictConfig(conf)
2512
2513 def test_config0_ok(self):
2514 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002515 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002516 self.apply_config(self.config0)
2517 logger = logging.getLogger()
2518 # Won't output anything
2519 logger.info(self.next_message())
2520 # Outputs a message
2521 logger.error(self.next_message())
2522 self.assert_log_lines([
2523 ('ERROR', '2'),
2524 ], stream=output)
2525 # Original logger output is empty.
2526 self.assert_log_lines([])
2527
2528 def test_config1_ok(self, config=config1):
2529 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002530 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002531 self.apply_config(config)
2532 logger = logging.getLogger("compiler.parser")
2533 # Both will output a message
2534 logger.info(self.next_message())
2535 logger.error(self.next_message())
2536 self.assert_log_lines([
2537 ('INFO', '1'),
2538 ('ERROR', '2'),
2539 ], stream=output)
2540 # Original logger output is empty.
2541 self.assert_log_lines([])
2542
2543 def test_config2_failure(self):
2544 # A simple config which overrides the default settings.
2545 self.assertRaises(Exception, self.apply_config, self.config2)
2546
2547 def test_config2a_failure(self):
2548 # A simple config which overrides the default settings.
2549 self.assertRaises(Exception, self.apply_config, self.config2a)
2550
2551 def test_config2b_failure(self):
2552 # A simple config which overrides the default settings.
2553 self.assertRaises(Exception, self.apply_config, self.config2b)
2554
2555 def test_config3_failure(self):
2556 # A simple config which overrides the default settings.
2557 self.assertRaises(Exception, self.apply_config, self.config3)
2558
2559 def test_config4_ok(self):
2560 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002561 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002562 self.apply_config(self.config4)
2563 #logger = logging.getLogger()
2564 try:
2565 raise RuntimeError()
2566 except RuntimeError:
2567 logging.exception("just testing")
2568 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002569 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002570 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2571 # Original logger output is empty
2572 self.assert_log_lines([])
2573
2574 def test_config4a_ok(self):
2575 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002576 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002577 self.apply_config(self.config4a)
2578 #logger = logging.getLogger()
2579 try:
2580 raise RuntimeError()
2581 except RuntimeError:
2582 logging.exception("just testing")
2583 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002584 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002585 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2586 # Original logger output is empty
2587 self.assert_log_lines([])
2588
2589 def test_config5_ok(self):
2590 self.test_config1_ok(config=self.config5)
2591
2592 def test_config6_failure(self):
2593 self.assertRaises(Exception, self.apply_config, self.config6)
2594
2595 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002596 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002597 self.apply_config(self.config1)
2598 logger = logging.getLogger("compiler.parser")
2599 # Both will output a message
2600 logger.info(self.next_message())
2601 logger.error(self.next_message())
2602 self.assert_log_lines([
2603 ('INFO', '1'),
2604 ('ERROR', '2'),
2605 ], stream=output)
2606 # Original logger output is empty.
2607 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002608 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002609 self.apply_config(self.config7)
2610 logger = logging.getLogger("compiler.parser")
2611 self.assertTrue(logger.disabled)
2612 logger = logging.getLogger("compiler.lexer")
2613 # Both will output a message
2614 logger.info(self.next_message())
2615 logger.error(self.next_message())
2616 self.assert_log_lines([
2617 ('INFO', '3'),
2618 ('ERROR', '4'),
2619 ], stream=output)
2620 # Original logger output is empty.
2621 self.assert_log_lines([])
2622
2623 #Same as test_config_7_ok but don't disable old loggers.
2624 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002625 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002626 self.apply_config(self.config1)
2627 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002628 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002629 logger.info(self.next_message())
2630 logger.error(self.next_message())
2631 self.assert_log_lines([
2632 ('INFO', '1'),
2633 ('ERROR', '2'),
2634 ], stream=output)
2635 # Original logger output is empty.
2636 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002637 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002638 self.apply_config(self.config8)
2639 logger = logging.getLogger("compiler.parser")
2640 self.assertFalse(logger.disabled)
2641 # Both will output a message
2642 logger.info(self.next_message())
2643 logger.error(self.next_message())
2644 logger = logging.getLogger("compiler.lexer")
2645 # Both will output a message
2646 logger.info(self.next_message())
2647 logger.error(self.next_message())
2648 self.assert_log_lines([
2649 ('INFO', '3'),
2650 ('ERROR', '4'),
2651 ('INFO', '5'),
2652 ('ERROR', '6'),
2653 ], stream=output)
2654 # Original logger output is empty.
2655 self.assert_log_lines([])
2656
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002657 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002658 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002659 self.apply_config(self.config1a)
2660 logger = logging.getLogger("compiler.parser")
2661 # See issue #11424. compiler-hyphenated sorts
2662 # between compiler and compiler.xyz and this
2663 # was preventing compiler.xyz from being included
2664 # in the child loggers of compiler because of an
2665 # overzealous loop termination condition.
2666 hyphenated = logging.getLogger('compiler-hyphenated')
2667 # All will output a message
2668 logger.info(self.next_message())
2669 logger.error(self.next_message())
2670 hyphenated.critical(self.next_message())
2671 self.assert_log_lines([
2672 ('INFO', '1'),
2673 ('ERROR', '2'),
2674 ('CRITICAL', '3'),
2675 ], stream=output)
2676 # Original logger output is empty.
2677 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002678 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002679 self.apply_config(self.config8a)
2680 logger = logging.getLogger("compiler.parser")
2681 self.assertFalse(logger.disabled)
2682 # Both will output a message
2683 logger.info(self.next_message())
2684 logger.error(self.next_message())
2685 logger = logging.getLogger("compiler.lexer")
2686 # Both will output a message
2687 logger.info(self.next_message())
2688 logger.error(self.next_message())
2689 # Will not appear
2690 hyphenated.critical(self.next_message())
2691 self.assert_log_lines([
2692 ('INFO', '4'),
2693 ('ERROR', '5'),
2694 ('INFO', '6'),
2695 ('ERROR', '7'),
2696 ], stream=output)
2697 # Original logger output is empty.
2698 self.assert_log_lines([])
2699
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002700 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002701 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002702 self.apply_config(self.config9)
2703 logger = logging.getLogger("compiler.parser")
2704 #Nothing will be output since both handler and logger are set to WARNING
2705 logger.info(self.next_message())
2706 self.assert_log_lines([], stream=output)
2707 self.apply_config(self.config9a)
2708 #Nothing will be output since both handler is still set to WARNING
2709 logger.info(self.next_message())
2710 self.assert_log_lines([], stream=output)
2711 self.apply_config(self.config9b)
2712 #Message should now be output
2713 logger.info(self.next_message())
2714 self.assert_log_lines([
2715 ('INFO', '3'),
2716 ], stream=output)
2717
2718 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002719 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002720 self.apply_config(self.config10)
2721 logger = logging.getLogger("compiler.parser")
2722 logger.warning(self.next_message())
2723 logger = logging.getLogger('compiler')
2724 #Not output, because filtered
2725 logger.warning(self.next_message())
2726 logger = logging.getLogger('compiler.lexer')
2727 #Not output, because filtered
2728 logger.warning(self.next_message())
2729 logger = logging.getLogger("compiler.parser.codegen")
2730 #Output, as not filtered
2731 logger.error(self.next_message())
2732 self.assert_log_lines([
2733 ('WARNING', '1'),
2734 ('ERROR', '4'),
2735 ], stream=output)
2736
2737 def test_config11_ok(self):
2738 self.test_config1_ok(self.config11)
2739
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002740 def test_config12_failure(self):
2741 self.assertRaises(Exception, self.apply_config, self.config12)
2742
2743 def test_config13_failure(self):
2744 self.assertRaises(Exception, self.apply_config, self.config13)
2745
Vinay Sajip8d270232012-11-15 14:20:18 +00002746 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002747 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002748 self.apply_config(self.config14)
2749 h = logging._handlers['hand1']
2750 self.assertEqual(h.foo, 'bar')
2751 self.assertEqual(h.terminator, '!\n')
2752 logging.warning('Exclamation')
2753 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2754
Victor Stinner45df8202010-04-28 22:31:17 +00002755 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002756 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002757 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002758 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002759 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002760 t.start()
2761 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002762 # Now get the port allocated
2763 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002764 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002765 try:
2766 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2767 sock.settimeout(2.0)
2768 sock.connect(('localhost', port))
2769
2770 slen = struct.pack('>L', len(text))
2771 s = slen + text
2772 sentsofar = 0
2773 left = len(s)
2774 while left > 0:
2775 sent = sock.send(s[sentsofar:])
2776 sentsofar += sent
2777 left -= sent
2778 sock.close()
2779 finally:
2780 t.ready.wait(2.0)
2781 logging.config.stopListening()
2782 t.join(2.0)
2783
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002784 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002785 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002786 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002787 self.setup_via_listener(json.dumps(self.config10))
2788 logger = logging.getLogger("compiler.parser")
2789 logger.warning(self.next_message())
2790 logger = logging.getLogger('compiler')
2791 #Not output, because filtered
2792 logger.warning(self.next_message())
2793 logger = logging.getLogger('compiler.lexer')
2794 #Not output, because filtered
2795 logger.warning(self.next_message())
2796 logger = logging.getLogger("compiler.parser.codegen")
2797 #Output, as not filtered
2798 logger.error(self.next_message())
2799 self.assert_log_lines([
2800 ('WARNING', '1'),
2801 ('ERROR', '4'),
2802 ], stream=output)
2803
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002804 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002805 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002806 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002807 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2808 logger = logging.getLogger("compiler.parser")
2809 # Both will output a message
2810 logger.info(self.next_message())
2811 logger.error(self.next_message())
2812 self.assert_log_lines([
2813 ('INFO', '1'),
2814 ('ERROR', '2'),
2815 ], stream=output)
2816 # Original logger output is empty.
2817 self.assert_log_lines([])
2818
Vinay Sajip4ded5512012-10-02 15:56:16 +01002819 @unittest.skipUnless(threading, 'Threading required for this test.')
2820 def test_listen_verify(self):
2821
2822 def verify_fail(stuff):
2823 return None
2824
2825 def verify_reverse(stuff):
2826 return stuff[::-1]
2827
2828 logger = logging.getLogger("compiler.parser")
2829 to_send = textwrap.dedent(ConfigFileTest.config1)
2830 # First, specify a verification function that will fail.
2831 # We expect to see no output, since our configuration
2832 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002833 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002834 self.setup_via_listener(to_send, verify_fail)
2835 # Both will output a message
2836 logger.info(self.next_message())
2837 logger.error(self.next_message())
2838 self.assert_log_lines([], stream=output)
2839 # Original logger output has the stuff we logged.
2840 self.assert_log_lines([
2841 ('INFO', '1'),
2842 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002843 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002844
2845 # Now, perform no verification. Our configuration
2846 # should take effect.
2847
Vinay Sajip1feedb42014-05-31 08:19:12 +01002848 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002849 self.setup_via_listener(to_send) # no verify callable specified
2850 logger = logging.getLogger("compiler.parser")
2851 # Both will output a message
2852 logger.info(self.next_message())
2853 logger.error(self.next_message())
2854 self.assert_log_lines([
2855 ('INFO', '3'),
2856 ('ERROR', '4'),
2857 ], stream=output)
2858 # Original logger output still has the stuff we logged before.
2859 self.assert_log_lines([
2860 ('INFO', '1'),
2861 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002862 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002863
2864 # Now, perform verification which transforms the bytes.
2865
Vinay Sajip1feedb42014-05-31 08:19:12 +01002866 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002867 self.setup_via_listener(to_send[::-1], verify_reverse)
2868 logger = logging.getLogger("compiler.parser")
2869 # Both will output a message
2870 logger.info(self.next_message())
2871 logger.error(self.next_message())
2872 self.assert_log_lines([
2873 ('INFO', '5'),
2874 ('ERROR', '6'),
2875 ], stream=output)
2876 # Original logger output still has the stuff we logged before.
2877 self.assert_log_lines([
2878 ('INFO', '1'),
2879 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002880 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002881
Vinay Sajip3f885b52013-03-22 15:19:54 +00002882 def test_out_of_order(self):
2883 self.apply_config(self.out_of_order)
2884 handler = logging.getLogger('mymodule').handlers[0]
2885 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002886 self.assertIsInstance(handler.formatter._style,
2887 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002888
Vinay Sajip373baef2011-04-26 20:05:24 +01002889 def test_baseconfig(self):
2890 d = {
2891 'atuple': (1, 2, 3),
2892 'alist': ['a', 'b', 'c'],
2893 'adict': {'d': 'e', 'f': 3 },
2894 'nest1': ('g', ('h', 'i'), 'j'),
2895 'nest2': ['k', ['l', 'm'], 'n'],
2896 'nest3': ['o', 'cfg://alist', 'p'],
2897 }
2898 bc = logging.config.BaseConfigurator(d)
2899 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2900 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2901 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2902 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2903 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2904 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2905 v = bc.convert('cfg://nest3')
2906 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2907 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2908 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2909 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002910
2911class ManagerTest(BaseTest):
2912 def test_manager_loggerclass(self):
2913 logged = []
2914
2915 class MyLogger(logging.Logger):
2916 def _log(self, level, msg, args, exc_info=None, extra=None):
2917 logged.append(msg)
2918
2919 man = logging.Manager(None)
2920 self.assertRaises(TypeError, man.setLoggerClass, int)
2921 man.setLoggerClass(MyLogger)
2922 logger = man.getLogger('test')
2923 logger.warning('should appear in logged')
2924 logging.warning('should not appear in logged')
2925
2926 self.assertEqual(logged, ['should appear in logged'])
2927
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002928 def test_set_log_record_factory(self):
2929 man = logging.Manager(None)
2930 expected = object()
2931 man.setLogRecordFactory(expected)
2932 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002933
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002934class ChildLoggerTest(BaseTest):
2935 def test_child_loggers(self):
2936 r = logging.getLogger()
2937 l1 = logging.getLogger('abc')
2938 l2 = logging.getLogger('def.ghi')
2939 c1 = r.getChild('xyz')
2940 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002941 self.assertIs(c1, logging.getLogger('xyz'))
2942 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002943 c1 = l1.getChild('def')
2944 c2 = c1.getChild('ghi')
2945 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002946 self.assertIs(c1, logging.getLogger('abc.def'))
2947 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2948 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002949
2950
Vinay Sajip6fac8172010-10-19 20:44:14 +00002951class DerivedLogRecord(logging.LogRecord):
2952 pass
2953
Vinay Sajip61561522010-12-03 11:50:38 +00002954class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002955
2956 def setUp(self):
2957 class CheckingFilter(logging.Filter):
2958 def __init__(self, cls):
2959 self.cls = cls
2960
2961 def filter(self, record):
2962 t = type(record)
2963 if t is not self.cls:
2964 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2965 self.cls)
2966 raise TypeError(msg)
2967 return True
2968
2969 BaseTest.setUp(self)
2970 self.filter = CheckingFilter(DerivedLogRecord)
2971 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002972 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002973
2974 def tearDown(self):
2975 self.root_logger.removeFilter(self.filter)
2976 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002977 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002978
2979 def test_logrecord_class(self):
2980 self.assertRaises(TypeError, self.root_logger.warning,
2981 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002982 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002983 self.root_logger.error(self.next_message())
2984 self.assert_log_lines([
2985 ('root', 'ERROR', '2'),
2986 ])
2987
2988
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002989class QueueHandlerTest(BaseTest):
2990 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002991 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002992
2993 def setUp(self):
2994 BaseTest.setUp(self)
2995 self.queue = queue.Queue(-1)
2996 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2997 self.que_logger = logging.getLogger('que')
2998 self.que_logger.propagate = False
2999 self.que_logger.setLevel(logging.WARNING)
3000 self.que_logger.addHandler(self.que_hdlr)
3001
3002 def tearDown(self):
3003 self.que_hdlr.close()
3004 BaseTest.tearDown(self)
3005
3006 def test_queue_handler(self):
3007 self.que_logger.debug(self.next_message())
3008 self.assertRaises(queue.Empty, self.queue.get_nowait)
3009 self.que_logger.info(self.next_message())
3010 self.assertRaises(queue.Empty, self.queue.get_nowait)
3011 msg = self.next_message()
3012 self.que_logger.warning(msg)
3013 data = self.queue.get_nowait()
3014 self.assertTrue(isinstance(data, logging.LogRecord))
3015 self.assertEqual(data.name, self.que_logger.name)
3016 self.assertEqual((data.msg, data.args), (msg, None))
3017
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003018 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3019 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003020 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003021 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003022 listener = logging.handlers.QueueListener(self.queue, handler)
3023 listener.start()
3024 try:
3025 self.que_logger.warning(self.next_message())
3026 self.que_logger.error(self.next_message())
3027 self.que_logger.critical(self.next_message())
3028 finally:
3029 listener.stop()
3030 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3031 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3032 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3033
Vinay Sajip37eb3382011-04-26 20:26:41 +01003034ZERO = datetime.timedelta(0)
3035
3036class UTC(datetime.tzinfo):
3037 def utcoffset(self, dt):
3038 return ZERO
3039
3040 dst = utcoffset
3041
3042 def tzname(self, dt):
3043 return 'UTC'
3044
3045utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003046
Vinay Sajipa39c5712010-10-25 13:57:39 +00003047class FormatterTest(unittest.TestCase):
3048 def setUp(self):
3049 self.common = {
3050 'name': 'formatter.test',
3051 'level': logging.DEBUG,
3052 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3053 'lineno': 42,
3054 'exc_info': None,
3055 'func': None,
3056 'msg': 'Message with %d %s',
3057 'args': (2, 'placeholders'),
3058 }
3059 self.variants = {
3060 }
3061
3062 def get_record(self, name=None):
3063 result = dict(self.common)
3064 if name is not None:
3065 result.update(self.variants[name])
3066 return logging.makeLogRecord(result)
3067
3068 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003069 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003070 r = self.get_record()
3071 f = logging.Formatter('${%(message)s}')
3072 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3073 f = logging.Formatter('%(random)s')
3074 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003075 self.assertFalse(f.usesTime())
3076 f = logging.Formatter('%(asctime)s')
3077 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003078 f = logging.Formatter('%(asctime)-15s')
3079 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003080 f = logging.Formatter('asctime')
3081 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003082
3083 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003084 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003085 r = self.get_record()
3086 f = logging.Formatter('$%{message}%$', style='{')
3087 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3088 f = logging.Formatter('{random}', style='{')
3089 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003090 self.assertFalse(f.usesTime())
3091 f = logging.Formatter('{asctime}', style='{')
3092 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003093 f = logging.Formatter('{asctime!s:15}', style='{')
3094 self.assertTrue(f.usesTime())
3095 f = logging.Formatter('{asctime:15}', style='{')
3096 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003097 f = logging.Formatter('asctime', style='{')
3098 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003099
3100 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003101 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003102 r = self.get_record()
3103 f = logging.Formatter('$message', style='$')
3104 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3105 f = logging.Formatter('$$%${message}%$$', style='$')
3106 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3107 f = logging.Formatter('${random}', style='$')
3108 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003109 self.assertFalse(f.usesTime())
3110 f = logging.Formatter('${asctime}', style='$')
3111 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003112 f = logging.Formatter('${asctime', style='$')
3113 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003114 f = logging.Formatter('$asctime', style='$')
3115 self.assertTrue(f.usesTime())
3116 f = logging.Formatter('asctime', style='$')
3117 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003118
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003119 def test_invalid_style(self):
3120 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3121
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003122 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003123 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003124 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3125 # We use None to indicate we want the local timezone
3126 # We're essentially converting a UTC time to local time
3127 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003128 r.msecs = 123
3129 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003130 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003131 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3132 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003133 f.format(r)
3134 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3135
3136class TestBufferingFormatter(logging.BufferingFormatter):
3137 def formatHeader(self, records):
3138 return '[(%d)' % len(records)
3139
3140 def formatFooter(self, records):
3141 return '(%d)]' % len(records)
3142
3143class BufferingFormatterTest(unittest.TestCase):
3144 def setUp(self):
3145 self.records = [
3146 logging.makeLogRecord({'msg': 'one'}),
3147 logging.makeLogRecord({'msg': 'two'}),
3148 ]
3149
3150 def test_default(self):
3151 f = logging.BufferingFormatter()
3152 self.assertEqual('', f.format([]))
3153 self.assertEqual('onetwo', f.format(self.records))
3154
3155 def test_custom(self):
3156 f = TestBufferingFormatter()
3157 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3158 lf = logging.Formatter('<%(message)s>')
3159 f = TestBufferingFormatter(lf)
3160 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003161
3162class ExceptionTest(BaseTest):
3163 def test_formatting(self):
3164 r = self.root_logger
3165 h = RecordingHandler()
3166 r.addHandler(h)
3167 try:
3168 raise RuntimeError('deliberate mistake')
3169 except:
3170 logging.exception('failed', stack_info=True)
3171 r.removeHandler(h)
3172 h.close()
3173 r = h.records[0]
3174 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3175 'call last):\n'))
3176 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3177 'deliberate mistake'))
3178 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3179 'call last):\n'))
3180 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3181 'stack_info=True)'))
3182
3183
Vinay Sajip5a27d402010-12-10 11:42:57 +00003184class LastResortTest(BaseTest):
3185 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003186 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003187 root = self.root_logger
3188 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003189 old_lastresort = logging.lastResort
3190 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003191
Vinay Sajip5a27d402010-12-10 11:42:57 +00003192 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003193 with support.captured_stderr() as stderr:
3194 root.debug('This should not appear')
3195 self.assertEqual(stderr.getvalue(), '')
3196 root.warning('Final chance!')
3197 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3198
3199 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003200 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003201 with support.captured_stderr() as stderr:
3202 root.warning('Final chance!')
3203 msg = 'No handlers could be found for logger "root"\n'
3204 self.assertEqual(stderr.getvalue(), msg)
3205
Vinay Sajip5a27d402010-12-10 11:42:57 +00003206 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003207 with support.captured_stderr() as stderr:
3208 root.warning('Final chance!')
3209 self.assertEqual(stderr.getvalue(), '')
3210
3211 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003212 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003213 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003214 with support.captured_stderr() as stderr:
3215 root.warning('Final chance!')
3216 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003217 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003218 root.addHandler(self.root_hdlr)
3219 logging.lastResort = old_lastresort
3220 logging.raiseExceptions = old_raise_exceptions
3221
3222
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003223class FakeHandler:
3224
3225 def __init__(self, identifier, called):
3226 for method in ('acquire', 'flush', 'close', 'release'):
3227 setattr(self, method, self.record_call(identifier, method, called))
3228
3229 def record_call(self, identifier, method_name, called):
3230 def inner():
3231 called.append('{} - {}'.format(identifier, method_name))
3232 return inner
3233
3234
3235class RecordingHandler(logging.NullHandler):
3236
3237 def __init__(self, *args, **kwargs):
3238 super(RecordingHandler, self).__init__(*args, **kwargs)
3239 self.records = []
3240
3241 def handle(self, record):
3242 """Keep track of all the emitted records."""
3243 self.records.append(record)
3244
3245
3246class ShutdownTest(BaseTest):
3247
Vinay Sajip5e66b162011-04-20 15:41:14 +01003248 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003249
3250 def setUp(self):
3251 super(ShutdownTest, self).setUp()
3252 self.called = []
3253
3254 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003255 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003256
3257 def raise_error(self, error):
3258 def inner():
3259 raise error()
3260 return inner
3261
3262 def test_no_failure(self):
3263 # create some fake handlers
3264 handler0 = FakeHandler(0, self.called)
3265 handler1 = FakeHandler(1, self.called)
3266 handler2 = FakeHandler(2, self.called)
3267
3268 # create live weakref to those handlers
3269 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3270
3271 logging.shutdown(handlerList=list(handlers))
3272
3273 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3274 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3275 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3276 self.assertEqual(expected, self.called)
3277
3278 def _test_with_failure_in_method(self, method, error):
3279 handler = FakeHandler(0, self.called)
3280 setattr(handler, method, self.raise_error(error))
3281 handlers = [logging.weakref.ref(handler)]
3282
3283 logging.shutdown(handlerList=list(handlers))
3284
3285 self.assertEqual('0 - release', self.called[-1])
3286
3287 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003288 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003289
3290 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003291 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003292
3293 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003294 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003295
3296 def test_with_valueerror_in_acquire(self):
3297 self._test_with_failure_in_method('acquire', ValueError)
3298
3299 def test_with_valueerror_in_flush(self):
3300 self._test_with_failure_in_method('flush', ValueError)
3301
3302 def test_with_valueerror_in_close(self):
3303 self._test_with_failure_in_method('close', ValueError)
3304
3305 def test_with_other_error_in_acquire_without_raise(self):
3306 logging.raiseExceptions = False
3307 self._test_with_failure_in_method('acquire', IndexError)
3308
3309 def test_with_other_error_in_flush_without_raise(self):
3310 logging.raiseExceptions = False
3311 self._test_with_failure_in_method('flush', IndexError)
3312
3313 def test_with_other_error_in_close_without_raise(self):
3314 logging.raiseExceptions = False
3315 self._test_with_failure_in_method('close', IndexError)
3316
3317 def test_with_other_error_in_acquire_with_raise(self):
3318 logging.raiseExceptions = True
3319 self.assertRaises(IndexError, self._test_with_failure_in_method,
3320 'acquire', IndexError)
3321
3322 def test_with_other_error_in_flush_with_raise(self):
3323 logging.raiseExceptions = True
3324 self.assertRaises(IndexError, self._test_with_failure_in_method,
3325 'flush', IndexError)
3326
3327 def test_with_other_error_in_close_with_raise(self):
3328 logging.raiseExceptions = True
3329 self.assertRaises(IndexError, self._test_with_failure_in_method,
3330 'close', IndexError)
3331
3332
3333class ModuleLevelMiscTest(BaseTest):
3334
Vinay Sajip5e66b162011-04-20 15:41:14 +01003335 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003336
3337 def test_disable(self):
3338 old_disable = logging.root.manager.disable
3339 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003340 self.assertEqual(old_disable, 0)
3341 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003342
3343 logging.disable(83)
3344 self.assertEqual(logging.root.manager.disable, 83)
3345
3346 def _test_log(self, method, level=None):
3347 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003348 support.patch(self, logging, 'basicConfig',
3349 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003350
3351 recording = RecordingHandler()
3352 logging.root.addHandler(recording)
3353
3354 log_method = getattr(logging, method)
3355 if level is not None:
3356 log_method(level, "test me: %r", recording)
3357 else:
3358 log_method("test me: %r", recording)
3359
3360 self.assertEqual(len(recording.records), 1)
3361 record = recording.records[0]
3362 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3363
3364 expected_level = level if level is not None else getattr(logging, method.upper())
3365 self.assertEqual(record.levelno, expected_level)
3366
3367 # basicConfig was not called!
3368 self.assertEqual(called, [])
3369
3370 def test_log(self):
3371 self._test_log('log', logging.ERROR)
3372
3373 def test_debug(self):
3374 self._test_log('debug')
3375
3376 def test_info(self):
3377 self._test_log('info')
3378
3379 def test_warning(self):
3380 self._test_log('warning')
3381
3382 def test_error(self):
3383 self._test_log('error')
3384
3385 def test_critical(self):
3386 self._test_log('critical')
3387
3388 def test_set_logger_class(self):
3389 self.assertRaises(TypeError, logging.setLoggerClass, object)
3390
3391 class MyLogger(logging.Logger):
3392 pass
3393
3394 logging.setLoggerClass(MyLogger)
3395 self.assertEqual(logging.getLoggerClass(), MyLogger)
3396
3397 logging.setLoggerClass(logging.Logger)
3398 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3399
Antoine Pitrou712cb732013-12-21 15:51:54 +01003400 def test_logging_at_shutdown(self):
3401 # Issue #20037
3402 code = """if 1:
3403 import logging
3404
3405 class A:
3406 def __del__(self):
3407 try:
3408 raise ValueError("some error")
3409 except Exception:
3410 logging.exception("exception in __del__")
3411
3412 a = A()"""
3413 rc, out, err = assert_python_ok("-c", code)
3414 err = err.decode()
3415 self.assertIn("exception in __del__", err)
3416 self.assertIn("ValueError: some error", err)
3417
3418
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003419class LogRecordTest(BaseTest):
3420 def test_str_rep(self):
3421 r = logging.makeLogRecord({})
3422 s = str(r)
3423 self.assertTrue(s.startswith('<LogRecord: '))
3424 self.assertTrue(s.endswith('>'))
3425
3426 def test_dict_arg(self):
3427 h = RecordingHandler()
3428 r = logging.getLogger()
3429 r.addHandler(h)
3430 d = {'less' : 'more' }
3431 logging.warning('less is %(less)s', d)
3432 self.assertIs(h.records[0].args, d)
3433 self.assertEqual(h.records[0].message, 'less is more')
3434 r.removeHandler(h)
3435 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003436
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003437 def test_multiprocessing(self):
3438 r = logging.makeLogRecord({})
3439 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003440 try:
3441 import multiprocessing as mp
3442 r = logging.makeLogRecord({})
3443 self.assertEqual(r.processName, mp.current_process().name)
3444 except ImportError:
3445 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003446
3447 def test_optional(self):
3448 r = logging.makeLogRecord({})
3449 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003450 if threading:
3451 NOT_NONE(r.thread)
3452 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003453 NOT_NONE(r.process)
3454 NOT_NONE(r.processName)
3455 log_threads = logging.logThreads
3456 log_processes = logging.logProcesses
3457 log_multiprocessing = logging.logMultiprocessing
3458 try:
3459 logging.logThreads = False
3460 logging.logProcesses = False
3461 logging.logMultiprocessing = False
3462 r = logging.makeLogRecord({})
3463 NONE = self.assertIsNone
3464 NONE(r.thread)
3465 NONE(r.threadName)
3466 NONE(r.process)
3467 NONE(r.processName)
3468 finally:
3469 logging.logThreads = log_threads
3470 logging.logProcesses = log_processes
3471 logging.logMultiprocessing = log_multiprocessing
3472
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003473class BasicConfigTest(unittest.TestCase):
3474
Vinay Sajip95bf5042011-04-20 11:50:56 +01003475 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003476
3477 def setUp(self):
3478 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003479 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003480 self.saved_handlers = logging._handlers.copy()
3481 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003482 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003483 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003484 logging.root.handlers = []
3485
3486 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003487 for h in logging.root.handlers[:]:
3488 logging.root.removeHandler(h)
3489 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003490 super(BasicConfigTest, self).tearDown()
3491
Vinay Sajip3def7e02011-04-20 10:58:06 +01003492 def cleanup(self):
3493 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003494 logging._handlers.clear()
3495 logging._handlers.update(self.saved_handlers)
3496 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003497 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003498
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003499 def test_no_kwargs(self):
3500 logging.basicConfig()
3501
3502 # handler defaults to a StreamHandler to sys.stderr
3503 self.assertEqual(len(logging.root.handlers), 1)
3504 handler = logging.root.handlers[0]
3505 self.assertIsInstance(handler, logging.StreamHandler)
3506 self.assertEqual(handler.stream, sys.stderr)
3507
3508 formatter = handler.formatter
3509 # format defaults to logging.BASIC_FORMAT
3510 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3511 # datefmt defaults to None
3512 self.assertIsNone(formatter.datefmt)
3513 # style defaults to %
3514 self.assertIsInstance(formatter._style, logging.PercentStyle)
3515
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003516 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003517 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518
Vinay Sajip1fd12022014-01-13 21:59:56 +00003519 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003520 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003521 logging.basicConfig(stream=sys.stdout, style="{")
3522 logging.error("Log an error")
3523 sys.stdout.seek(0)
3524 self.assertEqual(output.getvalue().strip(),
3525 "ERROR:root:Log an error")
3526
3527 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003528 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003529 logging.basicConfig(stream=sys.stdout, style="$")
3530 logging.error("Log an error")
3531 sys.stdout.seek(0)
3532 self.assertEqual(output.getvalue().strip(),
3533 "ERROR:root:Log an error")
3534
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003535 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003536
3537 def cleanup(h1, h2, fn):
3538 h1.close()
3539 h2.close()
3540 os.remove(fn)
3541
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003542 logging.basicConfig(filename='test.log')
3543
3544 self.assertEqual(len(logging.root.handlers), 1)
3545 handler = logging.root.handlers[0]
3546 self.assertIsInstance(handler, logging.FileHandler)
3547
3548 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003549 self.assertEqual(handler.stream.mode, expected.stream.mode)
3550 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003551 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003552
3553 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003554
3555 def cleanup(h1, h2, fn):
3556 h1.close()
3557 h2.close()
3558 os.remove(fn)
3559
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003560 logging.basicConfig(filename='test.log', filemode='wb')
3561
3562 handler = logging.root.handlers[0]
3563 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003564 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003565 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003566
3567 def test_stream(self):
3568 stream = io.StringIO()
3569 self.addCleanup(stream.close)
3570 logging.basicConfig(stream=stream)
3571
3572 self.assertEqual(len(logging.root.handlers), 1)
3573 handler = logging.root.handlers[0]
3574 self.assertIsInstance(handler, logging.StreamHandler)
3575 self.assertEqual(handler.stream, stream)
3576
3577 def test_format(self):
3578 logging.basicConfig(format='foo')
3579
3580 formatter = logging.root.handlers[0].formatter
3581 self.assertEqual(formatter._style._fmt, 'foo')
3582
3583 def test_datefmt(self):
3584 logging.basicConfig(datefmt='bar')
3585
3586 formatter = logging.root.handlers[0].formatter
3587 self.assertEqual(formatter.datefmt, 'bar')
3588
3589 def test_style(self):
3590 logging.basicConfig(style='$')
3591
3592 formatter = logging.root.handlers[0].formatter
3593 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3594
3595 def test_level(self):
3596 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003597 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003598
3599 logging.basicConfig(level=57)
3600 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003601 # Test that second call has no effect
3602 logging.basicConfig(level=58)
3603 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003604
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003605 def test_incompatible(self):
3606 assertRaises = self.assertRaises
3607 handlers = [logging.StreamHandler()]
3608 stream = sys.stderr
3609 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3610 stream=stream)
3611 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3612 handlers=handlers)
3613 assertRaises(ValueError, logging.basicConfig, stream=stream,
3614 handlers=handlers)
3615
3616 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003617 handlers = [
3618 logging.StreamHandler(),
3619 logging.StreamHandler(sys.stdout),
3620 logging.StreamHandler(),
3621 ]
3622 f = logging.Formatter()
3623 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003624 logging.basicConfig(handlers=handlers)
3625 self.assertIs(handlers[0], logging.root.handlers[0])
3626 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003627 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003628 self.assertIsNotNone(handlers[0].formatter)
3629 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003630 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003631 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3632
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003633 def _test_log(self, method, level=None):
3634 # logging.root has no handlers so basicConfig should be called
3635 called = []
3636
3637 old_basic_config = logging.basicConfig
3638 def my_basic_config(*a, **kw):
3639 old_basic_config()
3640 old_level = logging.root.level
3641 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003642 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003643 called.append((a, kw))
3644
Vinay Sajip1feedb42014-05-31 08:19:12 +01003645 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003646
3647 log_method = getattr(logging, method)
3648 if level is not None:
3649 log_method(level, "test me")
3650 else:
3651 log_method("test me")
3652
3653 # basicConfig was called with no arguments
3654 self.assertEqual(called, [((), {})])
3655
3656 def test_log(self):
3657 self._test_log('log', logging.WARNING)
3658
3659 def test_debug(self):
3660 self._test_log('debug')
3661
3662 def test_info(self):
3663 self._test_log('info')
3664
3665 def test_warning(self):
3666 self._test_log('warning')
3667
3668 def test_error(self):
3669 self._test_log('error')
3670
3671 def test_critical(self):
3672 self._test_log('critical')
3673
3674
3675class LoggerAdapterTest(unittest.TestCase):
3676
3677 def setUp(self):
3678 super(LoggerAdapterTest, self).setUp()
3679 old_handler_list = logging._handlerList[:]
3680
3681 self.recording = RecordingHandler()
3682 self.logger = logging.root
3683 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003684 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003685 self.addCleanup(self.recording.close)
3686
3687 def cleanup():
3688 logging._handlerList[:] = old_handler_list
3689
3690 self.addCleanup(cleanup)
3691 self.addCleanup(logging.shutdown)
3692 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3693
3694 def test_exception(self):
3695 msg = 'testing exception: %r'
3696 exc = None
3697 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003698 1 / 0
3699 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003700 exc = e
3701 self.adapter.exception(msg, self.recording)
3702
3703 self.assertEqual(len(self.recording.records), 1)
3704 record = self.recording.records[0]
3705 self.assertEqual(record.levelno, logging.ERROR)
3706 self.assertEqual(record.msg, msg)
3707 self.assertEqual(record.args, (self.recording,))
3708 self.assertEqual(record.exc_info,
3709 (exc.__class__, exc, exc.__traceback__))
3710
3711 def test_critical(self):
3712 msg = 'critical test! %r'
3713 self.adapter.critical(msg, self.recording)
3714
3715 self.assertEqual(len(self.recording.records), 1)
3716 record = self.recording.records[0]
3717 self.assertEqual(record.levelno, logging.CRITICAL)
3718 self.assertEqual(record.msg, msg)
3719 self.assertEqual(record.args, (self.recording,))
3720
3721 def test_is_enabled_for(self):
3722 old_disable = self.adapter.logger.manager.disable
3723 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003724 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3725 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003726 self.assertFalse(self.adapter.isEnabledFor(32))
3727
3728 def test_has_handlers(self):
3729 self.assertTrue(self.adapter.hasHandlers())
3730
3731 for handler in self.logger.handlers:
3732 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003733
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003734 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003735 self.assertFalse(self.adapter.hasHandlers())
3736
3737
3738class LoggerTest(BaseTest):
3739
3740 def setUp(self):
3741 super(LoggerTest, self).setUp()
3742 self.recording = RecordingHandler()
3743 self.logger = logging.Logger(name='blah')
3744 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003745 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003746 self.addCleanup(self.recording.close)
3747 self.addCleanup(logging.shutdown)
3748
3749 def test_set_invalid_level(self):
3750 self.assertRaises(TypeError, self.logger.setLevel, object())
3751
3752 def test_exception(self):
3753 msg = 'testing exception: %r'
3754 exc = None
3755 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003756 1 / 0
3757 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003758 exc = e
3759 self.logger.exception(msg, self.recording)
3760
3761 self.assertEqual(len(self.recording.records), 1)
3762 record = self.recording.records[0]
3763 self.assertEqual(record.levelno, logging.ERROR)
3764 self.assertEqual(record.msg, msg)
3765 self.assertEqual(record.args, (self.recording,))
3766 self.assertEqual(record.exc_info,
3767 (exc.__class__, exc, exc.__traceback__))
3768
3769 def test_log_invalid_level_with_raise(self):
3770 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003771 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003772
3773 logging.raiseExceptions = True
3774 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3775
3776 def test_log_invalid_level_no_raise(self):
3777 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003778 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003779
3780 logging.raiseExceptions = False
3781 self.logger.log('10', 'test message') # no exception happens
3782
3783 def test_find_caller_with_stack_info(self):
3784 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003785 support.patch(self, logging.traceback, 'print_stack',
3786 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003787
3788 self.logger.findCaller(stack_info=True)
3789
3790 self.assertEqual(len(called), 1)
3791 self.assertEqual('Stack (most recent call last):\n', called[0])
3792
3793 def test_make_record_with_extra_overwrite(self):
3794 name = 'my record'
3795 level = 13
3796 fn = lno = msg = args = exc_info = func = sinfo = None
3797 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3798 exc_info, func, sinfo)
3799
3800 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3801 extra = {key: 'some value'}
3802 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3803 fn, lno, msg, args, exc_info,
3804 extra=extra, sinfo=sinfo)
3805
3806 def test_make_record_with_extra_no_overwrite(self):
3807 name = 'my record'
3808 level = 13
3809 fn = lno = msg = args = exc_info = func = sinfo = None
3810 extra = {'valid_key': 'some value'}
3811 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3812 exc_info, extra=extra, sinfo=sinfo)
3813 self.assertIn('valid_key', result.__dict__)
3814
3815 def test_has_handlers(self):
3816 self.assertTrue(self.logger.hasHandlers())
3817
3818 for handler in self.logger.handlers:
3819 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003820 self.assertFalse(self.logger.hasHandlers())
3821
3822 def test_has_handlers_no_propagate(self):
3823 child_logger = logging.getLogger('blah.child')
3824 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825 self.assertFalse(child_logger.hasHandlers())
3826
3827 def test_is_enabled_for(self):
3828 old_disable = self.logger.manager.disable
3829 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003830 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003831 self.assertFalse(self.logger.isEnabledFor(22))
3832
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003833 def test_root_logger_aliases(self):
3834 root = logging.getLogger()
3835 self.assertIs(root, logging.root)
3836 self.assertIs(root, logging.getLogger(None))
3837 self.assertIs(root, logging.getLogger(''))
3838 self.assertIs(root, logging.getLogger('foo').root)
3839 self.assertIs(root, logging.getLogger('foo.bar').root)
3840 self.assertIs(root, logging.getLogger('foo').parent)
3841
3842 self.assertIsNot(root, logging.getLogger('\0'))
3843 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3844
3845 def test_invalid_names(self):
3846 self.assertRaises(TypeError, logging.getLogger, any)
3847 self.assertRaises(TypeError, logging.getLogger, b'foo')
3848
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003849
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003850class BaseFileTest(BaseTest):
3851 "Base class for handler tests that write log files"
3852
3853 def setUp(self):
3854 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003855 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3856 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003857 self.rmfiles = []
3858
3859 def tearDown(self):
3860 for fn in self.rmfiles:
3861 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003862 if os.path.exists(self.fn):
3863 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003864 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003865
3866 def assertLogFile(self, filename):
3867 "Assert a log file is there and register it for deletion"
3868 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003869 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003870 self.rmfiles.append(filename)
3871
3872
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003873class FileHandlerTest(BaseFileTest):
3874 def test_delay(self):
3875 os.unlink(self.fn)
3876 fh = logging.FileHandler(self.fn, delay=True)
3877 self.assertIsNone(fh.stream)
3878 self.assertFalse(os.path.exists(self.fn))
3879 fh.handle(logging.makeLogRecord({}))
3880 self.assertIsNotNone(fh.stream)
3881 self.assertTrue(os.path.exists(self.fn))
3882 fh.close()
3883
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003884class RotatingFileHandlerTest(BaseFileTest):
3885 def next_rec(self):
3886 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3887 self.next_message(), None, None, None)
3888
3889 def test_should_not_rollover(self):
3890 # If maxbytes is zero rollover never occurs
3891 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3892 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003893 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003894
3895 def test_should_rollover(self):
3896 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3897 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003898 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003899
3900 def test_file_created(self):
3901 # checks that the file is created and assumes it was created
3902 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003903 rh = logging.handlers.RotatingFileHandler(self.fn)
3904 rh.emit(self.next_rec())
3905 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003906 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003907
3908 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003909 def namer(name):
3910 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003911 rh = logging.handlers.RotatingFileHandler(
3912 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003913 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003914 rh.emit(self.next_rec())
3915 self.assertLogFile(self.fn)
3916 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003917 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003918 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003919 self.assertLogFile(namer(self.fn + ".2"))
3920 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3921 rh.close()
3922
Vinay Sajip1feedb42014-05-31 08:19:12 +01003923 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003924 def test_rotator(self):
3925 def namer(name):
3926 return name + ".gz"
3927
3928 def rotator(source, dest):
3929 with open(source, "rb") as sf:
3930 data = sf.read()
3931 compressed = zlib.compress(data, 9)
3932 with open(dest, "wb") as df:
3933 df.write(compressed)
3934 os.remove(source)
3935
3936 rh = logging.handlers.RotatingFileHandler(
3937 self.fn, backupCount=2, maxBytes=1)
3938 rh.rotator = rotator
3939 rh.namer = namer
3940 m1 = self.next_rec()
3941 rh.emit(m1)
3942 self.assertLogFile(self.fn)
3943 m2 = self.next_rec()
3944 rh.emit(m2)
3945 fn = namer(self.fn + ".1")
3946 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003947 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003948 with open(fn, "rb") as f:
3949 compressed = f.read()
3950 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003951 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003952 rh.emit(self.next_rec())
3953 fn = namer(self.fn + ".2")
3954 self.assertLogFile(fn)
3955 with open(fn, "rb") as f:
3956 compressed = f.read()
3957 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003958 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003959 rh.emit(self.next_rec())
3960 fn = namer(self.fn + ".2")
3961 with open(fn, "rb") as f:
3962 compressed = f.read()
3963 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003964 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003965 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003966 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003967
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003968class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003969 # other test methods added below
3970 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003971 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3972 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003973 fmt = logging.Formatter('%(asctime)s %(message)s')
3974 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003975 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003976 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003977 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003978 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003979 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003980 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003981 fh.close()
3982 # At this point, we should have a recent rotated file which we
3983 # can test for the existence of. However, in practice, on some
3984 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003985 # in time to go to look for the log file. So, we go back a fair
3986 # bit, and stop as soon as we see a rotated file. In theory this
3987 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003988 found = False
3989 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003990 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003991 for secs in range(GO_BACK):
3992 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003993 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3994 found = os.path.exists(fn)
3995 if found:
3996 self.rmfiles.append(fn)
3997 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003998 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3999 if not found:
4000 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004001 dn, fn = os.path.split(self.fn)
4002 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004003 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4004 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004005 for f in files:
4006 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004007 path = os.path.join(dn, f)
4008 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004009 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004010 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004011
Vinay Sajip0372e102011-05-05 12:59:14 +01004012 def test_invalid(self):
4013 assertRaises = self.assertRaises
4014 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004015 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004016 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004017 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004018 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004019 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004020
Vinay Sajipa7130792013-04-12 17:04:23 +01004021 def test_compute_rollover_daily_attime(self):
4022 currentTime = 0
4023 atTime = datetime.time(12, 0, 0)
4024 rh = logging.handlers.TimedRotatingFileHandler(
4025 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4026 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004027 try:
4028 actual = rh.computeRollover(currentTime)
4029 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004030
Vinay Sajipd86ac962013-04-14 12:20:46 +01004031 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4032 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4033 finally:
4034 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004035
Vinay Sajip10e8c492013-05-18 10:19:54 -07004036 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004037 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004038 currentTime = int(time.time())
4039 today = currentTime - currentTime % 86400
4040
Vinay Sajipa7130792013-04-12 17:04:23 +01004041 atTime = datetime.time(12, 0, 0)
4042
Vinay Sajip10e8c492013-05-18 10:19:54 -07004043 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004044 for day in range(7):
4045 rh = logging.handlers.TimedRotatingFileHandler(
4046 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4047 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004048 try:
4049 if wday > day:
4050 # The rollover day has already passed this week, so we
4051 # go over into next week
4052 expected = (7 - wday + day)
4053 else:
4054 expected = (day - wday)
4055 # At this point expected is in days from now, convert to seconds
4056 expected *= 24 * 60 * 60
4057 # Add in the rollover time
4058 expected += 12 * 60 * 60
4059 # Add in adjustment for today
4060 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004061 actual = rh.computeRollover(today)
4062 if actual != expected:
4063 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004064 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004065 self.assertEqual(actual, expected)
4066 if day == wday:
4067 # goes into following week
4068 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004069 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004070 if actual != expected:
4071 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004072 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004073 self.assertEqual(actual, expected)
4074 finally:
4075 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004076
4077
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004078def secs(**kw):
4079 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4080
4081for when, exp in (('S', 1),
4082 ('M', 60),
4083 ('H', 60 * 60),
4084 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004085 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004086 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004087 ('W0', secs(days=4, hours=24)),
4088 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004089 def test_compute_rollover(self, when=when, exp=exp):
4090 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004091 self.fn, when=when, interval=1, backupCount=0, utc=True)
4092 currentTime = 0.0
4093 actual = rh.computeRollover(currentTime)
4094 if exp != actual:
4095 # Failures occur on some systems for MIDNIGHT and W0.
4096 # Print detailed calculation for MIDNIGHT so we can try to see
4097 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004098 if when == 'MIDNIGHT':
4099 try:
4100 if rh.utc:
4101 t = time.gmtime(currentTime)
4102 else:
4103 t = time.localtime(currentTime)
4104 currentHour = t[3]
4105 currentMinute = t[4]
4106 currentSecond = t[5]
4107 # r is the number of seconds left between now and midnight
4108 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4109 currentMinute) * 60 +
4110 currentSecond)
4111 result = currentTime + r
4112 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4113 print('currentHour: %s' % currentHour, file=sys.stderr)
4114 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4115 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4116 print('r: %s' % r, file=sys.stderr)
4117 print('result: %s' % result, file=sys.stderr)
4118 except Exception:
4119 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4120 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004121 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004122 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4123
Vinay Sajip60ccd822011-05-09 17:32:09 +01004124
4125@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4126class NTEventLogHandlerTest(BaseTest):
4127 def test_basic(self):
4128 logtype = 'Application'
4129 elh = win32evtlog.OpenEventLog(None, logtype)
4130 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4131 h = logging.handlers.NTEventLogHandler('test_logging')
4132 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4133 h.handle(r)
4134 h.close()
4135 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004136 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004137 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4138 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4139 found = False
4140 GO_BACK = 100
4141 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4142 for e in events:
4143 if e.SourceName != 'test_logging':
4144 continue
4145 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4146 if msg != 'Test Log Message\r\n':
4147 continue
4148 found = True
4149 break
4150 msg = 'Record not found in event log, went back %d records' % GO_BACK
4151 self.assertTrue(found, msg=msg)
4152
Christian Heimes180510d2008-03-03 19:15:45 +00004153# Set the locale to the platform-dependent default. I have no idea
4154# why the test does this, but in any case we save the current locale
4155# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004156@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004157def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004158 support.run_unittest(
4159 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4160 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4161 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4162 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4163 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4164 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4165 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4166 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4167 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4168 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
4169 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004170
Christian Heimes180510d2008-03-03 19:15:45 +00004171if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004172 test_main()