blob: f89587844d4635eb43594b96ca33856a3502fcac [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):
Vinay Sajip30298b42013-06-07 15:21:41 +0100682 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
683 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100684 self._handler = handler
685 self._thread = None
686 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100687
Vinay Sajipce7c9782011-05-17 07:15:53 +0100688 def process_message(self, peer, mailfrom, rcpttos, data):
689 """
690 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100691
Vinay Sajipce7c9782011-05-17 07:15:53 +0100692 Typically, this will be a test case method.
693 :param peer: The client (host, port) tuple.
694 :param mailfrom: The address of the sender.
695 :param rcpttos: The addresses of the recipients.
696 :param data: The message.
697 """
698 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100699
Vinay Sajipce7c9782011-05-17 07:15:53 +0100700 def start(self):
701 """
702 Start the server running on a separate daemon thread.
703 """
704 self._thread = t = threading.Thread(target=self.serve_forever,
705 args=(self.poll_interval,))
706 t.setDaemon(True)
707 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100708
Vinay Sajipce7c9782011-05-17 07:15:53 +0100709 def serve_forever(self, poll_interval):
710 """
711 Run the :mod:`asyncore` loop until normal termination
712 conditions arise.
713 :param poll_interval: The interval, in seconds, used in the underlying
714 :func:`select` or :func:`poll` call by
715 :func:`asyncore.loop`.
716 """
717 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100718 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200719 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100720 # On FreeBSD 8, closing the server repeatably
721 # raises this error. We swallow it if the
722 # server has been closed.
723 if self.connected or self.accepting:
724 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100725
Vinay Sajipce7c9782011-05-17 07:15:53 +0100726 def stop(self, timeout=None):
727 """
728 Stop the thread by closing the server instance.
729 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100730
Vinay Sajipce7c9782011-05-17 07:15:53 +0100731 :param timeout: How long to wait for the server thread
732 to terminate.
733 """
734 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100735 self._thread.join(timeout)
736 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100737
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 class ControlMixin(object):
739 """
740 This mixin is used to start a server on a separate thread, and
741 shut it down programmatically. Request handling is simplified - instead
742 of needing to derive a suitable RequestHandler subclass, you just
743 provide a callable which will be passed each received request to be
744 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100745
Vinay Sajipce7c9782011-05-17 07:15:53 +0100746 :param handler: A handler callable which will be called with a
747 single parameter - the request - in order to
748 process the request. This handler is called on the
749 server thread, effectively meaning that requests are
750 processed serially. While not quite Web scale ;-),
751 this should be fine for testing applications.
752 :param poll_interval: The polling interval in seconds.
753 """
754 def __init__(self, handler, poll_interval):
755 self._thread = None
756 self.poll_interval = poll_interval
757 self._handler = handler
758 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100759
Vinay Sajipce7c9782011-05-17 07:15:53 +0100760 def start(self):
761 """
762 Create a daemon thread to run the server, and start it.
763 """
764 self._thread = t = threading.Thread(target=self.serve_forever,
765 args=(self.poll_interval,))
766 t.setDaemon(True)
767 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100768
Vinay Sajipce7c9782011-05-17 07:15:53 +0100769 def serve_forever(self, poll_interval):
770 """
771 Run the server. Set the ready flag before entering the
772 service loop.
773 """
774 self.ready.set()
775 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100776
Vinay Sajipce7c9782011-05-17 07:15:53 +0100777 def stop(self, timeout=None):
778 """
779 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100780
Vinay Sajipce7c9782011-05-17 07:15:53 +0100781 :param timeout: How long to wait for the server thread
782 to terminate.
783 """
784 self.shutdown()
785 if self._thread is not None:
786 self._thread.join(timeout)
787 self._thread = None
788 self.server_close()
789 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100790
Vinay Sajipce7c9782011-05-17 07:15:53 +0100791 class TestHTTPServer(ControlMixin, HTTPServer):
792 """
793 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100794
Vinay Sajipce7c9782011-05-17 07:15:53 +0100795 :param addr: A tuple with the IP address and port to listen on.
796 :param handler: A handler callable which will be called with a
797 single parameter - the request - in order to
798 process the request.
799 :param poll_interval: The polling interval in seconds.
800 :param log: Pass ``True`` to enable log messages.
801 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100802 def __init__(self, addr, handler, poll_interval=0.5,
803 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100804 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
805 def __getattr__(self, name, default=None):
806 if name.startswith('do_'):
807 return self.process_request
808 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100809
Vinay Sajipce7c9782011-05-17 07:15:53 +0100810 def process_request(self):
811 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100812
Vinay Sajipce7c9782011-05-17 07:15:53 +0100813 def log_message(self, format, *args):
814 if log:
815 super(DelegatingHTTPRequestHandler,
816 self).log_message(format, *args)
817 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
818 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100819 self.sslctx = sslctx
820
821 def get_request(self):
822 try:
823 sock, addr = self.socket.accept()
824 if self.sslctx:
825 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200826 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100827 # socket errors are silenced by the caller, print them here
828 sys.stderr.write("Got an error:\n%s\n" % e)
829 raise
830 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100831
Vinay Sajipce7c9782011-05-17 07:15:53 +0100832 class TestTCPServer(ControlMixin, ThreadingTCPServer):
833 """
834 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100835
Vinay Sajipce7c9782011-05-17 07:15:53 +0100836 :param addr: A tuple with the IP address and port to listen on.
837 :param handler: A handler callable which will be called with a single
838 parameter - the request - in order to process the request.
839 :param poll_interval: The polling interval in seconds.
840 :bind_and_activate: If True (the default), binds the server and starts it
841 listening. If False, you need to call
842 :meth:`server_bind` and :meth:`server_activate` at
843 some later time before calling :meth:`start`, so that
844 the server will set up the socket and listen on it.
845 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100846
Vinay Sajipce7c9782011-05-17 07:15:53 +0100847 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100848
Vinay Sajipce7c9782011-05-17 07:15:53 +0100849 def __init__(self, addr, handler, poll_interval=0.5,
850 bind_and_activate=True):
851 class DelegatingTCPRequestHandler(StreamRequestHandler):
852
853 def handle(self):
854 self.server._handler(self)
855 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
856 bind_and_activate)
857 ControlMixin.__init__(self, handler, poll_interval)
858
859 def server_bind(self):
860 super(TestTCPServer, self).server_bind()
861 self.port = self.socket.getsockname()[1]
862
Vinay Sajip5421f352013-09-27 18:18:28 +0100863 class TestUnixStreamServer(TestTCPServer):
864 address_family = socket.AF_UNIX
865
Vinay Sajipce7c9782011-05-17 07:15:53 +0100866 class TestUDPServer(ControlMixin, ThreadingUDPServer):
867 """
868 A UDP server which is controllable using :class:`ControlMixin`.
869
870 :param addr: A tuple with the IP address and port to listen on.
871 :param handler: A handler callable which will be called with a
872 single parameter - the request - in order to
873 process the request.
874 :param poll_interval: The polling interval for shutdown requests,
875 in seconds.
876 :bind_and_activate: If True (the default), binds the server and
877 starts it listening. If False, you need to
878 call :meth:`server_bind` and
879 :meth:`server_activate` at some later time
880 before calling :meth:`start`, so that the server will
881 set up the socket and listen on it.
882 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100883 def __init__(self, addr, handler, poll_interval=0.5,
884 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100885 class DelegatingUDPRequestHandler(DatagramRequestHandler):
886
887 def handle(self):
888 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100889
890 def finish(self):
891 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100892 if data:
893 try:
894 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200895 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100896 if not self.server._closed:
897 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100898
Vinay Sajip3ef12292011-05-23 23:00:42 +0100899 ThreadingUDPServer.__init__(self, addr,
900 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100901 bind_and_activate)
902 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100903 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100904
905 def server_bind(self):
906 super(TestUDPServer, self).server_bind()
907 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100908
Vinay Sajipba980db2011-05-23 21:37:54 +0100909 def server_close(self):
910 super(TestUDPServer, self).server_close()
911 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100912
Vinay Sajip5421f352013-09-27 18:18:28 +0100913 class TestUnixDatagramServer(TestUDPServer):
914 address_family = socket.AF_UNIX
915
Vinay Sajip7367d082011-05-02 13:17:27 +0100916# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100917
Vinay Sajipce7c9782011-05-17 07:15:53 +0100918@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100919class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000920 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100921 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100922 sockmap = {}
923 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
924 sockmap)
925 server.start()
926 addr = ('localhost', server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000927 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
928 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100929 self.assertEqual(h.toaddrs, ['you'])
930 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100932 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100933 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000934 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000936 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 self.assertEqual(len(self.messages), 1)
938 peer, mailfrom, rcpttos, data = self.messages[0]
939 self.assertEqual(mailfrom, 'me')
940 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100941 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100942 self.assertTrue(data.endswith('\n\nHello'))
943 h.close()
944
945 def process_message(self, *args):
946 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100947 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100948
Christian Heimes180510d2008-03-03 19:15:45 +0000949class MemoryHandlerTest(BaseTest):
950
951 """Tests for the MemoryHandler."""
952
953 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300954 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000955
956 def setUp(self):
957 BaseTest.setUp(self)
958 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
959 self.root_hdlr)
960 self.mem_logger = logging.getLogger('mem')
961 self.mem_logger.propagate = 0
962 self.mem_logger.addHandler(self.mem_hdlr)
963
964 def tearDown(self):
965 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000966 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000967
968 def test_flush(self):
969 # The memory handler flushes to its target handler based on specific
970 # criteria (message count and message level).
971 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000972 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000973 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000974 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000975 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100976 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000977 lines = [
978 ('DEBUG', '1'),
979 ('INFO', '2'),
980 ('WARNING', '3'),
981 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000982 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000983 for n in (4, 14):
984 for i in range(9):
985 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000986 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000987 # This will flush because it's the 10th message since the last
988 # flush.
989 self.mem_logger.debug(self.next_message())
990 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000991 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000992
993 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000994 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000995
996
997class ExceptionFormatter(logging.Formatter):
998 """A special exception formatter."""
999 def formatException(self, ei):
1000 return "Got a [%s]" % ei[0].__name__
1001
1002
1003class ConfigFileTest(BaseTest):
1004
1005 """Reading logging config from a .ini-style config file."""
1006
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001007 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001008
1009 # config0 is a standard configuration.
1010 config0 = """
1011 [loggers]
1012 keys=root
1013
1014 [handlers]
1015 keys=hand1
1016
1017 [formatters]
1018 keys=form1
1019
1020 [logger_root]
1021 level=WARNING
1022 handlers=hand1
1023
1024 [handler_hand1]
1025 class=StreamHandler
1026 level=NOTSET
1027 formatter=form1
1028 args=(sys.stdout,)
1029
1030 [formatter_form1]
1031 format=%(levelname)s ++ %(message)s
1032 datefmt=
1033 """
1034
1035 # config1 adds a little to the standard configuration.
1036 config1 = """
1037 [loggers]
1038 keys=root,parser
1039
1040 [handlers]
1041 keys=hand1
1042
1043 [formatters]
1044 keys=form1
1045
1046 [logger_root]
1047 level=WARNING
1048 handlers=
1049
1050 [logger_parser]
1051 level=DEBUG
1052 handlers=hand1
1053 propagate=1
1054 qualname=compiler.parser
1055
1056 [handler_hand1]
1057 class=StreamHandler
1058 level=NOTSET
1059 formatter=form1
1060 args=(sys.stdout,)
1061
1062 [formatter_form1]
1063 format=%(levelname)s ++ %(message)s
1064 datefmt=
1065 """
1066
Vinay Sajip3f84b072011-03-07 17:49:33 +00001067 # config1a moves the handler to the root.
1068 config1a = """
1069 [loggers]
1070 keys=root,parser
1071
1072 [handlers]
1073 keys=hand1
1074
1075 [formatters]
1076 keys=form1
1077
1078 [logger_root]
1079 level=WARNING
1080 handlers=hand1
1081
1082 [logger_parser]
1083 level=DEBUG
1084 handlers=
1085 propagate=1
1086 qualname=compiler.parser
1087
1088 [handler_hand1]
1089 class=StreamHandler
1090 level=NOTSET
1091 formatter=form1
1092 args=(sys.stdout,)
1093
1094 [formatter_form1]
1095 format=%(levelname)s ++ %(message)s
1096 datefmt=
1097 """
1098
Christian Heimes180510d2008-03-03 19:15:45 +00001099 # config2 has a subtle configuration error that should be reported
1100 config2 = config1.replace("sys.stdout", "sys.stbout")
1101
1102 # config3 has a less subtle configuration error
1103 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1104
1105 # config4 specifies a custom formatter class to be loaded
1106 config4 = """
1107 [loggers]
1108 keys=root
1109
1110 [handlers]
1111 keys=hand1
1112
1113 [formatters]
1114 keys=form1
1115
1116 [logger_root]
1117 level=NOTSET
1118 handlers=hand1
1119
1120 [handler_hand1]
1121 class=StreamHandler
1122 level=NOTSET
1123 formatter=form1
1124 args=(sys.stdout,)
1125
1126 [formatter_form1]
1127 class=""" + __name__ + """.ExceptionFormatter
1128 format=%(levelname)s:%(name)s:%(message)s
1129 datefmt=
1130 """
1131
Georg Brandl3dbca812008-07-23 16:10:53 +00001132 # config5 specifies a custom handler class to be loaded
1133 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1134
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001135 # config6 uses ', ' delimiters in the handlers and formatters sections
1136 config6 = """
1137 [loggers]
1138 keys=root,parser
1139
1140 [handlers]
1141 keys=hand1, hand2
1142
1143 [formatters]
1144 keys=form1, form2
1145
1146 [logger_root]
1147 level=WARNING
1148 handlers=
1149
1150 [logger_parser]
1151 level=DEBUG
1152 handlers=hand1
1153 propagate=1
1154 qualname=compiler.parser
1155
1156 [handler_hand1]
1157 class=StreamHandler
1158 level=NOTSET
1159 formatter=form1
1160 args=(sys.stdout,)
1161
1162 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001163 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001164 level=NOTSET
1165 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001166 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001167
1168 [formatter_form1]
1169 format=%(levelname)s ++ %(message)s
1170 datefmt=
1171
1172 [formatter_form2]
1173 format=%(message)s
1174 datefmt=
1175 """
1176
Vinay Sajip3f84b072011-03-07 17:49:33 +00001177 # config7 adds a compiler logger.
1178 config7 = """
1179 [loggers]
1180 keys=root,parser,compiler
1181
1182 [handlers]
1183 keys=hand1
1184
1185 [formatters]
1186 keys=form1
1187
1188 [logger_root]
1189 level=WARNING
1190 handlers=hand1
1191
1192 [logger_compiler]
1193 level=DEBUG
1194 handlers=
1195 propagate=1
1196 qualname=compiler
1197
1198 [logger_parser]
1199 level=DEBUG
1200 handlers=
1201 propagate=1
1202 qualname=compiler.parser
1203
1204 [handler_hand1]
1205 class=StreamHandler
1206 level=NOTSET
1207 formatter=form1
1208 args=(sys.stdout,)
1209
1210 [formatter_form1]
1211 format=%(levelname)s ++ %(message)s
1212 datefmt=
1213 """
1214
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001215 disable_test = """
1216 [loggers]
1217 keys=root
1218
1219 [handlers]
1220 keys=screen
1221
1222 [formatters]
1223 keys=
1224
1225 [logger_root]
1226 level=DEBUG
1227 handlers=screen
1228
1229 [handler_screen]
1230 level=DEBUG
1231 class=StreamHandler
1232 args=(sys.stdout,)
1233 formatter=
1234 """
1235
1236 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001237 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001238 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001239
1240 def test_config0_ok(self):
1241 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001242 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001243 self.apply_config(self.config0)
1244 logger = logging.getLogger()
1245 # Won't output anything
1246 logger.info(self.next_message())
1247 # Outputs a message
1248 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001249 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001250 ('ERROR', '2'),
1251 ], stream=output)
1252 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001253 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001254
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001255 def test_config0_using_cp_ok(self):
1256 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001257 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001258 file = io.StringIO(textwrap.dedent(self.config0))
1259 cp = configparser.ConfigParser()
1260 cp.read_file(file)
1261 logging.config.fileConfig(cp)
1262 logger = logging.getLogger()
1263 # Won't output anything
1264 logger.info(self.next_message())
1265 # Outputs a message
1266 logger.error(self.next_message())
1267 self.assert_log_lines([
1268 ('ERROR', '2'),
1269 ], stream=output)
1270 # Original logger output is empty.
1271 self.assert_log_lines([])
1272
Georg Brandl3dbca812008-07-23 16:10:53 +00001273 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001274 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001275 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001276 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001277 logger = logging.getLogger("compiler.parser")
1278 # Both will output a message
1279 logger.info(self.next_message())
1280 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001281 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001282 ('INFO', '1'),
1283 ('ERROR', '2'),
1284 ], stream=output)
1285 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001286 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001287
1288 def test_config2_failure(self):
1289 # A simple config file which overrides the default settings.
1290 self.assertRaises(Exception, self.apply_config, self.config2)
1291
1292 def test_config3_failure(self):
1293 # A simple config file which overrides the default settings.
1294 self.assertRaises(Exception, self.apply_config, self.config3)
1295
1296 def test_config4_ok(self):
1297 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001298 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001299 self.apply_config(self.config4)
1300 logger = logging.getLogger()
1301 try:
1302 raise RuntimeError()
1303 except RuntimeError:
1304 logging.exception("just testing")
1305 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001306 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001307 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1308 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001309 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001310
Georg Brandl3dbca812008-07-23 16:10:53 +00001311 def test_config5_ok(self):
1312 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001313
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001314 def test_config6_ok(self):
1315 self.test_config1_ok(config=self.config6)
1316
Vinay Sajip3f84b072011-03-07 17:49:33 +00001317 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001318 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001319 self.apply_config(self.config1a)
1320 logger = logging.getLogger("compiler.parser")
1321 # See issue #11424. compiler-hyphenated sorts
1322 # between compiler and compiler.xyz and this
1323 # was preventing compiler.xyz from being included
1324 # in the child loggers of compiler because of an
1325 # overzealous loop termination condition.
1326 hyphenated = logging.getLogger('compiler-hyphenated')
1327 # All will output a message
1328 logger.info(self.next_message())
1329 logger.error(self.next_message())
1330 hyphenated.critical(self.next_message())
1331 self.assert_log_lines([
1332 ('INFO', '1'),
1333 ('ERROR', '2'),
1334 ('CRITICAL', '3'),
1335 ], stream=output)
1336 # Original logger output is empty.
1337 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001338 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001339 self.apply_config(self.config7)
1340 logger = logging.getLogger("compiler.parser")
1341 self.assertFalse(logger.disabled)
1342 # Both will output a message
1343 logger.info(self.next_message())
1344 logger.error(self.next_message())
1345 logger = logging.getLogger("compiler.lexer")
1346 # Both will output a message
1347 logger.info(self.next_message())
1348 logger.error(self.next_message())
1349 # Will not appear
1350 hyphenated.critical(self.next_message())
1351 self.assert_log_lines([
1352 ('INFO', '4'),
1353 ('ERROR', '5'),
1354 ('INFO', '6'),
1355 ('ERROR', '7'),
1356 ], stream=output)
1357 # Original logger output is empty.
1358 self.assert_log_lines([])
1359
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001360 def test_logger_disabling(self):
1361 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001362 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001363 self.assertFalse(logger.disabled)
1364 self.apply_config(self.disable_test)
1365 self.assertTrue(logger.disabled)
1366 self.apply_config(self.disable_test, disable_existing_loggers=False)
1367 self.assertFalse(logger.disabled)
1368
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001369
Victor Stinner45df8202010-04-28 22:31:17 +00001370@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001371class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001372
Christian Heimes180510d2008-03-03 19:15:45 +00001373 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001374
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001375 if threading:
1376 server_class = TestTCPServer
1377 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001378
Christian Heimes180510d2008-03-03 19:15:45 +00001379 def setUp(self):
1380 """Set up a TCP server to receive log messages, and a SocketHandler
1381 pointing to that server's address and port."""
1382 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001383 self.server = server = self.server_class(self.address,
1384 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001385 server.start()
1386 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001387 hcls = logging.handlers.SocketHandler
1388 if isinstance(server.server_address, tuple):
1389 self.sock_hdlr = hcls('localhost', server.port)
1390 else:
1391 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001392 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001393 self.root_logger.removeHandler(self.root_logger.handlers[0])
1394 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001395 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001396
Christian Heimes180510d2008-03-03 19:15:45 +00001397 def tearDown(self):
1398 """Shutdown the TCP server."""
1399 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001400 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001401 self.root_logger.removeHandler(self.sock_hdlr)
1402 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001403 finally:
1404 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001405
Vinay Sajip7367d082011-05-02 13:17:27 +01001406 def handle_socket(self, request):
1407 conn = request.connection
1408 while True:
1409 chunk = conn.recv(4)
1410 if len(chunk) < 4:
1411 break
1412 slen = struct.unpack(">L", chunk)[0]
1413 chunk = conn.recv(slen)
1414 while len(chunk) < slen:
1415 chunk = chunk + conn.recv(slen - len(chunk))
1416 obj = pickle.loads(chunk)
1417 record = logging.makeLogRecord(obj)
1418 self.log_output += record.msg + '\n'
1419 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001420
Christian Heimes180510d2008-03-03 19:15:45 +00001421 def test_output(self):
1422 # The log message sent to the SocketHandler is properly received.
1423 logger = logging.getLogger("tcp")
1424 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001425 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001426 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001427 self.handled.acquire()
1428 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001429
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001430 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001431 # Avoid timing-related failures due to SocketHandler's own hard-wired
1432 # one-second timeout on socket.create_connection() (issue #16264).
1433 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001434 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001435 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001436 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001437 try:
1438 raise RuntimeError('Deliberate mistake')
1439 except RuntimeError:
1440 self.root_logger.exception('Never sent')
1441 self.root_logger.error('Never sent, either')
1442 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001443 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001444 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1445 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001446
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001447def _get_temp_domain_socket():
1448 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1449 os.close(fd)
1450 # just need a name - file can't be present, or we'll get an
1451 # 'address already in use' error.
1452 os.remove(fn)
1453 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001454
1455@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001456class UnixSocketHandlerTest(SocketHandlerTest):
1457
1458 """Test for SocketHandler with unix sockets."""
1459
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001460 if threading:
1461 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001462
1463 def setUp(self):
1464 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001465 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001466 SocketHandlerTest.setUp(self)
1467
1468 def tearDown(self):
1469 SocketHandlerTest.tearDown(self)
1470 os.remove(self.address)
1471
1472@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001473class DatagramHandlerTest(BaseTest):
1474
1475 """Test for DatagramHandler."""
1476
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001477 if threading:
1478 server_class = TestUDPServer
1479 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001480
Vinay Sajip7367d082011-05-02 13:17:27 +01001481 def setUp(self):
1482 """Set up a UDP server to receive log messages, and a DatagramHandler
1483 pointing to that server's address and port."""
1484 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001485 self.server = server = self.server_class(self.address,
1486 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001487 server.start()
1488 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001489 hcls = logging.handlers.DatagramHandler
1490 if isinstance(server.server_address, tuple):
1491 self.sock_hdlr = hcls('localhost', server.port)
1492 else:
1493 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001494 self.log_output = ''
1495 self.root_logger.removeHandler(self.root_logger.handlers[0])
1496 self.root_logger.addHandler(self.sock_hdlr)
1497 self.handled = threading.Event()
1498
1499 def tearDown(self):
1500 """Shutdown the UDP server."""
1501 try:
1502 self.server.stop(2.0)
1503 self.root_logger.removeHandler(self.sock_hdlr)
1504 self.sock_hdlr.close()
1505 finally:
1506 BaseTest.tearDown(self)
1507
1508 def handle_datagram(self, request):
1509 slen = struct.pack('>L', 0) # length of prefix
1510 packet = request.packet[len(slen):]
1511 obj = pickle.loads(packet)
1512 record = logging.makeLogRecord(obj)
1513 self.log_output += record.msg + '\n'
1514 self.handled.set()
1515
1516 def test_output(self):
1517 # The log message sent to the DatagramHandler is properly received.
1518 logger = logging.getLogger("udp")
1519 logger.error("spam")
1520 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001521 self.handled.clear()
1522 logger.error("eggs")
1523 self.handled.wait()
1524 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001525
1526
1527@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001528class UnixDatagramHandlerTest(DatagramHandlerTest):
1529
1530 """Test for DatagramHandler using Unix sockets."""
1531
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001532 if threading:
1533 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001534
1535 def setUp(self):
1536 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001537 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001538 DatagramHandlerTest.setUp(self)
1539
1540 def tearDown(self):
1541 DatagramHandlerTest.tearDown(self)
1542 os.remove(self.address)
1543
1544@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001545class SysLogHandlerTest(BaseTest):
1546
1547 """Test for SysLogHandler using UDP."""
1548
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001549 if threading:
1550 server_class = TestUDPServer
1551 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001552
Vinay Sajip7367d082011-05-02 13:17:27 +01001553 def setUp(self):
1554 """Set up a UDP server to receive log messages, and a SysLogHandler
1555 pointing to that server's address and port."""
1556 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001557 self.server = server = self.server_class(self.address,
1558 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001559 server.start()
1560 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001561 hcls = logging.handlers.SysLogHandler
1562 if isinstance(server.server_address, tuple):
1563 self.sl_hdlr = hcls(('localhost', server.port))
1564 else:
1565 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 self.log_output = ''
1567 self.root_logger.removeHandler(self.root_logger.handlers[0])
1568 self.root_logger.addHandler(self.sl_hdlr)
1569 self.handled = threading.Event()
1570
1571 def tearDown(self):
1572 """Shutdown the UDP server."""
1573 try:
1574 self.server.stop(2.0)
1575 self.root_logger.removeHandler(self.sl_hdlr)
1576 self.sl_hdlr.close()
1577 finally:
1578 BaseTest.tearDown(self)
1579
1580 def handle_datagram(self, request):
1581 self.log_output = request.packet
1582 self.handled.set()
1583
1584 def test_output(self):
1585 # The log message sent to the SysLogHandler is properly received.
1586 logger = logging.getLogger("slh")
1587 logger.error("sp\xe4m")
1588 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001589 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001590 self.handled.clear()
1591 self.sl_hdlr.append_nul = False
1592 logger.error("sp\xe4m")
1593 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001594 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001595 self.handled.clear()
1596 self.sl_hdlr.ident = "h\xe4m-"
1597 logger.error("sp\xe4m")
1598 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001599 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001600
1601
1602@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001603class UnixSysLogHandlerTest(SysLogHandlerTest):
1604
1605 """Test for SysLogHandler with Unix sockets."""
1606
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001607 if threading:
1608 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001609
1610 def setUp(self):
1611 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001612 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001613 SysLogHandlerTest.setUp(self)
1614
1615 def tearDown(self):
1616 SysLogHandlerTest.tearDown(self)
1617 os.remove(self.address)
1618
Vinay Sajip5421f352013-09-27 18:18:28 +01001619@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001620class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001621 """Test for HTTPHandler."""
1622
Vinay Sajip9ba87612011-05-21 11:32:15 +01001623 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1624MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1625zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1626aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1627AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16280tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16295LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1630piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16312z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1632i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1633PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1634E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1635rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1636/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1637-----END RSA PRIVATE KEY-----
1638-----BEGIN CERTIFICATE-----
1639MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1640BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1641EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1642xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1643l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1644vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1645BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1646S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1647BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16484f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16491c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1650IRbTpvlHWPjsSvHz0ZOH
1651-----END CERTIFICATE-----"""
1652
Vinay Sajip7367d082011-05-02 13:17:27 +01001653 def setUp(self):
1654 """Set up an HTTP server to receive log messages, and a HTTPHandler
1655 pointing to that server's address and port."""
1656 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001657 self.handled = threading.Event()
1658
Vinay Sajip7367d082011-05-02 13:17:27 +01001659 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001660 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001661 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001662 if self.command == 'POST':
1663 try:
1664 rlen = int(request.headers['Content-Length'])
1665 self.post_data = request.rfile.read(rlen)
1666 except:
1667 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001668 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001669 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001670 self.handled.set()
1671
1672 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001673 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001674 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001675 root_logger = self.root_logger
1676 root_logger.removeHandler(self.root_logger.handlers[0])
1677 for secure in (False, True):
1678 addr = ('localhost', 0)
1679 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001680 try:
1681 import ssl
1682 fd, fn = tempfile.mkstemp()
1683 os.close(fd)
1684 with open(fn, 'w') as f:
1685 f.write(self.PEMFILE)
1686 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1687 sslctx.load_cert_chain(fn)
1688 os.unlink(fn)
1689 except ImportError:
1690 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001691 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001692 sslctx = None
1693 self.server = server = TestHTTPServer(addr, self.handle_request,
1694 0.01, sslctx=sslctx)
1695 server.start()
1696 server.ready.wait()
1697 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001698 secure_client = secure and sslctx
1699 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1700 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001701 self.log_data = None
1702 root_logger.addHandler(self.h_hdlr)
1703
1704 for method in ('GET', 'POST'):
1705 self.h_hdlr.method = method
1706 self.handled.clear()
1707 msg = "sp\xe4m"
1708 logger.error(msg)
1709 self.handled.wait()
1710 self.assertEqual(self.log_data.path, '/frob')
1711 self.assertEqual(self.command, method)
1712 if method == 'GET':
1713 d = parse_qs(self.log_data.query)
1714 else:
1715 d = parse_qs(self.post_data.decode('utf-8'))
1716 self.assertEqual(d['name'], ['http'])
1717 self.assertEqual(d['funcName'], ['test_output'])
1718 self.assertEqual(d['msg'], [msg])
1719
1720 self.server.stop(2.0)
1721 self.root_logger.removeHandler(self.h_hdlr)
1722 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001723
Christian Heimes180510d2008-03-03 19:15:45 +00001724class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001725
Christian Heimes180510d2008-03-03 19:15:45 +00001726 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001727
Christian Heimes180510d2008-03-03 19:15:45 +00001728 def setUp(self):
1729 """Create a dict to remember potentially destroyed objects."""
1730 BaseTest.setUp(self)
1731 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001732
Christian Heimes180510d2008-03-03 19:15:45 +00001733 def _watch_for_survival(self, *args):
1734 """Watch the given objects for survival, by creating weakrefs to
1735 them."""
1736 for obj in args:
1737 key = id(obj), repr(obj)
1738 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001739
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001740 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001741 """Assert that all objects watched for survival have survived."""
1742 # Trigger cycle breaking.
1743 gc.collect()
1744 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001745 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001746 if ref() is None:
1747 dead.append(repr_)
1748 if dead:
1749 self.fail("%d objects should have survived "
1750 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001751
Christian Heimes180510d2008-03-03 19:15:45 +00001752 def test_persistent_loggers(self):
1753 # Logger objects are persistent and retain their configuration, even
1754 # if visible references are destroyed.
1755 self.root_logger.setLevel(logging.INFO)
1756 foo = logging.getLogger("foo")
1757 self._watch_for_survival(foo)
1758 foo.setLevel(logging.DEBUG)
1759 self.root_logger.debug(self.next_message())
1760 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001761 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001762 ('foo', 'DEBUG', '2'),
1763 ])
1764 del foo
1765 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001766 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001767 # foo has retained its settings.
1768 bar = logging.getLogger("foo")
1769 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001770 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001771 ('foo', 'DEBUG', '2'),
1772 ('foo', 'DEBUG', '3'),
1773 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001774
Benjamin Petersonf91df042009-02-13 02:50:59 +00001775
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001776class EncodingTest(BaseTest):
1777 def test_encoding_plain_file(self):
1778 # In Python 2.x, a plain file object is treated as having no encoding.
1779 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001780 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1781 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001782 # the non-ascii data we write to the log.
1783 data = "foo\x80"
1784 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001785 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001786 log.addHandler(handler)
1787 try:
1788 # write non-ascii data to the log.
1789 log.warning(data)
1790 finally:
1791 log.removeHandler(handler)
1792 handler.close()
1793 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001794 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001795 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001796 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001797 finally:
1798 f.close()
1799 finally:
1800 if os.path.isfile(fn):
1801 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001802
Benjamin Petersonf91df042009-02-13 02:50:59 +00001803 def test_encoding_cyrillic_unicode(self):
1804 log = logging.getLogger("test")
1805 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1806 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1807 #Ensure it's written in a Cyrillic encoding
1808 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001809 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001810 stream = io.BytesIO()
1811 writer = writer_class(stream, 'strict')
1812 handler = logging.StreamHandler(writer)
1813 log.addHandler(handler)
1814 try:
1815 log.warning(message)
1816 finally:
1817 log.removeHandler(handler)
1818 handler.close()
1819 # check we wrote exactly those bytes, ignoring trailing \n etc
1820 s = stream.getvalue()
1821 #Compare against what the data should be when encoded in CP-1251
1822 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1823
1824
Georg Brandlf9734072008-12-07 15:30:06 +00001825class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001826
Georg Brandlf9734072008-12-07 15:30:06 +00001827 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001828 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001829 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001830 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001831 warnings.filterwarnings("always", category=UserWarning)
1832 stream = io.StringIO()
1833 h = logging.StreamHandler(stream)
1834 logger = logging.getLogger("py.warnings")
1835 logger.addHandler(h)
1836 warnings.warn("I'm warning you...")
1837 logger.removeHandler(h)
1838 s = stream.getvalue()
1839 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001840 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001841
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001842 #See if an explicit file uses the original implementation
1843 a_file = io.StringIO()
1844 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1845 a_file, "Dummy line")
1846 s = a_file.getvalue()
1847 a_file.close()
1848 self.assertEqual(s,
1849 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1850
1851 def test_warnings_no_handlers(self):
1852 with warnings.catch_warnings():
1853 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001854 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001855
1856 # confirm our assumption: no loggers are set
1857 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001858 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001859
1860 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001861 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001862 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001863
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001864
1865def formatFunc(format, datefmt=None):
1866 return logging.Formatter(format, datefmt)
1867
1868def handlerFunc():
1869 return logging.StreamHandler()
1870
1871class CustomHandler(logging.StreamHandler):
1872 pass
1873
1874class ConfigDictTest(BaseTest):
1875
1876 """Reading logging config from a dictionary."""
1877
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001878 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001879
1880 # config0 is a standard configuration.
1881 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001882 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001883 'formatters': {
1884 'form1' : {
1885 'format' : '%(levelname)s ++ %(message)s',
1886 },
1887 },
1888 'handlers' : {
1889 'hand1' : {
1890 'class' : 'logging.StreamHandler',
1891 'formatter' : 'form1',
1892 'level' : 'NOTSET',
1893 'stream' : 'ext://sys.stdout',
1894 },
1895 },
1896 'root' : {
1897 'level' : 'WARNING',
1898 'handlers' : ['hand1'],
1899 },
1900 }
1901
1902 # config1 adds a little to the standard configuration.
1903 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001904 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001905 'formatters': {
1906 'form1' : {
1907 'format' : '%(levelname)s ++ %(message)s',
1908 },
1909 },
1910 'handlers' : {
1911 'hand1' : {
1912 'class' : 'logging.StreamHandler',
1913 'formatter' : 'form1',
1914 'level' : 'NOTSET',
1915 'stream' : 'ext://sys.stdout',
1916 },
1917 },
1918 'loggers' : {
1919 'compiler.parser' : {
1920 'level' : 'DEBUG',
1921 'handlers' : ['hand1'],
1922 },
1923 },
1924 'root' : {
1925 'level' : 'WARNING',
1926 },
1927 }
1928
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001929 # config1a moves the handler to the root. Used with config8a
1930 config1a = {
1931 'version': 1,
1932 'formatters': {
1933 'form1' : {
1934 'format' : '%(levelname)s ++ %(message)s',
1935 },
1936 },
1937 'handlers' : {
1938 'hand1' : {
1939 'class' : 'logging.StreamHandler',
1940 'formatter' : 'form1',
1941 'level' : 'NOTSET',
1942 'stream' : 'ext://sys.stdout',
1943 },
1944 },
1945 'loggers' : {
1946 'compiler.parser' : {
1947 'level' : 'DEBUG',
1948 },
1949 },
1950 'root' : {
1951 'level' : 'WARNING',
1952 'handlers' : ['hand1'],
1953 },
1954 }
1955
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001956 # config2 has a subtle configuration error that should be reported
1957 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001958 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001959 'formatters': {
1960 'form1' : {
1961 'format' : '%(levelname)s ++ %(message)s',
1962 },
1963 },
1964 'handlers' : {
1965 'hand1' : {
1966 'class' : 'logging.StreamHandler',
1967 'formatter' : 'form1',
1968 'level' : 'NOTSET',
1969 'stream' : 'ext://sys.stdbout',
1970 },
1971 },
1972 'loggers' : {
1973 'compiler.parser' : {
1974 'level' : 'DEBUG',
1975 'handlers' : ['hand1'],
1976 },
1977 },
1978 'root' : {
1979 'level' : 'WARNING',
1980 },
1981 }
1982
1983 #As config1 but with a misspelt level on a handler
1984 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001985 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001986 'formatters': {
1987 'form1' : {
1988 'format' : '%(levelname)s ++ %(message)s',
1989 },
1990 },
1991 'handlers' : {
1992 'hand1' : {
1993 'class' : 'logging.StreamHandler',
1994 'formatter' : 'form1',
1995 'level' : 'NTOSET',
1996 'stream' : 'ext://sys.stdout',
1997 },
1998 },
1999 'loggers' : {
2000 'compiler.parser' : {
2001 'level' : 'DEBUG',
2002 'handlers' : ['hand1'],
2003 },
2004 },
2005 'root' : {
2006 'level' : 'WARNING',
2007 },
2008 }
2009
2010
2011 #As config1 but with a misspelt level on a logger
2012 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002013 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002014 'formatters': {
2015 'form1' : {
2016 'format' : '%(levelname)s ++ %(message)s',
2017 },
2018 },
2019 'handlers' : {
2020 'hand1' : {
2021 'class' : 'logging.StreamHandler',
2022 'formatter' : 'form1',
2023 'level' : 'NOTSET',
2024 'stream' : 'ext://sys.stdout',
2025 },
2026 },
2027 'loggers' : {
2028 'compiler.parser' : {
2029 'level' : 'DEBUG',
2030 'handlers' : ['hand1'],
2031 },
2032 },
2033 'root' : {
2034 'level' : 'WRANING',
2035 },
2036 }
2037
2038 # config3 has a less subtle configuration error
2039 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002040 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002041 'formatters': {
2042 'form1' : {
2043 'format' : '%(levelname)s ++ %(message)s',
2044 },
2045 },
2046 'handlers' : {
2047 'hand1' : {
2048 'class' : 'logging.StreamHandler',
2049 'formatter' : 'misspelled_name',
2050 'level' : 'NOTSET',
2051 'stream' : 'ext://sys.stdout',
2052 },
2053 },
2054 'loggers' : {
2055 'compiler.parser' : {
2056 'level' : 'DEBUG',
2057 'handlers' : ['hand1'],
2058 },
2059 },
2060 'root' : {
2061 'level' : 'WARNING',
2062 },
2063 }
2064
2065 # config4 specifies a custom formatter class to be loaded
2066 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002067 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002068 'formatters': {
2069 'form1' : {
2070 '()' : __name__ + '.ExceptionFormatter',
2071 'format' : '%(levelname)s:%(name)s:%(message)s',
2072 },
2073 },
2074 'handlers' : {
2075 'hand1' : {
2076 'class' : 'logging.StreamHandler',
2077 'formatter' : 'form1',
2078 'level' : 'NOTSET',
2079 'stream' : 'ext://sys.stdout',
2080 },
2081 },
2082 'root' : {
2083 'level' : 'NOTSET',
2084 'handlers' : ['hand1'],
2085 },
2086 }
2087
2088 # As config4 but using an actual callable rather than a string
2089 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002090 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002091 'formatters': {
2092 'form1' : {
2093 '()' : ExceptionFormatter,
2094 'format' : '%(levelname)s:%(name)s:%(message)s',
2095 },
2096 'form2' : {
2097 '()' : __name__ + '.formatFunc',
2098 'format' : '%(levelname)s:%(name)s:%(message)s',
2099 },
2100 'form3' : {
2101 '()' : formatFunc,
2102 'format' : '%(levelname)s:%(name)s:%(message)s',
2103 },
2104 },
2105 'handlers' : {
2106 'hand1' : {
2107 'class' : 'logging.StreamHandler',
2108 'formatter' : 'form1',
2109 'level' : 'NOTSET',
2110 'stream' : 'ext://sys.stdout',
2111 },
2112 'hand2' : {
2113 '()' : handlerFunc,
2114 },
2115 },
2116 'root' : {
2117 'level' : 'NOTSET',
2118 'handlers' : ['hand1'],
2119 },
2120 }
2121
2122 # config5 specifies a custom handler class to be loaded
2123 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002124 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125 'formatters': {
2126 'form1' : {
2127 'format' : '%(levelname)s ++ %(message)s',
2128 },
2129 },
2130 'handlers' : {
2131 'hand1' : {
2132 'class' : __name__ + '.CustomHandler',
2133 'formatter' : 'form1',
2134 'level' : 'NOTSET',
2135 'stream' : 'ext://sys.stdout',
2136 },
2137 },
2138 'loggers' : {
2139 'compiler.parser' : {
2140 'level' : 'DEBUG',
2141 'handlers' : ['hand1'],
2142 },
2143 },
2144 'root' : {
2145 'level' : 'WARNING',
2146 },
2147 }
2148
2149 # config6 specifies a custom handler class to be loaded
2150 # but has bad arguments
2151 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002152 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002153 'formatters': {
2154 'form1' : {
2155 'format' : '%(levelname)s ++ %(message)s',
2156 },
2157 },
2158 'handlers' : {
2159 'hand1' : {
2160 'class' : __name__ + '.CustomHandler',
2161 'formatter' : 'form1',
2162 'level' : 'NOTSET',
2163 'stream' : 'ext://sys.stdout',
2164 '9' : 'invalid parameter name',
2165 },
2166 },
2167 'loggers' : {
2168 'compiler.parser' : {
2169 'level' : 'DEBUG',
2170 'handlers' : ['hand1'],
2171 },
2172 },
2173 'root' : {
2174 'level' : 'WARNING',
2175 },
2176 }
2177
2178 #config 7 does not define compiler.parser but defines compiler.lexer
2179 #so compiler.parser should be disabled after applying it
2180 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002181 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002182 'formatters': {
2183 'form1' : {
2184 'format' : '%(levelname)s ++ %(message)s',
2185 },
2186 },
2187 'handlers' : {
2188 'hand1' : {
2189 'class' : 'logging.StreamHandler',
2190 'formatter' : 'form1',
2191 'level' : 'NOTSET',
2192 'stream' : 'ext://sys.stdout',
2193 },
2194 },
2195 'loggers' : {
2196 'compiler.lexer' : {
2197 'level' : 'DEBUG',
2198 'handlers' : ['hand1'],
2199 },
2200 },
2201 'root' : {
2202 'level' : 'WARNING',
2203 },
2204 }
2205
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002206 # config8 defines both compiler and compiler.lexer
2207 # so compiler.parser should not be disabled (since
2208 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002209 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002210 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002211 'disable_existing_loggers' : False,
2212 'formatters': {
2213 'form1' : {
2214 'format' : '%(levelname)s ++ %(message)s',
2215 },
2216 },
2217 'handlers' : {
2218 'hand1' : {
2219 'class' : 'logging.StreamHandler',
2220 'formatter' : 'form1',
2221 'level' : 'NOTSET',
2222 'stream' : 'ext://sys.stdout',
2223 },
2224 },
2225 'loggers' : {
2226 'compiler' : {
2227 'level' : 'DEBUG',
2228 'handlers' : ['hand1'],
2229 },
2230 'compiler.lexer' : {
2231 },
2232 },
2233 'root' : {
2234 'level' : 'WARNING',
2235 },
2236 }
2237
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002238 # config8a disables existing loggers
2239 config8a = {
2240 'version': 1,
2241 'disable_existing_loggers' : True,
2242 'formatters': {
2243 'form1' : {
2244 'format' : '%(levelname)s ++ %(message)s',
2245 },
2246 },
2247 'handlers' : {
2248 'hand1' : {
2249 'class' : 'logging.StreamHandler',
2250 'formatter' : 'form1',
2251 'level' : 'NOTSET',
2252 'stream' : 'ext://sys.stdout',
2253 },
2254 },
2255 'loggers' : {
2256 'compiler' : {
2257 'level' : 'DEBUG',
2258 'handlers' : ['hand1'],
2259 },
2260 'compiler.lexer' : {
2261 },
2262 },
2263 'root' : {
2264 'level' : 'WARNING',
2265 },
2266 }
2267
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002268 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002269 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002270 'formatters': {
2271 'form1' : {
2272 'format' : '%(levelname)s ++ %(message)s',
2273 },
2274 },
2275 'handlers' : {
2276 'hand1' : {
2277 'class' : 'logging.StreamHandler',
2278 'formatter' : 'form1',
2279 'level' : 'WARNING',
2280 'stream' : 'ext://sys.stdout',
2281 },
2282 },
2283 'loggers' : {
2284 'compiler.parser' : {
2285 'level' : 'WARNING',
2286 'handlers' : ['hand1'],
2287 },
2288 },
2289 'root' : {
2290 'level' : 'NOTSET',
2291 },
2292 }
2293
2294 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002295 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002296 'incremental' : True,
2297 'handlers' : {
2298 'hand1' : {
2299 'level' : 'WARNING',
2300 },
2301 },
2302 'loggers' : {
2303 'compiler.parser' : {
2304 'level' : 'INFO',
2305 },
2306 },
2307 }
2308
2309 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002310 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002311 'incremental' : True,
2312 'handlers' : {
2313 'hand1' : {
2314 'level' : 'INFO',
2315 },
2316 },
2317 'loggers' : {
2318 'compiler.parser' : {
2319 'level' : 'INFO',
2320 },
2321 },
2322 }
2323
2324 #As config1 but with a filter added
2325 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002326 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002327 'formatters': {
2328 'form1' : {
2329 'format' : '%(levelname)s ++ %(message)s',
2330 },
2331 },
2332 'filters' : {
2333 'filt1' : {
2334 'name' : 'compiler.parser',
2335 },
2336 },
2337 'handlers' : {
2338 'hand1' : {
2339 'class' : 'logging.StreamHandler',
2340 'formatter' : 'form1',
2341 'level' : 'NOTSET',
2342 'stream' : 'ext://sys.stdout',
2343 'filters' : ['filt1'],
2344 },
2345 },
2346 'loggers' : {
2347 'compiler.parser' : {
2348 'level' : 'DEBUG',
2349 'filters' : ['filt1'],
2350 },
2351 },
2352 'root' : {
2353 'level' : 'WARNING',
2354 'handlers' : ['hand1'],
2355 },
2356 }
2357
2358 #As config1 but using cfg:// references
2359 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002360 'version': 1,
2361 'true_formatters': {
2362 'form1' : {
2363 'format' : '%(levelname)s ++ %(message)s',
2364 },
2365 },
2366 'handler_configs': {
2367 'hand1' : {
2368 'class' : 'logging.StreamHandler',
2369 'formatter' : 'form1',
2370 'level' : 'NOTSET',
2371 'stream' : 'ext://sys.stdout',
2372 },
2373 },
2374 'formatters' : 'cfg://true_formatters',
2375 'handlers' : {
2376 'hand1' : 'cfg://handler_configs[hand1]',
2377 },
2378 'loggers' : {
2379 'compiler.parser' : {
2380 'level' : 'DEBUG',
2381 'handlers' : ['hand1'],
2382 },
2383 },
2384 'root' : {
2385 'level' : 'WARNING',
2386 },
2387 }
2388
2389 #As config11 but missing the version key
2390 config12 = {
2391 'true_formatters': {
2392 'form1' : {
2393 'format' : '%(levelname)s ++ %(message)s',
2394 },
2395 },
2396 'handler_configs': {
2397 'hand1' : {
2398 'class' : 'logging.StreamHandler',
2399 'formatter' : 'form1',
2400 'level' : 'NOTSET',
2401 'stream' : 'ext://sys.stdout',
2402 },
2403 },
2404 'formatters' : 'cfg://true_formatters',
2405 'handlers' : {
2406 'hand1' : 'cfg://handler_configs[hand1]',
2407 },
2408 'loggers' : {
2409 'compiler.parser' : {
2410 'level' : 'DEBUG',
2411 'handlers' : ['hand1'],
2412 },
2413 },
2414 'root' : {
2415 'level' : 'WARNING',
2416 },
2417 }
2418
2419 #As config11 but using an unsupported version
2420 config13 = {
2421 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002422 'true_formatters': {
2423 'form1' : {
2424 'format' : '%(levelname)s ++ %(message)s',
2425 },
2426 },
2427 'handler_configs': {
2428 'hand1' : {
2429 'class' : 'logging.StreamHandler',
2430 'formatter' : 'form1',
2431 'level' : 'NOTSET',
2432 'stream' : 'ext://sys.stdout',
2433 },
2434 },
2435 'formatters' : 'cfg://true_formatters',
2436 'handlers' : {
2437 'hand1' : 'cfg://handler_configs[hand1]',
2438 },
2439 'loggers' : {
2440 'compiler.parser' : {
2441 'level' : 'DEBUG',
2442 'handlers' : ['hand1'],
2443 },
2444 },
2445 'root' : {
2446 'level' : 'WARNING',
2447 },
2448 }
2449
Vinay Sajip8d270232012-11-15 14:20:18 +00002450 # As config0, but with properties
2451 config14 = {
2452 'version': 1,
2453 'formatters': {
2454 'form1' : {
2455 'format' : '%(levelname)s ++ %(message)s',
2456 },
2457 },
2458 'handlers' : {
2459 'hand1' : {
2460 'class' : 'logging.StreamHandler',
2461 'formatter' : 'form1',
2462 'level' : 'NOTSET',
2463 'stream' : 'ext://sys.stdout',
2464 '.': {
2465 'foo': 'bar',
2466 'terminator': '!\n',
2467 }
2468 },
2469 },
2470 'root' : {
2471 'level' : 'WARNING',
2472 'handlers' : ['hand1'],
2473 },
2474 }
2475
Vinay Sajip3f885b52013-03-22 15:19:54 +00002476 out_of_order = {
2477 "version": 1,
2478 "formatters": {
2479 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002480 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2481 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002482 }
2483 },
2484 "handlers": {
2485 "fileGlobal": {
2486 "class": "logging.StreamHandler",
2487 "level": "DEBUG",
2488 "formatter": "mySimpleFormatter"
2489 },
2490 "bufferGlobal": {
2491 "class": "logging.handlers.MemoryHandler",
2492 "capacity": 5,
2493 "formatter": "mySimpleFormatter",
2494 "target": "fileGlobal",
2495 "level": "DEBUG"
2496 }
2497 },
2498 "loggers": {
2499 "mymodule": {
2500 "level": "DEBUG",
2501 "handlers": ["bufferGlobal"],
2502 "propagate": "true"
2503 }
2504 }
2505 }
2506
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002507 def apply_config(self, conf):
2508 logging.config.dictConfig(conf)
2509
2510 def test_config0_ok(self):
2511 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002512 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002513 self.apply_config(self.config0)
2514 logger = logging.getLogger()
2515 # Won't output anything
2516 logger.info(self.next_message())
2517 # Outputs a message
2518 logger.error(self.next_message())
2519 self.assert_log_lines([
2520 ('ERROR', '2'),
2521 ], stream=output)
2522 # Original logger output is empty.
2523 self.assert_log_lines([])
2524
2525 def test_config1_ok(self, config=config1):
2526 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002527 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002528 self.apply_config(config)
2529 logger = logging.getLogger("compiler.parser")
2530 # Both will output a message
2531 logger.info(self.next_message())
2532 logger.error(self.next_message())
2533 self.assert_log_lines([
2534 ('INFO', '1'),
2535 ('ERROR', '2'),
2536 ], stream=output)
2537 # Original logger output is empty.
2538 self.assert_log_lines([])
2539
2540 def test_config2_failure(self):
2541 # A simple config which overrides the default settings.
2542 self.assertRaises(Exception, self.apply_config, self.config2)
2543
2544 def test_config2a_failure(self):
2545 # A simple config which overrides the default settings.
2546 self.assertRaises(Exception, self.apply_config, self.config2a)
2547
2548 def test_config2b_failure(self):
2549 # A simple config which overrides the default settings.
2550 self.assertRaises(Exception, self.apply_config, self.config2b)
2551
2552 def test_config3_failure(self):
2553 # A simple config which overrides the default settings.
2554 self.assertRaises(Exception, self.apply_config, self.config3)
2555
2556 def test_config4_ok(self):
2557 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002558 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002559 self.apply_config(self.config4)
2560 #logger = logging.getLogger()
2561 try:
2562 raise RuntimeError()
2563 except RuntimeError:
2564 logging.exception("just testing")
2565 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002566 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002567 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2568 # Original logger output is empty
2569 self.assert_log_lines([])
2570
2571 def test_config4a_ok(self):
2572 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002573 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002574 self.apply_config(self.config4a)
2575 #logger = logging.getLogger()
2576 try:
2577 raise RuntimeError()
2578 except RuntimeError:
2579 logging.exception("just testing")
2580 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002581 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002582 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2583 # Original logger output is empty
2584 self.assert_log_lines([])
2585
2586 def test_config5_ok(self):
2587 self.test_config1_ok(config=self.config5)
2588
2589 def test_config6_failure(self):
2590 self.assertRaises(Exception, self.apply_config, self.config6)
2591
2592 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002593 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002594 self.apply_config(self.config1)
2595 logger = logging.getLogger("compiler.parser")
2596 # Both will output a message
2597 logger.info(self.next_message())
2598 logger.error(self.next_message())
2599 self.assert_log_lines([
2600 ('INFO', '1'),
2601 ('ERROR', '2'),
2602 ], stream=output)
2603 # Original logger output is empty.
2604 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002605 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002606 self.apply_config(self.config7)
2607 logger = logging.getLogger("compiler.parser")
2608 self.assertTrue(logger.disabled)
2609 logger = logging.getLogger("compiler.lexer")
2610 # Both will output a message
2611 logger.info(self.next_message())
2612 logger.error(self.next_message())
2613 self.assert_log_lines([
2614 ('INFO', '3'),
2615 ('ERROR', '4'),
2616 ], stream=output)
2617 # Original logger output is empty.
2618 self.assert_log_lines([])
2619
2620 #Same as test_config_7_ok but don't disable old loggers.
2621 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002622 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002623 self.apply_config(self.config1)
2624 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002625 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002626 logger.info(self.next_message())
2627 logger.error(self.next_message())
2628 self.assert_log_lines([
2629 ('INFO', '1'),
2630 ('ERROR', '2'),
2631 ], stream=output)
2632 # Original logger output is empty.
2633 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002634 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002635 self.apply_config(self.config8)
2636 logger = logging.getLogger("compiler.parser")
2637 self.assertFalse(logger.disabled)
2638 # Both will output a message
2639 logger.info(self.next_message())
2640 logger.error(self.next_message())
2641 logger = logging.getLogger("compiler.lexer")
2642 # Both will output a message
2643 logger.info(self.next_message())
2644 logger.error(self.next_message())
2645 self.assert_log_lines([
2646 ('INFO', '3'),
2647 ('ERROR', '4'),
2648 ('INFO', '5'),
2649 ('ERROR', '6'),
2650 ], stream=output)
2651 # Original logger output is empty.
2652 self.assert_log_lines([])
2653
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002654 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002655 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002656 self.apply_config(self.config1a)
2657 logger = logging.getLogger("compiler.parser")
2658 # See issue #11424. compiler-hyphenated sorts
2659 # between compiler and compiler.xyz and this
2660 # was preventing compiler.xyz from being included
2661 # in the child loggers of compiler because of an
2662 # overzealous loop termination condition.
2663 hyphenated = logging.getLogger('compiler-hyphenated')
2664 # All will output a message
2665 logger.info(self.next_message())
2666 logger.error(self.next_message())
2667 hyphenated.critical(self.next_message())
2668 self.assert_log_lines([
2669 ('INFO', '1'),
2670 ('ERROR', '2'),
2671 ('CRITICAL', '3'),
2672 ], stream=output)
2673 # Original logger output is empty.
2674 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002675 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002676 self.apply_config(self.config8a)
2677 logger = logging.getLogger("compiler.parser")
2678 self.assertFalse(logger.disabled)
2679 # Both will output a message
2680 logger.info(self.next_message())
2681 logger.error(self.next_message())
2682 logger = logging.getLogger("compiler.lexer")
2683 # Both will output a message
2684 logger.info(self.next_message())
2685 logger.error(self.next_message())
2686 # Will not appear
2687 hyphenated.critical(self.next_message())
2688 self.assert_log_lines([
2689 ('INFO', '4'),
2690 ('ERROR', '5'),
2691 ('INFO', '6'),
2692 ('ERROR', '7'),
2693 ], stream=output)
2694 # Original logger output is empty.
2695 self.assert_log_lines([])
2696
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002697 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002698 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002699 self.apply_config(self.config9)
2700 logger = logging.getLogger("compiler.parser")
2701 #Nothing will be output since both handler and logger are set to WARNING
2702 logger.info(self.next_message())
2703 self.assert_log_lines([], stream=output)
2704 self.apply_config(self.config9a)
2705 #Nothing will be output since both handler is still set to WARNING
2706 logger.info(self.next_message())
2707 self.assert_log_lines([], stream=output)
2708 self.apply_config(self.config9b)
2709 #Message should now be output
2710 logger.info(self.next_message())
2711 self.assert_log_lines([
2712 ('INFO', '3'),
2713 ], stream=output)
2714
2715 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002716 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002717 self.apply_config(self.config10)
2718 logger = logging.getLogger("compiler.parser")
2719 logger.warning(self.next_message())
2720 logger = logging.getLogger('compiler')
2721 #Not output, because filtered
2722 logger.warning(self.next_message())
2723 logger = logging.getLogger('compiler.lexer')
2724 #Not output, because filtered
2725 logger.warning(self.next_message())
2726 logger = logging.getLogger("compiler.parser.codegen")
2727 #Output, as not filtered
2728 logger.error(self.next_message())
2729 self.assert_log_lines([
2730 ('WARNING', '1'),
2731 ('ERROR', '4'),
2732 ], stream=output)
2733
2734 def test_config11_ok(self):
2735 self.test_config1_ok(self.config11)
2736
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002737 def test_config12_failure(self):
2738 self.assertRaises(Exception, self.apply_config, self.config12)
2739
2740 def test_config13_failure(self):
2741 self.assertRaises(Exception, self.apply_config, self.config13)
2742
Vinay Sajip8d270232012-11-15 14:20:18 +00002743 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002744 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002745 self.apply_config(self.config14)
2746 h = logging._handlers['hand1']
2747 self.assertEqual(h.foo, 'bar')
2748 self.assertEqual(h.terminator, '!\n')
2749 logging.warning('Exclamation')
2750 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2751
Victor Stinner45df8202010-04-28 22:31:17 +00002752 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002753 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002754 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002755 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002756 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002757 t.start()
2758 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002759 # Now get the port allocated
2760 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002761 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002762 try:
2763 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2764 sock.settimeout(2.0)
2765 sock.connect(('localhost', port))
2766
2767 slen = struct.pack('>L', len(text))
2768 s = slen + text
2769 sentsofar = 0
2770 left = len(s)
2771 while left > 0:
2772 sent = sock.send(s[sentsofar:])
2773 sentsofar += sent
2774 left -= sent
2775 sock.close()
2776 finally:
2777 t.ready.wait(2.0)
2778 logging.config.stopListening()
2779 t.join(2.0)
2780
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002781 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002782 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002783 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002784 self.setup_via_listener(json.dumps(self.config10))
2785 logger = logging.getLogger("compiler.parser")
2786 logger.warning(self.next_message())
2787 logger = logging.getLogger('compiler')
2788 #Not output, because filtered
2789 logger.warning(self.next_message())
2790 logger = logging.getLogger('compiler.lexer')
2791 #Not output, because filtered
2792 logger.warning(self.next_message())
2793 logger = logging.getLogger("compiler.parser.codegen")
2794 #Output, as not filtered
2795 logger.error(self.next_message())
2796 self.assert_log_lines([
2797 ('WARNING', '1'),
2798 ('ERROR', '4'),
2799 ], stream=output)
2800
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002801 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002802 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002803 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002804 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2805 logger = logging.getLogger("compiler.parser")
2806 # Both will output a message
2807 logger.info(self.next_message())
2808 logger.error(self.next_message())
2809 self.assert_log_lines([
2810 ('INFO', '1'),
2811 ('ERROR', '2'),
2812 ], stream=output)
2813 # Original logger output is empty.
2814 self.assert_log_lines([])
2815
Vinay Sajip4ded5512012-10-02 15:56:16 +01002816 @unittest.skipUnless(threading, 'Threading required for this test.')
2817 def test_listen_verify(self):
2818
2819 def verify_fail(stuff):
2820 return None
2821
2822 def verify_reverse(stuff):
2823 return stuff[::-1]
2824
2825 logger = logging.getLogger("compiler.parser")
2826 to_send = textwrap.dedent(ConfigFileTest.config1)
2827 # First, specify a verification function that will fail.
2828 # We expect to see no output, since our configuration
2829 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002830 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002831 self.setup_via_listener(to_send, verify_fail)
2832 # Both will output a message
2833 logger.info(self.next_message())
2834 logger.error(self.next_message())
2835 self.assert_log_lines([], stream=output)
2836 # Original logger output has the stuff we logged.
2837 self.assert_log_lines([
2838 ('INFO', '1'),
2839 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002840 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002841
2842 # Now, perform no verification. Our configuration
2843 # should take effect.
2844
Vinay Sajip1feedb42014-05-31 08:19:12 +01002845 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002846 self.setup_via_listener(to_send) # no verify callable specified
2847 logger = logging.getLogger("compiler.parser")
2848 # Both will output a message
2849 logger.info(self.next_message())
2850 logger.error(self.next_message())
2851 self.assert_log_lines([
2852 ('INFO', '3'),
2853 ('ERROR', '4'),
2854 ], stream=output)
2855 # Original logger output still has the stuff we logged before.
2856 self.assert_log_lines([
2857 ('INFO', '1'),
2858 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002859 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002860
2861 # Now, perform verification which transforms the bytes.
2862
Vinay Sajip1feedb42014-05-31 08:19:12 +01002863 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002864 self.setup_via_listener(to_send[::-1], verify_reverse)
2865 logger = logging.getLogger("compiler.parser")
2866 # Both will output a message
2867 logger.info(self.next_message())
2868 logger.error(self.next_message())
2869 self.assert_log_lines([
2870 ('INFO', '5'),
2871 ('ERROR', '6'),
2872 ], stream=output)
2873 # Original logger output still has the stuff we logged before.
2874 self.assert_log_lines([
2875 ('INFO', '1'),
2876 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002877 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002878
Vinay Sajip3f885b52013-03-22 15:19:54 +00002879 def test_out_of_order(self):
2880 self.apply_config(self.out_of_order)
2881 handler = logging.getLogger('mymodule').handlers[0]
2882 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002883 self.assertIsInstance(handler.formatter._style,
2884 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002885
Vinay Sajip373baef2011-04-26 20:05:24 +01002886 def test_baseconfig(self):
2887 d = {
2888 'atuple': (1, 2, 3),
2889 'alist': ['a', 'b', 'c'],
2890 'adict': {'d': 'e', 'f': 3 },
2891 'nest1': ('g', ('h', 'i'), 'j'),
2892 'nest2': ['k', ['l', 'm'], 'n'],
2893 'nest3': ['o', 'cfg://alist', 'p'],
2894 }
2895 bc = logging.config.BaseConfigurator(d)
2896 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2897 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2898 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2899 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2900 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2901 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2902 v = bc.convert('cfg://nest3')
2903 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2904 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2905 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2906 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002907
2908class ManagerTest(BaseTest):
2909 def test_manager_loggerclass(self):
2910 logged = []
2911
2912 class MyLogger(logging.Logger):
2913 def _log(self, level, msg, args, exc_info=None, extra=None):
2914 logged.append(msg)
2915
2916 man = logging.Manager(None)
2917 self.assertRaises(TypeError, man.setLoggerClass, int)
2918 man.setLoggerClass(MyLogger)
2919 logger = man.getLogger('test')
2920 logger.warning('should appear in logged')
2921 logging.warning('should not appear in logged')
2922
2923 self.assertEqual(logged, ['should appear in logged'])
2924
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002925 def test_set_log_record_factory(self):
2926 man = logging.Manager(None)
2927 expected = object()
2928 man.setLogRecordFactory(expected)
2929 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002930
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002931class ChildLoggerTest(BaseTest):
2932 def test_child_loggers(self):
2933 r = logging.getLogger()
2934 l1 = logging.getLogger('abc')
2935 l2 = logging.getLogger('def.ghi')
2936 c1 = r.getChild('xyz')
2937 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002938 self.assertIs(c1, logging.getLogger('xyz'))
2939 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002940 c1 = l1.getChild('def')
2941 c2 = c1.getChild('ghi')
2942 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002943 self.assertIs(c1, logging.getLogger('abc.def'))
2944 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2945 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002946
2947
Vinay Sajip6fac8172010-10-19 20:44:14 +00002948class DerivedLogRecord(logging.LogRecord):
2949 pass
2950
Vinay Sajip61561522010-12-03 11:50:38 +00002951class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002952
2953 def setUp(self):
2954 class CheckingFilter(logging.Filter):
2955 def __init__(self, cls):
2956 self.cls = cls
2957
2958 def filter(self, record):
2959 t = type(record)
2960 if t is not self.cls:
2961 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2962 self.cls)
2963 raise TypeError(msg)
2964 return True
2965
2966 BaseTest.setUp(self)
2967 self.filter = CheckingFilter(DerivedLogRecord)
2968 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002969 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002970
2971 def tearDown(self):
2972 self.root_logger.removeFilter(self.filter)
2973 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002974 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002975
2976 def test_logrecord_class(self):
2977 self.assertRaises(TypeError, self.root_logger.warning,
2978 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002979 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002980 self.root_logger.error(self.next_message())
2981 self.assert_log_lines([
2982 ('root', 'ERROR', '2'),
2983 ])
2984
2985
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002986class QueueHandlerTest(BaseTest):
2987 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002988 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002989
2990 def setUp(self):
2991 BaseTest.setUp(self)
2992 self.queue = queue.Queue(-1)
2993 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2994 self.que_logger = logging.getLogger('que')
2995 self.que_logger.propagate = False
2996 self.que_logger.setLevel(logging.WARNING)
2997 self.que_logger.addHandler(self.que_hdlr)
2998
2999 def tearDown(self):
3000 self.que_hdlr.close()
3001 BaseTest.tearDown(self)
3002
3003 def test_queue_handler(self):
3004 self.que_logger.debug(self.next_message())
3005 self.assertRaises(queue.Empty, self.queue.get_nowait)
3006 self.que_logger.info(self.next_message())
3007 self.assertRaises(queue.Empty, self.queue.get_nowait)
3008 msg = self.next_message()
3009 self.que_logger.warning(msg)
3010 data = self.queue.get_nowait()
3011 self.assertTrue(isinstance(data, logging.LogRecord))
3012 self.assertEqual(data.name, self.que_logger.name)
3013 self.assertEqual((data.msg, data.args), (msg, None))
3014
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003015 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3016 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003017 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003018 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003019 listener = logging.handlers.QueueListener(self.queue, handler)
3020 listener.start()
3021 try:
3022 self.que_logger.warning(self.next_message())
3023 self.que_logger.error(self.next_message())
3024 self.que_logger.critical(self.next_message())
3025 finally:
3026 listener.stop()
3027 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3028 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3029 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3030
Vinay Sajip37eb3382011-04-26 20:26:41 +01003031ZERO = datetime.timedelta(0)
3032
3033class UTC(datetime.tzinfo):
3034 def utcoffset(self, dt):
3035 return ZERO
3036
3037 dst = utcoffset
3038
3039 def tzname(self, dt):
3040 return 'UTC'
3041
3042utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003043
Vinay Sajipa39c5712010-10-25 13:57:39 +00003044class FormatterTest(unittest.TestCase):
3045 def setUp(self):
3046 self.common = {
3047 'name': 'formatter.test',
3048 'level': logging.DEBUG,
3049 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3050 'lineno': 42,
3051 'exc_info': None,
3052 'func': None,
3053 'msg': 'Message with %d %s',
3054 'args': (2, 'placeholders'),
3055 }
3056 self.variants = {
3057 }
3058
3059 def get_record(self, name=None):
3060 result = dict(self.common)
3061 if name is not None:
3062 result.update(self.variants[name])
3063 return logging.makeLogRecord(result)
3064
3065 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003066 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003067 r = self.get_record()
3068 f = logging.Formatter('${%(message)s}')
3069 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3070 f = logging.Formatter('%(random)s')
3071 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003072 self.assertFalse(f.usesTime())
3073 f = logging.Formatter('%(asctime)s')
3074 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003075 f = logging.Formatter('%(asctime)-15s')
3076 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003077 f = logging.Formatter('asctime')
3078 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003079
3080 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003081 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003082 r = self.get_record()
3083 f = logging.Formatter('$%{message}%$', style='{')
3084 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3085 f = logging.Formatter('{random}', style='{')
3086 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003087 self.assertFalse(f.usesTime())
3088 f = logging.Formatter('{asctime}', style='{')
3089 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003090 f = logging.Formatter('{asctime!s:15}', style='{')
3091 self.assertTrue(f.usesTime())
3092 f = logging.Formatter('{asctime:15}', style='{')
3093 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003094 f = logging.Formatter('asctime', style='{')
3095 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003096
3097 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003098 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003099 r = self.get_record()
3100 f = logging.Formatter('$message', style='$')
3101 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3102 f = logging.Formatter('$$%${message}%$$', style='$')
3103 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3104 f = logging.Formatter('${random}', style='$')
3105 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003106 self.assertFalse(f.usesTime())
3107 f = logging.Formatter('${asctime}', style='$')
3108 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003109 f = logging.Formatter('${asctime', style='$')
3110 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003111 f = logging.Formatter('$asctime', style='$')
3112 self.assertTrue(f.usesTime())
3113 f = logging.Formatter('asctime', style='$')
3114 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003115
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003116 def test_invalid_style(self):
3117 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3118
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003119 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003120 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003121 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3122 # We use None to indicate we want the local timezone
3123 # We're essentially converting a UTC time to local time
3124 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003125 r.msecs = 123
3126 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003127 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003128 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3129 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003130 f.format(r)
3131 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3132
3133class TestBufferingFormatter(logging.BufferingFormatter):
3134 def formatHeader(self, records):
3135 return '[(%d)' % len(records)
3136
3137 def formatFooter(self, records):
3138 return '(%d)]' % len(records)
3139
3140class BufferingFormatterTest(unittest.TestCase):
3141 def setUp(self):
3142 self.records = [
3143 logging.makeLogRecord({'msg': 'one'}),
3144 logging.makeLogRecord({'msg': 'two'}),
3145 ]
3146
3147 def test_default(self):
3148 f = logging.BufferingFormatter()
3149 self.assertEqual('', f.format([]))
3150 self.assertEqual('onetwo', f.format(self.records))
3151
3152 def test_custom(self):
3153 f = TestBufferingFormatter()
3154 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3155 lf = logging.Formatter('<%(message)s>')
3156 f = TestBufferingFormatter(lf)
3157 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003158
3159class ExceptionTest(BaseTest):
3160 def test_formatting(self):
3161 r = self.root_logger
3162 h = RecordingHandler()
3163 r.addHandler(h)
3164 try:
3165 raise RuntimeError('deliberate mistake')
3166 except:
3167 logging.exception('failed', stack_info=True)
3168 r.removeHandler(h)
3169 h.close()
3170 r = h.records[0]
3171 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3172 'call last):\n'))
3173 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3174 'deliberate mistake'))
3175 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3176 'call last):\n'))
3177 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3178 'stack_info=True)'))
3179
3180
Vinay Sajip5a27d402010-12-10 11:42:57 +00003181class LastResortTest(BaseTest):
3182 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003183 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003184 root = self.root_logger
3185 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003186 old_lastresort = logging.lastResort
3187 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003188
Vinay Sajip5a27d402010-12-10 11:42:57 +00003189 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003190 with support.captured_stderr() as stderr:
3191 root.debug('This should not appear')
3192 self.assertEqual(stderr.getvalue(), '')
3193 root.warning('Final chance!')
3194 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3195
3196 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003197 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003198 with support.captured_stderr() as stderr:
3199 root.warning('Final chance!')
3200 msg = 'No handlers could be found for logger "root"\n'
3201 self.assertEqual(stderr.getvalue(), msg)
3202
Vinay Sajip5a27d402010-12-10 11:42:57 +00003203 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003204 with support.captured_stderr() as stderr:
3205 root.warning('Final chance!')
3206 self.assertEqual(stderr.getvalue(), '')
3207
3208 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003209 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003210 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003211 with support.captured_stderr() as stderr:
3212 root.warning('Final chance!')
3213 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003214 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003215 root.addHandler(self.root_hdlr)
3216 logging.lastResort = old_lastresort
3217 logging.raiseExceptions = old_raise_exceptions
3218
3219
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003220class FakeHandler:
3221
3222 def __init__(self, identifier, called):
3223 for method in ('acquire', 'flush', 'close', 'release'):
3224 setattr(self, method, self.record_call(identifier, method, called))
3225
3226 def record_call(self, identifier, method_name, called):
3227 def inner():
3228 called.append('{} - {}'.format(identifier, method_name))
3229 return inner
3230
3231
3232class RecordingHandler(logging.NullHandler):
3233
3234 def __init__(self, *args, **kwargs):
3235 super(RecordingHandler, self).__init__(*args, **kwargs)
3236 self.records = []
3237
3238 def handle(self, record):
3239 """Keep track of all the emitted records."""
3240 self.records.append(record)
3241
3242
3243class ShutdownTest(BaseTest):
3244
Vinay Sajip5e66b162011-04-20 15:41:14 +01003245 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003246
3247 def setUp(self):
3248 super(ShutdownTest, self).setUp()
3249 self.called = []
3250
3251 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003252 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003253
3254 def raise_error(self, error):
3255 def inner():
3256 raise error()
3257 return inner
3258
3259 def test_no_failure(self):
3260 # create some fake handlers
3261 handler0 = FakeHandler(0, self.called)
3262 handler1 = FakeHandler(1, self.called)
3263 handler2 = FakeHandler(2, self.called)
3264
3265 # create live weakref to those handlers
3266 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3267
3268 logging.shutdown(handlerList=list(handlers))
3269
3270 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3271 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3272 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3273 self.assertEqual(expected, self.called)
3274
3275 def _test_with_failure_in_method(self, method, error):
3276 handler = FakeHandler(0, self.called)
3277 setattr(handler, method, self.raise_error(error))
3278 handlers = [logging.weakref.ref(handler)]
3279
3280 logging.shutdown(handlerList=list(handlers))
3281
3282 self.assertEqual('0 - release', self.called[-1])
3283
3284 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003285 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003286
3287 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003288 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003289
3290 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003291 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003292
3293 def test_with_valueerror_in_acquire(self):
3294 self._test_with_failure_in_method('acquire', ValueError)
3295
3296 def test_with_valueerror_in_flush(self):
3297 self._test_with_failure_in_method('flush', ValueError)
3298
3299 def test_with_valueerror_in_close(self):
3300 self._test_with_failure_in_method('close', ValueError)
3301
3302 def test_with_other_error_in_acquire_without_raise(self):
3303 logging.raiseExceptions = False
3304 self._test_with_failure_in_method('acquire', IndexError)
3305
3306 def test_with_other_error_in_flush_without_raise(self):
3307 logging.raiseExceptions = False
3308 self._test_with_failure_in_method('flush', IndexError)
3309
3310 def test_with_other_error_in_close_without_raise(self):
3311 logging.raiseExceptions = False
3312 self._test_with_failure_in_method('close', IndexError)
3313
3314 def test_with_other_error_in_acquire_with_raise(self):
3315 logging.raiseExceptions = True
3316 self.assertRaises(IndexError, self._test_with_failure_in_method,
3317 'acquire', IndexError)
3318
3319 def test_with_other_error_in_flush_with_raise(self):
3320 logging.raiseExceptions = True
3321 self.assertRaises(IndexError, self._test_with_failure_in_method,
3322 'flush', IndexError)
3323
3324 def test_with_other_error_in_close_with_raise(self):
3325 logging.raiseExceptions = True
3326 self.assertRaises(IndexError, self._test_with_failure_in_method,
3327 'close', IndexError)
3328
3329
3330class ModuleLevelMiscTest(BaseTest):
3331
Vinay Sajip5e66b162011-04-20 15:41:14 +01003332 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003333
3334 def test_disable(self):
3335 old_disable = logging.root.manager.disable
3336 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003337 self.assertEqual(old_disable, 0)
3338 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003339
3340 logging.disable(83)
3341 self.assertEqual(logging.root.manager.disable, 83)
3342
3343 def _test_log(self, method, level=None):
3344 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003345 support.patch(self, logging, 'basicConfig',
3346 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003347
3348 recording = RecordingHandler()
3349 logging.root.addHandler(recording)
3350
3351 log_method = getattr(logging, method)
3352 if level is not None:
3353 log_method(level, "test me: %r", recording)
3354 else:
3355 log_method("test me: %r", recording)
3356
3357 self.assertEqual(len(recording.records), 1)
3358 record = recording.records[0]
3359 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3360
3361 expected_level = level if level is not None else getattr(logging, method.upper())
3362 self.assertEqual(record.levelno, expected_level)
3363
3364 # basicConfig was not called!
3365 self.assertEqual(called, [])
3366
3367 def test_log(self):
3368 self._test_log('log', logging.ERROR)
3369
3370 def test_debug(self):
3371 self._test_log('debug')
3372
3373 def test_info(self):
3374 self._test_log('info')
3375
3376 def test_warning(self):
3377 self._test_log('warning')
3378
3379 def test_error(self):
3380 self._test_log('error')
3381
3382 def test_critical(self):
3383 self._test_log('critical')
3384
3385 def test_set_logger_class(self):
3386 self.assertRaises(TypeError, logging.setLoggerClass, object)
3387
3388 class MyLogger(logging.Logger):
3389 pass
3390
3391 logging.setLoggerClass(MyLogger)
3392 self.assertEqual(logging.getLoggerClass(), MyLogger)
3393
3394 logging.setLoggerClass(logging.Logger)
3395 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3396
Antoine Pitrou712cb732013-12-21 15:51:54 +01003397 def test_logging_at_shutdown(self):
3398 # Issue #20037
3399 code = """if 1:
3400 import logging
3401
3402 class A:
3403 def __del__(self):
3404 try:
3405 raise ValueError("some error")
3406 except Exception:
3407 logging.exception("exception in __del__")
3408
3409 a = A()"""
3410 rc, out, err = assert_python_ok("-c", code)
3411 err = err.decode()
3412 self.assertIn("exception in __del__", err)
3413 self.assertIn("ValueError: some error", err)
3414
3415
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003416class LogRecordTest(BaseTest):
3417 def test_str_rep(self):
3418 r = logging.makeLogRecord({})
3419 s = str(r)
3420 self.assertTrue(s.startswith('<LogRecord: '))
3421 self.assertTrue(s.endswith('>'))
3422
3423 def test_dict_arg(self):
3424 h = RecordingHandler()
3425 r = logging.getLogger()
3426 r.addHandler(h)
3427 d = {'less' : 'more' }
3428 logging.warning('less is %(less)s', d)
3429 self.assertIs(h.records[0].args, d)
3430 self.assertEqual(h.records[0].message, 'less is more')
3431 r.removeHandler(h)
3432 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003433
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003434 def test_multiprocessing(self):
3435 r = logging.makeLogRecord({})
3436 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003437 try:
3438 import multiprocessing as mp
3439 r = logging.makeLogRecord({})
3440 self.assertEqual(r.processName, mp.current_process().name)
3441 except ImportError:
3442 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003443
3444 def test_optional(self):
3445 r = logging.makeLogRecord({})
3446 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003447 if threading:
3448 NOT_NONE(r.thread)
3449 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003450 NOT_NONE(r.process)
3451 NOT_NONE(r.processName)
3452 log_threads = logging.logThreads
3453 log_processes = logging.logProcesses
3454 log_multiprocessing = logging.logMultiprocessing
3455 try:
3456 logging.logThreads = False
3457 logging.logProcesses = False
3458 logging.logMultiprocessing = False
3459 r = logging.makeLogRecord({})
3460 NONE = self.assertIsNone
3461 NONE(r.thread)
3462 NONE(r.threadName)
3463 NONE(r.process)
3464 NONE(r.processName)
3465 finally:
3466 logging.logThreads = log_threads
3467 logging.logProcesses = log_processes
3468 logging.logMultiprocessing = log_multiprocessing
3469
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003470class BasicConfigTest(unittest.TestCase):
3471
Vinay Sajip95bf5042011-04-20 11:50:56 +01003472 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003473
3474 def setUp(self):
3475 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003476 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003477 self.saved_handlers = logging._handlers.copy()
3478 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003479 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003480 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003481 logging.root.handlers = []
3482
3483 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003484 for h in logging.root.handlers[:]:
3485 logging.root.removeHandler(h)
3486 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003487 super(BasicConfigTest, self).tearDown()
3488
Vinay Sajip3def7e02011-04-20 10:58:06 +01003489 def cleanup(self):
3490 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003491 logging._handlers.clear()
3492 logging._handlers.update(self.saved_handlers)
3493 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003494 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003495
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003496 def test_no_kwargs(self):
3497 logging.basicConfig()
3498
3499 # handler defaults to a StreamHandler to sys.stderr
3500 self.assertEqual(len(logging.root.handlers), 1)
3501 handler = logging.root.handlers[0]
3502 self.assertIsInstance(handler, logging.StreamHandler)
3503 self.assertEqual(handler.stream, sys.stderr)
3504
3505 formatter = handler.formatter
3506 # format defaults to logging.BASIC_FORMAT
3507 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3508 # datefmt defaults to None
3509 self.assertIsNone(formatter.datefmt)
3510 # style defaults to %
3511 self.assertIsInstance(formatter._style, logging.PercentStyle)
3512
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003513 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003514 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003515
Vinay Sajip1fd12022014-01-13 21:59:56 +00003516 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003517 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003518 logging.basicConfig(stream=sys.stdout, style="{")
3519 logging.error("Log an error")
3520 sys.stdout.seek(0)
3521 self.assertEqual(output.getvalue().strip(),
3522 "ERROR:root:Log an error")
3523
3524 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003525 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003526 logging.basicConfig(stream=sys.stdout, style="$")
3527 logging.error("Log an error")
3528 sys.stdout.seek(0)
3529 self.assertEqual(output.getvalue().strip(),
3530 "ERROR:root:Log an error")
3531
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003532 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003533
3534 def cleanup(h1, h2, fn):
3535 h1.close()
3536 h2.close()
3537 os.remove(fn)
3538
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003539 logging.basicConfig(filename='test.log')
3540
3541 self.assertEqual(len(logging.root.handlers), 1)
3542 handler = logging.root.handlers[0]
3543 self.assertIsInstance(handler, logging.FileHandler)
3544
3545 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003546 self.assertEqual(handler.stream.mode, expected.stream.mode)
3547 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003548 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003549
3550 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003551
3552 def cleanup(h1, h2, fn):
3553 h1.close()
3554 h2.close()
3555 os.remove(fn)
3556
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003557 logging.basicConfig(filename='test.log', filemode='wb')
3558
3559 handler = logging.root.handlers[0]
3560 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003562 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003563
3564 def test_stream(self):
3565 stream = io.StringIO()
3566 self.addCleanup(stream.close)
3567 logging.basicConfig(stream=stream)
3568
3569 self.assertEqual(len(logging.root.handlers), 1)
3570 handler = logging.root.handlers[0]
3571 self.assertIsInstance(handler, logging.StreamHandler)
3572 self.assertEqual(handler.stream, stream)
3573
3574 def test_format(self):
3575 logging.basicConfig(format='foo')
3576
3577 formatter = logging.root.handlers[0].formatter
3578 self.assertEqual(formatter._style._fmt, 'foo')
3579
3580 def test_datefmt(self):
3581 logging.basicConfig(datefmt='bar')
3582
3583 formatter = logging.root.handlers[0].formatter
3584 self.assertEqual(formatter.datefmt, 'bar')
3585
3586 def test_style(self):
3587 logging.basicConfig(style='$')
3588
3589 formatter = logging.root.handlers[0].formatter
3590 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3591
3592 def test_level(self):
3593 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003594 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003595
3596 logging.basicConfig(level=57)
3597 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003598 # Test that second call has no effect
3599 logging.basicConfig(level=58)
3600 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003601
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003602 def test_incompatible(self):
3603 assertRaises = self.assertRaises
3604 handlers = [logging.StreamHandler()]
3605 stream = sys.stderr
3606 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3607 stream=stream)
3608 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3609 handlers=handlers)
3610 assertRaises(ValueError, logging.basicConfig, stream=stream,
3611 handlers=handlers)
3612
3613 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003614 handlers = [
3615 logging.StreamHandler(),
3616 logging.StreamHandler(sys.stdout),
3617 logging.StreamHandler(),
3618 ]
3619 f = logging.Formatter()
3620 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003621 logging.basicConfig(handlers=handlers)
3622 self.assertIs(handlers[0], logging.root.handlers[0])
3623 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003624 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003625 self.assertIsNotNone(handlers[0].formatter)
3626 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003627 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003628 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3629
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003630 def _test_log(self, method, level=None):
3631 # logging.root has no handlers so basicConfig should be called
3632 called = []
3633
3634 old_basic_config = logging.basicConfig
3635 def my_basic_config(*a, **kw):
3636 old_basic_config()
3637 old_level = logging.root.level
3638 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003639 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003640 called.append((a, kw))
3641
Vinay Sajip1feedb42014-05-31 08:19:12 +01003642 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003643
3644 log_method = getattr(logging, method)
3645 if level is not None:
3646 log_method(level, "test me")
3647 else:
3648 log_method("test me")
3649
3650 # basicConfig was called with no arguments
3651 self.assertEqual(called, [((), {})])
3652
3653 def test_log(self):
3654 self._test_log('log', logging.WARNING)
3655
3656 def test_debug(self):
3657 self._test_log('debug')
3658
3659 def test_info(self):
3660 self._test_log('info')
3661
3662 def test_warning(self):
3663 self._test_log('warning')
3664
3665 def test_error(self):
3666 self._test_log('error')
3667
3668 def test_critical(self):
3669 self._test_log('critical')
3670
3671
3672class LoggerAdapterTest(unittest.TestCase):
3673
3674 def setUp(self):
3675 super(LoggerAdapterTest, self).setUp()
3676 old_handler_list = logging._handlerList[:]
3677
3678 self.recording = RecordingHandler()
3679 self.logger = logging.root
3680 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003681 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003682 self.addCleanup(self.recording.close)
3683
3684 def cleanup():
3685 logging._handlerList[:] = old_handler_list
3686
3687 self.addCleanup(cleanup)
3688 self.addCleanup(logging.shutdown)
3689 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3690
3691 def test_exception(self):
3692 msg = 'testing exception: %r'
3693 exc = None
3694 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003695 1 / 0
3696 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003697 exc = e
3698 self.adapter.exception(msg, self.recording)
3699
3700 self.assertEqual(len(self.recording.records), 1)
3701 record = self.recording.records[0]
3702 self.assertEqual(record.levelno, logging.ERROR)
3703 self.assertEqual(record.msg, msg)
3704 self.assertEqual(record.args, (self.recording,))
3705 self.assertEqual(record.exc_info,
3706 (exc.__class__, exc, exc.__traceback__))
3707
3708 def test_critical(self):
3709 msg = 'critical test! %r'
3710 self.adapter.critical(msg, self.recording)
3711
3712 self.assertEqual(len(self.recording.records), 1)
3713 record = self.recording.records[0]
3714 self.assertEqual(record.levelno, logging.CRITICAL)
3715 self.assertEqual(record.msg, msg)
3716 self.assertEqual(record.args, (self.recording,))
3717
3718 def test_is_enabled_for(self):
3719 old_disable = self.adapter.logger.manager.disable
3720 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003721 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3722 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003723 self.assertFalse(self.adapter.isEnabledFor(32))
3724
3725 def test_has_handlers(self):
3726 self.assertTrue(self.adapter.hasHandlers())
3727
3728 for handler in self.logger.handlers:
3729 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003730
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003731 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003732 self.assertFalse(self.adapter.hasHandlers())
3733
3734
3735class LoggerTest(BaseTest):
3736
3737 def setUp(self):
3738 super(LoggerTest, self).setUp()
3739 self.recording = RecordingHandler()
3740 self.logger = logging.Logger(name='blah')
3741 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003742 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003743 self.addCleanup(self.recording.close)
3744 self.addCleanup(logging.shutdown)
3745
3746 def test_set_invalid_level(self):
3747 self.assertRaises(TypeError, self.logger.setLevel, object())
3748
3749 def test_exception(self):
3750 msg = 'testing exception: %r'
3751 exc = None
3752 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003753 1 / 0
3754 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003755 exc = e
3756 self.logger.exception(msg, self.recording)
3757
3758 self.assertEqual(len(self.recording.records), 1)
3759 record = self.recording.records[0]
3760 self.assertEqual(record.levelno, logging.ERROR)
3761 self.assertEqual(record.msg, msg)
3762 self.assertEqual(record.args, (self.recording,))
3763 self.assertEqual(record.exc_info,
3764 (exc.__class__, exc, exc.__traceback__))
3765
3766 def test_log_invalid_level_with_raise(self):
3767 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003768 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003769
3770 logging.raiseExceptions = True
3771 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3772
3773 def test_log_invalid_level_no_raise(self):
3774 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003775 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003776
3777 logging.raiseExceptions = False
3778 self.logger.log('10', 'test message') # no exception happens
3779
3780 def test_find_caller_with_stack_info(self):
3781 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003782 support.patch(self, logging.traceback, 'print_stack',
3783 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003784
3785 self.logger.findCaller(stack_info=True)
3786
3787 self.assertEqual(len(called), 1)
3788 self.assertEqual('Stack (most recent call last):\n', called[0])
3789
3790 def test_make_record_with_extra_overwrite(self):
3791 name = 'my record'
3792 level = 13
3793 fn = lno = msg = args = exc_info = func = sinfo = None
3794 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3795 exc_info, func, sinfo)
3796
3797 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3798 extra = {key: 'some value'}
3799 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3800 fn, lno, msg, args, exc_info,
3801 extra=extra, sinfo=sinfo)
3802
3803 def test_make_record_with_extra_no_overwrite(self):
3804 name = 'my record'
3805 level = 13
3806 fn = lno = msg = args = exc_info = func = sinfo = None
3807 extra = {'valid_key': 'some value'}
3808 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3809 exc_info, extra=extra, sinfo=sinfo)
3810 self.assertIn('valid_key', result.__dict__)
3811
3812 def test_has_handlers(self):
3813 self.assertTrue(self.logger.hasHandlers())
3814
3815 for handler in self.logger.handlers:
3816 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003817 self.assertFalse(self.logger.hasHandlers())
3818
3819 def test_has_handlers_no_propagate(self):
3820 child_logger = logging.getLogger('blah.child')
3821 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003822 self.assertFalse(child_logger.hasHandlers())
3823
3824 def test_is_enabled_for(self):
3825 old_disable = self.logger.manager.disable
3826 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003827 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003828 self.assertFalse(self.logger.isEnabledFor(22))
3829
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003830 def test_root_logger_aliases(self):
3831 root = logging.getLogger()
3832 self.assertIs(root, logging.root)
3833 self.assertIs(root, logging.getLogger(None))
3834 self.assertIs(root, logging.getLogger(''))
3835 self.assertIs(root, logging.getLogger('foo').root)
3836 self.assertIs(root, logging.getLogger('foo.bar').root)
3837 self.assertIs(root, logging.getLogger('foo').parent)
3838
3839 self.assertIsNot(root, logging.getLogger('\0'))
3840 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3841
3842 def test_invalid_names(self):
3843 self.assertRaises(TypeError, logging.getLogger, any)
3844 self.assertRaises(TypeError, logging.getLogger, b'foo')
3845
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003846
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003847class BaseFileTest(BaseTest):
3848 "Base class for handler tests that write log files"
3849
3850 def setUp(self):
3851 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003852 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3853 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003854 self.rmfiles = []
3855
3856 def tearDown(self):
3857 for fn in self.rmfiles:
3858 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003859 if os.path.exists(self.fn):
3860 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003861 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003862
3863 def assertLogFile(self, filename):
3864 "Assert a log file is there and register it for deletion"
3865 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003866 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003867 self.rmfiles.append(filename)
3868
3869
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003870class FileHandlerTest(BaseFileTest):
3871 def test_delay(self):
3872 os.unlink(self.fn)
3873 fh = logging.FileHandler(self.fn, delay=True)
3874 self.assertIsNone(fh.stream)
3875 self.assertFalse(os.path.exists(self.fn))
3876 fh.handle(logging.makeLogRecord({}))
3877 self.assertIsNotNone(fh.stream)
3878 self.assertTrue(os.path.exists(self.fn))
3879 fh.close()
3880
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003881class RotatingFileHandlerTest(BaseFileTest):
3882 def next_rec(self):
3883 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3884 self.next_message(), None, None, None)
3885
3886 def test_should_not_rollover(self):
3887 # If maxbytes is zero rollover never occurs
3888 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3889 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003890 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003891
3892 def test_should_rollover(self):
3893 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3894 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003895 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003896
3897 def test_file_created(self):
3898 # checks that the file is created and assumes it was created
3899 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003900 rh = logging.handlers.RotatingFileHandler(self.fn)
3901 rh.emit(self.next_rec())
3902 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003903 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003904
3905 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003906 def namer(name):
3907 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003908 rh = logging.handlers.RotatingFileHandler(
3909 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003910 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003911 rh.emit(self.next_rec())
3912 self.assertLogFile(self.fn)
3913 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003914 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003915 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003916 self.assertLogFile(namer(self.fn + ".2"))
3917 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3918 rh.close()
3919
Vinay Sajip1feedb42014-05-31 08:19:12 +01003920 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003921 def test_rotator(self):
3922 def namer(name):
3923 return name + ".gz"
3924
3925 def rotator(source, dest):
3926 with open(source, "rb") as sf:
3927 data = sf.read()
3928 compressed = zlib.compress(data, 9)
3929 with open(dest, "wb") as df:
3930 df.write(compressed)
3931 os.remove(source)
3932
3933 rh = logging.handlers.RotatingFileHandler(
3934 self.fn, backupCount=2, maxBytes=1)
3935 rh.rotator = rotator
3936 rh.namer = namer
3937 m1 = self.next_rec()
3938 rh.emit(m1)
3939 self.assertLogFile(self.fn)
3940 m2 = self.next_rec()
3941 rh.emit(m2)
3942 fn = namer(self.fn + ".1")
3943 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003944 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003945 with open(fn, "rb") as f:
3946 compressed = f.read()
3947 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003948 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003949 rh.emit(self.next_rec())
3950 fn = namer(self.fn + ".2")
3951 self.assertLogFile(fn)
3952 with open(fn, "rb") as f:
3953 compressed = f.read()
3954 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003955 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003956 rh.emit(self.next_rec())
3957 fn = namer(self.fn + ".2")
3958 with open(fn, "rb") as f:
3959 compressed = f.read()
3960 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003961 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003962 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003963 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003964
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003965class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003966 # other test methods added below
3967 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003968 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3969 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003970 fmt = logging.Formatter('%(asctime)s %(message)s')
3971 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003972 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003973 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003974 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003975 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003976 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003977 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003978 fh.close()
3979 # At this point, we should have a recent rotated file which we
3980 # can test for the existence of. However, in practice, on some
3981 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003982 # in time to go to look for the log file. So, we go back a fair
3983 # bit, and stop as soon as we see a rotated file. In theory this
3984 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003985 found = False
3986 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003987 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003988 for secs in range(GO_BACK):
3989 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003990 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3991 found = os.path.exists(fn)
3992 if found:
3993 self.rmfiles.append(fn)
3994 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003995 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3996 if not found:
3997 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003998 dn, fn = os.path.split(self.fn)
3999 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004000 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4001 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004002 for f in files:
4003 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004004 path = os.path.join(dn, f)
4005 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004006 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004007 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004008
Vinay Sajip0372e102011-05-05 12:59:14 +01004009 def test_invalid(self):
4010 assertRaises = self.assertRaises
4011 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004012 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004013 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004014 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004015 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004016 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004017
Vinay Sajipa7130792013-04-12 17:04:23 +01004018 def test_compute_rollover_daily_attime(self):
4019 currentTime = 0
4020 atTime = datetime.time(12, 0, 0)
4021 rh = logging.handlers.TimedRotatingFileHandler(
4022 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4023 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004024 try:
4025 actual = rh.computeRollover(currentTime)
4026 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004027
Vinay Sajipd86ac962013-04-14 12:20:46 +01004028 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4029 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4030 finally:
4031 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004032
Vinay Sajip10e8c492013-05-18 10:19:54 -07004033 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004034 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004035 currentTime = int(time.time())
4036 today = currentTime - currentTime % 86400
4037
Vinay Sajipa7130792013-04-12 17:04:23 +01004038 atTime = datetime.time(12, 0, 0)
4039
Vinay Sajip10e8c492013-05-18 10:19:54 -07004040 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004041 for day in range(7):
4042 rh = logging.handlers.TimedRotatingFileHandler(
4043 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4044 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004045 try:
4046 if wday > day:
4047 # The rollover day has already passed this week, so we
4048 # go over into next week
4049 expected = (7 - wday + day)
4050 else:
4051 expected = (day - wday)
4052 # At this point expected is in days from now, convert to seconds
4053 expected *= 24 * 60 * 60
4054 # Add in the rollover time
4055 expected += 12 * 60 * 60
4056 # Add in adjustment for today
4057 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004058 actual = rh.computeRollover(today)
4059 if actual != expected:
4060 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004061 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004062 self.assertEqual(actual, expected)
4063 if day == wday:
4064 # goes into following week
4065 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004066 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004067 if actual != expected:
4068 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004069 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004070 self.assertEqual(actual, expected)
4071 finally:
4072 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004073
4074
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004075def secs(**kw):
4076 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4077
4078for when, exp in (('S', 1),
4079 ('M', 60),
4080 ('H', 60 * 60),
4081 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004082 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004083 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004084 ('W0', secs(days=4, hours=24)),
4085 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004086 def test_compute_rollover(self, when=when, exp=exp):
4087 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004088 self.fn, when=when, interval=1, backupCount=0, utc=True)
4089 currentTime = 0.0
4090 actual = rh.computeRollover(currentTime)
4091 if exp != actual:
4092 # Failures occur on some systems for MIDNIGHT and W0.
4093 # Print detailed calculation for MIDNIGHT so we can try to see
4094 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004095 if when == 'MIDNIGHT':
4096 try:
4097 if rh.utc:
4098 t = time.gmtime(currentTime)
4099 else:
4100 t = time.localtime(currentTime)
4101 currentHour = t[3]
4102 currentMinute = t[4]
4103 currentSecond = t[5]
4104 # r is the number of seconds left between now and midnight
4105 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4106 currentMinute) * 60 +
4107 currentSecond)
4108 result = currentTime + r
4109 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4110 print('currentHour: %s' % currentHour, file=sys.stderr)
4111 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4112 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4113 print('r: %s' % r, file=sys.stderr)
4114 print('result: %s' % result, file=sys.stderr)
4115 except Exception:
4116 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4117 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004118 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004119 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4120
Vinay Sajip60ccd822011-05-09 17:32:09 +01004121
4122@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4123class NTEventLogHandlerTest(BaseTest):
4124 def test_basic(self):
4125 logtype = 'Application'
4126 elh = win32evtlog.OpenEventLog(None, logtype)
4127 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4128 h = logging.handlers.NTEventLogHandler('test_logging')
4129 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4130 h.handle(r)
4131 h.close()
4132 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004133 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004134 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4135 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4136 found = False
4137 GO_BACK = 100
4138 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4139 for e in events:
4140 if e.SourceName != 'test_logging':
4141 continue
4142 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4143 if msg != 'Test Log Message\r\n':
4144 continue
4145 found = True
4146 break
4147 msg = 'Record not found in event log, went back %d records' % GO_BACK
4148 self.assertTrue(found, msg=msg)
4149
Christian Heimes180510d2008-03-03 19:15:45 +00004150# Set the locale to the platform-dependent default. I have no idea
4151# why the test does this, but in any case we save the current locale
4152# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004153@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004154def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004155 support.run_unittest(
4156 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4157 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4158 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4159 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4160 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4161 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4162 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4163 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4164 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4165 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
4166 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004167
Christian Heimes180510d2008-03-03 19:15:45 +00004168if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004169 test_main()