blob: eed67d09b8bb2c855a270cfc75573bf0eb62b9d3 [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajip3f885b52013-03-22 15:19:54 +00003# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00004#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose and without fee is hereby granted,
7# provided that the above copyright notice appear in all copies and that
8# both that copyright notice and this permission notice appear in
9# supporting documentation, and that the name of Vinay Sajip
10# not be used in advertising or publicity pertaining to distribution
11# of the software without specific, written prior permission.
12# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
16# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19"""Test harness for the logging module. Run all tests.
20
Vinay Sajip3f885b52013-03-22 15:19:54 +000021Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000022"""
23
Christian Heimes180510d2008-03-03 19:15:45 +000024import logging
25import logging.handlers
26import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000027
Benjamin Petersonf91df042009-02-13 02:50:59 +000028import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010029import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000030import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000031import pickle
32import io
33import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000034import json
Christian Heimes180510d2008-03-03 19:15:45 +000035import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000036import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010037import random
Christian Heimes180510d2008-03-03 19:15:45 +000038import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000039import select
Christian Heimes180510d2008-03-03 19:15:45 +000040import socket
Christian Heimes180510d2008-03-03 19:15:45 +000041import struct
42import sys
43import tempfile
Eric V. Smith851cad72012-03-11 22:46:04 -070044from test.support import (captured_stdout, run_with_locale, run_unittest,
45 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000046import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010047import time
Christian Heimes180510d2008-03-03 19:15:45 +000048import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000049import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000050import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000051try:
52 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010054 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010055 import asynchat
56 import asyncore
57 import errno
58 from http.server import HTTPServer, BaseHTTPRequestHandler
59 import smtpd
60 from urllib.parse import urlparse, parse_qs
61 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
62 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000063except ImportError:
64 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010065try:
66 import win32evtlog
67except ImportError:
68 win32evtlog = None
69try:
70 import win32evtlogutil
71except ImportError:
72 win32evtlogutil = None
73 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070074try:
75 import zlib
76except ImportError:
77 pass
Christian Heimes18c66892008-02-17 13:31:39 +000078
79
Christian Heimes180510d2008-03-03 19:15:45 +000080class BaseTest(unittest.TestCase):
81
82 """Base class for logging tests."""
83
84 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030085 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000086 message_num = 0
87
88 def setUp(self):
89 """Setup the default logging stream to an internal StringIO instance,
90 so that we can examine log output as we want."""
91 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000092 logging._acquireLock()
93 try:
Christian Heimes180510d2008-03-03 19:15:45 +000094 self.saved_handlers = logging._handlers.copy()
95 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000096 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070097 self.saved_name_to_level = logging._nameToLevel.copy()
98 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000099 self.logger_states = logger_states = {}
100 for name in saved_loggers:
101 logger_states[name] = getattr(saved_loggers[name],
102 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000103 finally:
104 logging._releaseLock()
105
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100106 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000107 self.logger1 = logging.getLogger("\xab\xd7\xbb")
108 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000109
Christian Heimes180510d2008-03-03 19:15:45 +0000110 self.root_logger = logging.getLogger("")
111 self.original_logging_level = self.root_logger.getEffectiveLevel()
112
113 self.stream = io.StringIO()
114 self.root_logger.setLevel(logging.DEBUG)
115 self.root_hdlr = logging.StreamHandler(self.stream)
116 self.root_formatter = logging.Formatter(self.log_format)
117 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000118 if self.logger1.hasHandlers():
119 hlist = self.logger1.handlers + self.root_logger.handlers
120 raise AssertionError('Unexpected handlers: %s' % hlist)
121 if self.logger2.hasHandlers():
122 hlist = self.logger2.handlers + self.root_logger.handlers
123 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000124 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000125 self.assertTrue(self.logger1.hasHandlers())
126 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000127
128 def tearDown(self):
129 """Remove our logging stream, and restore the original logging
130 level."""
131 self.stream.close()
132 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000133 while self.root_logger.handlers:
134 h = self.root_logger.handlers[0]
135 self.root_logger.removeHandler(h)
136 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000137 self.root_logger.setLevel(self.original_logging_level)
138 logging._acquireLock()
139 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700140 logging._levelToName.clear()
141 logging._levelToName.update(self.saved_level_to_name)
142 logging._nameToLevel.clear()
143 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000144 logging._handlers.clear()
145 logging._handlers.update(self.saved_handlers)
146 logging._handlerList[:] = self.saved_handler_list
147 loggerDict = logging.getLogger().manager.loggerDict
148 loggerDict.clear()
149 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000150 logger_states = self.logger_states
151 for name in self.logger_states:
152 if logger_states[name] is not None:
153 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000154 finally:
155 logging._releaseLock()
156
Vinay Sajip4ded5512012-10-02 15:56:16 +0100157 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000158 """Match the collected log lines against the regular expression
159 self.expected_log_pat, and compare the extracted group values to
160 the expected_values list of tuples."""
161 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100162 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300163 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100164 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000165 for actual, expected in zip(actual_lines, expected_values):
166 match = pat.search(actual)
167 if not match:
168 self.fail("Log line does not match expected pattern:\n" +
169 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000170 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000171 s = stream.read()
172 if s:
173 self.fail("Remaining output at end of log stream:\n" + s)
174
175 def next_message(self):
176 """Generate a message consisting solely of an auto-incrementing
177 integer."""
178 self.message_num += 1
179 return "%d" % self.message_num
180
181
182class BuiltinLevelsTest(BaseTest):
183 """Test builtin levels and their inheritance."""
184
185 def test_flat(self):
186 #Logging levels in a flat logger namespace.
187 m = self.next_message
188
189 ERR = logging.getLogger("ERR")
190 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000191 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000192 INF.setLevel(logging.INFO)
193 DEB = logging.getLogger("DEB")
194 DEB.setLevel(logging.DEBUG)
195
196 # These should log.
197 ERR.log(logging.CRITICAL, m())
198 ERR.error(m())
199
200 INF.log(logging.CRITICAL, m())
201 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 INF.info(m())
204
205 DEB.log(logging.CRITICAL, m())
206 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 DEB.warning(m())
208 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000209 DEB.debug(m())
210
211 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100212 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000213 ERR.info(m())
214 ERR.debug(m())
215
216 INF.debug(m())
217
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000218 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000219 ('ERR', 'CRITICAL', '1'),
220 ('ERR', 'ERROR', '2'),
221 ('INF', 'CRITICAL', '3'),
222 ('INF', 'ERROR', '4'),
223 ('INF', 'WARNING', '5'),
224 ('INF', 'INFO', '6'),
225 ('DEB', 'CRITICAL', '7'),
226 ('DEB', 'ERROR', '8'),
227 ('DEB', 'WARNING', '9'),
228 ('DEB', 'INFO', '10'),
229 ('DEB', 'DEBUG', '11'),
230 ])
231
232 def test_nested_explicit(self):
233 # Logging levels in a nested namespace, all explicitly set.
234 m = self.next_message
235
236 INF = logging.getLogger("INF")
237 INF.setLevel(logging.INFO)
238 INF_ERR = logging.getLogger("INF.ERR")
239 INF_ERR.setLevel(logging.ERROR)
240
241 # These should log.
242 INF_ERR.log(logging.CRITICAL, m())
243 INF_ERR.error(m())
244
245 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100246 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000247 INF_ERR.info(m())
248 INF_ERR.debug(m())
249
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000250 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000251 ('INF.ERR', 'CRITICAL', '1'),
252 ('INF.ERR', 'ERROR', '2'),
253 ])
254
255 def test_nested_inherited(self):
256 #Logging levels in a nested namespace, inherited from parent loggers.
257 m = self.next_message
258
259 INF = logging.getLogger("INF")
260 INF.setLevel(logging.INFO)
261 INF_ERR = logging.getLogger("INF.ERR")
262 INF_ERR.setLevel(logging.ERROR)
263 INF_UNDEF = logging.getLogger("INF.UNDEF")
264 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
265 UNDEF = logging.getLogger("UNDEF")
266
267 # These should log.
268 INF_UNDEF.log(logging.CRITICAL, m())
269 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100270 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000271 INF_UNDEF.info(m())
272 INF_ERR_UNDEF.log(logging.CRITICAL, m())
273 INF_ERR_UNDEF.error(m())
274
275 # These should not log.
276 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100277 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000278 INF_ERR_UNDEF.info(m())
279 INF_ERR_UNDEF.debug(m())
280
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000281 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000282 ('INF.UNDEF', 'CRITICAL', '1'),
283 ('INF.UNDEF', 'ERROR', '2'),
284 ('INF.UNDEF', 'WARNING', '3'),
285 ('INF.UNDEF', 'INFO', '4'),
286 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
287 ('INF.ERR.UNDEF', 'ERROR', '6'),
288 ])
289
290 def test_nested_with_virtual_parent(self):
291 # Logging levels when some parent does not exist yet.
292 m = self.next_message
293
294 INF = logging.getLogger("INF")
295 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
296 CHILD = logging.getLogger("INF.BADPARENT")
297 INF.setLevel(logging.INFO)
298
299 # These should log.
300 GRANDCHILD.log(logging.FATAL, m())
301 GRANDCHILD.info(m())
302 CHILD.log(logging.FATAL, m())
303 CHILD.info(m())
304
305 # These should not log.
306 GRANDCHILD.debug(m())
307 CHILD.debug(m())
308
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000309 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000310 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
311 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
312 ('INF.BADPARENT', 'CRITICAL', '3'),
313 ('INF.BADPARENT', 'INFO', '4'),
314 ])
315
316
317class BasicFilterTest(BaseTest):
318
319 """Test the bundled Filter class."""
320
321 def test_filter(self):
322 # Only messages satisfying the specified criteria pass through the
323 # filter.
324 filter_ = logging.Filter("spam.eggs")
325 handler = self.root_logger.handlers[0]
326 try:
327 handler.addFilter(filter_)
328 spam = logging.getLogger("spam")
329 spam_eggs = logging.getLogger("spam.eggs")
330 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
331 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
332
333 spam.info(self.next_message())
334 spam_eggs.info(self.next_message()) # Good.
335 spam_eggs_fish.info(self.next_message()) # Good.
336 spam_bakedbeans.info(self.next_message())
337
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000338 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000339 ('spam.eggs', 'INFO', '2'),
340 ('spam.eggs.fish', 'INFO', '3'),
341 ])
342 finally:
343 handler.removeFilter(filter_)
344
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000345 def test_callable_filter(self):
346 # Only messages satisfying the specified criteria pass through the
347 # filter.
348
349 def filterfunc(record):
350 parts = record.name.split('.')
351 prefix = '.'.join(parts[:2])
352 return prefix == 'spam.eggs'
353
354 handler = self.root_logger.handlers[0]
355 try:
356 handler.addFilter(filterfunc)
357 spam = logging.getLogger("spam")
358 spam_eggs = logging.getLogger("spam.eggs")
359 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
360 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
361
362 spam.info(self.next_message())
363 spam_eggs.info(self.next_message()) # Good.
364 spam_eggs_fish.info(self.next_message()) # Good.
365 spam_bakedbeans.info(self.next_message())
366
367 self.assert_log_lines([
368 ('spam.eggs', 'INFO', '2'),
369 ('spam.eggs.fish', 'INFO', '3'),
370 ])
371 finally:
372 handler.removeFilter(filterfunc)
373
Vinay Sajip985ef872011-04-26 19:34:04 +0100374 def test_empty_filter(self):
375 f = logging.Filter()
376 r = logging.makeLogRecord({'name': 'spam.eggs'})
377 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000378
379#
380# First, we define our levels. There can be as many as you want - the only
381# limitations are that they should be integers, the lowest should be > 0 and
382# larger values mean less information being logged. If you need specific
383# level values which do not fit into these limitations, you can use a
384# mapping dictionary to convert between your application levels and the
385# logging system.
386#
387SILENT = 120
388TACITURN = 119
389TERSE = 118
390EFFUSIVE = 117
391SOCIABLE = 116
392VERBOSE = 115
393TALKATIVE = 114
394GARRULOUS = 113
395CHATTERBOX = 112
396BORING = 111
397
398LEVEL_RANGE = range(BORING, SILENT + 1)
399
400#
401# Next, we define names for our levels. You don't need to do this - in which
402# case the system will use "Level n" to denote the text for the level.
403#
404my_logging_levels = {
405 SILENT : 'Silent',
406 TACITURN : 'Taciturn',
407 TERSE : 'Terse',
408 EFFUSIVE : 'Effusive',
409 SOCIABLE : 'Sociable',
410 VERBOSE : 'Verbose',
411 TALKATIVE : 'Talkative',
412 GARRULOUS : 'Garrulous',
413 CHATTERBOX : 'Chatterbox',
414 BORING : 'Boring',
415}
416
417class GarrulousFilter(logging.Filter):
418
419 """A filter which blocks garrulous messages."""
420
421 def filter(self, record):
422 return record.levelno != GARRULOUS
423
424class VerySpecificFilter(logging.Filter):
425
426 """A filter which blocks sociable and taciturn messages."""
427
428 def filter(self, record):
429 return record.levelno not in [SOCIABLE, TACITURN]
430
431
432class CustomLevelsAndFiltersTest(BaseTest):
433
434 """Test various filtering possibilities with custom logging levels."""
435
436 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300437 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000438
439 def setUp(self):
440 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000441 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000442 logging.addLevelName(k, v)
443
444 def log_at_all_levels(self, logger):
445 for lvl in LEVEL_RANGE:
446 logger.log(lvl, self.next_message())
447
448 def test_logger_filter(self):
449 # Filter at logger level.
450 self.root_logger.setLevel(VERBOSE)
451 # Levels >= 'Verbose' are good.
452 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000453 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000454 ('Verbose', '5'),
455 ('Sociable', '6'),
456 ('Effusive', '7'),
457 ('Terse', '8'),
458 ('Taciturn', '9'),
459 ('Silent', '10'),
460 ])
461
462 def test_handler_filter(self):
463 # Filter at handler level.
464 self.root_logger.handlers[0].setLevel(SOCIABLE)
465 try:
466 # Levels >= 'Sociable' are good.
467 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000468 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000469 ('Sociable', '6'),
470 ('Effusive', '7'),
471 ('Terse', '8'),
472 ('Taciturn', '9'),
473 ('Silent', '10'),
474 ])
475 finally:
476 self.root_logger.handlers[0].setLevel(logging.NOTSET)
477
478 def test_specific_filters(self):
479 # Set a specific filter object on the handler, and then add another
480 # filter object on the logger itself.
481 handler = self.root_logger.handlers[0]
482 specific_filter = None
483 garr = GarrulousFilter()
484 handler.addFilter(garr)
485 try:
486 self.log_at_all_levels(self.root_logger)
487 first_lines = [
488 # Notice how 'Garrulous' is missing
489 ('Boring', '1'),
490 ('Chatterbox', '2'),
491 ('Talkative', '4'),
492 ('Verbose', '5'),
493 ('Sociable', '6'),
494 ('Effusive', '7'),
495 ('Terse', '8'),
496 ('Taciturn', '9'),
497 ('Silent', '10'),
498 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000499 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000500
501 specific_filter = VerySpecificFilter()
502 self.root_logger.addFilter(specific_filter)
503 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000504 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000505 # Not only 'Garrulous' is still missing, but also 'Sociable'
506 # and 'Taciturn'
507 ('Boring', '11'),
508 ('Chatterbox', '12'),
509 ('Talkative', '14'),
510 ('Verbose', '15'),
511 ('Effusive', '17'),
512 ('Terse', '18'),
513 ('Silent', '20'),
514 ])
515 finally:
516 if specific_filter:
517 self.root_logger.removeFilter(specific_filter)
518 handler.removeFilter(garr)
519
520
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100521class HandlerTest(BaseTest):
522 def test_name(self):
523 h = logging.Handler()
524 h.name = 'generic'
525 self.assertEqual(h.name, 'generic')
526 h.name = 'anothergeneric'
527 self.assertEqual(h.name, 'anothergeneric')
528 self.assertRaises(NotImplementedError, h.emit, None)
529
Vinay Sajip5a35b062011-04-27 11:31:14 +0100530 def test_builtin_handlers(self):
531 # We can't actually *use* too many handlers in the tests,
532 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200533 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100534 for existing in (True, False):
535 fd, fn = tempfile.mkstemp()
536 os.close(fd)
537 if not existing:
538 os.unlink(fn)
539 h = logging.handlers.WatchedFileHandler(fn, delay=True)
540 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100541 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100542 self.assertEqual(dev, -1)
543 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100544 r = logging.makeLogRecord({'msg': 'Test'})
545 h.handle(r)
546 # Now remove the file.
547 os.unlink(fn)
548 self.assertFalse(os.path.exists(fn))
549 # The next call should recreate the file.
550 h.handle(r)
551 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100552 else:
553 self.assertEqual(h.dev, -1)
554 self.assertEqual(h.ino, -1)
555 h.close()
556 if existing:
557 os.unlink(fn)
558 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100559 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100560 else:
561 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100562 try:
563 h = logging.handlers.SysLogHandler(sockname)
564 self.assertEqual(h.facility, h.LOG_USER)
565 self.assertTrue(h.unixsocket)
566 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200567 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100568 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100569 for method in ('GET', 'POST', 'PUT'):
570 if method == 'PUT':
571 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
572 'localhost', '/log', method)
573 else:
574 h = logging.handlers.HTTPHandler('localhost', '/log', method)
575 h.close()
576 h = logging.handlers.BufferingHandler(0)
577 r = logging.makeLogRecord({})
578 self.assertTrue(h.shouldFlush(r))
579 h.close()
580 h = logging.handlers.BufferingHandler(1)
581 self.assertFalse(h.shouldFlush(r))
582 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100583
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100584 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100585 @unittest.skipUnless(threading, 'Threading required for this test.')
586 def test_race(self):
587 # Issue #14632 refers.
588 def remove_loop(fname, tries):
589 for _ in range(tries):
590 try:
591 os.unlink(fname)
592 except OSError:
593 pass
594 time.sleep(0.004 * random.randint(0, 4))
595
Vinay Sajipc94871a2012-04-25 10:51:35 +0100596 del_count = 500
597 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100598
Vinay Sajipa5798de2012-04-24 23:33:33 +0100599 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100600 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
601 os.close(fd)
602 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
603 remover.daemon = True
604 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100605 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100606 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
607 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100608 try:
609 for _ in range(log_count):
610 time.sleep(0.005)
611 r = logging.makeLogRecord({'msg': 'testing' })
612 h.handle(r)
613 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100614 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100615 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100616 if os.path.exists(fn):
617 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100618
619
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100620class BadStream(object):
621 def write(self, data):
622 raise RuntimeError('deliberate mistake')
623
624class TestStreamHandler(logging.StreamHandler):
625 def handleError(self, record):
626 self.error_record = record
627
628class StreamHandlerTest(BaseTest):
629 def test_error_handling(self):
630 h = TestStreamHandler(BadStream())
631 r = logging.makeLogRecord({})
632 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100633 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100634 try:
635 h.handle(r)
636 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100637 h = logging.StreamHandler(BadStream())
638 sys.stderr = sio = io.StringIO()
639 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100640 self.assertIn('\nRuntimeError: deliberate mistake\n',
641 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100642 logging.raiseExceptions = False
643 sys.stderr = sio = io.StringIO()
644 h.handle(r)
645 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100646 finally:
647 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100648 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100649
Vinay Sajip7367d082011-05-02 13:17:27 +0100650# -- The following section could be moved into a server_helper.py module
651# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100652
Vinay Sajipce7c9782011-05-17 07:15:53 +0100653if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100654 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100655 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100656 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100657
Vinay Sajipce7c9782011-05-17 07:15:53 +0100658 :param addr: A (host, port) tuple which the server listens on.
659 You can specify a port value of zero: the server's
660 *port* attribute will hold the actual port number
661 used, which can be used in client connections.
662 :param handler: A callable which will be called to process
663 incoming messages. The handler will be passed
664 the client address tuple, who the message is from,
665 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100666 :param poll_interval: The interval, in seconds, used in the underlying
667 :func:`select` or :func:`poll` call by
668 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100669 :param sockmap: A dictionary which will be used to hold
670 :class:`asyncore.dispatcher` instances used by
671 :func:`asyncore.loop`. This avoids changing the
672 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100673 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100674
675 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100676 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
677 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100678 self._handler = handler
679 self._thread = None
680 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100681
Vinay Sajipce7c9782011-05-17 07:15:53 +0100682 def process_message(self, peer, mailfrom, rcpttos, data):
683 """
684 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100685
Vinay Sajipce7c9782011-05-17 07:15:53 +0100686 Typically, this will be a test case method.
687 :param peer: The client (host, port) tuple.
688 :param mailfrom: The address of the sender.
689 :param rcpttos: The addresses of the recipients.
690 :param data: The message.
691 """
692 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100693
Vinay Sajipce7c9782011-05-17 07:15:53 +0100694 def start(self):
695 """
696 Start the server running on a separate daemon thread.
697 """
698 self._thread = t = threading.Thread(target=self.serve_forever,
699 args=(self.poll_interval,))
700 t.setDaemon(True)
701 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100702
Vinay Sajipce7c9782011-05-17 07:15:53 +0100703 def serve_forever(self, poll_interval):
704 """
705 Run the :mod:`asyncore` loop until normal termination
706 conditions arise.
707 :param poll_interval: The interval, in seconds, used in the underlying
708 :func:`select` or :func:`poll` call by
709 :func:`asyncore.loop`.
710 """
711 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100712 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200713 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100714 # On FreeBSD 8, closing the server repeatably
715 # raises this error. We swallow it if the
716 # server has been closed.
717 if self.connected or self.accepting:
718 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100719
Vinay Sajipce7c9782011-05-17 07:15:53 +0100720 def stop(self, timeout=None):
721 """
722 Stop the thread by closing the server instance.
723 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100724
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 :param timeout: How long to wait for the server thread
726 to terminate.
727 """
728 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100729 self._thread.join(timeout)
730 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100731
Vinay Sajipce7c9782011-05-17 07:15:53 +0100732 class ControlMixin(object):
733 """
734 This mixin is used to start a server on a separate thread, and
735 shut it down programmatically. Request handling is simplified - instead
736 of needing to derive a suitable RequestHandler subclass, you just
737 provide a callable which will be passed each received request to be
738 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100739
Vinay Sajipce7c9782011-05-17 07:15:53 +0100740 :param handler: A handler callable which will be called with a
741 single parameter - the request - in order to
742 process the request. This handler is called on the
743 server thread, effectively meaning that requests are
744 processed serially. While not quite Web scale ;-),
745 this should be fine for testing applications.
746 :param poll_interval: The polling interval in seconds.
747 """
748 def __init__(self, handler, poll_interval):
749 self._thread = None
750 self.poll_interval = poll_interval
751 self._handler = handler
752 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100753
Vinay Sajipce7c9782011-05-17 07:15:53 +0100754 def start(self):
755 """
756 Create a daemon thread to run the server, and start it.
757 """
758 self._thread = t = threading.Thread(target=self.serve_forever,
759 args=(self.poll_interval,))
760 t.setDaemon(True)
761 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100762
Vinay Sajipce7c9782011-05-17 07:15:53 +0100763 def serve_forever(self, poll_interval):
764 """
765 Run the server. Set the ready flag before entering the
766 service loop.
767 """
768 self.ready.set()
769 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100770
Vinay Sajipce7c9782011-05-17 07:15:53 +0100771 def stop(self, timeout=None):
772 """
773 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100774
Vinay Sajipce7c9782011-05-17 07:15:53 +0100775 :param timeout: How long to wait for the server thread
776 to terminate.
777 """
778 self.shutdown()
779 if self._thread is not None:
780 self._thread.join(timeout)
781 self._thread = None
782 self.server_close()
783 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100784
Vinay Sajipce7c9782011-05-17 07:15:53 +0100785 class TestHTTPServer(ControlMixin, HTTPServer):
786 """
787 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100788
Vinay Sajipce7c9782011-05-17 07:15:53 +0100789 :param addr: A tuple with the IP address and port to listen on.
790 :param handler: A handler callable which will be called with a
791 single parameter - the request - in order to
792 process the request.
793 :param poll_interval: The polling interval in seconds.
794 :param log: Pass ``True`` to enable log messages.
795 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100796 def __init__(self, addr, handler, poll_interval=0.5,
797 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100798 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
799 def __getattr__(self, name, default=None):
800 if name.startswith('do_'):
801 return self.process_request
802 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100803
Vinay Sajipce7c9782011-05-17 07:15:53 +0100804 def process_request(self):
805 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Vinay Sajipce7c9782011-05-17 07:15:53 +0100807 def log_message(self, format, *args):
808 if log:
809 super(DelegatingHTTPRequestHandler,
810 self).log_message(format, *args)
811 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
812 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100813 self.sslctx = sslctx
814
815 def get_request(self):
816 try:
817 sock, addr = self.socket.accept()
818 if self.sslctx:
819 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200820 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100821 # socket errors are silenced by the caller, print them here
822 sys.stderr.write("Got an error:\n%s\n" % e)
823 raise
824 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100825
Vinay Sajipce7c9782011-05-17 07:15:53 +0100826 class TestTCPServer(ControlMixin, ThreadingTCPServer):
827 """
828 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100829
Vinay Sajipce7c9782011-05-17 07:15:53 +0100830 :param addr: A tuple with the IP address and port to listen on.
831 :param handler: A handler callable which will be called with a single
832 parameter - the request - in order to process the request.
833 :param poll_interval: The polling interval in seconds.
834 :bind_and_activate: If True (the default), binds the server and starts it
835 listening. If False, you need to call
836 :meth:`server_bind` and :meth:`server_activate` at
837 some later time before calling :meth:`start`, so that
838 the server will set up the socket and listen on it.
839 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100842
Vinay Sajipce7c9782011-05-17 07:15:53 +0100843 def __init__(self, addr, handler, poll_interval=0.5,
844 bind_and_activate=True):
845 class DelegatingTCPRequestHandler(StreamRequestHandler):
846
847 def handle(self):
848 self.server._handler(self)
849 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
850 bind_and_activate)
851 ControlMixin.__init__(self, handler, poll_interval)
852
853 def server_bind(self):
854 super(TestTCPServer, self).server_bind()
855 self.port = self.socket.getsockname()[1]
856
857 class TestUDPServer(ControlMixin, ThreadingUDPServer):
858 """
859 A UDP server which is controllable using :class:`ControlMixin`.
860
861 :param addr: A tuple with the IP address and port to listen on.
862 :param handler: A handler callable which will be called with a
863 single parameter - the request - in order to
864 process the request.
865 :param poll_interval: The polling interval for shutdown requests,
866 in seconds.
867 :bind_and_activate: If True (the default), binds the server and
868 starts it listening. If False, you need to
869 call :meth:`server_bind` and
870 :meth:`server_activate` at some later time
871 before calling :meth:`start`, so that the server will
872 set up the socket and listen on it.
873 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100874 def __init__(self, addr, handler, poll_interval=0.5,
875 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100876 class DelegatingUDPRequestHandler(DatagramRequestHandler):
877
878 def handle(self):
879 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100880
881 def finish(self):
882 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100883 if data:
884 try:
885 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200886 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100887 if not self.server._closed:
888 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100889
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 ThreadingUDPServer.__init__(self, addr,
891 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100892 bind_and_activate)
893 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100894 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100895
896 def server_bind(self):
897 super(TestUDPServer, self).server_bind()
898 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100899
Vinay Sajipba980db2011-05-23 21:37:54 +0100900 def server_close(self):
901 super(TestUDPServer, self).server_close()
902 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100903
904# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100905
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100907class SMTPHandlerTest(BaseTest):
908 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100909 sockmap = {}
910 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
911 sockmap)
912 server.start()
913 addr = ('localhost', server.port)
Vinay Sajip4c3f4782012-04-22 18:19:50 +0100914 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
Vinay Sajipa463d252011-04-30 21:52:48 +0100915 self.assertEqual(h.toaddrs, ['you'])
916 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100917 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100918 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100919 h.handle(r)
Vinay Sajip17160fd2012-03-15 12:02:08 +0000920 self.handled.wait(5.0) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100921 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000922 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100923 self.assertEqual(len(self.messages), 1)
924 peer, mailfrom, rcpttos, data = self.messages[0]
925 self.assertEqual(mailfrom, 'me')
926 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100927 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100928 self.assertTrue(data.endswith('\n\nHello'))
929 h.close()
930
931 def process_message(self, *args):
932 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100933 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100934
Christian Heimes180510d2008-03-03 19:15:45 +0000935class MemoryHandlerTest(BaseTest):
936
937 """Tests for the MemoryHandler."""
938
939 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300940 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000941
942 def setUp(self):
943 BaseTest.setUp(self)
944 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
945 self.root_hdlr)
946 self.mem_logger = logging.getLogger('mem')
947 self.mem_logger.propagate = 0
948 self.mem_logger.addHandler(self.mem_hdlr)
949
950 def tearDown(self):
951 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000952 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000953
954 def test_flush(self):
955 # The memory handler flushes to its target handler based on specific
956 # criteria (message count and message level).
957 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000958 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000959 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000960 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000961 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100962 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000963 lines = [
964 ('DEBUG', '1'),
965 ('INFO', '2'),
966 ('WARNING', '3'),
967 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000968 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000969 for n in (4, 14):
970 for i in range(9):
971 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000972 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000973 # This will flush because it's the 10th message since the last
974 # flush.
975 self.mem_logger.debug(self.next_message())
976 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000977 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000978
979 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000980 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000981
982
983class ExceptionFormatter(logging.Formatter):
984 """A special exception formatter."""
985 def formatException(self, ei):
986 return "Got a [%s]" % ei[0].__name__
987
988
989class ConfigFileTest(BaseTest):
990
991 """Reading logging config from a .ini-style config file."""
992
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300993 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000994
995 # config0 is a standard configuration.
996 config0 = """
997 [loggers]
998 keys=root
999
1000 [handlers]
1001 keys=hand1
1002
1003 [formatters]
1004 keys=form1
1005
1006 [logger_root]
1007 level=WARNING
1008 handlers=hand1
1009
1010 [handler_hand1]
1011 class=StreamHandler
1012 level=NOTSET
1013 formatter=form1
1014 args=(sys.stdout,)
1015
1016 [formatter_form1]
1017 format=%(levelname)s ++ %(message)s
1018 datefmt=
1019 """
1020
1021 # config1 adds a little to the standard configuration.
1022 config1 = """
1023 [loggers]
1024 keys=root,parser
1025
1026 [handlers]
1027 keys=hand1
1028
1029 [formatters]
1030 keys=form1
1031
1032 [logger_root]
1033 level=WARNING
1034 handlers=
1035
1036 [logger_parser]
1037 level=DEBUG
1038 handlers=hand1
1039 propagate=1
1040 qualname=compiler.parser
1041
1042 [handler_hand1]
1043 class=StreamHandler
1044 level=NOTSET
1045 formatter=form1
1046 args=(sys.stdout,)
1047
1048 [formatter_form1]
1049 format=%(levelname)s ++ %(message)s
1050 datefmt=
1051 """
1052
Vinay Sajip3f84b072011-03-07 17:49:33 +00001053 # config1a moves the handler to the root.
1054 config1a = """
1055 [loggers]
1056 keys=root,parser
1057
1058 [handlers]
1059 keys=hand1
1060
1061 [formatters]
1062 keys=form1
1063
1064 [logger_root]
1065 level=WARNING
1066 handlers=hand1
1067
1068 [logger_parser]
1069 level=DEBUG
1070 handlers=
1071 propagate=1
1072 qualname=compiler.parser
1073
1074 [handler_hand1]
1075 class=StreamHandler
1076 level=NOTSET
1077 formatter=form1
1078 args=(sys.stdout,)
1079
1080 [formatter_form1]
1081 format=%(levelname)s ++ %(message)s
1082 datefmt=
1083 """
1084
Christian Heimes180510d2008-03-03 19:15:45 +00001085 # config2 has a subtle configuration error that should be reported
1086 config2 = config1.replace("sys.stdout", "sys.stbout")
1087
1088 # config3 has a less subtle configuration error
1089 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1090
1091 # config4 specifies a custom formatter class to be loaded
1092 config4 = """
1093 [loggers]
1094 keys=root
1095
1096 [handlers]
1097 keys=hand1
1098
1099 [formatters]
1100 keys=form1
1101
1102 [logger_root]
1103 level=NOTSET
1104 handlers=hand1
1105
1106 [handler_hand1]
1107 class=StreamHandler
1108 level=NOTSET
1109 formatter=form1
1110 args=(sys.stdout,)
1111
1112 [formatter_form1]
1113 class=""" + __name__ + """.ExceptionFormatter
1114 format=%(levelname)s:%(name)s:%(message)s
1115 datefmt=
1116 """
1117
Georg Brandl3dbca812008-07-23 16:10:53 +00001118 # config5 specifies a custom handler class to be loaded
1119 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1120
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001121 # config6 uses ', ' delimiters in the handlers and formatters sections
1122 config6 = """
1123 [loggers]
1124 keys=root,parser
1125
1126 [handlers]
1127 keys=hand1, hand2
1128
1129 [formatters]
1130 keys=form1, form2
1131
1132 [logger_root]
1133 level=WARNING
1134 handlers=
1135
1136 [logger_parser]
1137 level=DEBUG
1138 handlers=hand1
1139 propagate=1
1140 qualname=compiler.parser
1141
1142 [handler_hand1]
1143 class=StreamHandler
1144 level=NOTSET
1145 formatter=form1
1146 args=(sys.stdout,)
1147
1148 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001149 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001150 level=NOTSET
1151 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001152 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001153
1154 [formatter_form1]
1155 format=%(levelname)s ++ %(message)s
1156 datefmt=
1157
1158 [formatter_form2]
1159 format=%(message)s
1160 datefmt=
1161 """
1162
Vinay Sajip3f84b072011-03-07 17:49:33 +00001163 # config7 adds a compiler logger.
1164 config7 = """
1165 [loggers]
1166 keys=root,parser,compiler
1167
1168 [handlers]
1169 keys=hand1
1170
1171 [formatters]
1172 keys=form1
1173
1174 [logger_root]
1175 level=WARNING
1176 handlers=hand1
1177
1178 [logger_compiler]
1179 level=DEBUG
1180 handlers=
1181 propagate=1
1182 qualname=compiler
1183
1184 [logger_parser]
1185 level=DEBUG
1186 handlers=
1187 propagate=1
1188 qualname=compiler.parser
1189
1190 [handler_hand1]
1191 class=StreamHandler
1192 level=NOTSET
1193 formatter=form1
1194 args=(sys.stdout,)
1195
1196 [formatter_form1]
1197 format=%(levelname)s ++ %(message)s
1198 datefmt=
1199 """
1200
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001201 disable_test = """
1202 [loggers]
1203 keys=root
1204
1205 [handlers]
1206 keys=screen
1207
1208 [formatters]
1209 keys=
1210
1211 [logger_root]
1212 level=DEBUG
1213 handlers=screen
1214
1215 [handler_screen]
1216 level=DEBUG
1217 class=StreamHandler
1218 args=(sys.stdout,)
1219 formatter=
1220 """
1221
1222 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001223 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001224 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001225
1226 def test_config0_ok(self):
1227 # A simple config file which overrides the default settings.
1228 with captured_stdout() as output:
1229 self.apply_config(self.config0)
1230 logger = logging.getLogger()
1231 # Won't output anything
1232 logger.info(self.next_message())
1233 # Outputs a message
1234 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001235 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001236 ('ERROR', '2'),
1237 ], stream=output)
1238 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001239 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001240
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001241 def test_config0_using_cp_ok(self):
1242 # A simple config file which overrides the default settings.
1243 with captured_stdout() as output:
1244 file = io.StringIO(textwrap.dedent(self.config0))
1245 cp = configparser.ConfigParser()
1246 cp.read_file(file)
1247 logging.config.fileConfig(cp)
1248 logger = logging.getLogger()
1249 # Won't output anything
1250 logger.info(self.next_message())
1251 # Outputs a message
1252 logger.error(self.next_message())
1253 self.assert_log_lines([
1254 ('ERROR', '2'),
1255 ], stream=output)
1256 # Original logger output is empty.
1257 self.assert_log_lines([])
1258
Georg Brandl3dbca812008-07-23 16:10:53 +00001259 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001260 # A config file defining a sub-parser as well.
1261 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001262 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001263 logger = logging.getLogger("compiler.parser")
1264 # Both will output a message
1265 logger.info(self.next_message())
1266 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001267 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001268 ('INFO', '1'),
1269 ('ERROR', '2'),
1270 ], stream=output)
1271 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001272 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001273
1274 def test_config2_failure(self):
1275 # A simple config file which overrides the default settings.
1276 self.assertRaises(Exception, self.apply_config, self.config2)
1277
1278 def test_config3_failure(self):
1279 # A simple config file which overrides the default settings.
1280 self.assertRaises(Exception, self.apply_config, self.config3)
1281
1282 def test_config4_ok(self):
1283 # A config file specifying a custom formatter class.
1284 with captured_stdout() as output:
1285 self.apply_config(self.config4)
1286 logger = logging.getLogger()
1287 try:
1288 raise RuntimeError()
1289 except RuntimeError:
1290 logging.exception("just testing")
1291 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001292 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001293 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1294 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001295 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001296
Georg Brandl3dbca812008-07-23 16:10:53 +00001297 def test_config5_ok(self):
1298 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001299
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001300 def test_config6_ok(self):
1301 self.test_config1_ok(config=self.config6)
1302
Vinay Sajip3f84b072011-03-07 17:49:33 +00001303 def test_config7_ok(self):
1304 with captured_stdout() as output:
1305 self.apply_config(self.config1a)
1306 logger = logging.getLogger("compiler.parser")
1307 # See issue #11424. compiler-hyphenated sorts
1308 # between compiler and compiler.xyz and this
1309 # was preventing compiler.xyz from being included
1310 # in the child loggers of compiler because of an
1311 # overzealous loop termination condition.
1312 hyphenated = logging.getLogger('compiler-hyphenated')
1313 # All will output a message
1314 logger.info(self.next_message())
1315 logger.error(self.next_message())
1316 hyphenated.critical(self.next_message())
1317 self.assert_log_lines([
1318 ('INFO', '1'),
1319 ('ERROR', '2'),
1320 ('CRITICAL', '3'),
1321 ], stream=output)
1322 # Original logger output is empty.
1323 self.assert_log_lines([])
1324 with captured_stdout() as output:
1325 self.apply_config(self.config7)
1326 logger = logging.getLogger("compiler.parser")
1327 self.assertFalse(logger.disabled)
1328 # Both will output a message
1329 logger.info(self.next_message())
1330 logger.error(self.next_message())
1331 logger = logging.getLogger("compiler.lexer")
1332 # Both will output a message
1333 logger.info(self.next_message())
1334 logger.error(self.next_message())
1335 # Will not appear
1336 hyphenated.critical(self.next_message())
1337 self.assert_log_lines([
1338 ('INFO', '4'),
1339 ('ERROR', '5'),
1340 ('INFO', '6'),
1341 ('ERROR', '7'),
1342 ], stream=output)
1343 # Original logger output is empty.
1344 self.assert_log_lines([])
1345
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001346 def test_logger_disabling(self):
1347 self.apply_config(self.disable_test)
1348 logger = logging.getLogger('foo')
1349 self.assertFalse(logger.disabled)
1350 self.apply_config(self.disable_test)
1351 self.assertTrue(logger.disabled)
1352 self.apply_config(self.disable_test, disable_existing_loggers=False)
1353 self.assertFalse(logger.disabled)
1354
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001355
Victor Stinner45df8202010-04-28 22:31:17 +00001356@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001357class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001358
Christian Heimes180510d2008-03-03 19:15:45 +00001359 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001360
Christian Heimes180510d2008-03-03 19:15:45 +00001361 def setUp(self):
1362 """Set up a TCP server to receive log messages, and a SocketHandler
1363 pointing to that server's address and port."""
1364 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001365 addr = ('localhost', 0)
1366 self.server = server = TestTCPServer(addr, self.handle_socket,
1367 0.01)
1368 server.start()
1369 server.ready.wait()
1370 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1371 server.port)
1372 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001373 self.root_logger.removeHandler(self.root_logger.handlers[0])
1374 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001375 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001376
Christian Heimes180510d2008-03-03 19:15:45 +00001377 def tearDown(self):
1378 """Shutdown the TCP server."""
1379 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001380 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001381 self.root_logger.removeHandler(self.sock_hdlr)
1382 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001383 finally:
1384 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001385
Vinay Sajip7367d082011-05-02 13:17:27 +01001386 def handle_socket(self, request):
1387 conn = request.connection
1388 while True:
1389 chunk = conn.recv(4)
1390 if len(chunk) < 4:
1391 break
1392 slen = struct.unpack(">L", chunk)[0]
1393 chunk = conn.recv(slen)
1394 while len(chunk) < slen:
1395 chunk = chunk + conn.recv(slen - len(chunk))
1396 obj = pickle.loads(chunk)
1397 record = logging.makeLogRecord(obj)
1398 self.log_output += record.msg + '\n'
1399 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001400
Christian Heimes180510d2008-03-03 19:15:45 +00001401 def test_output(self):
1402 # The log message sent to the SocketHandler is properly received.
1403 logger = logging.getLogger("tcp")
1404 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001405 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001406 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001407 self.handled.acquire()
1408 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001409
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001410 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001411 # Avoid timing-related failures due to SocketHandler's own hard-wired
1412 # one-second timeout on socket.create_connection() (issue #16264).
1413 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001414 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001415 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001416 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001417 try:
1418 raise RuntimeError('Deliberate mistake')
1419 except RuntimeError:
1420 self.root_logger.exception('Never sent')
1421 self.root_logger.error('Never sent, either')
1422 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001423 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001424 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1425 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001426
Vinay Sajip7367d082011-05-02 13:17:27 +01001427
1428@unittest.skipUnless(threading, 'Threading required for this test.')
1429class DatagramHandlerTest(BaseTest):
1430
1431 """Test for DatagramHandler."""
1432
1433 def setUp(self):
1434 """Set up a UDP server to receive log messages, and a DatagramHandler
1435 pointing to that server's address and port."""
1436 BaseTest.setUp(self)
1437 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001438 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001439 server.start()
1440 server.ready.wait()
1441 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1442 server.port)
1443 self.log_output = ''
1444 self.root_logger.removeHandler(self.root_logger.handlers[0])
1445 self.root_logger.addHandler(self.sock_hdlr)
1446 self.handled = threading.Event()
1447
1448 def tearDown(self):
1449 """Shutdown the UDP server."""
1450 try:
1451 self.server.stop(2.0)
1452 self.root_logger.removeHandler(self.sock_hdlr)
1453 self.sock_hdlr.close()
1454 finally:
1455 BaseTest.tearDown(self)
1456
1457 def handle_datagram(self, request):
1458 slen = struct.pack('>L', 0) # length of prefix
1459 packet = request.packet[len(slen):]
1460 obj = pickle.loads(packet)
1461 record = logging.makeLogRecord(obj)
1462 self.log_output += record.msg + '\n'
1463 self.handled.set()
1464
1465 def test_output(self):
1466 # The log message sent to the DatagramHandler is properly received.
1467 logger = logging.getLogger("udp")
1468 logger.error("spam")
1469 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001470 self.handled.clear()
1471 logger.error("eggs")
1472 self.handled.wait()
1473 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001474
1475
1476@unittest.skipUnless(threading, 'Threading required for this test.')
1477class SysLogHandlerTest(BaseTest):
1478
1479 """Test for SysLogHandler using UDP."""
1480
1481 def setUp(self):
1482 """Set up a UDP server to receive log messages, and a SysLogHandler
1483 pointing to that server's address and port."""
1484 BaseTest.setUp(self)
1485 addr = ('localhost', 0)
1486 self.server = server = TestUDPServer(addr, self.handle_datagram,
1487 0.01)
1488 server.start()
1489 server.ready.wait()
1490 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1491 server.port))
1492 self.log_output = ''
1493 self.root_logger.removeHandler(self.root_logger.handlers[0])
1494 self.root_logger.addHandler(self.sl_hdlr)
1495 self.handled = threading.Event()
1496
1497 def tearDown(self):
1498 """Shutdown the UDP server."""
1499 try:
1500 self.server.stop(2.0)
1501 self.root_logger.removeHandler(self.sl_hdlr)
1502 self.sl_hdlr.close()
1503 finally:
1504 BaseTest.tearDown(self)
1505
1506 def handle_datagram(self, request):
1507 self.log_output = request.packet
1508 self.handled.set()
1509
1510 def test_output(self):
1511 # The log message sent to the SysLogHandler is properly received.
1512 logger = logging.getLogger("slh")
1513 logger.error("sp\xe4m")
1514 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001515 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001516 self.handled.clear()
1517 self.sl_hdlr.append_nul = False
1518 logger.error("sp\xe4m")
1519 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001520 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001521 self.handled.clear()
1522 self.sl_hdlr.ident = "h\xe4m-"
1523 logger.error("sp\xe4m")
1524 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001525 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001526
1527
1528@unittest.skipUnless(threading, 'Threading required for this test.')
1529class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001530 """Test for HTTPHandler."""
1531
Vinay Sajip9ba87612011-05-21 11:32:15 +01001532 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1533MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1534zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1535aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1536AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15370tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15385LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1539piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15402z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1541i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1542PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1543E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1544rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1545/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1546-----END RSA PRIVATE KEY-----
1547-----BEGIN CERTIFICATE-----
1548MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1549BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1550EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1551xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1552l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1553vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1554BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1555S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1556BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15574f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15581c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1559IRbTpvlHWPjsSvHz0ZOH
1560-----END CERTIFICATE-----"""
1561
Vinay Sajip7367d082011-05-02 13:17:27 +01001562 def setUp(self):
1563 """Set up an HTTP server to receive log messages, and a HTTPHandler
1564 pointing to that server's address and port."""
1565 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 self.handled = threading.Event()
1567
Vinay Sajip7367d082011-05-02 13:17:27 +01001568 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001569 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001570 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001571 if self.command == 'POST':
1572 try:
1573 rlen = int(request.headers['Content-Length'])
1574 self.post_data = request.rfile.read(rlen)
1575 except:
1576 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001577 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001578 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001579 self.handled.set()
1580
1581 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001582 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001583 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001584 root_logger = self.root_logger
1585 root_logger.removeHandler(self.root_logger.handlers[0])
1586 for secure in (False, True):
1587 addr = ('localhost', 0)
1588 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001589 try:
1590 import ssl
1591 fd, fn = tempfile.mkstemp()
1592 os.close(fd)
1593 with open(fn, 'w') as f:
1594 f.write(self.PEMFILE)
1595 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1596 sslctx.load_cert_chain(fn)
1597 os.unlink(fn)
1598 except ImportError:
1599 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001600 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001601 sslctx = None
1602 self.server = server = TestHTTPServer(addr, self.handle_request,
1603 0.01, sslctx=sslctx)
1604 server.start()
1605 server.ready.wait()
1606 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001607 secure_client = secure and sslctx
1608 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1609 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001610 self.log_data = None
1611 root_logger.addHandler(self.h_hdlr)
1612
1613 for method in ('GET', 'POST'):
1614 self.h_hdlr.method = method
1615 self.handled.clear()
1616 msg = "sp\xe4m"
1617 logger.error(msg)
1618 self.handled.wait()
1619 self.assertEqual(self.log_data.path, '/frob')
1620 self.assertEqual(self.command, method)
1621 if method == 'GET':
1622 d = parse_qs(self.log_data.query)
1623 else:
1624 d = parse_qs(self.post_data.decode('utf-8'))
1625 self.assertEqual(d['name'], ['http'])
1626 self.assertEqual(d['funcName'], ['test_output'])
1627 self.assertEqual(d['msg'], [msg])
1628
1629 self.server.stop(2.0)
1630 self.root_logger.removeHandler(self.h_hdlr)
1631 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001632
Christian Heimes180510d2008-03-03 19:15:45 +00001633class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001634
Christian Heimes180510d2008-03-03 19:15:45 +00001635 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001636
Christian Heimes180510d2008-03-03 19:15:45 +00001637 def setUp(self):
1638 """Create a dict to remember potentially destroyed objects."""
1639 BaseTest.setUp(self)
1640 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001641
Christian Heimes180510d2008-03-03 19:15:45 +00001642 def _watch_for_survival(self, *args):
1643 """Watch the given objects for survival, by creating weakrefs to
1644 them."""
1645 for obj in args:
1646 key = id(obj), repr(obj)
1647 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001648
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001649 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001650 """Assert that all objects watched for survival have survived."""
1651 # Trigger cycle breaking.
1652 gc.collect()
1653 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001654 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001655 if ref() is None:
1656 dead.append(repr_)
1657 if dead:
1658 self.fail("%d objects should have survived "
1659 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001660
Christian Heimes180510d2008-03-03 19:15:45 +00001661 def test_persistent_loggers(self):
1662 # Logger objects are persistent and retain their configuration, even
1663 # if visible references are destroyed.
1664 self.root_logger.setLevel(logging.INFO)
1665 foo = logging.getLogger("foo")
1666 self._watch_for_survival(foo)
1667 foo.setLevel(logging.DEBUG)
1668 self.root_logger.debug(self.next_message())
1669 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001670 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001671 ('foo', 'DEBUG', '2'),
1672 ])
1673 del foo
1674 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001675 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001676 # foo has retained its settings.
1677 bar = logging.getLogger("foo")
1678 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001679 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001680 ('foo', 'DEBUG', '2'),
1681 ('foo', 'DEBUG', '3'),
1682 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001683
Benjamin Petersonf91df042009-02-13 02:50:59 +00001684
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001685class EncodingTest(BaseTest):
1686 def test_encoding_plain_file(self):
1687 # In Python 2.x, a plain file object is treated as having no encoding.
1688 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001689 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1690 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001691 # the non-ascii data we write to the log.
1692 data = "foo\x80"
1693 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001694 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001695 log.addHandler(handler)
1696 try:
1697 # write non-ascii data to the log.
1698 log.warning(data)
1699 finally:
1700 log.removeHandler(handler)
1701 handler.close()
1702 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001703 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001704 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001705 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001706 finally:
1707 f.close()
1708 finally:
1709 if os.path.isfile(fn):
1710 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001711
Benjamin Petersonf91df042009-02-13 02:50:59 +00001712 def test_encoding_cyrillic_unicode(self):
1713 log = logging.getLogger("test")
1714 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1715 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1716 #Ensure it's written in a Cyrillic encoding
1717 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001718 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001719 stream = io.BytesIO()
1720 writer = writer_class(stream, 'strict')
1721 handler = logging.StreamHandler(writer)
1722 log.addHandler(handler)
1723 try:
1724 log.warning(message)
1725 finally:
1726 log.removeHandler(handler)
1727 handler.close()
1728 # check we wrote exactly those bytes, ignoring trailing \n etc
1729 s = stream.getvalue()
1730 #Compare against what the data should be when encoded in CP-1251
1731 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1732
1733
Georg Brandlf9734072008-12-07 15:30:06 +00001734class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001735
Georg Brandlf9734072008-12-07 15:30:06 +00001736 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001737 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001738 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001739 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001740 warnings.filterwarnings("always", category=UserWarning)
1741 stream = io.StringIO()
1742 h = logging.StreamHandler(stream)
1743 logger = logging.getLogger("py.warnings")
1744 logger.addHandler(h)
1745 warnings.warn("I'm warning you...")
1746 logger.removeHandler(h)
1747 s = stream.getvalue()
1748 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001749 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001750
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001751 #See if an explicit file uses the original implementation
1752 a_file = io.StringIO()
1753 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1754 a_file, "Dummy line")
1755 s = a_file.getvalue()
1756 a_file.close()
1757 self.assertEqual(s,
1758 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1759
1760 def test_warnings_no_handlers(self):
1761 with warnings.catch_warnings():
1762 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001763 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001764
1765 # confirm our assumption: no loggers are set
1766 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001767 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001768
1769 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001770 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001771 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001772
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001773
1774def formatFunc(format, datefmt=None):
1775 return logging.Formatter(format, datefmt)
1776
1777def handlerFunc():
1778 return logging.StreamHandler()
1779
1780class CustomHandler(logging.StreamHandler):
1781 pass
1782
1783class ConfigDictTest(BaseTest):
1784
1785 """Reading logging config from a dictionary."""
1786
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001787 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001788
1789 # config0 is a standard configuration.
1790 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001791 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001792 'formatters': {
1793 'form1' : {
1794 'format' : '%(levelname)s ++ %(message)s',
1795 },
1796 },
1797 'handlers' : {
1798 'hand1' : {
1799 'class' : 'logging.StreamHandler',
1800 'formatter' : 'form1',
1801 'level' : 'NOTSET',
1802 'stream' : 'ext://sys.stdout',
1803 },
1804 },
1805 'root' : {
1806 'level' : 'WARNING',
1807 'handlers' : ['hand1'],
1808 },
1809 }
1810
1811 # config1 adds a little to the standard configuration.
1812 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001813 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001814 'formatters': {
1815 'form1' : {
1816 'format' : '%(levelname)s ++ %(message)s',
1817 },
1818 },
1819 'handlers' : {
1820 'hand1' : {
1821 'class' : 'logging.StreamHandler',
1822 'formatter' : 'form1',
1823 'level' : 'NOTSET',
1824 'stream' : 'ext://sys.stdout',
1825 },
1826 },
1827 'loggers' : {
1828 'compiler.parser' : {
1829 'level' : 'DEBUG',
1830 'handlers' : ['hand1'],
1831 },
1832 },
1833 'root' : {
1834 'level' : 'WARNING',
1835 },
1836 }
1837
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001838 # config1a moves the handler to the root. Used with config8a
1839 config1a = {
1840 'version': 1,
1841 'formatters': {
1842 'form1' : {
1843 'format' : '%(levelname)s ++ %(message)s',
1844 },
1845 },
1846 'handlers' : {
1847 'hand1' : {
1848 'class' : 'logging.StreamHandler',
1849 'formatter' : 'form1',
1850 'level' : 'NOTSET',
1851 'stream' : 'ext://sys.stdout',
1852 },
1853 },
1854 'loggers' : {
1855 'compiler.parser' : {
1856 'level' : 'DEBUG',
1857 },
1858 },
1859 'root' : {
1860 'level' : 'WARNING',
1861 'handlers' : ['hand1'],
1862 },
1863 }
1864
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001865 # config2 has a subtle configuration error that should be reported
1866 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001867 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001868 'formatters': {
1869 'form1' : {
1870 'format' : '%(levelname)s ++ %(message)s',
1871 },
1872 },
1873 'handlers' : {
1874 'hand1' : {
1875 'class' : 'logging.StreamHandler',
1876 'formatter' : 'form1',
1877 'level' : 'NOTSET',
1878 'stream' : 'ext://sys.stdbout',
1879 },
1880 },
1881 'loggers' : {
1882 'compiler.parser' : {
1883 'level' : 'DEBUG',
1884 'handlers' : ['hand1'],
1885 },
1886 },
1887 'root' : {
1888 'level' : 'WARNING',
1889 },
1890 }
1891
1892 #As config1 but with a misspelt level on a handler
1893 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001894 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001895 'formatters': {
1896 'form1' : {
1897 'format' : '%(levelname)s ++ %(message)s',
1898 },
1899 },
1900 'handlers' : {
1901 'hand1' : {
1902 'class' : 'logging.StreamHandler',
1903 'formatter' : 'form1',
1904 'level' : 'NTOSET',
1905 'stream' : 'ext://sys.stdout',
1906 },
1907 },
1908 'loggers' : {
1909 'compiler.parser' : {
1910 'level' : 'DEBUG',
1911 'handlers' : ['hand1'],
1912 },
1913 },
1914 'root' : {
1915 'level' : 'WARNING',
1916 },
1917 }
1918
1919
1920 #As config1 but with a misspelt level on a logger
1921 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001922 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001923 'formatters': {
1924 'form1' : {
1925 'format' : '%(levelname)s ++ %(message)s',
1926 },
1927 },
1928 'handlers' : {
1929 'hand1' : {
1930 'class' : 'logging.StreamHandler',
1931 'formatter' : 'form1',
1932 'level' : 'NOTSET',
1933 'stream' : 'ext://sys.stdout',
1934 },
1935 },
1936 'loggers' : {
1937 'compiler.parser' : {
1938 'level' : 'DEBUG',
1939 'handlers' : ['hand1'],
1940 },
1941 },
1942 'root' : {
1943 'level' : 'WRANING',
1944 },
1945 }
1946
1947 # config3 has a less subtle configuration error
1948 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001949 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001950 'formatters': {
1951 'form1' : {
1952 'format' : '%(levelname)s ++ %(message)s',
1953 },
1954 },
1955 'handlers' : {
1956 'hand1' : {
1957 'class' : 'logging.StreamHandler',
1958 'formatter' : 'misspelled_name',
1959 'level' : 'NOTSET',
1960 'stream' : 'ext://sys.stdout',
1961 },
1962 },
1963 'loggers' : {
1964 'compiler.parser' : {
1965 'level' : 'DEBUG',
1966 'handlers' : ['hand1'],
1967 },
1968 },
1969 'root' : {
1970 'level' : 'WARNING',
1971 },
1972 }
1973
1974 # config4 specifies a custom formatter class to be loaded
1975 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001976 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001977 'formatters': {
1978 'form1' : {
1979 '()' : __name__ + '.ExceptionFormatter',
1980 'format' : '%(levelname)s:%(name)s:%(message)s',
1981 },
1982 },
1983 'handlers' : {
1984 'hand1' : {
1985 'class' : 'logging.StreamHandler',
1986 'formatter' : 'form1',
1987 'level' : 'NOTSET',
1988 'stream' : 'ext://sys.stdout',
1989 },
1990 },
1991 'root' : {
1992 'level' : 'NOTSET',
1993 'handlers' : ['hand1'],
1994 },
1995 }
1996
1997 # As config4 but using an actual callable rather than a string
1998 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001999 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002000 'formatters': {
2001 'form1' : {
2002 '()' : ExceptionFormatter,
2003 'format' : '%(levelname)s:%(name)s:%(message)s',
2004 },
2005 'form2' : {
2006 '()' : __name__ + '.formatFunc',
2007 'format' : '%(levelname)s:%(name)s:%(message)s',
2008 },
2009 'form3' : {
2010 '()' : formatFunc,
2011 'format' : '%(levelname)s:%(name)s:%(message)s',
2012 },
2013 },
2014 'handlers' : {
2015 'hand1' : {
2016 'class' : 'logging.StreamHandler',
2017 'formatter' : 'form1',
2018 'level' : 'NOTSET',
2019 'stream' : 'ext://sys.stdout',
2020 },
2021 'hand2' : {
2022 '()' : handlerFunc,
2023 },
2024 },
2025 'root' : {
2026 'level' : 'NOTSET',
2027 'handlers' : ['hand1'],
2028 },
2029 }
2030
2031 # config5 specifies a custom handler class to be loaded
2032 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002033 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002034 'formatters': {
2035 'form1' : {
2036 'format' : '%(levelname)s ++ %(message)s',
2037 },
2038 },
2039 'handlers' : {
2040 'hand1' : {
2041 'class' : __name__ + '.CustomHandler',
2042 'formatter' : 'form1',
2043 'level' : 'NOTSET',
2044 'stream' : 'ext://sys.stdout',
2045 },
2046 },
2047 'loggers' : {
2048 'compiler.parser' : {
2049 'level' : 'DEBUG',
2050 'handlers' : ['hand1'],
2051 },
2052 },
2053 'root' : {
2054 'level' : 'WARNING',
2055 },
2056 }
2057
2058 # config6 specifies a custom handler class to be loaded
2059 # but has bad arguments
2060 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002061 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002062 'formatters': {
2063 'form1' : {
2064 'format' : '%(levelname)s ++ %(message)s',
2065 },
2066 },
2067 'handlers' : {
2068 'hand1' : {
2069 'class' : __name__ + '.CustomHandler',
2070 'formatter' : 'form1',
2071 'level' : 'NOTSET',
2072 'stream' : 'ext://sys.stdout',
2073 '9' : 'invalid parameter name',
2074 },
2075 },
2076 'loggers' : {
2077 'compiler.parser' : {
2078 'level' : 'DEBUG',
2079 'handlers' : ['hand1'],
2080 },
2081 },
2082 'root' : {
2083 'level' : 'WARNING',
2084 },
2085 }
2086
2087 #config 7 does not define compiler.parser but defines compiler.lexer
2088 #so compiler.parser should be disabled after applying it
2089 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002090 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002091 'formatters': {
2092 'form1' : {
2093 'format' : '%(levelname)s ++ %(message)s',
2094 },
2095 },
2096 'handlers' : {
2097 'hand1' : {
2098 'class' : 'logging.StreamHandler',
2099 'formatter' : 'form1',
2100 'level' : 'NOTSET',
2101 'stream' : 'ext://sys.stdout',
2102 },
2103 },
2104 'loggers' : {
2105 'compiler.lexer' : {
2106 'level' : 'DEBUG',
2107 'handlers' : ['hand1'],
2108 },
2109 },
2110 'root' : {
2111 'level' : 'WARNING',
2112 },
2113 }
2114
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002115 # config8 defines both compiler and compiler.lexer
2116 # so compiler.parser should not be disabled (since
2117 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002118 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002119 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002120 'disable_existing_loggers' : False,
2121 'formatters': {
2122 'form1' : {
2123 'format' : '%(levelname)s ++ %(message)s',
2124 },
2125 },
2126 'handlers' : {
2127 'hand1' : {
2128 'class' : 'logging.StreamHandler',
2129 'formatter' : 'form1',
2130 'level' : 'NOTSET',
2131 'stream' : 'ext://sys.stdout',
2132 },
2133 },
2134 'loggers' : {
2135 'compiler' : {
2136 'level' : 'DEBUG',
2137 'handlers' : ['hand1'],
2138 },
2139 'compiler.lexer' : {
2140 },
2141 },
2142 'root' : {
2143 'level' : 'WARNING',
2144 },
2145 }
2146
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002147 # config8a disables existing loggers
2148 config8a = {
2149 'version': 1,
2150 'disable_existing_loggers' : True,
2151 'formatters': {
2152 'form1' : {
2153 'format' : '%(levelname)s ++ %(message)s',
2154 },
2155 },
2156 'handlers' : {
2157 'hand1' : {
2158 'class' : 'logging.StreamHandler',
2159 'formatter' : 'form1',
2160 'level' : 'NOTSET',
2161 'stream' : 'ext://sys.stdout',
2162 },
2163 },
2164 'loggers' : {
2165 'compiler' : {
2166 'level' : 'DEBUG',
2167 'handlers' : ['hand1'],
2168 },
2169 'compiler.lexer' : {
2170 },
2171 },
2172 'root' : {
2173 'level' : 'WARNING',
2174 },
2175 }
2176
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002177 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002178 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002179 'formatters': {
2180 'form1' : {
2181 'format' : '%(levelname)s ++ %(message)s',
2182 },
2183 },
2184 'handlers' : {
2185 'hand1' : {
2186 'class' : 'logging.StreamHandler',
2187 'formatter' : 'form1',
2188 'level' : 'WARNING',
2189 'stream' : 'ext://sys.stdout',
2190 },
2191 },
2192 'loggers' : {
2193 'compiler.parser' : {
2194 'level' : 'WARNING',
2195 'handlers' : ['hand1'],
2196 },
2197 },
2198 'root' : {
2199 'level' : 'NOTSET',
2200 },
2201 }
2202
2203 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002204 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002205 'incremental' : True,
2206 'handlers' : {
2207 'hand1' : {
2208 'level' : 'WARNING',
2209 },
2210 },
2211 'loggers' : {
2212 'compiler.parser' : {
2213 'level' : 'INFO',
2214 },
2215 },
2216 }
2217
2218 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002219 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002220 'incremental' : True,
2221 'handlers' : {
2222 'hand1' : {
2223 'level' : 'INFO',
2224 },
2225 },
2226 'loggers' : {
2227 'compiler.parser' : {
2228 'level' : 'INFO',
2229 },
2230 },
2231 }
2232
2233 #As config1 but with a filter added
2234 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002235 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002236 'formatters': {
2237 'form1' : {
2238 'format' : '%(levelname)s ++ %(message)s',
2239 },
2240 },
2241 'filters' : {
2242 'filt1' : {
2243 'name' : 'compiler.parser',
2244 },
2245 },
2246 'handlers' : {
2247 'hand1' : {
2248 'class' : 'logging.StreamHandler',
2249 'formatter' : 'form1',
2250 'level' : 'NOTSET',
2251 'stream' : 'ext://sys.stdout',
2252 'filters' : ['filt1'],
2253 },
2254 },
2255 'loggers' : {
2256 'compiler.parser' : {
2257 'level' : 'DEBUG',
2258 'filters' : ['filt1'],
2259 },
2260 },
2261 'root' : {
2262 'level' : 'WARNING',
2263 'handlers' : ['hand1'],
2264 },
2265 }
2266
2267 #As config1 but using cfg:// references
2268 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002269 'version': 1,
2270 'true_formatters': {
2271 'form1' : {
2272 'format' : '%(levelname)s ++ %(message)s',
2273 },
2274 },
2275 'handler_configs': {
2276 'hand1' : {
2277 'class' : 'logging.StreamHandler',
2278 'formatter' : 'form1',
2279 'level' : 'NOTSET',
2280 'stream' : 'ext://sys.stdout',
2281 },
2282 },
2283 'formatters' : 'cfg://true_formatters',
2284 'handlers' : {
2285 'hand1' : 'cfg://handler_configs[hand1]',
2286 },
2287 'loggers' : {
2288 'compiler.parser' : {
2289 'level' : 'DEBUG',
2290 'handlers' : ['hand1'],
2291 },
2292 },
2293 'root' : {
2294 'level' : 'WARNING',
2295 },
2296 }
2297
2298 #As config11 but missing the version key
2299 config12 = {
2300 'true_formatters': {
2301 'form1' : {
2302 'format' : '%(levelname)s ++ %(message)s',
2303 },
2304 },
2305 'handler_configs': {
2306 'hand1' : {
2307 'class' : 'logging.StreamHandler',
2308 'formatter' : 'form1',
2309 'level' : 'NOTSET',
2310 'stream' : 'ext://sys.stdout',
2311 },
2312 },
2313 'formatters' : 'cfg://true_formatters',
2314 'handlers' : {
2315 'hand1' : 'cfg://handler_configs[hand1]',
2316 },
2317 'loggers' : {
2318 'compiler.parser' : {
2319 'level' : 'DEBUG',
2320 'handlers' : ['hand1'],
2321 },
2322 },
2323 'root' : {
2324 'level' : 'WARNING',
2325 },
2326 }
2327
2328 #As config11 but using an unsupported version
2329 config13 = {
2330 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002331 'true_formatters': {
2332 'form1' : {
2333 'format' : '%(levelname)s ++ %(message)s',
2334 },
2335 },
2336 'handler_configs': {
2337 'hand1' : {
2338 'class' : 'logging.StreamHandler',
2339 'formatter' : 'form1',
2340 'level' : 'NOTSET',
2341 'stream' : 'ext://sys.stdout',
2342 },
2343 },
2344 'formatters' : 'cfg://true_formatters',
2345 'handlers' : {
2346 'hand1' : 'cfg://handler_configs[hand1]',
2347 },
2348 'loggers' : {
2349 'compiler.parser' : {
2350 'level' : 'DEBUG',
2351 'handlers' : ['hand1'],
2352 },
2353 },
2354 'root' : {
2355 'level' : 'WARNING',
2356 },
2357 }
2358
Vinay Sajip8d270232012-11-15 14:20:18 +00002359 # As config0, but with properties
2360 config14 = {
2361 'version': 1,
2362 'formatters': {
2363 'form1' : {
2364 'format' : '%(levelname)s ++ %(message)s',
2365 },
2366 },
2367 'handlers' : {
2368 'hand1' : {
2369 'class' : 'logging.StreamHandler',
2370 'formatter' : 'form1',
2371 'level' : 'NOTSET',
2372 'stream' : 'ext://sys.stdout',
2373 '.': {
2374 'foo': 'bar',
2375 'terminator': '!\n',
2376 }
2377 },
2378 },
2379 'root' : {
2380 'level' : 'WARNING',
2381 'handlers' : ['hand1'],
2382 },
2383 }
2384
Vinay Sajip3f885b52013-03-22 15:19:54 +00002385 out_of_order = {
2386 "version": 1,
2387 "formatters": {
2388 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002389 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2390 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002391 }
2392 },
2393 "handlers": {
2394 "fileGlobal": {
2395 "class": "logging.StreamHandler",
2396 "level": "DEBUG",
2397 "formatter": "mySimpleFormatter"
2398 },
2399 "bufferGlobal": {
2400 "class": "logging.handlers.MemoryHandler",
2401 "capacity": 5,
2402 "formatter": "mySimpleFormatter",
2403 "target": "fileGlobal",
2404 "level": "DEBUG"
2405 }
2406 },
2407 "loggers": {
2408 "mymodule": {
2409 "level": "DEBUG",
2410 "handlers": ["bufferGlobal"],
2411 "propagate": "true"
2412 }
2413 }
2414 }
2415
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002416 def apply_config(self, conf):
2417 logging.config.dictConfig(conf)
2418
2419 def test_config0_ok(self):
2420 # A simple config which overrides the default settings.
2421 with captured_stdout() as output:
2422 self.apply_config(self.config0)
2423 logger = logging.getLogger()
2424 # Won't output anything
2425 logger.info(self.next_message())
2426 # Outputs a message
2427 logger.error(self.next_message())
2428 self.assert_log_lines([
2429 ('ERROR', '2'),
2430 ], stream=output)
2431 # Original logger output is empty.
2432 self.assert_log_lines([])
2433
2434 def test_config1_ok(self, config=config1):
2435 # A config defining a sub-parser as well.
2436 with captured_stdout() as output:
2437 self.apply_config(config)
2438 logger = logging.getLogger("compiler.parser")
2439 # Both will output a message
2440 logger.info(self.next_message())
2441 logger.error(self.next_message())
2442 self.assert_log_lines([
2443 ('INFO', '1'),
2444 ('ERROR', '2'),
2445 ], stream=output)
2446 # Original logger output is empty.
2447 self.assert_log_lines([])
2448
2449 def test_config2_failure(self):
2450 # A simple config which overrides the default settings.
2451 self.assertRaises(Exception, self.apply_config, self.config2)
2452
2453 def test_config2a_failure(self):
2454 # A simple config which overrides the default settings.
2455 self.assertRaises(Exception, self.apply_config, self.config2a)
2456
2457 def test_config2b_failure(self):
2458 # A simple config which overrides the default settings.
2459 self.assertRaises(Exception, self.apply_config, self.config2b)
2460
2461 def test_config3_failure(self):
2462 # A simple config which overrides the default settings.
2463 self.assertRaises(Exception, self.apply_config, self.config3)
2464
2465 def test_config4_ok(self):
2466 # A config specifying a custom formatter class.
2467 with captured_stdout() as output:
2468 self.apply_config(self.config4)
2469 #logger = logging.getLogger()
2470 try:
2471 raise RuntimeError()
2472 except RuntimeError:
2473 logging.exception("just testing")
2474 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002475 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002476 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2477 # Original logger output is empty
2478 self.assert_log_lines([])
2479
2480 def test_config4a_ok(self):
2481 # A config specifying a custom formatter class.
2482 with captured_stdout() as output:
2483 self.apply_config(self.config4a)
2484 #logger = logging.getLogger()
2485 try:
2486 raise RuntimeError()
2487 except RuntimeError:
2488 logging.exception("just testing")
2489 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002490 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002491 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2492 # Original logger output is empty
2493 self.assert_log_lines([])
2494
2495 def test_config5_ok(self):
2496 self.test_config1_ok(config=self.config5)
2497
2498 def test_config6_failure(self):
2499 self.assertRaises(Exception, self.apply_config, self.config6)
2500
2501 def test_config7_ok(self):
2502 with captured_stdout() as output:
2503 self.apply_config(self.config1)
2504 logger = logging.getLogger("compiler.parser")
2505 # Both will output a message
2506 logger.info(self.next_message())
2507 logger.error(self.next_message())
2508 self.assert_log_lines([
2509 ('INFO', '1'),
2510 ('ERROR', '2'),
2511 ], stream=output)
2512 # Original logger output is empty.
2513 self.assert_log_lines([])
2514 with captured_stdout() as output:
2515 self.apply_config(self.config7)
2516 logger = logging.getLogger("compiler.parser")
2517 self.assertTrue(logger.disabled)
2518 logger = logging.getLogger("compiler.lexer")
2519 # Both will output a message
2520 logger.info(self.next_message())
2521 logger.error(self.next_message())
2522 self.assert_log_lines([
2523 ('INFO', '3'),
2524 ('ERROR', '4'),
2525 ], stream=output)
2526 # Original logger output is empty.
2527 self.assert_log_lines([])
2528
2529 #Same as test_config_7_ok but don't disable old loggers.
2530 def test_config_8_ok(self):
2531 with captured_stdout() as output:
2532 self.apply_config(self.config1)
2533 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002534 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002535 logger.info(self.next_message())
2536 logger.error(self.next_message())
2537 self.assert_log_lines([
2538 ('INFO', '1'),
2539 ('ERROR', '2'),
2540 ], stream=output)
2541 # Original logger output is empty.
2542 self.assert_log_lines([])
2543 with captured_stdout() as output:
2544 self.apply_config(self.config8)
2545 logger = logging.getLogger("compiler.parser")
2546 self.assertFalse(logger.disabled)
2547 # Both will output a message
2548 logger.info(self.next_message())
2549 logger.error(self.next_message())
2550 logger = logging.getLogger("compiler.lexer")
2551 # Both will output a message
2552 logger.info(self.next_message())
2553 logger.error(self.next_message())
2554 self.assert_log_lines([
2555 ('INFO', '3'),
2556 ('ERROR', '4'),
2557 ('INFO', '5'),
2558 ('ERROR', '6'),
2559 ], stream=output)
2560 # Original logger output is empty.
2561 self.assert_log_lines([])
2562
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002563 def test_config_8a_ok(self):
2564 with captured_stdout() as output:
2565 self.apply_config(self.config1a)
2566 logger = logging.getLogger("compiler.parser")
2567 # See issue #11424. compiler-hyphenated sorts
2568 # between compiler and compiler.xyz and this
2569 # was preventing compiler.xyz from being included
2570 # in the child loggers of compiler because of an
2571 # overzealous loop termination condition.
2572 hyphenated = logging.getLogger('compiler-hyphenated')
2573 # All will output a message
2574 logger.info(self.next_message())
2575 logger.error(self.next_message())
2576 hyphenated.critical(self.next_message())
2577 self.assert_log_lines([
2578 ('INFO', '1'),
2579 ('ERROR', '2'),
2580 ('CRITICAL', '3'),
2581 ], stream=output)
2582 # Original logger output is empty.
2583 self.assert_log_lines([])
2584 with captured_stdout() as output:
2585 self.apply_config(self.config8a)
2586 logger = logging.getLogger("compiler.parser")
2587 self.assertFalse(logger.disabled)
2588 # Both will output a message
2589 logger.info(self.next_message())
2590 logger.error(self.next_message())
2591 logger = logging.getLogger("compiler.lexer")
2592 # Both will output a message
2593 logger.info(self.next_message())
2594 logger.error(self.next_message())
2595 # Will not appear
2596 hyphenated.critical(self.next_message())
2597 self.assert_log_lines([
2598 ('INFO', '4'),
2599 ('ERROR', '5'),
2600 ('INFO', '6'),
2601 ('ERROR', '7'),
2602 ], stream=output)
2603 # Original logger output is empty.
2604 self.assert_log_lines([])
2605
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002606 def test_config_9_ok(self):
2607 with captured_stdout() as output:
2608 self.apply_config(self.config9)
2609 logger = logging.getLogger("compiler.parser")
2610 #Nothing will be output since both handler and logger are set to WARNING
2611 logger.info(self.next_message())
2612 self.assert_log_lines([], stream=output)
2613 self.apply_config(self.config9a)
2614 #Nothing will be output since both handler is still set to WARNING
2615 logger.info(self.next_message())
2616 self.assert_log_lines([], stream=output)
2617 self.apply_config(self.config9b)
2618 #Message should now be output
2619 logger.info(self.next_message())
2620 self.assert_log_lines([
2621 ('INFO', '3'),
2622 ], stream=output)
2623
2624 def test_config_10_ok(self):
2625 with captured_stdout() as output:
2626 self.apply_config(self.config10)
2627 logger = logging.getLogger("compiler.parser")
2628 logger.warning(self.next_message())
2629 logger = logging.getLogger('compiler')
2630 #Not output, because filtered
2631 logger.warning(self.next_message())
2632 logger = logging.getLogger('compiler.lexer')
2633 #Not output, because filtered
2634 logger.warning(self.next_message())
2635 logger = logging.getLogger("compiler.parser.codegen")
2636 #Output, as not filtered
2637 logger.error(self.next_message())
2638 self.assert_log_lines([
2639 ('WARNING', '1'),
2640 ('ERROR', '4'),
2641 ], stream=output)
2642
2643 def test_config11_ok(self):
2644 self.test_config1_ok(self.config11)
2645
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002646 def test_config12_failure(self):
2647 self.assertRaises(Exception, self.apply_config, self.config12)
2648
2649 def test_config13_failure(self):
2650 self.assertRaises(Exception, self.apply_config, self.config13)
2651
Vinay Sajip8d270232012-11-15 14:20:18 +00002652 def test_config14_ok(self):
2653 with captured_stdout() as output:
2654 self.apply_config(self.config14)
2655 h = logging._handlers['hand1']
2656 self.assertEqual(h.foo, 'bar')
2657 self.assertEqual(h.terminator, '!\n')
2658 logging.warning('Exclamation')
2659 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2660
Victor Stinner45df8202010-04-28 22:31:17 +00002661 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002662 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002663 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002664 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002665 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002666 t.start()
2667 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002668 # Now get the port allocated
2669 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002670 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002671 try:
2672 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2673 sock.settimeout(2.0)
2674 sock.connect(('localhost', port))
2675
2676 slen = struct.pack('>L', len(text))
2677 s = slen + text
2678 sentsofar = 0
2679 left = len(s)
2680 while left > 0:
2681 sent = sock.send(s[sentsofar:])
2682 sentsofar += sent
2683 left -= sent
2684 sock.close()
2685 finally:
2686 t.ready.wait(2.0)
2687 logging.config.stopListening()
2688 t.join(2.0)
2689
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002690 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002691 def test_listen_config_10_ok(self):
2692 with captured_stdout() as output:
2693 self.setup_via_listener(json.dumps(self.config10))
2694 logger = logging.getLogger("compiler.parser")
2695 logger.warning(self.next_message())
2696 logger = logging.getLogger('compiler')
2697 #Not output, because filtered
2698 logger.warning(self.next_message())
2699 logger = logging.getLogger('compiler.lexer')
2700 #Not output, because filtered
2701 logger.warning(self.next_message())
2702 logger = logging.getLogger("compiler.parser.codegen")
2703 #Output, as not filtered
2704 logger.error(self.next_message())
2705 self.assert_log_lines([
2706 ('WARNING', '1'),
2707 ('ERROR', '4'),
2708 ], stream=output)
2709
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002710 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002711 def test_listen_config_1_ok(self):
2712 with captured_stdout() as output:
2713 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2714 logger = logging.getLogger("compiler.parser")
2715 # Both will output a message
2716 logger.info(self.next_message())
2717 logger.error(self.next_message())
2718 self.assert_log_lines([
2719 ('INFO', '1'),
2720 ('ERROR', '2'),
2721 ], stream=output)
2722 # Original logger output is empty.
2723 self.assert_log_lines([])
2724
Vinay Sajip4ded5512012-10-02 15:56:16 +01002725 @unittest.skipUnless(threading, 'Threading required for this test.')
2726 def test_listen_verify(self):
2727
2728 def verify_fail(stuff):
2729 return None
2730
2731 def verify_reverse(stuff):
2732 return stuff[::-1]
2733
2734 logger = logging.getLogger("compiler.parser")
2735 to_send = textwrap.dedent(ConfigFileTest.config1)
2736 # First, specify a verification function that will fail.
2737 # We expect to see no output, since our configuration
2738 # never took effect.
2739 with captured_stdout() as output:
2740 self.setup_via_listener(to_send, verify_fail)
2741 # Both will output a message
2742 logger.info(self.next_message())
2743 logger.error(self.next_message())
2744 self.assert_log_lines([], stream=output)
2745 # Original logger output has the stuff we logged.
2746 self.assert_log_lines([
2747 ('INFO', '1'),
2748 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002749 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002750
2751 # Now, perform no verification. Our configuration
2752 # should take effect.
2753
2754 with captured_stdout() as output:
2755 self.setup_via_listener(to_send) # no verify callable specified
2756 logger = logging.getLogger("compiler.parser")
2757 # Both will output a message
2758 logger.info(self.next_message())
2759 logger.error(self.next_message())
2760 self.assert_log_lines([
2761 ('INFO', '3'),
2762 ('ERROR', '4'),
2763 ], stream=output)
2764 # Original logger output still has the stuff we logged before.
2765 self.assert_log_lines([
2766 ('INFO', '1'),
2767 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002768 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002769
2770 # Now, perform verification which transforms the bytes.
2771
2772 with captured_stdout() as output:
2773 self.setup_via_listener(to_send[::-1], verify_reverse)
2774 logger = logging.getLogger("compiler.parser")
2775 # Both will output a message
2776 logger.info(self.next_message())
2777 logger.error(self.next_message())
2778 self.assert_log_lines([
2779 ('INFO', '5'),
2780 ('ERROR', '6'),
2781 ], stream=output)
2782 # Original logger output still has the stuff we logged before.
2783 self.assert_log_lines([
2784 ('INFO', '1'),
2785 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002786 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002787
Vinay Sajip3f885b52013-03-22 15:19:54 +00002788 def test_out_of_order(self):
2789 self.apply_config(self.out_of_order)
2790 handler = logging.getLogger('mymodule').handlers[0]
2791 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002792 self.assertIsInstance(handler.formatter._style,
2793 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002794
Vinay Sajip373baef2011-04-26 20:05:24 +01002795 def test_baseconfig(self):
2796 d = {
2797 'atuple': (1, 2, 3),
2798 'alist': ['a', 'b', 'c'],
2799 'adict': {'d': 'e', 'f': 3 },
2800 'nest1': ('g', ('h', 'i'), 'j'),
2801 'nest2': ['k', ['l', 'm'], 'n'],
2802 'nest3': ['o', 'cfg://alist', 'p'],
2803 }
2804 bc = logging.config.BaseConfigurator(d)
2805 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2806 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2807 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2808 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2809 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2810 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2811 v = bc.convert('cfg://nest3')
2812 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2813 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2814 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2815 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002816
2817class ManagerTest(BaseTest):
2818 def test_manager_loggerclass(self):
2819 logged = []
2820
2821 class MyLogger(logging.Logger):
2822 def _log(self, level, msg, args, exc_info=None, extra=None):
2823 logged.append(msg)
2824
2825 man = logging.Manager(None)
2826 self.assertRaises(TypeError, man.setLoggerClass, int)
2827 man.setLoggerClass(MyLogger)
2828 logger = man.getLogger('test')
2829 logger.warning('should appear in logged')
2830 logging.warning('should not appear in logged')
2831
2832 self.assertEqual(logged, ['should appear in logged'])
2833
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002834 def test_set_log_record_factory(self):
2835 man = logging.Manager(None)
2836 expected = object()
2837 man.setLogRecordFactory(expected)
2838 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002839
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002840class ChildLoggerTest(BaseTest):
2841 def test_child_loggers(self):
2842 r = logging.getLogger()
2843 l1 = logging.getLogger('abc')
2844 l2 = logging.getLogger('def.ghi')
2845 c1 = r.getChild('xyz')
2846 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002847 self.assertIs(c1, logging.getLogger('xyz'))
2848 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002849 c1 = l1.getChild('def')
2850 c2 = c1.getChild('ghi')
2851 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002852 self.assertIs(c1, logging.getLogger('abc.def'))
2853 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2854 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002855
2856
Vinay Sajip6fac8172010-10-19 20:44:14 +00002857class DerivedLogRecord(logging.LogRecord):
2858 pass
2859
Vinay Sajip61561522010-12-03 11:50:38 +00002860class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002861
2862 def setUp(self):
2863 class CheckingFilter(logging.Filter):
2864 def __init__(self, cls):
2865 self.cls = cls
2866
2867 def filter(self, record):
2868 t = type(record)
2869 if t is not self.cls:
2870 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2871 self.cls)
2872 raise TypeError(msg)
2873 return True
2874
2875 BaseTest.setUp(self)
2876 self.filter = CheckingFilter(DerivedLogRecord)
2877 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002878 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002879
2880 def tearDown(self):
2881 self.root_logger.removeFilter(self.filter)
2882 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002883 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002884
2885 def test_logrecord_class(self):
2886 self.assertRaises(TypeError, self.root_logger.warning,
2887 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002888 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002889 self.root_logger.error(self.next_message())
2890 self.assert_log_lines([
2891 ('root', 'ERROR', '2'),
2892 ])
2893
2894
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002895class QueueHandlerTest(BaseTest):
2896 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002897 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002898
2899 def setUp(self):
2900 BaseTest.setUp(self)
2901 self.queue = queue.Queue(-1)
2902 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2903 self.que_logger = logging.getLogger('que')
2904 self.que_logger.propagate = False
2905 self.que_logger.setLevel(logging.WARNING)
2906 self.que_logger.addHandler(self.que_hdlr)
2907
2908 def tearDown(self):
2909 self.que_hdlr.close()
2910 BaseTest.tearDown(self)
2911
2912 def test_queue_handler(self):
2913 self.que_logger.debug(self.next_message())
2914 self.assertRaises(queue.Empty, self.queue.get_nowait)
2915 self.que_logger.info(self.next_message())
2916 self.assertRaises(queue.Empty, self.queue.get_nowait)
2917 msg = self.next_message()
2918 self.que_logger.warning(msg)
2919 data = self.queue.get_nowait()
2920 self.assertTrue(isinstance(data, logging.LogRecord))
2921 self.assertEqual(data.name, self.que_logger.name)
2922 self.assertEqual((data.msg, data.args), (msg, None))
2923
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002924 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2925 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002926 def test_queue_listener(self):
2927 handler = TestHandler(Matcher())
2928 listener = logging.handlers.QueueListener(self.queue, handler)
2929 listener.start()
2930 try:
2931 self.que_logger.warning(self.next_message())
2932 self.que_logger.error(self.next_message())
2933 self.que_logger.critical(self.next_message())
2934 finally:
2935 listener.stop()
2936 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2937 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2938 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2939
Vinay Sajip37eb3382011-04-26 20:26:41 +01002940ZERO = datetime.timedelta(0)
2941
2942class UTC(datetime.tzinfo):
2943 def utcoffset(self, dt):
2944 return ZERO
2945
2946 dst = utcoffset
2947
2948 def tzname(self, dt):
2949 return 'UTC'
2950
2951utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002952
Vinay Sajipa39c5712010-10-25 13:57:39 +00002953class FormatterTest(unittest.TestCase):
2954 def setUp(self):
2955 self.common = {
2956 'name': 'formatter.test',
2957 'level': logging.DEBUG,
2958 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2959 'lineno': 42,
2960 'exc_info': None,
2961 'func': None,
2962 'msg': 'Message with %d %s',
2963 'args': (2, 'placeholders'),
2964 }
2965 self.variants = {
2966 }
2967
2968 def get_record(self, name=None):
2969 result = dict(self.common)
2970 if name is not None:
2971 result.update(self.variants[name])
2972 return logging.makeLogRecord(result)
2973
2974 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002975 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002976 r = self.get_record()
2977 f = logging.Formatter('${%(message)s}')
2978 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2979 f = logging.Formatter('%(random)s')
2980 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002981 self.assertFalse(f.usesTime())
2982 f = logging.Formatter('%(asctime)s')
2983 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002984 f = logging.Formatter('%(asctime)-15s')
2985 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002986 f = logging.Formatter('asctime')
2987 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002988
2989 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002990 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002991 r = self.get_record()
2992 f = logging.Formatter('$%{message}%$', style='{')
2993 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2994 f = logging.Formatter('{random}', style='{')
2995 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002996 self.assertFalse(f.usesTime())
2997 f = logging.Formatter('{asctime}', style='{')
2998 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002999 f = logging.Formatter('{asctime!s:15}', style='{')
3000 self.assertTrue(f.usesTime())
3001 f = logging.Formatter('{asctime:15}', style='{')
3002 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003003 f = logging.Formatter('asctime', style='{')
3004 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003005
3006 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003007 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003008 r = self.get_record()
3009 f = logging.Formatter('$message', style='$')
3010 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3011 f = logging.Formatter('$$%${message}%$$', style='$')
3012 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3013 f = logging.Formatter('${random}', style='$')
3014 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003015 self.assertFalse(f.usesTime())
3016 f = logging.Formatter('${asctime}', style='$')
3017 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003018 f = logging.Formatter('${asctime', style='$')
3019 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003020 f = logging.Formatter('$asctime', style='$')
3021 self.assertTrue(f.usesTime())
3022 f = logging.Formatter('asctime', style='$')
3023 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003024
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003025 def test_invalid_style(self):
3026 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3027
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003028 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003029 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003030 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3031 # We use None to indicate we want the local timezone
3032 # We're essentially converting a UTC time to local time
3033 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003034 r.msecs = 123
3035 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003036 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003037 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3038 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003039 f.format(r)
3040 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3041
3042class TestBufferingFormatter(logging.BufferingFormatter):
3043 def formatHeader(self, records):
3044 return '[(%d)' % len(records)
3045
3046 def formatFooter(self, records):
3047 return '(%d)]' % len(records)
3048
3049class BufferingFormatterTest(unittest.TestCase):
3050 def setUp(self):
3051 self.records = [
3052 logging.makeLogRecord({'msg': 'one'}),
3053 logging.makeLogRecord({'msg': 'two'}),
3054 ]
3055
3056 def test_default(self):
3057 f = logging.BufferingFormatter()
3058 self.assertEqual('', f.format([]))
3059 self.assertEqual('onetwo', f.format(self.records))
3060
3061 def test_custom(self):
3062 f = TestBufferingFormatter()
3063 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3064 lf = logging.Formatter('<%(message)s>')
3065 f = TestBufferingFormatter(lf)
3066 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003067
3068class ExceptionTest(BaseTest):
3069 def test_formatting(self):
3070 r = self.root_logger
3071 h = RecordingHandler()
3072 r.addHandler(h)
3073 try:
3074 raise RuntimeError('deliberate mistake')
3075 except:
3076 logging.exception('failed', stack_info=True)
3077 r.removeHandler(h)
3078 h.close()
3079 r = h.records[0]
3080 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3081 'call last):\n'))
3082 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3083 'deliberate mistake'))
3084 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3085 'call last):\n'))
3086 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3087 'stack_info=True)'))
3088
3089
Vinay Sajip5a27d402010-12-10 11:42:57 +00003090class LastResortTest(BaseTest):
3091 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003092 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003093 root = self.root_logger
3094 root.removeHandler(self.root_hdlr)
3095 old_stderr = sys.stderr
3096 old_lastresort = logging.lastResort
3097 old_raise_exceptions = logging.raiseExceptions
3098 try:
3099 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003100 root.debug('This should not appear')
3101 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003102 root.warning('This is your final chance!')
3103 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3104 #No handlers and no last resort, so 'No handlers' message
3105 logging.lastResort = None
3106 sys.stderr = sio = io.StringIO()
3107 root.warning('This is your final chance!')
3108 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3109 # 'No handlers' message only printed once
3110 sys.stderr = sio = io.StringIO()
3111 root.warning('This is your final chance!')
3112 self.assertEqual(sio.getvalue(), '')
3113 root.manager.emittedNoHandlerWarning = False
3114 #If raiseExceptions is False, no message is printed
3115 logging.raiseExceptions = False
3116 sys.stderr = sio = io.StringIO()
3117 root.warning('This is your final chance!')
3118 self.assertEqual(sio.getvalue(), '')
3119 finally:
3120 sys.stderr = old_stderr
3121 root.addHandler(self.root_hdlr)
3122 logging.lastResort = old_lastresort
3123 logging.raiseExceptions = old_raise_exceptions
3124
3125
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003126class FakeHandler:
3127
3128 def __init__(self, identifier, called):
3129 for method in ('acquire', 'flush', 'close', 'release'):
3130 setattr(self, method, self.record_call(identifier, method, called))
3131
3132 def record_call(self, identifier, method_name, called):
3133 def inner():
3134 called.append('{} - {}'.format(identifier, method_name))
3135 return inner
3136
3137
3138class RecordingHandler(logging.NullHandler):
3139
3140 def __init__(self, *args, **kwargs):
3141 super(RecordingHandler, self).__init__(*args, **kwargs)
3142 self.records = []
3143
3144 def handle(self, record):
3145 """Keep track of all the emitted records."""
3146 self.records.append(record)
3147
3148
3149class ShutdownTest(BaseTest):
3150
Vinay Sajip5e66b162011-04-20 15:41:14 +01003151 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003152
3153 def setUp(self):
3154 super(ShutdownTest, self).setUp()
3155 self.called = []
3156
3157 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003158 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003159
3160 def raise_error(self, error):
3161 def inner():
3162 raise error()
3163 return inner
3164
3165 def test_no_failure(self):
3166 # create some fake handlers
3167 handler0 = FakeHandler(0, self.called)
3168 handler1 = FakeHandler(1, self.called)
3169 handler2 = FakeHandler(2, self.called)
3170
3171 # create live weakref to those handlers
3172 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3173
3174 logging.shutdown(handlerList=list(handlers))
3175
3176 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3177 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3178 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3179 self.assertEqual(expected, self.called)
3180
3181 def _test_with_failure_in_method(self, method, error):
3182 handler = FakeHandler(0, self.called)
3183 setattr(handler, method, self.raise_error(error))
3184 handlers = [logging.weakref.ref(handler)]
3185
3186 logging.shutdown(handlerList=list(handlers))
3187
3188 self.assertEqual('0 - release', self.called[-1])
3189
3190 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003191 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003192
3193 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003194 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003195
3196 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003197 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003198
3199 def test_with_valueerror_in_acquire(self):
3200 self._test_with_failure_in_method('acquire', ValueError)
3201
3202 def test_with_valueerror_in_flush(self):
3203 self._test_with_failure_in_method('flush', ValueError)
3204
3205 def test_with_valueerror_in_close(self):
3206 self._test_with_failure_in_method('close', ValueError)
3207
3208 def test_with_other_error_in_acquire_without_raise(self):
3209 logging.raiseExceptions = False
3210 self._test_with_failure_in_method('acquire', IndexError)
3211
3212 def test_with_other_error_in_flush_without_raise(self):
3213 logging.raiseExceptions = False
3214 self._test_with_failure_in_method('flush', IndexError)
3215
3216 def test_with_other_error_in_close_without_raise(self):
3217 logging.raiseExceptions = False
3218 self._test_with_failure_in_method('close', IndexError)
3219
3220 def test_with_other_error_in_acquire_with_raise(self):
3221 logging.raiseExceptions = True
3222 self.assertRaises(IndexError, self._test_with_failure_in_method,
3223 'acquire', IndexError)
3224
3225 def test_with_other_error_in_flush_with_raise(self):
3226 logging.raiseExceptions = True
3227 self.assertRaises(IndexError, self._test_with_failure_in_method,
3228 'flush', IndexError)
3229
3230 def test_with_other_error_in_close_with_raise(self):
3231 logging.raiseExceptions = True
3232 self.assertRaises(IndexError, self._test_with_failure_in_method,
3233 'close', IndexError)
3234
3235
3236class ModuleLevelMiscTest(BaseTest):
3237
Vinay Sajip5e66b162011-04-20 15:41:14 +01003238 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003239
3240 def test_disable(self):
3241 old_disable = logging.root.manager.disable
3242 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003243 self.assertEqual(old_disable, 0)
3244 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003245
3246 logging.disable(83)
3247 self.assertEqual(logging.root.manager.disable, 83)
3248
3249 def _test_log(self, method, level=None):
3250 called = []
3251 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003252 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003253
3254 recording = RecordingHandler()
3255 logging.root.addHandler(recording)
3256
3257 log_method = getattr(logging, method)
3258 if level is not None:
3259 log_method(level, "test me: %r", recording)
3260 else:
3261 log_method("test me: %r", recording)
3262
3263 self.assertEqual(len(recording.records), 1)
3264 record = recording.records[0]
3265 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3266
3267 expected_level = level if level is not None else getattr(logging, method.upper())
3268 self.assertEqual(record.levelno, expected_level)
3269
3270 # basicConfig was not called!
3271 self.assertEqual(called, [])
3272
3273 def test_log(self):
3274 self._test_log('log', logging.ERROR)
3275
3276 def test_debug(self):
3277 self._test_log('debug')
3278
3279 def test_info(self):
3280 self._test_log('info')
3281
3282 def test_warning(self):
3283 self._test_log('warning')
3284
3285 def test_error(self):
3286 self._test_log('error')
3287
3288 def test_critical(self):
3289 self._test_log('critical')
3290
3291 def test_set_logger_class(self):
3292 self.assertRaises(TypeError, logging.setLoggerClass, object)
3293
3294 class MyLogger(logging.Logger):
3295 pass
3296
3297 logging.setLoggerClass(MyLogger)
3298 self.assertEqual(logging.getLoggerClass(), MyLogger)
3299
3300 logging.setLoggerClass(logging.Logger)
3301 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3302
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003303class LogRecordTest(BaseTest):
3304 def test_str_rep(self):
3305 r = logging.makeLogRecord({})
3306 s = str(r)
3307 self.assertTrue(s.startswith('<LogRecord: '))
3308 self.assertTrue(s.endswith('>'))
3309
3310 def test_dict_arg(self):
3311 h = RecordingHandler()
3312 r = logging.getLogger()
3313 r.addHandler(h)
3314 d = {'less' : 'more' }
3315 logging.warning('less is %(less)s', d)
3316 self.assertIs(h.records[0].args, d)
3317 self.assertEqual(h.records[0].message, 'less is more')
3318 r.removeHandler(h)
3319 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003320
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003321 def test_multiprocessing(self):
3322 r = logging.makeLogRecord({})
3323 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003324 try:
3325 import multiprocessing as mp
3326 r = logging.makeLogRecord({})
3327 self.assertEqual(r.processName, mp.current_process().name)
3328 except ImportError:
3329 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003330
3331 def test_optional(self):
3332 r = logging.makeLogRecord({})
3333 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003334 if threading:
3335 NOT_NONE(r.thread)
3336 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003337 NOT_NONE(r.process)
3338 NOT_NONE(r.processName)
3339 log_threads = logging.logThreads
3340 log_processes = logging.logProcesses
3341 log_multiprocessing = logging.logMultiprocessing
3342 try:
3343 logging.logThreads = False
3344 logging.logProcesses = False
3345 logging.logMultiprocessing = False
3346 r = logging.makeLogRecord({})
3347 NONE = self.assertIsNone
3348 NONE(r.thread)
3349 NONE(r.threadName)
3350 NONE(r.process)
3351 NONE(r.processName)
3352 finally:
3353 logging.logThreads = log_threads
3354 logging.logProcesses = log_processes
3355 logging.logMultiprocessing = log_multiprocessing
3356
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003357class BasicConfigTest(unittest.TestCase):
3358
Vinay Sajip95bf5042011-04-20 11:50:56 +01003359 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003360
3361 def setUp(self):
3362 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003363 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003364 self.saved_handlers = logging._handlers.copy()
3365 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003366 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003367 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003368 logging.root.handlers = []
3369
3370 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003371 for h in logging.root.handlers[:]:
3372 logging.root.removeHandler(h)
3373 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003374 super(BasicConfigTest, self).tearDown()
3375
Vinay Sajip3def7e02011-04-20 10:58:06 +01003376 def cleanup(self):
3377 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003378 logging._handlers.clear()
3379 logging._handlers.update(self.saved_handlers)
3380 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003381 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003382
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003383 def test_no_kwargs(self):
3384 logging.basicConfig()
3385
3386 # handler defaults to a StreamHandler to sys.stderr
3387 self.assertEqual(len(logging.root.handlers), 1)
3388 handler = logging.root.handlers[0]
3389 self.assertIsInstance(handler, logging.StreamHandler)
3390 self.assertEqual(handler.stream, sys.stderr)
3391
3392 formatter = handler.formatter
3393 # format defaults to logging.BASIC_FORMAT
3394 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3395 # datefmt defaults to None
3396 self.assertIsNone(formatter.datefmt)
3397 # style defaults to %
3398 self.assertIsInstance(formatter._style, logging.PercentStyle)
3399
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003400 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003401 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003402
3403 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003404
3405 def cleanup(h1, h2, fn):
3406 h1.close()
3407 h2.close()
3408 os.remove(fn)
3409
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003410 logging.basicConfig(filename='test.log')
3411
3412 self.assertEqual(len(logging.root.handlers), 1)
3413 handler = logging.root.handlers[0]
3414 self.assertIsInstance(handler, logging.FileHandler)
3415
3416 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003417 self.assertEqual(handler.stream.mode, expected.stream.mode)
3418 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003419 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003420
3421 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003422
3423 def cleanup(h1, h2, fn):
3424 h1.close()
3425 h2.close()
3426 os.remove(fn)
3427
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003428 logging.basicConfig(filename='test.log', filemode='wb')
3429
3430 handler = logging.root.handlers[0]
3431 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003432 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003433 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003434
3435 def test_stream(self):
3436 stream = io.StringIO()
3437 self.addCleanup(stream.close)
3438 logging.basicConfig(stream=stream)
3439
3440 self.assertEqual(len(logging.root.handlers), 1)
3441 handler = logging.root.handlers[0]
3442 self.assertIsInstance(handler, logging.StreamHandler)
3443 self.assertEqual(handler.stream, stream)
3444
3445 def test_format(self):
3446 logging.basicConfig(format='foo')
3447
3448 formatter = logging.root.handlers[0].formatter
3449 self.assertEqual(formatter._style._fmt, 'foo')
3450
3451 def test_datefmt(self):
3452 logging.basicConfig(datefmt='bar')
3453
3454 formatter = logging.root.handlers[0].formatter
3455 self.assertEqual(formatter.datefmt, 'bar')
3456
3457 def test_style(self):
3458 logging.basicConfig(style='$')
3459
3460 formatter = logging.root.handlers[0].formatter
3461 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3462
3463 def test_level(self):
3464 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003465 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003466
3467 logging.basicConfig(level=57)
3468 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003469 # Test that second call has no effect
3470 logging.basicConfig(level=58)
3471 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003472
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003473 def test_incompatible(self):
3474 assertRaises = self.assertRaises
3475 handlers = [logging.StreamHandler()]
3476 stream = sys.stderr
3477 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3478 stream=stream)
3479 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3480 handlers=handlers)
3481 assertRaises(ValueError, logging.basicConfig, stream=stream,
3482 handlers=handlers)
3483
3484 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003485 handlers = [
3486 logging.StreamHandler(),
3487 logging.StreamHandler(sys.stdout),
3488 logging.StreamHandler(),
3489 ]
3490 f = logging.Formatter()
3491 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003492 logging.basicConfig(handlers=handlers)
3493 self.assertIs(handlers[0], logging.root.handlers[0])
3494 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003495 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003496 self.assertIsNotNone(handlers[0].formatter)
3497 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003498 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003499 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3500
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003501 def _test_log(self, method, level=None):
3502 # logging.root has no handlers so basicConfig should be called
3503 called = []
3504
3505 old_basic_config = logging.basicConfig
3506 def my_basic_config(*a, **kw):
3507 old_basic_config()
3508 old_level = logging.root.level
3509 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003510 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003511 called.append((a, kw))
3512
3513 patch(self, logging, 'basicConfig', my_basic_config)
3514
3515 log_method = getattr(logging, method)
3516 if level is not None:
3517 log_method(level, "test me")
3518 else:
3519 log_method("test me")
3520
3521 # basicConfig was called with no arguments
3522 self.assertEqual(called, [((), {})])
3523
3524 def test_log(self):
3525 self._test_log('log', logging.WARNING)
3526
3527 def test_debug(self):
3528 self._test_log('debug')
3529
3530 def test_info(self):
3531 self._test_log('info')
3532
3533 def test_warning(self):
3534 self._test_log('warning')
3535
3536 def test_error(self):
3537 self._test_log('error')
3538
3539 def test_critical(self):
3540 self._test_log('critical')
3541
3542
3543class LoggerAdapterTest(unittest.TestCase):
3544
3545 def setUp(self):
3546 super(LoggerAdapterTest, self).setUp()
3547 old_handler_list = logging._handlerList[:]
3548
3549 self.recording = RecordingHandler()
3550 self.logger = logging.root
3551 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003552 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003553 self.addCleanup(self.recording.close)
3554
3555 def cleanup():
3556 logging._handlerList[:] = old_handler_list
3557
3558 self.addCleanup(cleanup)
3559 self.addCleanup(logging.shutdown)
3560 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3561
3562 def test_exception(self):
3563 msg = 'testing exception: %r'
3564 exc = None
3565 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003566 1 / 0
3567 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003568 exc = e
3569 self.adapter.exception(msg, self.recording)
3570
3571 self.assertEqual(len(self.recording.records), 1)
3572 record = self.recording.records[0]
3573 self.assertEqual(record.levelno, logging.ERROR)
3574 self.assertEqual(record.msg, msg)
3575 self.assertEqual(record.args, (self.recording,))
3576 self.assertEqual(record.exc_info,
3577 (exc.__class__, exc, exc.__traceback__))
3578
3579 def test_critical(self):
3580 msg = 'critical test! %r'
3581 self.adapter.critical(msg, self.recording)
3582
3583 self.assertEqual(len(self.recording.records), 1)
3584 record = self.recording.records[0]
3585 self.assertEqual(record.levelno, logging.CRITICAL)
3586 self.assertEqual(record.msg, msg)
3587 self.assertEqual(record.args, (self.recording,))
3588
3589 def test_is_enabled_for(self):
3590 old_disable = self.adapter.logger.manager.disable
3591 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003592 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3593 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003594 self.assertFalse(self.adapter.isEnabledFor(32))
3595
3596 def test_has_handlers(self):
3597 self.assertTrue(self.adapter.hasHandlers())
3598
3599 for handler in self.logger.handlers:
3600 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003601
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003602 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003603 self.assertFalse(self.adapter.hasHandlers())
3604
3605
3606class LoggerTest(BaseTest):
3607
3608 def setUp(self):
3609 super(LoggerTest, self).setUp()
3610 self.recording = RecordingHandler()
3611 self.logger = logging.Logger(name='blah')
3612 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003613 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003614 self.addCleanup(self.recording.close)
3615 self.addCleanup(logging.shutdown)
3616
3617 def test_set_invalid_level(self):
3618 self.assertRaises(TypeError, self.logger.setLevel, object())
3619
3620 def test_exception(self):
3621 msg = 'testing exception: %r'
3622 exc = None
3623 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003624 1 / 0
3625 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003626 exc = e
3627 self.logger.exception(msg, self.recording)
3628
3629 self.assertEqual(len(self.recording.records), 1)
3630 record = self.recording.records[0]
3631 self.assertEqual(record.levelno, logging.ERROR)
3632 self.assertEqual(record.msg, msg)
3633 self.assertEqual(record.args, (self.recording,))
3634 self.assertEqual(record.exc_info,
3635 (exc.__class__, exc, exc.__traceback__))
3636
3637 def test_log_invalid_level_with_raise(self):
3638 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003639 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003640
3641 logging.raiseExceptions = True
3642 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3643
3644 def test_log_invalid_level_no_raise(self):
3645 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003646 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003647
3648 logging.raiseExceptions = False
3649 self.logger.log('10', 'test message') # no exception happens
3650
3651 def test_find_caller_with_stack_info(self):
3652 called = []
3653 patch(self, logging.traceback, 'print_stack',
3654 lambda f, file: called.append(file.getvalue()))
3655
3656 self.logger.findCaller(stack_info=True)
3657
3658 self.assertEqual(len(called), 1)
3659 self.assertEqual('Stack (most recent call last):\n', called[0])
3660
3661 def test_make_record_with_extra_overwrite(self):
3662 name = 'my record'
3663 level = 13
3664 fn = lno = msg = args = exc_info = func = sinfo = None
3665 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3666 exc_info, func, sinfo)
3667
3668 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3669 extra = {key: 'some value'}
3670 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3671 fn, lno, msg, args, exc_info,
3672 extra=extra, sinfo=sinfo)
3673
3674 def test_make_record_with_extra_no_overwrite(self):
3675 name = 'my record'
3676 level = 13
3677 fn = lno = msg = args = exc_info = func = sinfo = None
3678 extra = {'valid_key': 'some value'}
3679 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3680 exc_info, extra=extra, sinfo=sinfo)
3681 self.assertIn('valid_key', result.__dict__)
3682
3683 def test_has_handlers(self):
3684 self.assertTrue(self.logger.hasHandlers())
3685
3686 for handler in self.logger.handlers:
3687 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003688 self.assertFalse(self.logger.hasHandlers())
3689
3690 def test_has_handlers_no_propagate(self):
3691 child_logger = logging.getLogger('blah.child')
3692 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003693 self.assertFalse(child_logger.hasHandlers())
3694
3695 def test_is_enabled_for(self):
3696 old_disable = self.logger.manager.disable
3697 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003698 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003699 self.assertFalse(self.logger.isEnabledFor(22))
3700
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003701 def test_root_logger_aliases(self):
3702 root = logging.getLogger()
3703 self.assertIs(root, logging.root)
3704 self.assertIs(root, logging.getLogger(None))
3705 self.assertIs(root, logging.getLogger(''))
3706 self.assertIs(root, logging.getLogger('foo').root)
3707 self.assertIs(root, logging.getLogger('foo.bar').root)
3708 self.assertIs(root, logging.getLogger('foo').parent)
3709
3710 self.assertIsNot(root, logging.getLogger('\0'))
3711 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3712
3713 def test_invalid_names(self):
3714 self.assertRaises(TypeError, logging.getLogger, any)
3715 self.assertRaises(TypeError, logging.getLogger, b'foo')
3716
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003717
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003718class BaseFileTest(BaseTest):
3719 "Base class for handler tests that write log files"
3720
3721 def setUp(self):
3722 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003723 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3724 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003725 self.rmfiles = []
3726
3727 def tearDown(self):
3728 for fn in self.rmfiles:
3729 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003730 if os.path.exists(self.fn):
3731 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003732 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003733
3734 def assertLogFile(self, filename):
3735 "Assert a log file is there and register it for deletion"
3736 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003737 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003738 self.rmfiles.append(filename)
3739
3740
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003741class FileHandlerTest(BaseFileTest):
3742 def test_delay(self):
3743 os.unlink(self.fn)
3744 fh = logging.FileHandler(self.fn, delay=True)
3745 self.assertIsNone(fh.stream)
3746 self.assertFalse(os.path.exists(self.fn))
3747 fh.handle(logging.makeLogRecord({}))
3748 self.assertIsNotNone(fh.stream)
3749 self.assertTrue(os.path.exists(self.fn))
3750 fh.close()
3751
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003752class RotatingFileHandlerTest(BaseFileTest):
3753 def next_rec(self):
3754 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3755 self.next_message(), None, None, None)
3756
3757 def test_should_not_rollover(self):
3758 # If maxbytes is zero rollover never occurs
3759 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3760 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003761 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003762
3763 def test_should_rollover(self):
3764 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3765 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003766 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003767
3768 def test_file_created(self):
3769 # checks that the file is created and assumes it was created
3770 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003771 rh = logging.handlers.RotatingFileHandler(self.fn)
3772 rh.emit(self.next_rec())
3773 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003774 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003775
3776 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003777 def namer(name):
3778 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003779 rh = logging.handlers.RotatingFileHandler(
3780 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003781 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003782 rh.emit(self.next_rec())
3783 self.assertLogFile(self.fn)
3784 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003785 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003786 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003787 self.assertLogFile(namer(self.fn + ".2"))
3788 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3789 rh.close()
3790
Eric V. Smith851cad72012-03-11 22:46:04 -07003791 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003792 def test_rotator(self):
3793 def namer(name):
3794 return name + ".gz"
3795
3796 def rotator(source, dest):
3797 with open(source, "rb") as sf:
3798 data = sf.read()
3799 compressed = zlib.compress(data, 9)
3800 with open(dest, "wb") as df:
3801 df.write(compressed)
3802 os.remove(source)
3803
3804 rh = logging.handlers.RotatingFileHandler(
3805 self.fn, backupCount=2, maxBytes=1)
3806 rh.rotator = rotator
3807 rh.namer = namer
3808 m1 = self.next_rec()
3809 rh.emit(m1)
3810 self.assertLogFile(self.fn)
3811 m2 = self.next_rec()
3812 rh.emit(m2)
3813 fn = namer(self.fn + ".1")
3814 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003815 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003816 with open(fn, "rb") as f:
3817 compressed = f.read()
3818 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003819 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003820 rh.emit(self.next_rec())
3821 fn = namer(self.fn + ".2")
3822 self.assertLogFile(fn)
3823 with open(fn, "rb") as f:
3824 compressed = f.read()
3825 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003826 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003827 rh.emit(self.next_rec())
3828 fn = namer(self.fn + ".2")
3829 with open(fn, "rb") as f:
3830 compressed = f.read()
3831 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003832 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003833 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003834 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003835
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003836class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003837 # other test methods added below
3838 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003839 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3840 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003841 fmt = logging.Formatter('%(asctime)s %(message)s')
3842 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003843 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003844 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003845 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003846 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003847 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003848 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003849 fh.close()
3850 # At this point, we should have a recent rotated file which we
3851 # can test for the existence of. However, in practice, on some
3852 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003853 # in time to go to look for the log file. So, we go back a fair
3854 # bit, and stop as soon as we see a rotated file. In theory this
3855 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003856 found = False
3857 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003858 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003859 for secs in range(GO_BACK):
3860 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003861 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3862 found = os.path.exists(fn)
3863 if found:
3864 self.rmfiles.append(fn)
3865 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003866 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3867 if not found:
3868 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003869 dn, fn = os.path.split(self.fn)
3870 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003871 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3872 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003873 for f in files:
3874 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003875 path = os.path.join(dn, f)
3876 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003877 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003878 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003879
Vinay Sajip0372e102011-05-05 12:59:14 +01003880 def test_invalid(self):
3881 assertRaises = self.assertRaises
3882 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003883 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003884 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003885 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003886 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003887 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003888
Vinay Sajipa7130792013-04-12 17:04:23 +01003889 def test_compute_rollover_daily_attime(self):
3890 currentTime = 0
3891 atTime = datetime.time(12, 0, 0)
3892 rh = logging.handlers.TimedRotatingFileHandler(
3893 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
3894 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01003895 try:
3896 actual = rh.computeRollover(currentTime)
3897 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01003898
Vinay Sajipd86ac962013-04-14 12:20:46 +01003899 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
3900 self.assertEqual(actual, currentTime + 36 * 60 * 60)
3901 finally:
3902 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01003903
Vinay Sajip10e8c492013-05-18 10:19:54 -07003904 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01003905 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01003906 currentTime = int(time.time())
3907 today = currentTime - currentTime % 86400
3908
Vinay Sajipa7130792013-04-12 17:04:23 +01003909 atTime = datetime.time(12, 0, 0)
3910
Vinay Sajip10e8c492013-05-18 10:19:54 -07003911 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01003912 for day in range(7):
3913 rh = logging.handlers.TimedRotatingFileHandler(
3914 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
3915 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01003916 try:
3917 if wday > day:
3918 # The rollover day has already passed this week, so we
3919 # go over into next week
3920 expected = (7 - wday + day)
3921 else:
3922 expected = (day - wday)
3923 # At this point expected is in days from now, convert to seconds
3924 expected *= 24 * 60 * 60
3925 # Add in the rollover time
3926 expected += 12 * 60 * 60
3927 # Add in adjustment for today
3928 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01003929 actual = rh.computeRollover(today)
3930 if actual != expected:
3931 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01003932 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01003933 self.assertEqual(actual, expected)
3934 if day == wday:
3935 # goes into following week
3936 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01003937 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01003938 if actual != expected:
3939 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01003940 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01003941 self.assertEqual(actual, expected)
3942 finally:
3943 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01003944
3945
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003946def secs(**kw):
3947 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3948
3949for when, exp in (('S', 1),
3950 ('M', 60),
3951 ('H', 60 * 60),
3952 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003953 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003954 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003955 ('W0', secs(days=4, hours=24)),
3956 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003957 def test_compute_rollover(self, when=when, exp=exp):
3958 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003959 self.fn, when=when, interval=1, backupCount=0, utc=True)
3960 currentTime = 0.0
3961 actual = rh.computeRollover(currentTime)
3962 if exp != actual:
3963 # Failures occur on some systems for MIDNIGHT and W0.
3964 # Print detailed calculation for MIDNIGHT so we can try to see
3965 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00003966 if when == 'MIDNIGHT':
3967 try:
3968 if rh.utc:
3969 t = time.gmtime(currentTime)
3970 else:
3971 t = time.localtime(currentTime)
3972 currentHour = t[3]
3973 currentMinute = t[4]
3974 currentSecond = t[5]
3975 # r is the number of seconds left between now and midnight
3976 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3977 currentMinute) * 60 +
3978 currentSecond)
3979 result = currentTime + r
3980 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3981 print('currentHour: %s' % currentHour, file=sys.stderr)
3982 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3983 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3984 print('r: %s' % r, file=sys.stderr)
3985 print('result: %s' % result, file=sys.stderr)
3986 except Exception:
3987 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3988 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003989 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003990 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3991
Vinay Sajip60ccd822011-05-09 17:32:09 +01003992
3993@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
3994class NTEventLogHandlerTest(BaseTest):
3995 def test_basic(self):
3996 logtype = 'Application'
3997 elh = win32evtlog.OpenEventLog(None, logtype)
3998 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
3999 h = logging.handlers.NTEventLogHandler('test_logging')
4000 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4001 h.handle(r)
4002 h.close()
4003 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004004 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004005 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4006 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4007 found = False
4008 GO_BACK = 100
4009 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4010 for e in events:
4011 if e.SourceName != 'test_logging':
4012 continue
4013 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4014 if msg != 'Test Log Message\r\n':
4015 continue
4016 found = True
4017 break
4018 msg = 'Record not found in event log, went back %d records' % GO_BACK
4019 self.assertTrue(found, msg=msg)
4020
Christian Heimes180510d2008-03-03 19:15:45 +00004021# Set the locale to the platform-dependent default. I have no idea
4022# why the test does this, but in any case we save the current locale
4023# first and restore it at the end.
4024@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004025def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004026 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004027 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004028 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4029 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4030 ManagerTest, FormatterTest, BufferingFormatterTest,
4031 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4032 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4033 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4034 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004035 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004036 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00004037 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004038 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004039
Christian Heimes180510d2008-03-03 19:15:45 +00004040if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004041 test_main()