blob: fea2b00fe3937cc118e95c200887b00bb1b1e14a [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()
Christian Heimes180510d2008-03-03 19:15:45 +000097 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000098 self.logger_states = logger_states = {}
99 for name in saved_loggers:
100 logger_states[name] = getattr(saved_loggers[name],
101 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000102 finally:
103 logging._releaseLock()
104
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100105 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000106 self.logger1 = logging.getLogger("\xab\xd7\xbb")
107 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000108
Christian Heimes180510d2008-03-03 19:15:45 +0000109 self.root_logger = logging.getLogger("")
110 self.original_logging_level = self.root_logger.getEffectiveLevel()
111
112 self.stream = io.StringIO()
113 self.root_logger.setLevel(logging.DEBUG)
114 self.root_hdlr = logging.StreamHandler(self.stream)
115 self.root_formatter = logging.Formatter(self.log_format)
116 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000117 if self.logger1.hasHandlers():
118 hlist = self.logger1.handlers + self.root_logger.handlers
119 raise AssertionError('Unexpected handlers: %s' % hlist)
120 if self.logger2.hasHandlers():
121 hlist = self.logger2.handlers + self.root_logger.handlers
122 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000123 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000124 self.assertTrue(self.logger1.hasHandlers())
125 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000126
127 def tearDown(self):
128 """Remove our logging stream, and restore the original logging
129 level."""
130 self.stream.close()
131 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000132 while self.root_logger.handlers:
133 h = self.root_logger.handlers[0]
134 self.root_logger.removeHandler(h)
135 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000136 self.root_logger.setLevel(self.original_logging_level)
137 logging._acquireLock()
138 try:
139 logging._levelNames.clear()
140 logging._levelNames.update(self.saved_level_names)
141 logging._handlers.clear()
142 logging._handlers.update(self.saved_handlers)
143 logging._handlerList[:] = self.saved_handler_list
144 loggerDict = logging.getLogger().manager.loggerDict
145 loggerDict.clear()
146 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000147 logger_states = self.logger_states
148 for name in self.logger_states:
149 if logger_states[name] is not None:
150 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000151 finally:
152 logging._releaseLock()
153
Vinay Sajip4ded5512012-10-02 15:56:16 +0100154 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000155 """Match the collected log lines against the regular expression
156 self.expected_log_pat, and compare the extracted group values to
157 the expected_values list of tuples."""
158 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100159 pat = re.compile(pat or self.expected_log_pat)
Christian Heimes180510d2008-03-03 19:15:45 +0000160 try:
Vinay Sajip4ded5512012-10-02 15:56:16 +0100161 if hasattr(stream, 'reset'):
162 stream.reset()
163 elif hasattr(stream, 'seek'):
164 stream.seek(0)
Christian Heimes180510d2008-03-03 19:15:45 +0000165 actual_lines = stream.readlines()
166 except AttributeError:
167 # StringIO.StringIO lacks a reset() method.
168 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100169 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000170 for actual, expected in zip(actual_lines, expected_values):
171 match = pat.search(actual)
172 if not match:
173 self.fail("Log line does not match expected pattern:\n" +
174 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000175 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000176 s = stream.read()
177 if s:
178 self.fail("Remaining output at end of log stream:\n" + s)
179
180 def next_message(self):
181 """Generate a message consisting solely of an auto-incrementing
182 integer."""
183 self.message_num += 1
184 return "%d" % self.message_num
185
186
187class BuiltinLevelsTest(BaseTest):
188 """Test builtin levels and their inheritance."""
189
190 def test_flat(self):
191 #Logging levels in a flat logger namespace.
192 m = self.next_message
193
194 ERR = logging.getLogger("ERR")
195 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000196 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000197 INF.setLevel(logging.INFO)
198 DEB = logging.getLogger("DEB")
199 DEB.setLevel(logging.DEBUG)
200
201 # These should log.
202 ERR.log(logging.CRITICAL, m())
203 ERR.error(m())
204
205 INF.log(logging.CRITICAL, m())
206 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000208 INF.info(m())
209
210 DEB.log(logging.CRITICAL, m())
211 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100212 DEB.warning(m())
213 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000214 DEB.debug(m())
215
216 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100217 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000218 ERR.info(m())
219 ERR.debug(m())
220
221 INF.debug(m())
222
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000223 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000224 ('ERR', 'CRITICAL', '1'),
225 ('ERR', 'ERROR', '2'),
226 ('INF', 'CRITICAL', '3'),
227 ('INF', 'ERROR', '4'),
228 ('INF', 'WARNING', '5'),
229 ('INF', 'INFO', '6'),
230 ('DEB', 'CRITICAL', '7'),
231 ('DEB', 'ERROR', '8'),
232 ('DEB', 'WARNING', '9'),
233 ('DEB', 'INFO', '10'),
234 ('DEB', 'DEBUG', '11'),
235 ])
236
237 def test_nested_explicit(self):
238 # Logging levels in a nested namespace, all explicitly set.
239 m = self.next_message
240
241 INF = logging.getLogger("INF")
242 INF.setLevel(logging.INFO)
243 INF_ERR = logging.getLogger("INF.ERR")
244 INF_ERR.setLevel(logging.ERROR)
245
246 # These should log.
247 INF_ERR.log(logging.CRITICAL, m())
248 INF_ERR.error(m())
249
250 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100251 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000252 INF_ERR.info(m())
253 INF_ERR.debug(m())
254
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000255 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000256 ('INF.ERR', 'CRITICAL', '1'),
257 ('INF.ERR', 'ERROR', '2'),
258 ])
259
260 def test_nested_inherited(self):
261 #Logging levels in a nested namespace, inherited from parent loggers.
262 m = self.next_message
263
264 INF = logging.getLogger("INF")
265 INF.setLevel(logging.INFO)
266 INF_ERR = logging.getLogger("INF.ERR")
267 INF_ERR.setLevel(logging.ERROR)
268 INF_UNDEF = logging.getLogger("INF.UNDEF")
269 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
270 UNDEF = logging.getLogger("UNDEF")
271
272 # These should log.
273 INF_UNDEF.log(logging.CRITICAL, m())
274 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100275 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000276 INF_UNDEF.info(m())
277 INF_ERR_UNDEF.log(logging.CRITICAL, m())
278 INF_ERR_UNDEF.error(m())
279
280 # These should not log.
281 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100282 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000283 INF_ERR_UNDEF.info(m())
284 INF_ERR_UNDEF.debug(m())
285
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000286 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000287 ('INF.UNDEF', 'CRITICAL', '1'),
288 ('INF.UNDEF', 'ERROR', '2'),
289 ('INF.UNDEF', 'WARNING', '3'),
290 ('INF.UNDEF', 'INFO', '4'),
291 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
292 ('INF.ERR.UNDEF', 'ERROR', '6'),
293 ])
294
295 def test_nested_with_virtual_parent(self):
296 # Logging levels when some parent does not exist yet.
297 m = self.next_message
298
299 INF = logging.getLogger("INF")
300 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
301 CHILD = logging.getLogger("INF.BADPARENT")
302 INF.setLevel(logging.INFO)
303
304 # These should log.
305 GRANDCHILD.log(logging.FATAL, m())
306 GRANDCHILD.info(m())
307 CHILD.log(logging.FATAL, m())
308 CHILD.info(m())
309
310 # These should not log.
311 GRANDCHILD.debug(m())
312 CHILD.debug(m())
313
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000314 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000315 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
316 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
317 ('INF.BADPARENT', 'CRITICAL', '3'),
318 ('INF.BADPARENT', 'INFO', '4'),
319 ])
320
321
322class BasicFilterTest(BaseTest):
323
324 """Test the bundled Filter class."""
325
326 def test_filter(self):
327 # Only messages satisfying the specified criteria pass through the
328 # filter.
329 filter_ = logging.Filter("spam.eggs")
330 handler = self.root_logger.handlers[0]
331 try:
332 handler.addFilter(filter_)
333 spam = logging.getLogger("spam")
334 spam_eggs = logging.getLogger("spam.eggs")
335 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
336 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
337
338 spam.info(self.next_message())
339 spam_eggs.info(self.next_message()) # Good.
340 spam_eggs_fish.info(self.next_message()) # Good.
341 spam_bakedbeans.info(self.next_message())
342
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000343 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000344 ('spam.eggs', 'INFO', '2'),
345 ('spam.eggs.fish', 'INFO', '3'),
346 ])
347 finally:
348 handler.removeFilter(filter_)
349
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000350 def test_callable_filter(self):
351 # Only messages satisfying the specified criteria pass through the
352 # filter.
353
354 def filterfunc(record):
355 parts = record.name.split('.')
356 prefix = '.'.join(parts[:2])
357 return prefix == 'spam.eggs'
358
359 handler = self.root_logger.handlers[0]
360 try:
361 handler.addFilter(filterfunc)
362 spam = logging.getLogger("spam")
363 spam_eggs = logging.getLogger("spam.eggs")
364 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
365 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
366
367 spam.info(self.next_message())
368 spam_eggs.info(self.next_message()) # Good.
369 spam_eggs_fish.info(self.next_message()) # Good.
370 spam_bakedbeans.info(self.next_message())
371
372 self.assert_log_lines([
373 ('spam.eggs', 'INFO', '2'),
374 ('spam.eggs.fish', 'INFO', '3'),
375 ])
376 finally:
377 handler.removeFilter(filterfunc)
378
Vinay Sajip985ef872011-04-26 19:34:04 +0100379 def test_empty_filter(self):
380 f = logging.Filter()
381 r = logging.makeLogRecord({'name': 'spam.eggs'})
382 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000383
384#
385# First, we define our levels. There can be as many as you want - the only
386# limitations are that they should be integers, the lowest should be > 0 and
387# larger values mean less information being logged. If you need specific
388# level values which do not fit into these limitations, you can use a
389# mapping dictionary to convert between your application levels and the
390# logging system.
391#
392SILENT = 120
393TACITURN = 119
394TERSE = 118
395EFFUSIVE = 117
396SOCIABLE = 116
397VERBOSE = 115
398TALKATIVE = 114
399GARRULOUS = 113
400CHATTERBOX = 112
401BORING = 111
402
403LEVEL_RANGE = range(BORING, SILENT + 1)
404
405#
406# Next, we define names for our levels. You don't need to do this - in which
407# case the system will use "Level n" to denote the text for the level.
408#
409my_logging_levels = {
410 SILENT : 'Silent',
411 TACITURN : 'Taciturn',
412 TERSE : 'Terse',
413 EFFUSIVE : 'Effusive',
414 SOCIABLE : 'Sociable',
415 VERBOSE : 'Verbose',
416 TALKATIVE : 'Talkative',
417 GARRULOUS : 'Garrulous',
418 CHATTERBOX : 'Chatterbox',
419 BORING : 'Boring',
420}
421
422class GarrulousFilter(logging.Filter):
423
424 """A filter which blocks garrulous messages."""
425
426 def filter(self, record):
427 return record.levelno != GARRULOUS
428
429class VerySpecificFilter(logging.Filter):
430
431 """A filter which blocks sociable and taciturn messages."""
432
433 def filter(self, record):
434 return record.levelno not in [SOCIABLE, TACITURN]
435
436
437class CustomLevelsAndFiltersTest(BaseTest):
438
439 """Test various filtering possibilities with custom logging levels."""
440
441 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300442 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000443
444 def setUp(self):
445 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000446 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000447 logging.addLevelName(k, v)
448
449 def log_at_all_levels(self, logger):
450 for lvl in LEVEL_RANGE:
451 logger.log(lvl, self.next_message())
452
453 def test_logger_filter(self):
454 # Filter at logger level.
455 self.root_logger.setLevel(VERBOSE)
456 # Levels >= 'Verbose' are good.
457 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000458 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000459 ('Verbose', '5'),
460 ('Sociable', '6'),
461 ('Effusive', '7'),
462 ('Terse', '8'),
463 ('Taciturn', '9'),
464 ('Silent', '10'),
465 ])
466
467 def test_handler_filter(self):
468 # Filter at handler level.
469 self.root_logger.handlers[0].setLevel(SOCIABLE)
470 try:
471 # Levels >= 'Sociable' are good.
472 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000473 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000474 ('Sociable', '6'),
475 ('Effusive', '7'),
476 ('Terse', '8'),
477 ('Taciturn', '9'),
478 ('Silent', '10'),
479 ])
480 finally:
481 self.root_logger.handlers[0].setLevel(logging.NOTSET)
482
483 def test_specific_filters(self):
484 # Set a specific filter object on the handler, and then add another
485 # filter object on the logger itself.
486 handler = self.root_logger.handlers[0]
487 specific_filter = None
488 garr = GarrulousFilter()
489 handler.addFilter(garr)
490 try:
491 self.log_at_all_levels(self.root_logger)
492 first_lines = [
493 # Notice how 'Garrulous' is missing
494 ('Boring', '1'),
495 ('Chatterbox', '2'),
496 ('Talkative', '4'),
497 ('Verbose', '5'),
498 ('Sociable', '6'),
499 ('Effusive', '7'),
500 ('Terse', '8'),
501 ('Taciturn', '9'),
502 ('Silent', '10'),
503 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000504 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000505
506 specific_filter = VerySpecificFilter()
507 self.root_logger.addFilter(specific_filter)
508 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000509 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000510 # Not only 'Garrulous' is still missing, but also 'Sociable'
511 # and 'Taciturn'
512 ('Boring', '11'),
513 ('Chatterbox', '12'),
514 ('Talkative', '14'),
515 ('Verbose', '15'),
516 ('Effusive', '17'),
517 ('Terse', '18'),
518 ('Silent', '20'),
519 ])
520 finally:
521 if specific_filter:
522 self.root_logger.removeFilter(specific_filter)
523 handler.removeFilter(garr)
524
525
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100526class HandlerTest(BaseTest):
527 def test_name(self):
528 h = logging.Handler()
529 h.name = 'generic'
530 self.assertEqual(h.name, 'generic')
531 h.name = 'anothergeneric'
532 self.assertEqual(h.name, 'anothergeneric')
533 self.assertRaises(NotImplementedError, h.emit, None)
534
Vinay Sajip5a35b062011-04-27 11:31:14 +0100535 def test_builtin_handlers(self):
536 # We can't actually *use* too many handlers in the tests,
537 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200538 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100539 for existing in (True, False):
540 fd, fn = tempfile.mkstemp()
541 os.close(fd)
542 if not existing:
543 os.unlink(fn)
544 h = logging.handlers.WatchedFileHandler(fn, delay=True)
545 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100546 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100547 self.assertEqual(dev, -1)
548 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100549 r = logging.makeLogRecord({'msg': 'Test'})
550 h.handle(r)
551 # Now remove the file.
552 os.unlink(fn)
553 self.assertFalse(os.path.exists(fn))
554 # The next call should recreate the file.
555 h.handle(r)
556 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100557 else:
558 self.assertEqual(h.dev, -1)
559 self.assertEqual(h.ino, -1)
560 h.close()
561 if existing:
562 os.unlink(fn)
563 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100564 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100565 else:
566 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100567 try:
568 h = logging.handlers.SysLogHandler(sockname)
569 self.assertEqual(h.facility, h.LOG_USER)
570 self.assertTrue(h.unixsocket)
571 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200572 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100573 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100574 for method in ('GET', 'POST', 'PUT'):
575 if method == 'PUT':
576 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
577 'localhost', '/log', method)
578 else:
579 h = logging.handlers.HTTPHandler('localhost', '/log', method)
580 h.close()
581 h = logging.handlers.BufferingHandler(0)
582 r = logging.makeLogRecord({})
583 self.assertTrue(h.shouldFlush(r))
584 h.close()
585 h = logging.handlers.BufferingHandler(1)
586 self.assertFalse(h.shouldFlush(r))
587 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100588
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100589 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100590 @unittest.skipUnless(threading, 'Threading required for this test.')
591 def test_race(self):
592 # Issue #14632 refers.
593 def remove_loop(fname, tries):
594 for _ in range(tries):
595 try:
596 os.unlink(fname)
597 except OSError:
598 pass
599 time.sleep(0.004 * random.randint(0, 4))
600
Vinay Sajipc94871a2012-04-25 10:51:35 +0100601 del_count = 500
602 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603
Vinay Sajipa5798de2012-04-24 23:33:33 +0100604 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100605 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
606 os.close(fd)
607 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
608 remover.daemon = True
609 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100610 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100611 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
612 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100613 try:
614 for _ in range(log_count):
615 time.sleep(0.005)
616 r = logging.makeLogRecord({'msg': 'testing' })
617 h.handle(r)
618 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100619 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100620 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100621 if os.path.exists(fn):
622 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623
624
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100625class BadStream(object):
626 def write(self, data):
627 raise RuntimeError('deliberate mistake')
628
629class TestStreamHandler(logging.StreamHandler):
630 def handleError(self, record):
631 self.error_record = record
632
633class StreamHandlerTest(BaseTest):
634 def test_error_handling(self):
635 h = TestStreamHandler(BadStream())
636 r = logging.makeLogRecord({})
637 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100638 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100639 try:
640 h.handle(r)
641 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100642 h = logging.StreamHandler(BadStream())
643 sys.stderr = sio = io.StringIO()
644 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100645 self.assertIn('\nRuntimeError: deliberate mistake\n',
646 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100647 logging.raiseExceptions = False
648 sys.stderr = sio = io.StringIO()
649 h.handle(r)
650 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100651 finally:
652 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100653 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100654
Vinay Sajip7367d082011-05-02 13:17:27 +0100655# -- The following section could be moved into a server_helper.py module
656# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100657
Vinay Sajipce7c9782011-05-17 07:15:53 +0100658if threading:
659 class TestSMTPChannel(smtpd.SMTPChannel):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100660 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100661 This derived class has had to be created because smtpd does not
662 support use of custom channel maps, although they are allowed by
663 asyncore's design. Issue #11959 has been raised to address this,
664 and if resolved satisfactorily, some of this code can be removed.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100665 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100666 def __init__(self, server, conn, addr, sockmap):
667 asynchat.async_chat.__init__(self, conn, sockmap)
668 self.smtp_server = server
669 self.conn = conn
670 self.addr = addr
R David Murrayd1a30c92012-05-26 14:33:59 -0400671 self.data_size_limit = None
Vinay Sajipce7c9782011-05-17 07:15:53 +0100672 self.received_lines = []
673 self.smtp_state = self.COMMAND
674 self.seen_greeting = ''
675 self.mailfrom = None
676 self.rcpttos = []
677 self.received_data = ''
678 self.fqdn = socket.getfqdn()
679 self.num_bytes = 0
680 try:
681 self.peer = conn.getpeername()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200682 except OSError as err:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100683 # a race condition may occur if the other end is closing
684 # before we can get the peername
685 self.close()
686 if err.args[0] != errno.ENOTCONN:
687 raise
688 return
689 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
690 self.set_terminator(b'\r\n')
R David Murrayd1a30c92012-05-26 14:33:59 -0400691 self.extended_smtp = False
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajip314b92b2011-05-02 14:31:16 +0100693
Vinay Sajipce7c9782011-05-17 07:15:53 +0100694 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100695 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100696 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100697
Vinay Sajipce7c9782011-05-17 07:15:53 +0100698 :param addr: A (host, port) tuple which the server listens on.
699 You can specify a port value of zero: the server's
700 *port* attribute will hold the actual port number
701 used, which can be used in client connections.
702 :param handler: A callable which will be called to process
703 incoming messages. The handler will be passed
704 the client address tuple, who the message is from,
705 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100706 :param poll_interval: The interval, in seconds, used in the underlying
707 :func:`select` or :func:`poll` call by
708 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100709 :param sockmap: A dictionary which will be used to hold
710 :class:`asyncore.dispatcher` instances used by
711 :func:`asyncore.loop`. This avoids changing the
712 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100713 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100714 channel_class = TestSMTPChannel
715
716 def __init__(self, addr, handler, poll_interval, sockmap):
717 self._localaddr = addr
718 self._remoteaddr = None
R David Murrayd1a30c92012-05-26 14:33:59 -0400719 self.data_size_limit = None
Vinay Sajipce7c9782011-05-17 07:15:53 +0100720 self.sockmap = sockmap
721 asyncore.dispatcher.__init__(self, map=sockmap)
722 try:
723 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
724 sock.setblocking(0)
725 self.set_socket(sock, map=sockmap)
726 # try to re-use a server port if possible
727 self.set_reuse_addr()
728 self.bind(addr)
729 self.port = sock.getsockname()[1]
730 self.listen(5)
731 except:
732 self.close()
Vinay Sajipe73afad2011-05-10 07:48:28 +0100733 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100734 self._handler = handler
735 self._thread = None
736 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100737
Vinay Sajipce7c9782011-05-17 07:15:53 +0100738 def handle_accepted(self, conn, addr):
739 """
740 Redefined only because the base class does not pass in a
741 map, forcing use of a global in :mod:`asyncore`.
742 """
743 channel = self.channel_class(self, conn, addr, self.sockmap)
Vinay Sajip314b92b2011-05-02 14:31:16 +0100744
Vinay Sajipce7c9782011-05-17 07:15:53 +0100745 def process_message(self, peer, mailfrom, rcpttos, data):
746 """
747 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100748
Vinay Sajipce7c9782011-05-17 07:15:53 +0100749 Typically, this will be a test case method.
750 :param peer: The client (host, port) tuple.
751 :param mailfrom: The address of the sender.
752 :param rcpttos: The addresses of the recipients.
753 :param data: The message.
754 """
755 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100756
Vinay Sajipce7c9782011-05-17 07:15:53 +0100757 def start(self):
758 """
759 Start the server running on a separate daemon thread.
760 """
761 self._thread = t = threading.Thread(target=self.serve_forever,
762 args=(self.poll_interval,))
763 t.setDaemon(True)
764 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100765
Vinay Sajipce7c9782011-05-17 07:15:53 +0100766 def serve_forever(self, poll_interval):
767 """
768 Run the :mod:`asyncore` loop until normal termination
769 conditions arise.
770 :param poll_interval: The interval, in seconds, used in the underlying
771 :func:`select` or :func:`poll` call by
772 :func:`asyncore.loop`.
773 """
774 try:
775 asyncore.loop(poll_interval, map=self.sockmap)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200776 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100777 # On FreeBSD 8, closing the server repeatably
778 # raises this error. We swallow it if the
779 # server has been closed.
780 if self.connected or self.accepting:
781 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100782
Vinay Sajipce7c9782011-05-17 07:15:53 +0100783 def stop(self, timeout=None):
784 """
785 Stop the thread by closing the server instance.
786 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100787
Vinay Sajipce7c9782011-05-17 07:15:53 +0100788 :param timeout: How long to wait for the server thread
789 to terminate.
790 """
791 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100792 self._thread.join(timeout)
793 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100794
Vinay Sajipce7c9782011-05-17 07:15:53 +0100795 class ControlMixin(object):
796 """
797 This mixin is used to start a server on a separate thread, and
798 shut it down programmatically. Request handling is simplified - instead
799 of needing to derive a suitable RequestHandler subclass, you just
800 provide a callable which will be passed each received request to be
801 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100802
Vinay Sajipce7c9782011-05-17 07:15:53 +0100803 :param handler: A handler callable which will be called with a
804 single parameter - the request - in order to
805 process the request. This handler is called on the
806 server thread, effectively meaning that requests are
807 processed serially. While not quite Web scale ;-),
808 this should be fine for testing applications.
809 :param poll_interval: The polling interval in seconds.
810 """
811 def __init__(self, handler, poll_interval):
812 self._thread = None
813 self.poll_interval = poll_interval
814 self._handler = handler
815 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100816
Vinay Sajipce7c9782011-05-17 07:15:53 +0100817 def start(self):
818 """
819 Create a daemon thread to run the server, and start it.
820 """
821 self._thread = t = threading.Thread(target=self.serve_forever,
822 args=(self.poll_interval,))
823 t.setDaemon(True)
824 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100825
Vinay Sajipce7c9782011-05-17 07:15:53 +0100826 def serve_forever(self, poll_interval):
827 """
828 Run the server. Set the ready flag before entering the
829 service loop.
830 """
831 self.ready.set()
832 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100833
Vinay Sajipce7c9782011-05-17 07:15:53 +0100834 def stop(self, timeout=None):
835 """
836 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100837
Vinay Sajipce7c9782011-05-17 07:15:53 +0100838 :param timeout: How long to wait for the server thread
839 to terminate.
840 """
841 self.shutdown()
842 if self._thread is not None:
843 self._thread.join(timeout)
844 self._thread = None
845 self.server_close()
846 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 class TestHTTPServer(ControlMixin, HTTPServer):
849 """
850 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Vinay Sajipce7c9782011-05-17 07:15:53 +0100852 :param addr: A tuple with the IP address and port to listen on.
853 :param handler: A handler callable which will be called with a
854 single parameter - the request - in order to
855 process the request.
856 :param poll_interval: The polling interval in seconds.
857 :param log: Pass ``True`` to enable log messages.
858 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100859 def __init__(self, addr, handler, poll_interval=0.5,
860 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
862 def __getattr__(self, name, default=None):
863 if name.startswith('do_'):
864 return self.process_request
865 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100866
Vinay Sajipce7c9782011-05-17 07:15:53 +0100867 def process_request(self):
868 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100869
Vinay Sajipce7c9782011-05-17 07:15:53 +0100870 def log_message(self, format, *args):
871 if log:
872 super(DelegatingHTTPRequestHandler,
873 self).log_message(format, *args)
874 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
875 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100876 self.sslctx = sslctx
877
878 def get_request(self):
879 try:
880 sock, addr = self.socket.accept()
881 if self.sslctx:
882 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200883 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100884 # socket errors are silenced by the caller, print them here
885 sys.stderr.write("Got an error:\n%s\n" % e)
886 raise
887 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100888
Vinay Sajipce7c9782011-05-17 07:15:53 +0100889 class TestTCPServer(ControlMixin, ThreadingTCPServer):
890 """
891 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100892
Vinay Sajipce7c9782011-05-17 07:15:53 +0100893 :param addr: A tuple with the IP address and port to listen on.
894 :param handler: A handler callable which will be called with a single
895 parameter - the request - in order to process the request.
896 :param poll_interval: The polling interval in seconds.
897 :bind_and_activate: If True (the default), binds the server and starts it
898 listening. If False, you need to call
899 :meth:`server_bind` and :meth:`server_activate` at
900 some later time before calling :meth:`start`, so that
901 the server will set up the socket and listen on it.
902 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100903
Vinay Sajipce7c9782011-05-17 07:15:53 +0100904 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100905
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906 def __init__(self, addr, handler, poll_interval=0.5,
907 bind_and_activate=True):
908 class DelegatingTCPRequestHandler(StreamRequestHandler):
909
910 def handle(self):
911 self.server._handler(self)
912 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
913 bind_and_activate)
914 ControlMixin.__init__(self, handler, poll_interval)
915
916 def server_bind(self):
917 super(TestTCPServer, self).server_bind()
918 self.port = self.socket.getsockname()[1]
919
920 class TestUDPServer(ControlMixin, ThreadingUDPServer):
921 """
922 A UDP server which is controllable using :class:`ControlMixin`.
923
924 :param addr: A tuple with the IP address and port to listen on.
925 :param handler: A handler callable which will be called with a
926 single parameter - the request - in order to
927 process the request.
928 :param poll_interval: The polling interval for shutdown requests,
929 in seconds.
930 :bind_and_activate: If True (the default), binds the server and
931 starts it listening. If False, you need to
932 call :meth:`server_bind` and
933 :meth:`server_activate` at some later time
934 before calling :meth:`start`, so that the server will
935 set up the socket and listen on it.
936 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100937 def __init__(self, addr, handler, poll_interval=0.5,
938 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100939 class DelegatingUDPRequestHandler(DatagramRequestHandler):
940
941 def handle(self):
942 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100943
944 def finish(self):
945 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100946 if data:
947 try:
948 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200949 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100950 if not self.server._closed:
951 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100952
Vinay Sajip3ef12292011-05-23 23:00:42 +0100953 ThreadingUDPServer.__init__(self, addr,
954 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100955 bind_and_activate)
956 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100957 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100958
959 def server_bind(self):
960 super(TestUDPServer, self).server_bind()
961 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100962
Vinay Sajipba980db2011-05-23 21:37:54 +0100963 def server_close(self):
964 super(TestUDPServer, self).server_close()
965 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100966
967# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100968
Vinay Sajipce7c9782011-05-17 07:15:53 +0100969@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100970class SMTPHandlerTest(BaseTest):
971 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100972 sockmap = {}
973 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
974 sockmap)
975 server.start()
976 addr = ('localhost', server.port)
Vinay Sajip4c3f4782012-04-22 18:19:50 +0100977 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
Vinay Sajipa463d252011-04-30 21:52:48 +0100978 self.assertEqual(h.toaddrs, ['you'])
979 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100980 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100981 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100982 h.handle(r)
Vinay Sajip17160fd2012-03-15 12:02:08 +0000983 self.handled.wait(5.0) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100984 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000985 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100986 self.assertEqual(len(self.messages), 1)
987 peer, mailfrom, rcpttos, data = self.messages[0]
988 self.assertEqual(mailfrom, 'me')
989 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100990 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100991 self.assertTrue(data.endswith('\n\nHello'))
992 h.close()
993
994 def process_message(self, *args):
995 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100996 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100997
Christian Heimes180510d2008-03-03 19:15:45 +0000998class MemoryHandlerTest(BaseTest):
999
1000 """Tests for the MemoryHandler."""
1001
1002 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001003 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001004
1005 def setUp(self):
1006 BaseTest.setUp(self)
1007 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1008 self.root_hdlr)
1009 self.mem_logger = logging.getLogger('mem')
1010 self.mem_logger.propagate = 0
1011 self.mem_logger.addHandler(self.mem_hdlr)
1012
1013 def tearDown(self):
1014 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001015 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001016
1017 def test_flush(self):
1018 # The memory handler flushes to its target handler based on specific
1019 # criteria (message count and message level).
1020 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001021 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001022 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001023 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001024 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001025 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001026 lines = [
1027 ('DEBUG', '1'),
1028 ('INFO', '2'),
1029 ('WARNING', '3'),
1030 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001031 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001032 for n in (4, 14):
1033 for i in range(9):
1034 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001035 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001036 # This will flush because it's the 10th message since the last
1037 # flush.
1038 self.mem_logger.debug(self.next_message())
1039 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001040 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001041
1042 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001043 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001044
1045
1046class ExceptionFormatter(logging.Formatter):
1047 """A special exception formatter."""
1048 def formatException(self, ei):
1049 return "Got a [%s]" % ei[0].__name__
1050
1051
1052class ConfigFileTest(BaseTest):
1053
1054 """Reading logging config from a .ini-style config file."""
1055
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001056 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001057
1058 # config0 is a standard configuration.
1059 config0 = """
1060 [loggers]
1061 keys=root
1062
1063 [handlers]
1064 keys=hand1
1065
1066 [formatters]
1067 keys=form1
1068
1069 [logger_root]
1070 level=WARNING
1071 handlers=hand1
1072
1073 [handler_hand1]
1074 class=StreamHandler
1075 level=NOTSET
1076 formatter=form1
1077 args=(sys.stdout,)
1078
1079 [formatter_form1]
1080 format=%(levelname)s ++ %(message)s
1081 datefmt=
1082 """
1083
1084 # config1 adds a little to the standard configuration.
1085 config1 = """
1086 [loggers]
1087 keys=root,parser
1088
1089 [handlers]
1090 keys=hand1
1091
1092 [formatters]
1093 keys=form1
1094
1095 [logger_root]
1096 level=WARNING
1097 handlers=
1098
1099 [logger_parser]
1100 level=DEBUG
1101 handlers=hand1
1102 propagate=1
1103 qualname=compiler.parser
1104
1105 [handler_hand1]
1106 class=StreamHandler
1107 level=NOTSET
1108 formatter=form1
1109 args=(sys.stdout,)
1110
1111 [formatter_form1]
1112 format=%(levelname)s ++ %(message)s
1113 datefmt=
1114 """
1115
Vinay Sajip3f84b072011-03-07 17:49:33 +00001116 # config1a moves the handler to the root.
1117 config1a = """
1118 [loggers]
1119 keys=root,parser
1120
1121 [handlers]
1122 keys=hand1
1123
1124 [formatters]
1125 keys=form1
1126
1127 [logger_root]
1128 level=WARNING
1129 handlers=hand1
1130
1131 [logger_parser]
1132 level=DEBUG
1133 handlers=
1134 propagate=1
1135 qualname=compiler.parser
1136
1137 [handler_hand1]
1138 class=StreamHandler
1139 level=NOTSET
1140 formatter=form1
1141 args=(sys.stdout,)
1142
1143 [formatter_form1]
1144 format=%(levelname)s ++ %(message)s
1145 datefmt=
1146 """
1147
Christian Heimes180510d2008-03-03 19:15:45 +00001148 # config2 has a subtle configuration error that should be reported
1149 config2 = config1.replace("sys.stdout", "sys.stbout")
1150
1151 # config3 has a less subtle configuration error
1152 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1153
1154 # config4 specifies a custom formatter class to be loaded
1155 config4 = """
1156 [loggers]
1157 keys=root
1158
1159 [handlers]
1160 keys=hand1
1161
1162 [formatters]
1163 keys=form1
1164
1165 [logger_root]
1166 level=NOTSET
1167 handlers=hand1
1168
1169 [handler_hand1]
1170 class=StreamHandler
1171 level=NOTSET
1172 formatter=form1
1173 args=(sys.stdout,)
1174
1175 [formatter_form1]
1176 class=""" + __name__ + """.ExceptionFormatter
1177 format=%(levelname)s:%(name)s:%(message)s
1178 datefmt=
1179 """
1180
Georg Brandl3dbca812008-07-23 16:10:53 +00001181 # config5 specifies a custom handler class to be loaded
1182 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1183
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001184 # config6 uses ', ' delimiters in the handlers and formatters sections
1185 config6 = """
1186 [loggers]
1187 keys=root,parser
1188
1189 [handlers]
1190 keys=hand1, hand2
1191
1192 [formatters]
1193 keys=form1, form2
1194
1195 [logger_root]
1196 level=WARNING
1197 handlers=
1198
1199 [logger_parser]
1200 level=DEBUG
1201 handlers=hand1
1202 propagate=1
1203 qualname=compiler.parser
1204
1205 [handler_hand1]
1206 class=StreamHandler
1207 level=NOTSET
1208 formatter=form1
1209 args=(sys.stdout,)
1210
1211 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001212 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001213 level=NOTSET
1214 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001215 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001216
1217 [formatter_form1]
1218 format=%(levelname)s ++ %(message)s
1219 datefmt=
1220
1221 [formatter_form2]
1222 format=%(message)s
1223 datefmt=
1224 """
1225
Vinay Sajip3f84b072011-03-07 17:49:33 +00001226 # config7 adds a compiler logger.
1227 config7 = """
1228 [loggers]
1229 keys=root,parser,compiler
1230
1231 [handlers]
1232 keys=hand1
1233
1234 [formatters]
1235 keys=form1
1236
1237 [logger_root]
1238 level=WARNING
1239 handlers=hand1
1240
1241 [logger_compiler]
1242 level=DEBUG
1243 handlers=
1244 propagate=1
1245 qualname=compiler
1246
1247 [logger_parser]
1248 level=DEBUG
1249 handlers=
1250 propagate=1
1251 qualname=compiler.parser
1252
1253 [handler_hand1]
1254 class=StreamHandler
1255 level=NOTSET
1256 formatter=form1
1257 args=(sys.stdout,)
1258
1259 [formatter_form1]
1260 format=%(levelname)s ++ %(message)s
1261 datefmt=
1262 """
1263
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001264 disable_test = """
1265 [loggers]
1266 keys=root
1267
1268 [handlers]
1269 keys=screen
1270
1271 [formatters]
1272 keys=
1273
1274 [logger_root]
1275 level=DEBUG
1276 handlers=screen
1277
1278 [handler_screen]
1279 level=DEBUG
1280 class=StreamHandler
1281 args=(sys.stdout,)
1282 formatter=
1283 """
1284
1285 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001286 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001287 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001288
1289 def test_config0_ok(self):
1290 # A simple config file which overrides the default settings.
1291 with captured_stdout() as output:
1292 self.apply_config(self.config0)
1293 logger = logging.getLogger()
1294 # Won't output anything
1295 logger.info(self.next_message())
1296 # Outputs a message
1297 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001298 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001299 ('ERROR', '2'),
1300 ], stream=output)
1301 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001302 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001303
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001304 def test_config0_using_cp_ok(self):
1305 # A simple config file which overrides the default settings.
1306 with captured_stdout() as output:
1307 file = io.StringIO(textwrap.dedent(self.config0))
1308 cp = configparser.ConfigParser()
1309 cp.read_file(file)
1310 logging.config.fileConfig(cp)
1311 logger = logging.getLogger()
1312 # Won't output anything
1313 logger.info(self.next_message())
1314 # Outputs a message
1315 logger.error(self.next_message())
1316 self.assert_log_lines([
1317 ('ERROR', '2'),
1318 ], stream=output)
1319 # Original logger output is empty.
1320 self.assert_log_lines([])
1321
Georg Brandl3dbca812008-07-23 16:10:53 +00001322 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001323 # A config file defining a sub-parser as well.
1324 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001325 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001326 logger = logging.getLogger("compiler.parser")
1327 # Both will output a message
1328 logger.info(self.next_message())
1329 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001330 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001331 ('INFO', '1'),
1332 ('ERROR', '2'),
1333 ], stream=output)
1334 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001335 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001336
1337 def test_config2_failure(self):
1338 # A simple config file which overrides the default settings.
1339 self.assertRaises(Exception, self.apply_config, self.config2)
1340
1341 def test_config3_failure(self):
1342 # A simple config file which overrides the default settings.
1343 self.assertRaises(Exception, self.apply_config, self.config3)
1344
1345 def test_config4_ok(self):
1346 # A config file specifying a custom formatter class.
1347 with captured_stdout() as output:
1348 self.apply_config(self.config4)
1349 logger = logging.getLogger()
1350 try:
1351 raise RuntimeError()
1352 except RuntimeError:
1353 logging.exception("just testing")
1354 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001355 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001356 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1357 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001358 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001359
Georg Brandl3dbca812008-07-23 16:10:53 +00001360 def test_config5_ok(self):
1361 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001362
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001363 def test_config6_ok(self):
1364 self.test_config1_ok(config=self.config6)
1365
Vinay Sajip3f84b072011-03-07 17:49:33 +00001366 def test_config7_ok(self):
1367 with captured_stdout() as output:
1368 self.apply_config(self.config1a)
1369 logger = logging.getLogger("compiler.parser")
1370 # See issue #11424. compiler-hyphenated sorts
1371 # between compiler and compiler.xyz and this
1372 # was preventing compiler.xyz from being included
1373 # in the child loggers of compiler because of an
1374 # overzealous loop termination condition.
1375 hyphenated = logging.getLogger('compiler-hyphenated')
1376 # All will output a message
1377 logger.info(self.next_message())
1378 logger.error(self.next_message())
1379 hyphenated.critical(self.next_message())
1380 self.assert_log_lines([
1381 ('INFO', '1'),
1382 ('ERROR', '2'),
1383 ('CRITICAL', '3'),
1384 ], stream=output)
1385 # Original logger output is empty.
1386 self.assert_log_lines([])
1387 with captured_stdout() as output:
1388 self.apply_config(self.config7)
1389 logger = logging.getLogger("compiler.parser")
1390 self.assertFalse(logger.disabled)
1391 # Both will output a message
1392 logger.info(self.next_message())
1393 logger.error(self.next_message())
1394 logger = logging.getLogger("compiler.lexer")
1395 # Both will output a message
1396 logger.info(self.next_message())
1397 logger.error(self.next_message())
1398 # Will not appear
1399 hyphenated.critical(self.next_message())
1400 self.assert_log_lines([
1401 ('INFO', '4'),
1402 ('ERROR', '5'),
1403 ('INFO', '6'),
1404 ('ERROR', '7'),
1405 ], stream=output)
1406 # Original logger output is empty.
1407 self.assert_log_lines([])
1408
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001409 def test_logger_disabling(self):
1410 self.apply_config(self.disable_test)
1411 logger = logging.getLogger('foo')
1412 self.assertFalse(logger.disabled)
1413 self.apply_config(self.disable_test)
1414 self.assertTrue(logger.disabled)
1415 self.apply_config(self.disable_test, disable_existing_loggers=False)
1416 self.assertFalse(logger.disabled)
1417
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001418
Victor Stinner45df8202010-04-28 22:31:17 +00001419@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001420class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001421
Christian Heimes180510d2008-03-03 19:15:45 +00001422 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001423
Christian Heimes180510d2008-03-03 19:15:45 +00001424 def setUp(self):
1425 """Set up a TCP server to receive log messages, and a SocketHandler
1426 pointing to that server's address and port."""
1427 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001428 addr = ('localhost', 0)
1429 self.server = server = TestTCPServer(addr, self.handle_socket,
1430 0.01)
1431 server.start()
1432 server.ready.wait()
1433 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1434 server.port)
1435 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001436 self.root_logger.removeHandler(self.root_logger.handlers[0])
1437 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001438 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001439
Christian Heimes180510d2008-03-03 19:15:45 +00001440 def tearDown(self):
1441 """Shutdown the TCP server."""
1442 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001443 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001444 self.root_logger.removeHandler(self.sock_hdlr)
1445 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001446 finally:
1447 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001448
Vinay Sajip7367d082011-05-02 13:17:27 +01001449 def handle_socket(self, request):
1450 conn = request.connection
1451 while True:
1452 chunk = conn.recv(4)
1453 if len(chunk) < 4:
1454 break
1455 slen = struct.unpack(">L", chunk)[0]
1456 chunk = conn.recv(slen)
1457 while len(chunk) < slen:
1458 chunk = chunk + conn.recv(slen - len(chunk))
1459 obj = pickle.loads(chunk)
1460 record = logging.makeLogRecord(obj)
1461 self.log_output += record.msg + '\n'
1462 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001463
Christian Heimes180510d2008-03-03 19:15:45 +00001464 def test_output(self):
1465 # The log message sent to the SocketHandler is properly received.
1466 logger = logging.getLogger("tcp")
1467 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001468 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001469 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001470 self.handled.acquire()
1471 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001472
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001473 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001474 # Avoid timing-related failures due to SocketHandler's own hard-wired
1475 # one-second timeout on socket.create_connection() (issue #16264).
1476 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001477 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001478 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001479 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001480 try:
1481 raise RuntimeError('Deliberate mistake')
1482 except RuntimeError:
1483 self.root_logger.exception('Never sent')
1484 self.root_logger.error('Never sent, either')
1485 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001486 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001487 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1488 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001489
Vinay Sajip7367d082011-05-02 13:17:27 +01001490
1491@unittest.skipUnless(threading, 'Threading required for this test.')
1492class DatagramHandlerTest(BaseTest):
1493
1494 """Test for DatagramHandler."""
1495
1496 def setUp(self):
1497 """Set up a UDP server to receive log messages, and a DatagramHandler
1498 pointing to that server's address and port."""
1499 BaseTest.setUp(self)
1500 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001501 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001502 server.start()
1503 server.ready.wait()
1504 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1505 server.port)
1506 self.log_output = ''
1507 self.root_logger.removeHandler(self.root_logger.handlers[0])
1508 self.root_logger.addHandler(self.sock_hdlr)
1509 self.handled = threading.Event()
1510
1511 def tearDown(self):
1512 """Shutdown the UDP server."""
1513 try:
1514 self.server.stop(2.0)
1515 self.root_logger.removeHandler(self.sock_hdlr)
1516 self.sock_hdlr.close()
1517 finally:
1518 BaseTest.tearDown(self)
1519
1520 def handle_datagram(self, request):
1521 slen = struct.pack('>L', 0) # length of prefix
1522 packet = request.packet[len(slen):]
1523 obj = pickle.loads(packet)
1524 record = logging.makeLogRecord(obj)
1525 self.log_output += record.msg + '\n'
1526 self.handled.set()
1527
1528 def test_output(self):
1529 # The log message sent to the DatagramHandler is properly received.
1530 logger = logging.getLogger("udp")
1531 logger.error("spam")
1532 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001533 self.handled.clear()
1534 logger.error("eggs")
1535 self.handled.wait()
1536 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001537
1538
1539@unittest.skipUnless(threading, 'Threading required for this test.')
1540class SysLogHandlerTest(BaseTest):
1541
1542 """Test for SysLogHandler using UDP."""
1543
1544 def setUp(self):
1545 """Set up a UDP server to receive log messages, and a SysLogHandler
1546 pointing to that server's address and port."""
1547 BaseTest.setUp(self)
1548 addr = ('localhost', 0)
1549 self.server = server = TestUDPServer(addr, self.handle_datagram,
1550 0.01)
1551 server.start()
1552 server.ready.wait()
1553 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1554 server.port))
1555 self.log_output = ''
1556 self.root_logger.removeHandler(self.root_logger.handlers[0])
1557 self.root_logger.addHandler(self.sl_hdlr)
1558 self.handled = threading.Event()
1559
1560 def tearDown(self):
1561 """Shutdown the UDP server."""
1562 try:
1563 self.server.stop(2.0)
1564 self.root_logger.removeHandler(self.sl_hdlr)
1565 self.sl_hdlr.close()
1566 finally:
1567 BaseTest.tearDown(self)
1568
1569 def handle_datagram(self, request):
1570 self.log_output = request.packet
1571 self.handled.set()
1572
1573 def test_output(self):
1574 # The log message sent to the SysLogHandler is properly received.
1575 logger = logging.getLogger("slh")
1576 logger.error("sp\xe4m")
1577 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001578 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001579 self.handled.clear()
1580 self.sl_hdlr.append_nul = False
1581 logger.error("sp\xe4m")
1582 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001583 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001584 self.handled.clear()
1585 self.sl_hdlr.ident = "h\xe4m-"
1586 logger.error("sp\xe4m")
1587 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001588 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001589
1590
1591@unittest.skipUnless(threading, 'Threading required for this test.')
1592class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001593 """Test for HTTPHandler."""
1594
Vinay Sajip9ba87612011-05-21 11:32:15 +01001595 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1596MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1597zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1598aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1599AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16000tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16015LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1602piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16032z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1604i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1605PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1606E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1607rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1608/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1609-----END RSA PRIVATE KEY-----
1610-----BEGIN CERTIFICATE-----
1611MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1612BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1613EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1614xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1615l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1616vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1617BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1618S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1619BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16204f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16211c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1622IRbTpvlHWPjsSvHz0ZOH
1623-----END CERTIFICATE-----"""
1624
Vinay Sajip7367d082011-05-02 13:17:27 +01001625 def setUp(self):
1626 """Set up an HTTP server to receive log messages, and a HTTPHandler
1627 pointing to that server's address and port."""
1628 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001629 self.handled = threading.Event()
1630
Vinay Sajip7367d082011-05-02 13:17:27 +01001631 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001632 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001633 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001634 if self.command == 'POST':
1635 try:
1636 rlen = int(request.headers['Content-Length'])
1637 self.post_data = request.rfile.read(rlen)
1638 except:
1639 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001640 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001641 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001642 self.handled.set()
1643
1644 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001645 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001646 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001647 root_logger = self.root_logger
1648 root_logger.removeHandler(self.root_logger.handlers[0])
1649 for secure in (False, True):
1650 addr = ('localhost', 0)
1651 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001652 try:
1653 import ssl
1654 fd, fn = tempfile.mkstemp()
1655 os.close(fd)
1656 with open(fn, 'w') as f:
1657 f.write(self.PEMFILE)
1658 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1659 sslctx.load_cert_chain(fn)
1660 os.unlink(fn)
1661 except ImportError:
1662 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001663 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001664 sslctx = None
1665 self.server = server = TestHTTPServer(addr, self.handle_request,
1666 0.01, sslctx=sslctx)
1667 server.start()
1668 server.ready.wait()
1669 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001670 secure_client = secure and sslctx
1671 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1672 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001673 self.log_data = None
1674 root_logger.addHandler(self.h_hdlr)
1675
1676 for method in ('GET', 'POST'):
1677 self.h_hdlr.method = method
1678 self.handled.clear()
1679 msg = "sp\xe4m"
1680 logger.error(msg)
1681 self.handled.wait()
1682 self.assertEqual(self.log_data.path, '/frob')
1683 self.assertEqual(self.command, method)
1684 if method == 'GET':
1685 d = parse_qs(self.log_data.query)
1686 else:
1687 d = parse_qs(self.post_data.decode('utf-8'))
1688 self.assertEqual(d['name'], ['http'])
1689 self.assertEqual(d['funcName'], ['test_output'])
1690 self.assertEqual(d['msg'], [msg])
1691
1692 self.server.stop(2.0)
1693 self.root_logger.removeHandler(self.h_hdlr)
1694 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001695
Christian Heimes180510d2008-03-03 19:15:45 +00001696class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001697
Christian Heimes180510d2008-03-03 19:15:45 +00001698 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001699
Christian Heimes180510d2008-03-03 19:15:45 +00001700 def setUp(self):
1701 """Create a dict to remember potentially destroyed objects."""
1702 BaseTest.setUp(self)
1703 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001704
Christian Heimes180510d2008-03-03 19:15:45 +00001705 def _watch_for_survival(self, *args):
1706 """Watch the given objects for survival, by creating weakrefs to
1707 them."""
1708 for obj in args:
1709 key = id(obj), repr(obj)
1710 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001711
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001712 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001713 """Assert that all objects watched for survival have survived."""
1714 # Trigger cycle breaking.
1715 gc.collect()
1716 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001717 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001718 if ref() is None:
1719 dead.append(repr_)
1720 if dead:
1721 self.fail("%d objects should have survived "
1722 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001723
Christian Heimes180510d2008-03-03 19:15:45 +00001724 def test_persistent_loggers(self):
1725 # Logger objects are persistent and retain their configuration, even
1726 # if visible references are destroyed.
1727 self.root_logger.setLevel(logging.INFO)
1728 foo = logging.getLogger("foo")
1729 self._watch_for_survival(foo)
1730 foo.setLevel(logging.DEBUG)
1731 self.root_logger.debug(self.next_message())
1732 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001733 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001734 ('foo', 'DEBUG', '2'),
1735 ])
1736 del foo
1737 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001738 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001739 # foo has retained its settings.
1740 bar = logging.getLogger("foo")
1741 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001742 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001743 ('foo', 'DEBUG', '2'),
1744 ('foo', 'DEBUG', '3'),
1745 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001746
Benjamin Petersonf91df042009-02-13 02:50:59 +00001747
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001748class EncodingTest(BaseTest):
1749 def test_encoding_plain_file(self):
1750 # In Python 2.x, a plain file object is treated as having no encoding.
1751 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001752 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1753 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001754 # the non-ascii data we write to the log.
1755 data = "foo\x80"
1756 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001757 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001758 log.addHandler(handler)
1759 try:
1760 # write non-ascii data to the log.
1761 log.warning(data)
1762 finally:
1763 log.removeHandler(handler)
1764 handler.close()
1765 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001766 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001767 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001768 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001769 finally:
1770 f.close()
1771 finally:
1772 if os.path.isfile(fn):
1773 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001774
Benjamin Petersonf91df042009-02-13 02:50:59 +00001775 def test_encoding_cyrillic_unicode(self):
1776 log = logging.getLogger("test")
1777 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1778 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1779 #Ensure it's written in a Cyrillic encoding
1780 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001781 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001782 stream = io.BytesIO()
1783 writer = writer_class(stream, 'strict')
1784 handler = logging.StreamHandler(writer)
1785 log.addHandler(handler)
1786 try:
1787 log.warning(message)
1788 finally:
1789 log.removeHandler(handler)
1790 handler.close()
1791 # check we wrote exactly those bytes, ignoring trailing \n etc
1792 s = stream.getvalue()
1793 #Compare against what the data should be when encoded in CP-1251
1794 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1795
1796
Georg Brandlf9734072008-12-07 15:30:06 +00001797class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001798
Georg Brandlf9734072008-12-07 15:30:06 +00001799 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001800 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001801 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001802 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001803 warnings.filterwarnings("always", category=UserWarning)
1804 stream = io.StringIO()
1805 h = logging.StreamHandler(stream)
1806 logger = logging.getLogger("py.warnings")
1807 logger.addHandler(h)
1808 warnings.warn("I'm warning you...")
1809 logger.removeHandler(h)
1810 s = stream.getvalue()
1811 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001812 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001813
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001814 #See if an explicit file uses the original implementation
1815 a_file = io.StringIO()
1816 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1817 a_file, "Dummy line")
1818 s = a_file.getvalue()
1819 a_file.close()
1820 self.assertEqual(s,
1821 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1822
1823 def test_warnings_no_handlers(self):
1824 with warnings.catch_warnings():
1825 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001826 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001827
1828 # confirm our assumption: no loggers are set
1829 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001830 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001831
1832 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001833 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001834 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001835
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001836
1837def formatFunc(format, datefmt=None):
1838 return logging.Formatter(format, datefmt)
1839
1840def handlerFunc():
1841 return logging.StreamHandler()
1842
1843class CustomHandler(logging.StreamHandler):
1844 pass
1845
1846class ConfigDictTest(BaseTest):
1847
1848 """Reading logging config from a dictionary."""
1849
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001850 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001851
1852 # config0 is a standard configuration.
1853 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001854 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001855 'formatters': {
1856 'form1' : {
1857 'format' : '%(levelname)s ++ %(message)s',
1858 },
1859 },
1860 'handlers' : {
1861 'hand1' : {
1862 'class' : 'logging.StreamHandler',
1863 'formatter' : 'form1',
1864 'level' : 'NOTSET',
1865 'stream' : 'ext://sys.stdout',
1866 },
1867 },
1868 'root' : {
1869 'level' : 'WARNING',
1870 'handlers' : ['hand1'],
1871 },
1872 }
1873
1874 # config1 adds a little to the standard configuration.
1875 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001876 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001877 'formatters': {
1878 'form1' : {
1879 'format' : '%(levelname)s ++ %(message)s',
1880 },
1881 },
1882 'handlers' : {
1883 'hand1' : {
1884 'class' : 'logging.StreamHandler',
1885 'formatter' : 'form1',
1886 'level' : 'NOTSET',
1887 'stream' : 'ext://sys.stdout',
1888 },
1889 },
1890 'loggers' : {
1891 'compiler.parser' : {
1892 'level' : 'DEBUG',
1893 'handlers' : ['hand1'],
1894 },
1895 },
1896 'root' : {
1897 'level' : 'WARNING',
1898 },
1899 }
1900
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001901 # config1a moves the handler to the root. Used with config8a
1902 config1a = {
1903 'version': 1,
1904 'formatters': {
1905 'form1' : {
1906 'format' : '%(levelname)s ++ %(message)s',
1907 },
1908 },
1909 'handlers' : {
1910 'hand1' : {
1911 'class' : 'logging.StreamHandler',
1912 'formatter' : 'form1',
1913 'level' : 'NOTSET',
1914 'stream' : 'ext://sys.stdout',
1915 },
1916 },
1917 'loggers' : {
1918 'compiler.parser' : {
1919 'level' : 'DEBUG',
1920 },
1921 },
1922 'root' : {
1923 'level' : 'WARNING',
1924 'handlers' : ['hand1'],
1925 },
1926 }
1927
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001928 # config2 has a subtle configuration error that should be reported
1929 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001930 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001931 'formatters': {
1932 'form1' : {
1933 'format' : '%(levelname)s ++ %(message)s',
1934 },
1935 },
1936 'handlers' : {
1937 'hand1' : {
1938 'class' : 'logging.StreamHandler',
1939 'formatter' : 'form1',
1940 'level' : 'NOTSET',
1941 'stream' : 'ext://sys.stdbout',
1942 },
1943 },
1944 'loggers' : {
1945 'compiler.parser' : {
1946 'level' : 'DEBUG',
1947 'handlers' : ['hand1'],
1948 },
1949 },
1950 'root' : {
1951 'level' : 'WARNING',
1952 },
1953 }
1954
1955 #As config1 but with a misspelt level on a handler
1956 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001957 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001958 'formatters': {
1959 'form1' : {
1960 'format' : '%(levelname)s ++ %(message)s',
1961 },
1962 },
1963 'handlers' : {
1964 'hand1' : {
1965 'class' : 'logging.StreamHandler',
1966 'formatter' : 'form1',
1967 'level' : 'NTOSET',
1968 'stream' : 'ext://sys.stdout',
1969 },
1970 },
1971 'loggers' : {
1972 'compiler.parser' : {
1973 'level' : 'DEBUG',
1974 'handlers' : ['hand1'],
1975 },
1976 },
1977 'root' : {
1978 'level' : 'WARNING',
1979 },
1980 }
1981
1982
1983 #As config1 but with a misspelt level on a logger
1984 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001985 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001986 'formatters': {
1987 'form1' : {
1988 'format' : '%(levelname)s ++ %(message)s',
1989 },
1990 },
1991 'handlers' : {
1992 'hand1' : {
1993 'class' : 'logging.StreamHandler',
1994 'formatter' : 'form1',
1995 'level' : 'NOTSET',
1996 'stream' : 'ext://sys.stdout',
1997 },
1998 },
1999 'loggers' : {
2000 'compiler.parser' : {
2001 'level' : 'DEBUG',
2002 'handlers' : ['hand1'],
2003 },
2004 },
2005 'root' : {
2006 'level' : 'WRANING',
2007 },
2008 }
2009
2010 # config3 has a less subtle configuration error
2011 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002012 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002013 'formatters': {
2014 'form1' : {
2015 'format' : '%(levelname)s ++ %(message)s',
2016 },
2017 },
2018 'handlers' : {
2019 'hand1' : {
2020 'class' : 'logging.StreamHandler',
2021 'formatter' : 'misspelled_name',
2022 'level' : 'NOTSET',
2023 'stream' : 'ext://sys.stdout',
2024 },
2025 },
2026 'loggers' : {
2027 'compiler.parser' : {
2028 'level' : 'DEBUG',
2029 'handlers' : ['hand1'],
2030 },
2031 },
2032 'root' : {
2033 'level' : 'WARNING',
2034 },
2035 }
2036
2037 # config4 specifies a custom formatter class to be loaded
2038 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002039 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002040 'formatters': {
2041 'form1' : {
2042 '()' : __name__ + '.ExceptionFormatter',
2043 'format' : '%(levelname)s:%(name)s:%(message)s',
2044 },
2045 },
2046 'handlers' : {
2047 'hand1' : {
2048 'class' : 'logging.StreamHandler',
2049 'formatter' : 'form1',
2050 'level' : 'NOTSET',
2051 'stream' : 'ext://sys.stdout',
2052 },
2053 },
2054 'root' : {
2055 'level' : 'NOTSET',
2056 'handlers' : ['hand1'],
2057 },
2058 }
2059
2060 # As config4 but using an actual callable rather than a string
2061 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002062 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002063 'formatters': {
2064 'form1' : {
2065 '()' : ExceptionFormatter,
2066 'format' : '%(levelname)s:%(name)s:%(message)s',
2067 },
2068 'form2' : {
2069 '()' : __name__ + '.formatFunc',
2070 'format' : '%(levelname)s:%(name)s:%(message)s',
2071 },
2072 'form3' : {
2073 '()' : formatFunc,
2074 'format' : '%(levelname)s:%(name)s:%(message)s',
2075 },
2076 },
2077 'handlers' : {
2078 'hand1' : {
2079 'class' : 'logging.StreamHandler',
2080 'formatter' : 'form1',
2081 'level' : 'NOTSET',
2082 'stream' : 'ext://sys.stdout',
2083 },
2084 'hand2' : {
2085 '()' : handlerFunc,
2086 },
2087 },
2088 'root' : {
2089 'level' : 'NOTSET',
2090 'handlers' : ['hand1'],
2091 },
2092 }
2093
2094 # config5 specifies a custom handler class to be loaded
2095 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002097 'formatters': {
2098 'form1' : {
2099 'format' : '%(levelname)s ++ %(message)s',
2100 },
2101 },
2102 'handlers' : {
2103 'hand1' : {
2104 'class' : __name__ + '.CustomHandler',
2105 'formatter' : 'form1',
2106 'level' : 'NOTSET',
2107 'stream' : 'ext://sys.stdout',
2108 },
2109 },
2110 'loggers' : {
2111 'compiler.parser' : {
2112 'level' : 'DEBUG',
2113 'handlers' : ['hand1'],
2114 },
2115 },
2116 'root' : {
2117 'level' : 'WARNING',
2118 },
2119 }
2120
2121 # config6 specifies a custom handler class to be loaded
2122 # but has bad arguments
2123 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002124 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125 'formatters': {
2126 'form1' : {
2127 'format' : '%(levelname)s ++ %(message)s',
2128 },
2129 },
2130 'handlers' : {
2131 'hand1' : {
2132 'class' : __name__ + '.CustomHandler',
2133 'formatter' : 'form1',
2134 'level' : 'NOTSET',
2135 'stream' : 'ext://sys.stdout',
2136 '9' : 'invalid parameter name',
2137 },
2138 },
2139 'loggers' : {
2140 'compiler.parser' : {
2141 'level' : 'DEBUG',
2142 'handlers' : ['hand1'],
2143 },
2144 },
2145 'root' : {
2146 'level' : 'WARNING',
2147 },
2148 }
2149
2150 #config 7 does not define compiler.parser but defines compiler.lexer
2151 #so compiler.parser should be disabled after applying it
2152 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002153 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002154 'formatters': {
2155 'form1' : {
2156 'format' : '%(levelname)s ++ %(message)s',
2157 },
2158 },
2159 'handlers' : {
2160 'hand1' : {
2161 'class' : 'logging.StreamHandler',
2162 'formatter' : 'form1',
2163 'level' : 'NOTSET',
2164 'stream' : 'ext://sys.stdout',
2165 },
2166 },
2167 'loggers' : {
2168 'compiler.lexer' : {
2169 'level' : 'DEBUG',
2170 'handlers' : ['hand1'],
2171 },
2172 },
2173 'root' : {
2174 'level' : 'WARNING',
2175 },
2176 }
2177
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002178 # config8 defines both compiler and compiler.lexer
2179 # so compiler.parser should not be disabled (since
2180 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002181 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002182 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002183 'disable_existing_loggers' : False,
2184 'formatters': {
2185 'form1' : {
2186 'format' : '%(levelname)s ++ %(message)s',
2187 },
2188 },
2189 'handlers' : {
2190 'hand1' : {
2191 'class' : 'logging.StreamHandler',
2192 'formatter' : 'form1',
2193 'level' : 'NOTSET',
2194 'stream' : 'ext://sys.stdout',
2195 },
2196 },
2197 'loggers' : {
2198 'compiler' : {
2199 'level' : 'DEBUG',
2200 'handlers' : ['hand1'],
2201 },
2202 'compiler.lexer' : {
2203 },
2204 },
2205 'root' : {
2206 'level' : 'WARNING',
2207 },
2208 }
2209
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002210 # config8a disables existing loggers
2211 config8a = {
2212 'version': 1,
2213 'disable_existing_loggers' : True,
2214 'formatters': {
2215 'form1' : {
2216 'format' : '%(levelname)s ++ %(message)s',
2217 },
2218 },
2219 'handlers' : {
2220 'hand1' : {
2221 'class' : 'logging.StreamHandler',
2222 'formatter' : 'form1',
2223 'level' : 'NOTSET',
2224 'stream' : 'ext://sys.stdout',
2225 },
2226 },
2227 'loggers' : {
2228 'compiler' : {
2229 'level' : 'DEBUG',
2230 'handlers' : ['hand1'],
2231 },
2232 'compiler.lexer' : {
2233 },
2234 },
2235 'root' : {
2236 'level' : 'WARNING',
2237 },
2238 }
2239
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002240 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002241 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002242 'formatters': {
2243 'form1' : {
2244 'format' : '%(levelname)s ++ %(message)s',
2245 },
2246 },
2247 'handlers' : {
2248 'hand1' : {
2249 'class' : 'logging.StreamHandler',
2250 'formatter' : 'form1',
2251 'level' : 'WARNING',
2252 'stream' : 'ext://sys.stdout',
2253 },
2254 },
2255 'loggers' : {
2256 'compiler.parser' : {
2257 'level' : 'WARNING',
2258 'handlers' : ['hand1'],
2259 },
2260 },
2261 'root' : {
2262 'level' : 'NOTSET',
2263 },
2264 }
2265
2266 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002267 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002268 'incremental' : True,
2269 'handlers' : {
2270 'hand1' : {
2271 'level' : 'WARNING',
2272 },
2273 },
2274 'loggers' : {
2275 'compiler.parser' : {
2276 'level' : 'INFO',
2277 },
2278 },
2279 }
2280
2281 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002282 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002283 'incremental' : True,
2284 'handlers' : {
2285 'hand1' : {
2286 'level' : 'INFO',
2287 },
2288 },
2289 'loggers' : {
2290 'compiler.parser' : {
2291 'level' : 'INFO',
2292 },
2293 },
2294 }
2295
2296 #As config1 but with a filter added
2297 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002298 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002299 'formatters': {
2300 'form1' : {
2301 'format' : '%(levelname)s ++ %(message)s',
2302 },
2303 },
2304 'filters' : {
2305 'filt1' : {
2306 'name' : 'compiler.parser',
2307 },
2308 },
2309 'handlers' : {
2310 'hand1' : {
2311 'class' : 'logging.StreamHandler',
2312 'formatter' : 'form1',
2313 'level' : 'NOTSET',
2314 'stream' : 'ext://sys.stdout',
2315 'filters' : ['filt1'],
2316 },
2317 },
2318 'loggers' : {
2319 'compiler.parser' : {
2320 'level' : 'DEBUG',
2321 'filters' : ['filt1'],
2322 },
2323 },
2324 'root' : {
2325 'level' : 'WARNING',
2326 'handlers' : ['hand1'],
2327 },
2328 }
2329
2330 #As config1 but using cfg:// references
2331 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002332 'version': 1,
2333 'true_formatters': {
2334 'form1' : {
2335 'format' : '%(levelname)s ++ %(message)s',
2336 },
2337 },
2338 'handler_configs': {
2339 'hand1' : {
2340 'class' : 'logging.StreamHandler',
2341 'formatter' : 'form1',
2342 'level' : 'NOTSET',
2343 'stream' : 'ext://sys.stdout',
2344 },
2345 },
2346 'formatters' : 'cfg://true_formatters',
2347 'handlers' : {
2348 'hand1' : 'cfg://handler_configs[hand1]',
2349 },
2350 'loggers' : {
2351 'compiler.parser' : {
2352 'level' : 'DEBUG',
2353 'handlers' : ['hand1'],
2354 },
2355 },
2356 'root' : {
2357 'level' : 'WARNING',
2358 },
2359 }
2360
2361 #As config11 but missing the version key
2362 config12 = {
2363 'true_formatters': {
2364 'form1' : {
2365 'format' : '%(levelname)s ++ %(message)s',
2366 },
2367 },
2368 'handler_configs': {
2369 'hand1' : {
2370 'class' : 'logging.StreamHandler',
2371 'formatter' : 'form1',
2372 'level' : 'NOTSET',
2373 'stream' : 'ext://sys.stdout',
2374 },
2375 },
2376 'formatters' : 'cfg://true_formatters',
2377 'handlers' : {
2378 'hand1' : 'cfg://handler_configs[hand1]',
2379 },
2380 'loggers' : {
2381 'compiler.parser' : {
2382 'level' : 'DEBUG',
2383 'handlers' : ['hand1'],
2384 },
2385 },
2386 'root' : {
2387 'level' : 'WARNING',
2388 },
2389 }
2390
2391 #As config11 but using an unsupported version
2392 config13 = {
2393 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002394 'true_formatters': {
2395 'form1' : {
2396 'format' : '%(levelname)s ++ %(message)s',
2397 },
2398 },
2399 'handler_configs': {
2400 'hand1' : {
2401 'class' : 'logging.StreamHandler',
2402 'formatter' : 'form1',
2403 'level' : 'NOTSET',
2404 'stream' : 'ext://sys.stdout',
2405 },
2406 },
2407 'formatters' : 'cfg://true_formatters',
2408 'handlers' : {
2409 'hand1' : 'cfg://handler_configs[hand1]',
2410 },
2411 'loggers' : {
2412 'compiler.parser' : {
2413 'level' : 'DEBUG',
2414 'handlers' : ['hand1'],
2415 },
2416 },
2417 'root' : {
2418 'level' : 'WARNING',
2419 },
2420 }
2421
Vinay Sajip8d270232012-11-15 14:20:18 +00002422 # As config0, but with properties
2423 config14 = {
2424 'version': 1,
2425 'formatters': {
2426 'form1' : {
2427 'format' : '%(levelname)s ++ %(message)s',
2428 },
2429 },
2430 'handlers' : {
2431 'hand1' : {
2432 'class' : 'logging.StreamHandler',
2433 'formatter' : 'form1',
2434 'level' : 'NOTSET',
2435 'stream' : 'ext://sys.stdout',
2436 '.': {
2437 'foo': 'bar',
2438 'terminator': '!\n',
2439 }
2440 },
2441 },
2442 'root' : {
2443 'level' : 'WARNING',
2444 'handlers' : ['hand1'],
2445 },
2446 }
2447
Vinay Sajip3f885b52013-03-22 15:19:54 +00002448 out_of_order = {
2449 "version": 1,
2450 "formatters": {
2451 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002452 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2453 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002454 }
2455 },
2456 "handlers": {
2457 "fileGlobal": {
2458 "class": "logging.StreamHandler",
2459 "level": "DEBUG",
2460 "formatter": "mySimpleFormatter"
2461 },
2462 "bufferGlobal": {
2463 "class": "logging.handlers.MemoryHandler",
2464 "capacity": 5,
2465 "formatter": "mySimpleFormatter",
2466 "target": "fileGlobal",
2467 "level": "DEBUG"
2468 }
2469 },
2470 "loggers": {
2471 "mymodule": {
2472 "level": "DEBUG",
2473 "handlers": ["bufferGlobal"],
2474 "propagate": "true"
2475 }
2476 }
2477 }
2478
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002479 def apply_config(self, conf):
2480 logging.config.dictConfig(conf)
2481
2482 def test_config0_ok(self):
2483 # A simple config which overrides the default settings.
2484 with captured_stdout() as output:
2485 self.apply_config(self.config0)
2486 logger = logging.getLogger()
2487 # Won't output anything
2488 logger.info(self.next_message())
2489 # Outputs a message
2490 logger.error(self.next_message())
2491 self.assert_log_lines([
2492 ('ERROR', '2'),
2493 ], stream=output)
2494 # Original logger output is empty.
2495 self.assert_log_lines([])
2496
2497 def test_config1_ok(self, config=config1):
2498 # A config defining a sub-parser as well.
2499 with captured_stdout() as output:
2500 self.apply_config(config)
2501 logger = logging.getLogger("compiler.parser")
2502 # Both will output a message
2503 logger.info(self.next_message())
2504 logger.error(self.next_message())
2505 self.assert_log_lines([
2506 ('INFO', '1'),
2507 ('ERROR', '2'),
2508 ], stream=output)
2509 # Original logger output is empty.
2510 self.assert_log_lines([])
2511
2512 def test_config2_failure(self):
2513 # A simple config which overrides the default settings.
2514 self.assertRaises(Exception, self.apply_config, self.config2)
2515
2516 def test_config2a_failure(self):
2517 # A simple config which overrides the default settings.
2518 self.assertRaises(Exception, self.apply_config, self.config2a)
2519
2520 def test_config2b_failure(self):
2521 # A simple config which overrides the default settings.
2522 self.assertRaises(Exception, self.apply_config, self.config2b)
2523
2524 def test_config3_failure(self):
2525 # A simple config which overrides the default settings.
2526 self.assertRaises(Exception, self.apply_config, self.config3)
2527
2528 def test_config4_ok(self):
2529 # A config specifying a custom formatter class.
2530 with captured_stdout() as output:
2531 self.apply_config(self.config4)
2532 #logger = logging.getLogger()
2533 try:
2534 raise RuntimeError()
2535 except RuntimeError:
2536 logging.exception("just testing")
2537 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002538 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002539 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2540 # Original logger output is empty
2541 self.assert_log_lines([])
2542
2543 def test_config4a_ok(self):
2544 # A config specifying a custom formatter class.
2545 with captured_stdout() as output:
2546 self.apply_config(self.config4a)
2547 #logger = logging.getLogger()
2548 try:
2549 raise RuntimeError()
2550 except RuntimeError:
2551 logging.exception("just testing")
2552 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002553 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002554 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2555 # Original logger output is empty
2556 self.assert_log_lines([])
2557
2558 def test_config5_ok(self):
2559 self.test_config1_ok(config=self.config5)
2560
2561 def test_config6_failure(self):
2562 self.assertRaises(Exception, self.apply_config, self.config6)
2563
2564 def test_config7_ok(self):
2565 with captured_stdout() as output:
2566 self.apply_config(self.config1)
2567 logger = logging.getLogger("compiler.parser")
2568 # Both will output a message
2569 logger.info(self.next_message())
2570 logger.error(self.next_message())
2571 self.assert_log_lines([
2572 ('INFO', '1'),
2573 ('ERROR', '2'),
2574 ], stream=output)
2575 # Original logger output is empty.
2576 self.assert_log_lines([])
2577 with captured_stdout() as output:
2578 self.apply_config(self.config7)
2579 logger = logging.getLogger("compiler.parser")
2580 self.assertTrue(logger.disabled)
2581 logger = logging.getLogger("compiler.lexer")
2582 # Both will output a message
2583 logger.info(self.next_message())
2584 logger.error(self.next_message())
2585 self.assert_log_lines([
2586 ('INFO', '3'),
2587 ('ERROR', '4'),
2588 ], stream=output)
2589 # Original logger output is empty.
2590 self.assert_log_lines([])
2591
2592 #Same as test_config_7_ok but don't disable old loggers.
2593 def test_config_8_ok(self):
2594 with captured_stdout() as output:
2595 self.apply_config(self.config1)
2596 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002597 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002598 logger.info(self.next_message())
2599 logger.error(self.next_message())
2600 self.assert_log_lines([
2601 ('INFO', '1'),
2602 ('ERROR', '2'),
2603 ], stream=output)
2604 # Original logger output is empty.
2605 self.assert_log_lines([])
2606 with captured_stdout() as output:
2607 self.apply_config(self.config8)
2608 logger = logging.getLogger("compiler.parser")
2609 self.assertFalse(logger.disabled)
2610 # Both will output a message
2611 logger.info(self.next_message())
2612 logger.error(self.next_message())
2613 logger = logging.getLogger("compiler.lexer")
2614 # Both will output a message
2615 logger.info(self.next_message())
2616 logger.error(self.next_message())
2617 self.assert_log_lines([
2618 ('INFO', '3'),
2619 ('ERROR', '4'),
2620 ('INFO', '5'),
2621 ('ERROR', '6'),
2622 ], stream=output)
2623 # Original logger output is empty.
2624 self.assert_log_lines([])
2625
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002626 def test_config_8a_ok(self):
2627 with captured_stdout() as output:
2628 self.apply_config(self.config1a)
2629 logger = logging.getLogger("compiler.parser")
2630 # See issue #11424. compiler-hyphenated sorts
2631 # between compiler and compiler.xyz and this
2632 # was preventing compiler.xyz from being included
2633 # in the child loggers of compiler because of an
2634 # overzealous loop termination condition.
2635 hyphenated = logging.getLogger('compiler-hyphenated')
2636 # All will output a message
2637 logger.info(self.next_message())
2638 logger.error(self.next_message())
2639 hyphenated.critical(self.next_message())
2640 self.assert_log_lines([
2641 ('INFO', '1'),
2642 ('ERROR', '2'),
2643 ('CRITICAL', '3'),
2644 ], stream=output)
2645 # Original logger output is empty.
2646 self.assert_log_lines([])
2647 with captured_stdout() as output:
2648 self.apply_config(self.config8a)
2649 logger = logging.getLogger("compiler.parser")
2650 self.assertFalse(logger.disabled)
2651 # Both will output a message
2652 logger.info(self.next_message())
2653 logger.error(self.next_message())
2654 logger = logging.getLogger("compiler.lexer")
2655 # Both will output a message
2656 logger.info(self.next_message())
2657 logger.error(self.next_message())
2658 # Will not appear
2659 hyphenated.critical(self.next_message())
2660 self.assert_log_lines([
2661 ('INFO', '4'),
2662 ('ERROR', '5'),
2663 ('INFO', '6'),
2664 ('ERROR', '7'),
2665 ], stream=output)
2666 # Original logger output is empty.
2667 self.assert_log_lines([])
2668
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002669 def test_config_9_ok(self):
2670 with captured_stdout() as output:
2671 self.apply_config(self.config9)
2672 logger = logging.getLogger("compiler.parser")
2673 #Nothing will be output since both handler and logger are set to WARNING
2674 logger.info(self.next_message())
2675 self.assert_log_lines([], stream=output)
2676 self.apply_config(self.config9a)
2677 #Nothing will be output since both handler is still set to WARNING
2678 logger.info(self.next_message())
2679 self.assert_log_lines([], stream=output)
2680 self.apply_config(self.config9b)
2681 #Message should now be output
2682 logger.info(self.next_message())
2683 self.assert_log_lines([
2684 ('INFO', '3'),
2685 ], stream=output)
2686
2687 def test_config_10_ok(self):
2688 with captured_stdout() as output:
2689 self.apply_config(self.config10)
2690 logger = logging.getLogger("compiler.parser")
2691 logger.warning(self.next_message())
2692 logger = logging.getLogger('compiler')
2693 #Not output, because filtered
2694 logger.warning(self.next_message())
2695 logger = logging.getLogger('compiler.lexer')
2696 #Not output, because filtered
2697 logger.warning(self.next_message())
2698 logger = logging.getLogger("compiler.parser.codegen")
2699 #Output, as not filtered
2700 logger.error(self.next_message())
2701 self.assert_log_lines([
2702 ('WARNING', '1'),
2703 ('ERROR', '4'),
2704 ], stream=output)
2705
2706 def test_config11_ok(self):
2707 self.test_config1_ok(self.config11)
2708
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002709 def test_config12_failure(self):
2710 self.assertRaises(Exception, self.apply_config, self.config12)
2711
2712 def test_config13_failure(self):
2713 self.assertRaises(Exception, self.apply_config, self.config13)
2714
Vinay Sajip8d270232012-11-15 14:20:18 +00002715 def test_config14_ok(self):
2716 with captured_stdout() as output:
2717 self.apply_config(self.config14)
2718 h = logging._handlers['hand1']
2719 self.assertEqual(h.foo, 'bar')
2720 self.assertEqual(h.terminator, '!\n')
2721 logging.warning('Exclamation')
2722 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2723
Victor Stinner45df8202010-04-28 22:31:17 +00002724 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002725 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002726 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002727 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002728 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002729 t.start()
2730 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002731 # Now get the port allocated
2732 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002733 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002734 try:
2735 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2736 sock.settimeout(2.0)
2737 sock.connect(('localhost', port))
2738
2739 slen = struct.pack('>L', len(text))
2740 s = slen + text
2741 sentsofar = 0
2742 left = len(s)
2743 while left > 0:
2744 sent = sock.send(s[sentsofar:])
2745 sentsofar += sent
2746 left -= sent
2747 sock.close()
2748 finally:
2749 t.ready.wait(2.0)
2750 logging.config.stopListening()
2751 t.join(2.0)
2752
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002753 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002754 def test_listen_config_10_ok(self):
2755 with captured_stdout() as output:
2756 self.setup_via_listener(json.dumps(self.config10))
2757 logger = logging.getLogger("compiler.parser")
2758 logger.warning(self.next_message())
2759 logger = logging.getLogger('compiler')
2760 #Not output, because filtered
2761 logger.warning(self.next_message())
2762 logger = logging.getLogger('compiler.lexer')
2763 #Not output, because filtered
2764 logger.warning(self.next_message())
2765 logger = logging.getLogger("compiler.parser.codegen")
2766 #Output, as not filtered
2767 logger.error(self.next_message())
2768 self.assert_log_lines([
2769 ('WARNING', '1'),
2770 ('ERROR', '4'),
2771 ], stream=output)
2772
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002773 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002774 def test_listen_config_1_ok(self):
2775 with captured_stdout() as output:
2776 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2777 logger = logging.getLogger("compiler.parser")
2778 # Both will output a message
2779 logger.info(self.next_message())
2780 logger.error(self.next_message())
2781 self.assert_log_lines([
2782 ('INFO', '1'),
2783 ('ERROR', '2'),
2784 ], stream=output)
2785 # Original logger output is empty.
2786 self.assert_log_lines([])
2787
Vinay Sajip4ded5512012-10-02 15:56:16 +01002788 @unittest.skipUnless(threading, 'Threading required for this test.')
2789 def test_listen_verify(self):
2790
2791 def verify_fail(stuff):
2792 return None
2793
2794 def verify_reverse(stuff):
2795 return stuff[::-1]
2796
2797 logger = logging.getLogger("compiler.parser")
2798 to_send = textwrap.dedent(ConfigFileTest.config1)
2799 # First, specify a verification function that will fail.
2800 # We expect to see no output, since our configuration
2801 # never took effect.
2802 with captured_stdout() as output:
2803 self.setup_via_listener(to_send, verify_fail)
2804 # Both will output a message
2805 logger.info(self.next_message())
2806 logger.error(self.next_message())
2807 self.assert_log_lines([], stream=output)
2808 # Original logger output has the stuff we logged.
2809 self.assert_log_lines([
2810 ('INFO', '1'),
2811 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002812 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002813
2814 # Now, perform no verification. Our configuration
2815 # should take effect.
2816
2817 with captured_stdout() as output:
2818 self.setup_via_listener(to_send) # no verify callable specified
2819 logger = logging.getLogger("compiler.parser")
2820 # Both will output a message
2821 logger.info(self.next_message())
2822 logger.error(self.next_message())
2823 self.assert_log_lines([
2824 ('INFO', '3'),
2825 ('ERROR', '4'),
2826 ], stream=output)
2827 # Original logger output still has the stuff we logged before.
2828 self.assert_log_lines([
2829 ('INFO', '1'),
2830 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002831 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002832
2833 # Now, perform verification which transforms the bytes.
2834
2835 with captured_stdout() as output:
2836 self.setup_via_listener(to_send[::-1], verify_reverse)
2837 logger = logging.getLogger("compiler.parser")
2838 # Both will output a message
2839 logger.info(self.next_message())
2840 logger.error(self.next_message())
2841 self.assert_log_lines([
2842 ('INFO', '5'),
2843 ('ERROR', '6'),
2844 ], stream=output)
2845 # Original logger output still has the stuff we logged before.
2846 self.assert_log_lines([
2847 ('INFO', '1'),
2848 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002849 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002850
Vinay Sajip3f885b52013-03-22 15:19:54 +00002851 def test_out_of_order(self):
2852 self.apply_config(self.out_of_order)
2853 handler = logging.getLogger('mymodule').handlers[0]
2854 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002855 self.assertIsInstance(handler.formatter._style,
2856 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002857
Vinay Sajip373baef2011-04-26 20:05:24 +01002858 def test_baseconfig(self):
2859 d = {
2860 'atuple': (1, 2, 3),
2861 'alist': ['a', 'b', 'c'],
2862 'adict': {'d': 'e', 'f': 3 },
2863 'nest1': ('g', ('h', 'i'), 'j'),
2864 'nest2': ['k', ['l', 'm'], 'n'],
2865 'nest3': ['o', 'cfg://alist', 'p'],
2866 }
2867 bc = logging.config.BaseConfigurator(d)
2868 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2869 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2870 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2871 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2872 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2873 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2874 v = bc.convert('cfg://nest3')
2875 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2876 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2877 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2878 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002879
2880class ManagerTest(BaseTest):
2881 def test_manager_loggerclass(self):
2882 logged = []
2883
2884 class MyLogger(logging.Logger):
2885 def _log(self, level, msg, args, exc_info=None, extra=None):
2886 logged.append(msg)
2887
2888 man = logging.Manager(None)
2889 self.assertRaises(TypeError, man.setLoggerClass, int)
2890 man.setLoggerClass(MyLogger)
2891 logger = man.getLogger('test')
2892 logger.warning('should appear in logged')
2893 logging.warning('should not appear in logged')
2894
2895 self.assertEqual(logged, ['should appear in logged'])
2896
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002897 def test_set_log_record_factory(self):
2898 man = logging.Manager(None)
2899 expected = object()
2900 man.setLogRecordFactory(expected)
2901 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002902
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002903class ChildLoggerTest(BaseTest):
2904 def test_child_loggers(self):
2905 r = logging.getLogger()
2906 l1 = logging.getLogger('abc')
2907 l2 = logging.getLogger('def.ghi')
2908 c1 = r.getChild('xyz')
2909 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002910 self.assertIs(c1, logging.getLogger('xyz'))
2911 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002912 c1 = l1.getChild('def')
2913 c2 = c1.getChild('ghi')
2914 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002915 self.assertIs(c1, logging.getLogger('abc.def'))
2916 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2917 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002918
2919
Vinay Sajip6fac8172010-10-19 20:44:14 +00002920class DerivedLogRecord(logging.LogRecord):
2921 pass
2922
Vinay Sajip61561522010-12-03 11:50:38 +00002923class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002924
2925 def setUp(self):
2926 class CheckingFilter(logging.Filter):
2927 def __init__(self, cls):
2928 self.cls = cls
2929
2930 def filter(self, record):
2931 t = type(record)
2932 if t is not self.cls:
2933 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2934 self.cls)
2935 raise TypeError(msg)
2936 return True
2937
2938 BaseTest.setUp(self)
2939 self.filter = CheckingFilter(DerivedLogRecord)
2940 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002941 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002942
2943 def tearDown(self):
2944 self.root_logger.removeFilter(self.filter)
2945 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002946 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002947
2948 def test_logrecord_class(self):
2949 self.assertRaises(TypeError, self.root_logger.warning,
2950 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002951 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002952 self.root_logger.error(self.next_message())
2953 self.assert_log_lines([
2954 ('root', 'ERROR', '2'),
2955 ])
2956
2957
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002958class QueueHandlerTest(BaseTest):
2959 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002960 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002961
2962 def setUp(self):
2963 BaseTest.setUp(self)
2964 self.queue = queue.Queue(-1)
2965 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2966 self.que_logger = logging.getLogger('que')
2967 self.que_logger.propagate = False
2968 self.que_logger.setLevel(logging.WARNING)
2969 self.que_logger.addHandler(self.que_hdlr)
2970
2971 def tearDown(self):
2972 self.que_hdlr.close()
2973 BaseTest.tearDown(self)
2974
2975 def test_queue_handler(self):
2976 self.que_logger.debug(self.next_message())
2977 self.assertRaises(queue.Empty, self.queue.get_nowait)
2978 self.que_logger.info(self.next_message())
2979 self.assertRaises(queue.Empty, self.queue.get_nowait)
2980 msg = self.next_message()
2981 self.que_logger.warning(msg)
2982 data = self.queue.get_nowait()
2983 self.assertTrue(isinstance(data, logging.LogRecord))
2984 self.assertEqual(data.name, self.que_logger.name)
2985 self.assertEqual((data.msg, data.args), (msg, None))
2986
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002987 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2988 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002989 def test_queue_listener(self):
2990 handler = TestHandler(Matcher())
2991 listener = logging.handlers.QueueListener(self.queue, handler)
2992 listener.start()
2993 try:
2994 self.que_logger.warning(self.next_message())
2995 self.que_logger.error(self.next_message())
2996 self.que_logger.critical(self.next_message())
2997 finally:
2998 listener.stop()
2999 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3000 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3001 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3002
Vinay Sajip37eb3382011-04-26 20:26:41 +01003003ZERO = datetime.timedelta(0)
3004
3005class UTC(datetime.tzinfo):
3006 def utcoffset(self, dt):
3007 return ZERO
3008
3009 dst = utcoffset
3010
3011 def tzname(self, dt):
3012 return 'UTC'
3013
3014utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003015
Vinay Sajipa39c5712010-10-25 13:57:39 +00003016class FormatterTest(unittest.TestCase):
3017 def setUp(self):
3018 self.common = {
3019 'name': 'formatter.test',
3020 'level': logging.DEBUG,
3021 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3022 'lineno': 42,
3023 'exc_info': None,
3024 'func': None,
3025 'msg': 'Message with %d %s',
3026 'args': (2, 'placeholders'),
3027 }
3028 self.variants = {
3029 }
3030
3031 def get_record(self, name=None):
3032 result = dict(self.common)
3033 if name is not None:
3034 result.update(self.variants[name])
3035 return logging.makeLogRecord(result)
3036
3037 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003038 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003039 r = self.get_record()
3040 f = logging.Formatter('${%(message)s}')
3041 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3042 f = logging.Formatter('%(random)s')
3043 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003044 self.assertFalse(f.usesTime())
3045 f = logging.Formatter('%(asctime)s')
3046 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003047 f = logging.Formatter('%(asctime)-15s')
3048 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003049 f = logging.Formatter('asctime')
3050 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003051
3052 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003053 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003054 r = self.get_record()
3055 f = logging.Formatter('$%{message}%$', style='{')
3056 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3057 f = logging.Formatter('{random}', style='{')
3058 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003059 self.assertFalse(f.usesTime())
3060 f = logging.Formatter('{asctime}', style='{')
3061 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003062 f = logging.Formatter('{asctime!s:15}', style='{')
3063 self.assertTrue(f.usesTime())
3064 f = logging.Formatter('{asctime:15}', style='{')
3065 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003066 f = logging.Formatter('asctime', style='{')
3067 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003068
3069 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003070 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003071 r = self.get_record()
3072 f = logging.Formatter('$message', style='$')
3073 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3074 f = logging.Formatter('$$%${message}%$$', style='$')
3075 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3076 f = logging.Formatter('${random}', style='$')
3077 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003078 self.assertFalse(f.usesTime())
3079 f = logging.Formatter('${asctime}', style='$')
3080 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003081 f = logging.Formatter('${asctime', style='$')
3082 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003083 f = logging.Formatter('$asctime', style='$')
3084 self.assertTrue(f.usesTime())
3085 f = logging.Formatter('asctime', style='$')
3086 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003087
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003088 def test_invalid_style(self):
3089 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3090
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003091 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003092 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003093 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3094 # We use None to indicate we want the local timezone
3095 # We're essentially converting a UTC time to local time
3096 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003097 r.msecs = 123
3098 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003099 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003100 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3101 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003102 f.format(r)
3103 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3104
3105class TestBufferingFormatter(logging.BufferingFormatter):
3106 def formatHeader(self, records):
3107 return '[(%d)' % len(records)
3108
3109 def formatFooter(self, records):
3110 return '(%d)]' % len(records)
3111
3112class BufferingFormatterTest(unittest.TestCase):
3113 def setUp(self):
3114 self.records = [
3115 logging.makeLogRecord({'msg': 'one'}),
3116 logging.makeLogRecord({'msg': 'two'}),
3117 ]
3118
3119 def test_default(self):
3120 f = logging.BufferingFormatter()
3121 self.assertEqual('', f.format([]))
3122 self.assertEqual('onetwo', f.format(self.records))
3123
3124 def test_custom(self):
3125 f = TestBufferingFormatter()
3126 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3127 lf = logging.Formatter('<%(message)s>')
3128 f = TestBufferingFormatter(lf)
3129 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003130
3131class ExceptionTest(BaseTest):
3132 def test_formatting(self):
3133 r = self.root_logger
3134 h = RecordingHandler()
3135 r.addHandler(h)
3136 try:
3137 raise RuntimeError('deliberate mistake')
3138 except:
3139 logging.exception('failed', stack_info=True)
3140 r.removeHandler(h)
3141 h.close()
3142 r = h.records[0]
3143 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3144 'call last):\n'))
3145 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3146 'deliberate mistake'))
3147 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3148 'call last):\n'))
3149 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3150 'stack_info=True)'))
3151
3152
Vinay Sajip5a27d402010-12-10 11:42:57 +00003153class LastResortTest(BaseTest):
3154 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003155 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003156 root = self.root_logger
3157 root.removeHandler(self.root_hdlr)
3158 old_stderr = sys.stderr
3159 old_lastresort = logging.lastResort
3160 old_raise_exceptions = logging.raiseExceptions
3161 try:
3162 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003163 root.debug('This should not appear')
3164 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003165 root.warning('This is your final chance!')
3166 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3167 #No handlers and no last resort, so 'No handlers' message
3168 logging.lastResort = None
3169 sys.stderr = sio = io.StringIO()
3170 root.warning('This is your final chance!')
3171 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3172 # 'No handlers' message only printed once
3173 sys.stderr = sio = io.StringIO()
3174 root.warning('This is your final chance!')
3175 self.assertEqual(sio.getvalue(), '')
3176 root.manager.emittedNoHandlerWarning = False
3177 #If raiseExceptions is False, no message is printed
3178 logging.raiseExceptions = False
3179 sys.stderr = sio = io.StringIO()
3180 root.warning('This is your final chance!')
3181 self.assertEqual(sio.getvalue(), '')
3182 finally:
3183 sys.stderr = old_stderr
3184 root.addHandler(self.root_hdlr)
3185 logging.lastResort = old_lastresort
3186 logging.raiseExceptions = old_raise_exceptions
3187
3188
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003189class FakeHandler:
3190
3191 def __init__(self, identifier, called):
3192 for method in ('acquire', 'flush', 'close', 'release'):
3193 setattr(self, method, self.record_call(identifier, method, called))
3194
3195 def record_call(self, identifier, method_name, called):
3196 def inner():
3197 called.append('{} - {}'.format(identifier, method_name))
3198 return inner
3199
3200
3201class RecordingHandler(logging.NullHandler):
3202
3203 def __init__(self, *args, **kwargs):
3204 super(RecordingHandler, self).__init__(*args, **kwargs)
3205 self.records = []
3206
3207 def handle(self, record):
3208 """Keep track of all the emitted records."""
3209 self.records.append(record)
3210
3211
3212class ShutdownTest(BaseTest):
3213
Vinay Sajip5e66b162011-04-20 15:41:14 +01003214 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003215
3216 def setUp(self):
3217 super(ShutdownTest, self).setUp()
3218 self.called = []
3219
3220 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003221 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003222
3223 def raise_error(self, error):
3224 def inner():
3225 raise error()
3226 return inner
3227
3228 def test_no_failure(self):
3229 # create some fake handlers
3230 handler0 = FakeHandler(0, self.called)
3231 handler1 = FakeHandler(1, self.called)
3232 handler2 = FakeHandler(2, self.called)
3233
3234 # create live weakref to those handlers
3235 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3236
3237 logging.shutdown(handlerList=list(handlers))
3238
3239 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3240 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3241 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3242 self.assertEqual(expected, self.called)
3243
3244 def _test_with_failure_in_method(self, method, error):
3245 handler = FakeHandler(0, self.called)
3246 setattr(handler, method, self.raise_error(error))
3247 handlers = [logging.weakref.ref(handler)]
3248
3249 logging.shutdown(handlerList=list(handlers))
3250
3251 self.assertEqual('0 - release', self.called[-1])
3252
3253 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003254 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003255
3256 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003257 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003258
3259 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003260 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003261
3262 def test_with_valueerror_in_acquire(self):
3263 self._test_with_failure_in_method('acquire', ValueError)
3264
3265 def test_with_valueerror_in_flush(self):
3266 self._test_with_failure_in_method('flush', ValueError)
3267
3268 def test_with_valueerror_in_close(self):
3269 self._test_with_failure_in_method('close', ValueError)
3270
3271 def test_with_other_error_in_acquire_without_raise(self):
3272 logging.raiseExceptions = False
3273 self._test_with_failure_in_method('acquire', IndexError)
3274
3275 def test_with_other_error_in_flush_without_raise(self):
3276 logging.raiseExceptions = False
3277 self._test_with_failure_in_method('flush', IndexError)
3278
3279 def test_with_other_error_in_close_without_raise(self):
3280 logging.raiseExceptions = False
3281 self._test_with_failure_in_method('close', IndexError)
3282
3283 def test_with_other_error_in_acquire_with_raise(self):
3284 logging.raiseExceptions = True
3285 self.assertRaises(IndexError, self._test_with_failure_in_method,
3286 'acquire', IndexError)
3287
3288 def test_with_other_error_in_flush_with_raise(self):
3289 logging.raiseExceptions = True
3290 self.assertRaises(IndexError, self._test_with_failure_in_method,
3291 'flush', IndexError)
3292
3293 def test_with_other_error_in_close_with_raise(self):
3294 logging.raiseExceptions = True
3295 self.assertRaises(IndexError, self._test_with_failure_in_method,
3296 'close', IndexError)
3297
3298
3299class ModuleLevelMiscTest(BaseTest):
3300
Vinay Sajip5e66b162011-04-20 15:41:14 +01003301 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003302
3303 def test_disable(self):
3304 old_disable = logging.root.manager.disable
3305 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003306 self.assertEqual(old_disable, 0)
3307 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003308
3309 logging.disable(83)
3310 self.assertEqual(logging.root.manager.disable, 83)
3311
3312 def _test_log(self, method, level=None):
3313 called = []
3314 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003315 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003316
3317 recording = RecordingHandler()
3318 logging.root.addHandler(recording)
3319
3320 log_method = getattr(logging, method)
3321 if level is not None:
3322 log_method(level, "test me: %r", recording)
3323 else:
3324 log_method("test me: %r", recording)
3325
3326 self.assertEqual(len(recording.records), 1)
3327 record = recording.records[0]
3328 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3329
3330 expected_level = level if level is not None else getattr(logging, method.upper())
3331 self.assertEqual(record.levelno, expected_level)
3332
3333 # basicConfig was not called!
3334 self.assertEqual(called, [])
3335
3336 def test_log(self):
3337 self._test_log('log', logging.ERROR)
3338
3339 def test_debug(self):
3340 self._test_log('debug')
3341
3342 def test_info(self):
3343 self._test_log('info')
3344
3345 def test_warning(self):
3346 self._test_log('warning')
3347
3348 def test_error(self):
3349 self._test_log('error')
3350
3351 def test_critical(self):
3352 self._test_log('critical')
3353
3354 def test_set_logger_class(self):
3355 self.assertRaises(TypeError, logging.setLoggerClass, object)
3356
3357 class MyLogger(logging.Logger):
3358 pass
3359
3360 logging.setLoggerClass(MyLogger)
3361 self.assertEqual(logging.getLoggerClass(), MyLogger)
3362
3363 logging.setLoggerClass(logging.Logger)
3364 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3365
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003366class LogRecordTest(BaseTest):
3367 def test_str_rep(self):
3368 r = logging.makeLogRecord({})
3369 s = str(r)
3370 self.assertTrue(s.startswith('<LogRecord: '))
3371 self.assertTrue(s.endswith('>'))
3372
3373 def test_dict_arg(self):
3374 h = RecordingHandler()
3375 r = logging.getLogger()
3376 r.addHandler(h)
3377 d = {'less' : 'more' }
3378 logging.warning('less is %(less)s', d)
3379 self.assertIs(h.records[0].args, d)
3380 self.assertEqual(h.records[0].message, 'less is more')
3381 r.removeHandler(h)
3382 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003383
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003384 def test_multiprocessing(self):
3385 r = logging.makeLogRecord({})
3386 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003387 try:
3388 import multiprocessing as mp
3389 r = logging.makeLogRecord({})
3390 self.assertEqual(r.processName, mp.current_process().name)
3391 except ImportError:
3392 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003393
3394 def test_optional(self):
3395 r = logging.makeLogRecord({})
3396 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003397 if threading:
3398 NOT_NONE(r.thread)
3399 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003400 NOT_NONE(r.process)
3401 NOT_NONE(r.processName)
3402 log_threads = logging.logThreads
3403 log_processes = logging.logProcesses
3404 log_multiprocessing = logging.logMultiprocessing
3405 try:
3406 logging.logThreads = False
3407 logging.logProcesses = False
3408 logging.logMultiprocessing = False
3409 r = logging.makeLogRecord({})
3410 NONE = self.assertIsNone
3411 NONE(r.thread)
3412 NONE(r.threadName)
3413 NONE(r.process)
3414 NONE(r.processName)
3415 finally:
3416 logging.logThreads = log_threads
3417 logging.logProcesses = log_processes
3418 logging.logMultiprocessing = log_multiprocessing
3419
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003420class BasicConfigTest(unittest.TestCase):
3421
Vinay Sajip95bf5042011-04-20 11:50:56 +01003422 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003423
3424 def setUp(self):
3425 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003426 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003427 self.saved_handlers = logging._handlers.copy()
3428 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003429 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003430 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003431 logging.root.handlers = []
3432
3433 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003434 for h in logging.root.handlers[:]:
3435 logging.root.removeHandler(h)
3436 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003437 super(BasicConfigTest, self).tearDown()
3438
Vinay Sajip3def7e02011-04-20 10:58:06 +01003439 def cleanup(self):
3440 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003441 logging._handlers.clear()
3442 logging._handlers.update(self.saved_handlers)
3443 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003444 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003445
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003446 def test_no_kwargs(self):
3447 logging.basicConfig()
3448
3449 # handler defaults to a StreamHandler to sys.stderr
3450 self.assertEqual(len(logging.root.handlers), 1)
3451 handler = logging.root.handlers[0]
3452 self.assertIsInstance(handler, logging.StreamHandler)
3453 self.assertEqual(handler.stream, sys.stderr)
3454
3455 formatter = handler.formatter
3456 # format defaults to logging.BASIC_FORMAT
3457 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3458 # datefmt defaults to None
3459 self.assertIsNone(formatter.datefmt)
3460 # style defaults to %
3461 self.assertIsInstance(formatter._style, logging.PercentStyle)
3462
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003463 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003464 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003465
3466 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003467
3468 def cleanup(h1, h2, fn):
3469 h1.close()
3470 h2.close()
3471 os.remove(fn)
3472
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003473 logging.basicConfig(filename='test.log')
3474
3475 self.assertEqual(len(logging.root.handlers), 1)
3476 handler = logging.root.handlers[0]
3477 self.assertIsInstance(handler, logging.FileHandler)
3478
3479 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003480 self.assertEqual(handler.stream.mode, expected.stream.mode)
3481 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003482 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003483
3484 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003485
3486 def cleanup(h1, h2, fn):
3487 h1.close()
3488 h2.close()
3489 os.remove(fn)
3490
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003491 logging.basicConfig(filename='test.log', filemode='wb')
3492
3493 handler = logging.root.handlers[0]
3494 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003495 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003496 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003497
3498 def test_stream(self):
3499 stream = io.StringIO()
3500 self.addCleanup(stream.close)
3501 logging.basicConfig(stream=stream)
3502
3503 self.assertEqual(len(logging.root.handlers), 1)
3504 handler = logging.root.handlers[0]
3505 self.assertIsInstance(handler, logging.StreamHandler)
3506 self.assertEqual(handler.stream, stream)
3507
3508 def test_format(self):
3509 logging.basicConfig(format='foo')
3510
3511 formatter = logging.root.handlers[0].formatter
3512 self.assertEqual(formatter._style._fmt, 'foo')
3513
3514 def test_datefmt(self):
3515 logging.basicConfig(datefmt='bar')
3516
3517 formatter = logging.root.handlers[0].formatter
3518 self.assertEqual(formatter.datefmt, 'bar')
3519
3520 def test_style(self):
3521 logging.basicConfig(style='$')
3522
3523 formatter = logging.root.handlers[0].formatter
3524 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3525
3526 def test_level(self):
3527 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003528 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003529
3530 logging.basicConfig(level=57)
3531 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003532 # Test that second call has no effect
3533 logging.basicConfig(level=58)
3534 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003535
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003536 def test_incompatible(self):
3537 assertRaises = self.assertRaises
3538 handlers = [logging.StreamHandler()]
3539 stream = sys.stderr
3540 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3541 stream=stream)
3542 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3543 handlers=handlers)
3544 assertRaises(ValueError, logging.basicConfig, stream=stream,
3545 handlers=handlers)
3546
3547 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003548 handlers = [
3549 logging.StreamHandler(),
3550 logging.StreamHandler(sys.stdout),
3551 logging.StreamHandler(),
3552 ]
3553 f = logging.Formatter()
3554 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003555 logging.basicConfig(handlers=handlers)
3556 self.assertIs(handlers[0], logging.root.handlers[0])
3557 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003558 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003559 self.assertIsNotNone(handlers[0].formatter)
3560 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003561 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003562 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3563
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003564 def _test_log(self, method, level=None):
3565 # logging.root has no handlers so basicConfig should be called
3566 called = []
3567
3568 old_basic_config = logging.basicConfig
3569 def my_basic_config(*a, **kw):
3570 old_basic_config()
3571 old_level = logging.root.level
3572 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003573 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003574 called.append((a, kw))
3575
3576 patch(self, logging, 'basicConfig', my_basic_config)
3577
3578 log_method = getattr(logging, method)
3579 if level is not None:
3580 log_method(level, "test me")
3581 else:
3582 log_method("test me")
3583
3584 # basicConfig was called with no arguments
3585 self.assertEqual(called, [((), {})])
3586
3587 def test_log(self):
3588 self._test_log('log', logging.WARNING)
3589
3590 def test_debug(self):
3591 self._test_log('debug')
3592
3593 def test_info(self):
3594 self._test_log('info')
3595
3596 def test_warning(self):
3597 self._test_log('warning')
3598
3599 def test_error(self):
3600 self._test_log('error')
3601
3602 def test_critical(self):
3603 self._test_log('critical')
3604
3605
3606class LoggerAdapterTest(unittest.TestCase):
3607
3608 def setUp(self):
3609 super(LoggerAdapterTest, self).setUp()
3610 old_handler_list = logging._handlerList[:]
3611
3612 self.recording = RecordingHandler()
3613 self.logger = logging.root
3614 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003615 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003616 self.addCleanup(self.recording.close)
3617
3618 def cleanup():
3619 logging._handlerList[:] = old_handler_list
3620
3621 self.addCleanup(cleanup)
3622 self.addCleanup(logging.shutdown)
3623 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3624
3625 def test_exception(self):
3626 msg = 'testing exception: %r'
3627 exc = None
3628 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003629 1 / 0
3630 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003631 exc = e
3632 self.adapter.exception(msg, self.recording)
3633
3634 self.assertEqual(len(self.recording.records), 1)
3635 record = self.recording.records[0]
3636 self.assertEqual(record.levelno, logging.ERROR)
3637 self.assertEqual(record.msg, msg)
3638 self.assertEqual(record.args, (self.recording,))
3639 self.assertEqual(record.exc_info,
3640 (exc.__class__, exc, exc.__traceback__))
3641
3642 def test_critical(self):
3643 msg = 'critical test! %r'
3644 self.adapter.critical(msg, self.recording)
3645
3646 self.assertEqual(len(self.recording.records), 1)
3647 record = self.recording.records[0]
3648 self.assertEqual(record.levelno, logging.CRITICAL)
3649 self.assertEqual(record.msg, msg)
3650 self.assertEqual(record.args, (self.recording,))
3651
3652 def test_is_enabled_for(self):
3653 old_disable = self.adapter.logger.manager.disable
3654 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003655 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3656 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003657 self.assertFalse(self.adapter.isEnabledFor(32))
3658
3659 def test_has_handlers(self):
3660 self.assertTrue(self.adapter.hasHandlers())
3661
3662 for handler in self.logger.handlers:
3663 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003664
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003665 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003666 self.assertFalse(self.adapter.hasHandlers())
3667
3668
3669class LoggerTest(BaseTest):
3670
3671 def setUp(self):
3672 super(LoggerTest, self).setUp()
3673 self.recording = RecordingHandler()
3674 self.logger = logging.Logger(name='blah')
3675 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003676 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003677 self.addCleanup(self.recording.close)
3678 self.addCleanup(logging.shutdown)
3679
3680 def test_set_invalid_level(self):
3681 self.assertRaises(TypeError, self.logger.setLevel, object())
3682
3683 def test_exception(self):
3684 msg = 'testing exception: %r'
3685 exc = None
3686 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003687 1 / 0
3688 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003689 exc = e
3690 self.logger.exception(msg, self.recording)
3691
3692 self.assertEqual(len(self.recording.records), 1)
3693 record = self.recording.records[0]
3694 self.assertEqual(record.levelno, logging.ERROR)
3695 self.assertEqual(record.msg, msg)
3696 self.assertEqual(record.args, (self.recording,))
3697 self.assertEqual(record.exc_info,
3698 (exc.__class__, exc, exc.__traceback__))
3699
3700 def test_log_invalid_level_with_raise(self):
3701 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003702 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003703
3704 logging.raiseExceptions = True
3705 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3706
3707 def test_log_invalid_level_no_raise(self):
3708 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003709 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003710
3711 logging.raiseExceptions = False
3712 self.logger.log('10', 'test message') # no exception happens
3713
3714 def test_find_caller_with_stack_info(self):
3715 called = []
3716 patch(self, logging.traceback, 'print_stack',
3717 lambda f, file: called.append(file.getvalue()))
3718
3719 self.logger.findCaller(stack_info=True)
3720
3721 self.assertEqual(len(called), 1)
3722 self.assertEqual('Stack (most recent call last):\n', called[0])
3723
3724 def test_make_record_with_extra_overwrite(self):
3725 name = 'my record'
3726 level = 13
3727 fn = lno = msg = args = exc_info = func = sinfo = None
3728 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3729 exc_info, func, sinfo)
3730
3731 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3732 extra = {key: 'some value'}
3733 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3734 fn, lno, msg, args, exc_info,
3735 extra=extra, sinfo=sinfo)
3736
3737 def test_make_record_with_extra_no_overwrite(self):
3738 name = 'my record'
3739 level = 13
3740 fn = lno = msg = args = exc_info = func = sinfo = None
3741 extra = {'valid_key': 'some value'}
3742 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3743 exc_info, extra=extra, sinfo=sinfo)
3744 self.assertIn('valid_key', result.__dict__)
3745
3746 def test_has_handlers(self):
3747 self.assertTrue(self.logger.hasHandlers())
3748
3749 for handler in self.logger.handlers:
3750 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751 self.assertFalse(self.logger.hasHandlers())
3752
3753 def test_has_handlers_no_propagate(self):
3754 child_logger = logging.getLogger('blah.child')
3755 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003756 self.assertFalse(child_logger.hasHandlers())
3757
3758 def test_is_enabled_for(self):
3759 old_disable = self.logger.manager.disable
3760 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003761 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003762 self.assertFalse(self.logger.isEnabledFor(22))
3763
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003764 def test_root_logger_aliases(self):
3765 root = logging.getLogger()
3766 self.assertIs(root, logging.root)
3767 self.assertIs(root, logging.getLogger(None))
3768 self.assertIs(root, logging.getLogger(''))
3769 self.assertIs(root, logging.getLogger('foo').root)
3770 self.assertIs(root, logging.getLogger('foo.bar').root)
3771 self.assertIs(root, logging.getLogger('foo').parent)
3772
3773 self.assertIsNot(root, logging.getLogger('\0'))
3774 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3775
3776 def test_invalid_names(self):
3777 self.assertRaises(TypeError, logging.getLogger, any)
3778 self.assertRaises(TypeError, logging.getLogger, b'foo')
3779
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003780
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003781class BaseFileTest(BaseTest):
3782 "Base class for handler tests that write log files"
3783
3784 def setUp(self):
3785 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003786 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3787 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003788 self.rmfiles = []
3789
3790 def tearDown(self):
3791 for fn in self.rmfiles:
3792 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003793 if os.path.exists(self.fn):
3794 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003795 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003796
3797 def assertLogFile(self, filename):
3798 "Assert a log file is there and register it for deletion"
3799 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003800 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003801 self.rmfiles.append(filename)
3802
3803
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003804class FileHandlerTest(BaseFileTest):
3805 def test_delay(self):
3806 os.unlink(self.fn)
3807 fh = logging.FileHandler(self.fn, delay=True)
3808 self.assertIsNone(fh.stream)
3809 self.assertFalse(os.path.exists(self.fn))
3810 fh.handle(logging.makeLogRecord({}))
3811 self.assertIsNotNone(fh.stream)
3812 self.assertTrue(os.path.exists(self.fn))
3813 fh.close()
3814
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003815class RotatingFileHandlerTest(BaseFileTest):
3816 def next_rec(self):
3817 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3818 self.next_message(), None, None, None)
3819
3820 def test_should_not_rollover(self):
3821 # If maxbytes is zero rollover never occurs
3822 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3823 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003824 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003825
3826 def test_should_rollover(self):
3827 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3828 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003829 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003830
3831 def test_file_created(self):
3832 # checks that the file is created and assumes it was created
3833 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003834 rh = logging.handlers.RotatingFileHandler(self.fn)
3835 rh.emit(self.next_rec())
3836 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003837 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003838
3839 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003840 def namer(name):
3841 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003842 rh = logging.handlers.RotatingFileHandler(
3843 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003844 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003845 rh.emit(self.next_rec())
3846 self.assertLogFile(self.fn)
3847 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003848 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003849 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003850 self.assertLogFile(namer(self.fn + ".2"))
3851 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3852 rh.close()
3853
Eric V. Smith851cad72012-03-11 22:46:04 -07003854 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003855 def test_rotator(self):
3856 def namer(name):
3857 return name + ".gz"
3858
3859 def rotator(source, dest):
3860 with open(source, "rb") as sf:
3861 data = sf.read()
3862 compressed = zlib.compress(data, 9)
3863 with open(dest, "wb") as df:
3864 df.write(compressed)
3865 os.remove(source)
3866
3867 rh = logging.handlers.RotatingFileHandler(
3868 self.fn, backupCount=2, maxBytes=1)
3869 rh.rotator = rotator
3870 rh.namer = namer
3871 m1 = self.next_rec()
3872 rh.emit(m1)
3873 self.assertLogFile(self.fn)
3874 m2 = self.next_rec()
3875 rh.emit(m2)
3876 fn = namer(self.fn + ".1")
3877 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003878 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003879 with open(fn, "rb") as f:
3880 compressed = f.read()
3881 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003882 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003883 rh.emit(self.next_rec())
3884 fn = namer(self.fn + ".2")
3885 self.assertLogFile(fn)
3886 with open(fn, "rb") as f:
3887 compressed = f.read()
3888 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003889 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003890 rh.emit(self.next_rec())
3891 fn = namer(self.fn + ".2")
3892 with open(fn, "rb") as f:
3893 compressed = f.read()
3894 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003895 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003896 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003897 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003898
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003899class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003900 # other test methods added below
3901 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003902 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3903 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003904 fmt = logging.Formatter('%(asctime)s %(message)s')
3905 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003906 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003907 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003908 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003909 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003910 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003911 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003912 fh.close()
3913 # At this point, we should have a recent rotated file which we
3914 # can test for the existence of. However, in practice, on some
3915 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003916 # in time to go to look for the log file. So, we go back a fair
3917 # bit, and stop as soon as we see a rotated file. In theory this
3918 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003919 found = False
3920 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003921 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003922 for secs in range(GO_BACK):
3923 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003924 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3925 found = os.path.exists(fn)
3926 if found:
3927 self.rmfiles.append(fn)
3928 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003929 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3930 if not found:
3931 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003932 dn, fn = os.path.split(self.fn)
3933 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003934 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3935 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003936 for f in files:
3937 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003938 path = os.path.join(dn, f)
3939 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003940 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003941 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003942
Vinay Sajip0372e102011-05-05 12:59:14 +01003943 def test_invalid(self):
3944 assertRaises = self.assertRaises
3945 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003946 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003947 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003948 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003949 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003950 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003951
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003952def secs(**kw):
3953 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3954
3955for when, exp in (('S', 1),
3956 ('M', 60),
3957 ('H', 60 * 60),
3958 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003959 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003960 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003961 ('W0', secs(days=4, hours=24)),
3962 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003963 def test_compute_rollover(self, when=when, exp=exp):
3964 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003965 self.fn, when=when, interval=1, backupCount=0, utc=True)
3966 currentTime = 0.0
3967 actual = rh.computeRollover(currentTime)
3968 if exp != actual:
3969 # Failures occur on some systems for MIDNIGHT and W0.
3970 # Print detailed calculation for MIDNIGHT so we can try to see
3971 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00003972 if when == 'MIDNIGHT':
3973 try:
3974 if rh.utc:
3975 t = time.gmtime(currentTime)
3976 else:
3977 t = time.localtime(currentTime)
3978 currentHour = t[3]
3979 currentMinute = t[4]
3980 currentSecond = t[5]
3981 # r is the number of seconds left between now and midnight
3982 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3983 currentMinute) * 60 +
3984 currentSecond)
3985 result = currentTime + r
3986 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3987 print('currentHour: %s' % currentHour, file=sys.stderr)
3988 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3989 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3990 print('r: %s' % r, file=sys.stderr)
3991 print('result: %s' % result, file=sys.stderr)
3992 except Exception:
3993 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3994 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003995 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003996 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3997
Vinay Sajip60ccd822011-05-09 17:32:09 +01003998
3999@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4000class NTEventLogHandlerTest(BaseTest):
4001 def test_basic(self):
4002 logtype = 'Application'
4003 elh = win32evtlog.OpenEventLog(None, logtype)
4004 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4005 h = logging.handlers.NTEventLogHandler('test_logging')
4006 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4007 h.handle(r)
4008 h.close()
4009 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004010 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004011 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4012 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4013 found = False
4014 GO_BACK = 100
4015 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4016 for e in events:
4017 if e.SourceName != 'test_logging':
4018 continue
4019 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4020 if msg != 'Test Log Message\r\n':
4021 continue
4022 found = True
4023 break
4024 msg = 'Record not found in event log, went back %d records' % GO_BACK
4025 self.assertTrue(found, msg=msg)
4026
Christian Heimes180510d2008-03-03 19:15:45 +00004027# Set the locale to the platform-dependent default. I have no idea
4028# why the test does this, but in any case we save the current locale
4029# first and restore it at the end.
4030@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004031def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004032 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004033 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004034 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4035 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4036 ManagerTest, FormatterTest, BufferingFormatterTest,
4037 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4038 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4039 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4040 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004041 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004042 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00004043 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004044 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004045
Christian Heimes180510d2008-03-03 19:15:45 +00004046if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004047 test_main()