blob: ddab2e0ecd53a01d1f6e391fcbcdf434970b82f3 [file] [log] [blame]
Vinay Sajip3f885b52013-03-22 15:19:54 +00001# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip3f885b52013-03-22 15:19:54 +000019Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000029import pickle
30import io
31import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000032import json
Christian Heimes180510d2008-03-03 19:15:45 +000033import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000034import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010035import random
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000037import select
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Antoine Pitrou712cb732013-12-21 15:51:54 +010042from test.script_helper import assert_python_ok
Eric V. Smith851cad72012-03-11 22:46:04 -070043from test.support import (captured_stdout, run_with_locale, run_unittest,
Serhiy Storchaka750eae12015-07-21 22:39:26 +030044 patch, requires_zlib, TestHandler, Matcher, HOST,
45 swap_attr)
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,
Vinay Sajip5421f352013-09-27 18:18:28 +010062 ThreadingTCPServer, StreamRequestHandler,
63 ThreadingUnixStreamServer,
64 ThreadingUnixDatagramServer)
Victor Stinner45df8202010-04-28 22:31:17 +000065except ImportError:
66 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010067try:
68 import win32evtlog
69except ImportError:
70 win32evtlog = None
71try:
72 import win32evtlogutil
73except ImportError:
74 win32evtlogutil = None
75 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070076try:
77 import zlib
78except ImportError:
79 pass
Christian Heimes18c66892008-02-17 13:31:39 +000080
Christian Heimes180510d2008-03-03 19:15:45 +000081class BaseTest(unittest.TestCase):
82
83 """Base class for logging tests."""
84
85 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030086 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000087 message_num = 0
88
89 def setUp(self):
90 """Setup the default logging stream to an internal StringIO instance,
91 so that we can examine log output as we want."""
92 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000093 logging._acquireLock()
94 try:
Christian Heimes180510d2008-03-03 19:15:45 +000095 self.saved_handlers = logging._handlers.copy()
96 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000097 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070098 self.saved_name_to_level = logging._nameToLevel.copy()
99 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000100 self.logger_states = logger_states = {}
101 for name in saved_loggers:
102 logger_states[name] = getattr(saved_loggers[name],
103 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000104 finally:
105 logging._releaseLock()
106
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100107 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000108 self.logger1 = logging.getLogger("\xab\xd7\xbb")
109 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000110
Christian Heimes180510d2008-03-03 19:15:45 +0000111 self.root_logger = logging.getLogger("")
112 self.original_logging_level = self.root_logger.getEffectiveLevel()
113
114 self.stream = io.StringIO()
115 self.root_logger.setLevel(logging.DEBUG)
116 self.root_hdlr = logging.StreamHandler(self.stream)
117 self.root_formatter = logging.Formatter(self.log_format)
118 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000119 if self.logger1.hasHandlers():
120 hlist = self.logger1.handlers + self.root_logger.handlers
121 raise AssertionError('Unexpected handlers: %s' % hlist)
122 if self.logger2.hasHandlers():
123 hlist = self.logger2.handlers + self.root_logger.handlers
124 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000125 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000126 self.assertTrue(self.logger1.hasHandlers())
127 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000128
129 def tearDown(self):
130 """Remove our logging stream, and restore the original logging
131 level."""
132 self.stream.close()
133 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000134 while self.root_logger.handlers:
135 h = self.root_logger.handlers[0]
136 self.root_logger.removeHandler(h)
137 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000138 self.root_logger.setLevel(self.original_logging_level)
139 logging._acquireLock()
140 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700141 logging._levelToName.clear()
142 logging._levelToName.update(self.saved_level_to_name)
143 logging._nameToLevel.clear()
144 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000145 logging._handlers.clear()
146 logging._handlers.update(self.saved_handlers)
147 logging._handlerList[:] = self.saved_handler_list
148 loggerDict = logging.getLogger().manager.loggerDict
149 loggerDict.clear()
150 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000151 logger_states = self.logger_states
152 for name in self.logger_states:
153 if logger_states[name] is not None:
154 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000155 finally:
156 logging._releaseLock()
157
Vinay Sajip4ded5512012-10-02 15:56:16 +0100158 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000159 """Match the collected log lines against the regular expression
160 self.expected_log_pat, and compare the extracted group values to
161 the expected_values list of tuples."""
162 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100163 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300164 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100165 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000166 for actual, expected in zip(actual_lines, expected_values):
167 match = pat.search(actual)
168 if not match:
169 self.fail("Log line does not match expected pattern:\n" +
170 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000171 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000172 s = stream.read()
173 if s:
174 self.fail("Remaining output at end of log stream:\n" + s)
175
176 def next_message(self):
177 """Generate a message consisting solely of an auto-incrementing
178 integer."""
179 self.message_num += 1
180 return "%d" % self.message_num
181
182
183class BuiltinLevelsTest(BaseTest):
184 """Test builtin levels and their inheritance."""
185
186 def test_flat(self):
187 #Logging levels in a flat logger namespace.
188 m = self.next_message
189
190 ERR = logging.getLogger("ERR")
191 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000192 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000193 INF.setLevel(logging.INFO)
194 DEB = logging.getLogger("DEB")
195 DEB.setLevel(logging.DEBUG)
196
197 # These should log.
198 ERR.log(logging.CRITICAL, m())
199 ERR.error(m())
200
201 INF.log(logging.CRITICAL, m())
202 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100203 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 INF.info(m())
205
206 DEB.log(logging.CRITICAL, m())
207 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100208 DEB.warning(m())
209 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000210 DEB.debug(m())
211
212 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100213 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000214 ERR.info(m())
215 ERR.debug(m())
216
217 INF.debug(m())
218
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000219 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000220 ('ERR', 'CRITICAL', '1'),
221 ('ERR', 'ERROR', '2'),
222 ('INF', 'CRITICAL', '3'),
223 ('INF', 'ERROR', '4'),
224 ('INF', 'WARNING', '5'),
225 ('INF', 'INFO', '6'),
226 ('DEB', 'CRITICAL', '7'),
227 ('DEB', 'ERROR', '8'),
228 ('DEB', 'WARNING', '9'),
229 ('DEB', 'INFO', '10'),
230 ('DEB', 'DEBUG', '11'),
231 ])
232
233 def test_nested_explicit(self):
234 # Logging levels in a nested namespace, all explicitly set.
235 m = self.next_message
236
237 INF = logging.getLogger("INF")
238 INF.setLevel(logging.INFO)
239 INF_ERR = logging.getLogger("INF.ERR")
240 INF_ERR.setLevel(logging.ERROR)
241
242 # These should log.
243 INF_ERR.log(logging.CRITICAL, m())
244 INF_ERR.error(m())
245
246 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100247 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000248 INF_ERR.info(m())
249 INF_ERR.debug(m())
250
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000251 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000252 ('INF.ERR', 'CRITICAL', '1'),
253 ('INF.ERR', 'ERROR', '2'),
254 ])
255
256 def test_nested_inherited(self):
257 #Logging levels in a nested namespace, inherited from parent loggers.
258 m = self.next_message
259
260 INF = logging.getLogger("INF")
261 INF.setLevel(logging.INFO)
262 INF_ERR = logging.getLogger("INF.ERR")
263 INF_ERR.setLevel(logging.ERROR)
264 INF_UNDEF = logging.getLogger("INF.UNDEF")
265 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
266 UNDEF = logging.getLogger("UNDEF")
267
268 # These should log.
269 INF_UNDEF.log(logging.CRITICAL, m())
270 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100271 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000272 INF_UNDEF.info(m())
273 INF_ERR_UNDEF.log(logging.CRITICAL, m())
274 INF_ERR_UNDEF.error(m())
275
276 # These should not log.
277 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100278 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000279 INF_ERR_UNDEF.info(m())
280 INF_ERR_UNDEF.debug(m())
281
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000282 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000283 ('INF.UNDEF', 'CRITICAL', '1'),
284 ('INF.UNDEF', 'ERROR', '2'),
285 ('INF.UNDEF', 'WARNING', '3'),
286 ('INF.UNDEF', 'INFO', '4'),
287 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
288 ('INF.ERR.UNDEF', 'ERROR', '6'),
289 ])
290
291 def test_nested_with_virtual_parent(self):
292 # Logging levels when some parent does not exist yet.
293 m = self.next_message
294
295 INF = logging.getLogger("INF")
296 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
297 CHILD = logging.getLogger("INF.BADPARENT")
298 INF.setLevel(logging.INFO)
299
300 # These should log.
301 GRANDCHILD.log(logging.FATAL, m())
302 GRANDCHILD.info(m())
303 CHILD.log(logging.FATAL, m())
304 CHILD.info(m())
305
306 # These should not log.
307 GRANDCHILD.debug(m())
308 CHILD.debug(m())
309
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000310 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000311 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
312 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
313 ('INF.BADPARENT', 'CRITICAL', '3'),
314 ('INF.BADPARENT', 'INFO', '4'),
315 ])
316
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100317 def test_regression_22386(self):
318 """See issue #22386 for more information."""
319 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
320 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000321
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)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000597 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100598 except OSError:
599 pass
600 time.sleep(0.004 * random.randint(0, 4))
601
Vinay Sajipc94871a2012-04-25 10:51:35 +0100602 del_count = 500
603 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100604
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000605 self.handle_time = None
606 self.deletion_time = None
607
Vinay Sajipa5798de2012-04-24 23:33:33 +0100608 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100609 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
610 os.close(fd)
611 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
612 remover.daemon = True
613 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100614 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100615 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
616 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100617 try:
618 for _ in range(log_count):
619 time.sleep(0.005)
620 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000621 try:
622 self.handle_time = time.time()
623 h.handle(r)
624 except Exception:
625 print('Deleted at %s, '
626 'opened at %s' % (self.deletion_time,
627 self.handle_time))
628 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100629 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100630 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100631 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100632 if os.path.exists(fn):
633 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100634
635
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100636class BadStream(object):
637 def write(self, data):
638 raise RuntimeError('deliberate mistake')
639
640class TestStreamHandler(logging.StreamHandler):
641 def handleError(self, record):
642 self.error_record = record
643
644class StreamHandlerTest(BaseTest):
645 def test_error_handling(self):
646 h = TestStreamHandler(BadStream())
647 r = logging.makeLogRecord({})
648 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100649 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100650 try:
651 h.handle(r)
652 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100653 h = logging.StreamHandler(BadStream())
654 sys.stderr = sio = io.StringIO()
655 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100656 self.assertIn('\nRuntimeError: deliberate mistake\n',
657 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100658 logging.raiseExceptions = False
659 sys.stderr = sio = io.StringIO()
660 h.handle(r)
661 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100662 finally:
663 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100664 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100665
Vinay Sajip7367d082011-05-02 13:17:27 +0100666# -- The following section could be moved into a server_helper.py module
667# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100668
Vinay Sajipce7c9782011-05-17 07:15:53 +0100669if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100670 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100671 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100672 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100673
Vinay Sajipce7c9782011-05-17 07:15:53 +0100674 :param addr: A (host, port) tuple which the server listens on.
675 You can specify a port value of zero: the server's
676 *port* attribute will hold the actual port number
677 used, which can be used in client connections.
678 :param handler: A callable which will be called to process
679 incoming messages. The handler will be passed
680 the client address tuple, who the message is from,
681 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100682 :param poll_interval: The interval, in seconds, used in the underlying
683 :func:`select` or :func:`poll` call by
684 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100685 :param sockmap: A dictionary which will be used to hold
686 :class:`asyncore.dispatcher` instances used by
687 :func:`asyncore.loop`. This avoids changing the
688 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100689 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100690
691 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100692 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
693 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100694 self._handler = handler
695 self._thread = None
696 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100697
Vinay Sajipce7c9782011-05-17 07:15:53 +0100698 def process_message(self, peer, mailfrom, rcpttos, data):
699 """
700 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100701
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702 Typically, this will be a test case method.
703 :param peer: The client (host, port) tuple.
704 :param mailfrom: The address of the sender.
705 :param rcpttos: The addresses of the recipients.
706 :param data: The message.
707 """
708 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100709
Vinay Sajipce7c9782011-05-17 07:15:53 +0100710 def start(self):
711 """
712 Start the server running on a separate daemon thread.
713 """
714 self._thread = t = threading.Thread(target=self.serve_forever,
715 args=(self.poll_interval,))
716 t.setDaemon(True)
717 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100718
Vinay Sajipce7c9782011-05-17 07:15:53 +0100719 def serve_forever(self, poll_interval):
720 """
721 Run the :mod:`asyncore` loop until normal termination
722 conditions arise.
723 :param poll_interval: The interval, in seconds, used in the underlying
724 :func:`select` or :func:`poll` call by
725 :func:`asyncore.loop`.
726 """
727 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100728 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200729 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100730 # On FreeBSD 8, closing the server repeatably
731 # raises this error. We swallow it if the
732 # server has been closed.
733 if self.connected or self.accepting:
734 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 def stop(self, timeout=None):
737 """
738 Stop the thread by closing the server instance.
739 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100740
Vinay Sajipce7c9782011-05-17 07:15:53 +0100741 :param timeout: How long to wait for the server thread
742 to terminate.
743 """
744 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100745 self._thread.join(timeout)
746 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100747
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 class ControlMixin(object):
749 """
750 This mixin is used to start a server on a separate thread, and
751 shut it down programmatically. Request handling is simplified - instead
752 of needing to derive a suitable RequestHandler subclass, you just
753 provide a callable which will be passed each received request to be
754 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100755
Vinay Sajipce7c9782011-05-17 07:15:53 +0100756 :param handler: A handler callable which will be called with a
757 single parameter - the request - in order to
758 process the request. This handler is called on the
759 server thread, effectively meaning that requests are
760 processed serially. While not quite Web scale ;-),
761 this should be fine for testing applications.
762 :param poll_interval: The polling interval in seconds.
763 """
764 def __init__(self, handler, poll_interval):
765 self._thread = None
766 self.poll_interval = poll_interval
767 self._handler = handler
768 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def start(self):
771 """
772 Create a daemon thread to run the server, and start it.
773 """
774 self._thread = t = threading.Thread(target=self.serve_forever,
775 args=(self.poll_interval,))
776 t.setDaemon(True)
777 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100778
Vinay Sajipce7c9782011-05-17 07:15:53 +0100779 def serve_forever(self, poll_interval):
780 """
781 Run the server. Set the ready flag before entering the
782 service loop.
783 """
784 self.ready.set()
785 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100786
Vinay Sajipce7c9782011-05-17 07:15:53 +0100787 def stop(self, timeout=None):
788 """
789 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100790
Vinay Sajipce7c9782011-05-17 07:15:53 +0100791 :param timeout: How long to wait for the server thread
792 to terminate.
793 """
794 self.shutdown()
795 if self._thread is not None:
796 self._thread.join(timeout)
797 self._thread = None
798 self.server_close()
799 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100800
Vinay Sajipce7c9782011-05-17 07:15:53 +0100801 class TestHTTPServer(ControlMixin, HTTPServer):
802 """
803 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100804
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 :param addr: A tuple with the IP address and port to listen on.
806 :param handler: A handler callable which will be called with a
807 single parameter - the request - in order to
808 process the request.
809 :param poll_interval: The polling interval in seconds.
810 :param log: Pass ``True`` to enable log messages.
811 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100812 def __init__(self, addr, handler, poll_interval=0.5,
813 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
815 def __getattr__(self, name, default=None):
816 if name.startswith('do_'):
817 return self.process_request
818 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100819
Vinay Sajipce7c9782011-05-17 07:15:53 +0100820 def process_request(self):
821 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100822
Vinay Sajipce7c9782011-05-17 07:15:53 +0100823 def log_message(self, format, *args):
824 if log:
825 super(DelegatingHTTPRequestHandler,
826 self).log_message(format, *args)
827 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
828 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100829 self.sslctx = sslctx
830
831 def get_request(self):
832 try:
833 sock, addr = self.socket.accept()
834 if self.sslctx:
835 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200836 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100837 # socket errors are silenced by the caller, print them here
838 sys.stderr.write("Got an error:\n%s\n" % e)
839 raise
840 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100841
Vinay Sajipce7c9782011-05-17 07:15:53 +0100842 class TestTCPServer(ControlMixin, ThreadingTCPServer):
843 """
844 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100845
Vinay Sajipce7c9782011-05-17 07:15:53 +0100846 :param addr: A tuple with the IP address and port to listen on.
847 :param handler: A handler callable which will be called with a single
848 parameter - the request - in order to process the request.
849 :param poll_interval: The polling interval in seconds.
850 :bind_and_activate: If True (the default), binds the server and starts it
851 listening. If False, you need to call
852 :meth:`server_bind` and :meth:`server_activate` at
853 some later time before calling :meth:`start`, so that
854 the server will set up the socket and listen on it.
855 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100856
Vinay Sajipce7c9782011-05-17 07:15:53 +0100857 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100858
Vinay Sajipce7c9782011-05-17 07:15:53 +0100859 def __init__(self, addr, handler, poll_interval=0.5,
860 bind_and_activate=True):
861 class DelegatingTCPRequestHandler(StreamRequestHandler):
862
863 def handle(self):
864 self.server._handler(self)
865 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
866 bind_and_activate)
867 ControlMixin.__init__(self, handler, poll_interval)
868
869 def server_bind(self):
870 super(TestTCPServer, self).server_bind()
871 self.port = self.socket.getsockname()[1]
872
873 class TestUDPServer(ControlMixin, ThreadingUDPServer):
874 """
875 A UDP server which is controllable using :class:`ControlMixin`.
876
877 :param addr: A tuple with the IP address and port to listen on.
878 :param handler: A handler callable which will be called with a
879 single parameter - the request - in order to
880 process the request.
881 :param poll_interval: The polling interval for shutdown requests,
882 in seconds.
883 :bind_and_activate: If True (the default), binds the server and
884 starts it listening. If False, you need to
885 call :meth:`server_bind` and
886 :meth:`server_activate` at some later time
887 before calling :meth:`start`, so that the server will
888 set up the socket and listen on it.
889 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 def __init__(self, addr, handler, poll_interval=0.5,
891 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100892 class DelegatingUDPRequestHandler(DatagramRequestHandler):
893
894 def handle(self):
895 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100896
897 def finish(self):
898 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100899 if data:
900 try:
901 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200902 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100903 if not self.server._closed:
904 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100905
Vinay Sajip3ef12292011-05-23 23:00:42 +0100906 ThreadingUDPServer.__init__(self, addr,
907 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100908 bind_and_activate)
909 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100910 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100911
912 def server_bind(self):
913 super(TestUDPServer, self).server_bind()
914 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100915
Vinay Sajipba980db2011-05-23 21:37:54 +0100916 def server_close(self):
917 super(TestUDPServer, self).server_close()
918 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100919
Victor Stinnerec5a8602014-06-02 14:41:51 +0200920 if hasattr(socket, "AF_UNIX"):
921 class TestUnixStreamServer(TestTCPServer):
922 address_family = socket.AF_UNIX
923
924 class TestUnixDatagramServer(TestUDPServer):
925 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100926
Vinay Sajip7367d082011-05-02 13:17:27 +0100927# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100928
Vinay Sajipce7c9782011-05-17 07:15:53 +0100929@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100930class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000931 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100932 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100933 sockmap = {}
Ned Deily3bbb37e2015-01-17 17:31:13 -0800934 server = TestSMTPServer((HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100935 sockmap)
936 server.start()
Ned Deily3bbb37e2015-01-17 17:31:13 -0800937 addr = (HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000938 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
939 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100940 self.assertEqual(h.toaddrs, ['you'])
941 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100942 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100943 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100944 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000945 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100946 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000947 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100948 self.assertEqual(len(self.messages), 1)
949 peer, mailfrom, rcpttos, data = self.messages[0]
950 self.assertEqual(mailfrom, 'me')
951 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100952 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100953 self.assertTrue(data.endswith('\n\nHello'))
954 h.close()
955
956 def process_message(self, *args):
957 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100958 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100959
Christian Heimes180510d2008-03-03 19:15:45 +0000960class MemoryHandlerTest(BaseTest):
961
962 """Tests for the MemoryHandler."""
963
964 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300965 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000966
967 def setUp(self):
968 BaseTest.setUp(self)
969 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
970 self.root_hdlr)
971 self.mem_logger = logging.getLogger('mem')
972 self.mem_logger.propagate = 0
973 self.mem_logger.addHandler(self.mem_hdlr)
974
975 def tearDown(self):
976 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000977 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000978
979 def test_flush(self):
980 # The memory handler flushes to its target handler based on specific
981 # criteria (message count and message level).
982 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000983 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000984 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000985 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000986 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100987 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000988 lines = [
989 ('DEBUG', '1'),
990 ('INFO', '2'),
991 ('WARNING', '3'),
992 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000993 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000994 for n in (4, 14):
995 for i in range(9):
996 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000997 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000998 # This will flush because it's the 10th message since the last
999 # flush.
1000 self.mem_logger.debug(self.next_message())
1001 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001002 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001003
1004 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001005 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001006
1007
1008class ExceptionFormatter(logging.Formatter):
1009 """A special exception formatter."""
1010 def formatException(self, ei):
1011 return "Got a [%s]" % ei[0].__name__
1012
1013
1014class ConfigFileTest(BaseTest):
1015
1016 """Reading logging config from a .ini-style config file."""
1017
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001018 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001019
1020 # config0 is a standard configuration.
1021 config0 = """
1022 [loggers]
1023 keys=root
1024
1025 [handlers]
1026 keys=hand1
1027
1028 [formatters]
1029 keys=form1
1030
1031 [logger_root]
1032 level=WARNING
1033 handlers=hand1
1034
1035 [handler_hand1]
1036 class=StreamHandler
1037 level=NOTSET
1038 formatter=form1
1039 args=(sys.stdout,)
1040
1041 [formatter_form1]
1042 format=%(levelname)s ++ %(message)s
1043 datefmt=
1044 """
1045
1046 # config1 adds a little to the standard configuration.
1047 config1 = """
1048 [loggers]
1049 keys=root,parser
1050
1051 [handlers]
1052 keys=hand1
1053
1054 [formatters]
1055 keys=form1
1056
1057 [logger_root]
1058 level=WARNING
1059 handlers=
1060
1061 [logger_parser]
1062 level=DEBUG
1063 handlers=hand1
1064 propagate=1
1065 qualname=compiler.parser
1066
1067 [handler_hand1]
1068 class=StreamHandler
1069 level=NOTSET
1070 formatter=form1
1071 args=(sys.stdout,)
1072
1073 [formatter_form1]
1074 format=%(levelname)s ++ %(message)s
1075 datefmt=
1076 """
1077
Vinay Sajip3f84b072011-03-07 17:49:33 +00001078 # config1a moves the handler to the root.
1079 config1a = """
1080 [loggers]
1081 keys=root,parser
1082
1083 [handlers]
1084 keys=hand1
1085
1086 [formatters]
1087 keys=form1
1088
1089 [logger_root]
1090 level=WARNING
1091 handlers=hand1
1092
1093 [logger_parser]
1094 level=DEBUG
1095 handlers=
1096 propagate=1
1097 qualname=compiler.parser
1098
1099 [handler_hand1]
1100 class=StreamHandler
1101 level=NOTSET
1102 formatter=form1
1103 args=(sys.stdout,)
1104
1105 [formatter_form1]
1106 format=%(levelname)s ++ %(message)s
1107 datefmt=
1108 """
1109
Christian Heimes180510d2008-03-03 19:15:45 +00001110 # config2 has a subtle configuration error that should be reported
1111 config2 = config1.replace("sys.stdout", "sys.stbout")
1112
1113 # config3 has a less subtle configuration error
1114 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1115
1116 # config4 specifies a custom formatter class to be loaded
1117 config4 = """
1118 [loggers]
1119 keys=root
1120
1121 [handlers]
1122 keys=hand1
1123
1124 [formatters]
1125 keys=form1
1126
1127 [logger_root]
1128 level=NOTSET
1129 handlers=hand1
1130
1131 [handler_hand1]
1132 class=StreamHandler
1133 level=NOTSET
1134 formatter=form1
1135 args=(sys.stdout,)
1136
1137 [formatter_form1]
1138 class=""" + __name__ + """.ExceptionFormatter
1139 format=%(levelname)s:%(name)s:%(message)s
1140 datefmt=
1141 """
1142
Georg Brandl3dbca812008-07-23 16:10:53 +00001143 # config5 specifies a custom handler class to be loaded
1144 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1145
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001146 # config6 uses ', ' delimiters in the handlers and formatters sections
1147 config6 = """
1148 [loggers]
1149 keys=root,parser
1150
1151 [handlers]
1152 keys=hand1, hand2
1153
1154 [formatters]
1155 keys=form1, form2
1156
1157 [logger_root]
1158 level=WARNING
1159 handlers=
1160
1161 [logger_parser]
1162 level=DEBUG
1163 handlers=hand1
1164 propagate=1
1165 qualname=compiler.parser
1166
1167 [handler_hand1]
1168 class=StreamHandler
1169 level=NOTSET
1170 formatter=form1
1171 args=(sys.stdout,)
1172
1173 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001174 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001175 level=NOTSET
1176 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001177 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001178
1179 [formatter_form1]
1180 format=%(levelname)s ++ %(message)s
1181 datefmt=
1182
1183 [formatter_form2]
1184 format=%(message)s
1185 datefmt=
1186 """
1187
Vinay Sajip3f84b072011-03-07 17:49:33 +00001188 # config7 adds a compiler logger.
1189 config7 = """
1190 [loggers]
1191 keys=root,parser,compiler
1192
1193 [handlers]
1194 keys=hand1
1195
1196 [formatters]
1197 keys=form1
1198
1199 [logger_root]
1200 level=WARNING
1201 handlers=hand1
1202
1203 [logger_compiler]
1204 level=DEBUG
1205 handlers=
1206 propagate=1
1207 qualname=compiler
1208
1209 [logger_parser]
1210 level=DEBUG
1211 handlers=
1212 propagate=1
1213 qualname=compiler.parser
1214
1215 [handler_hand1]
1216 class=StreamHandler
1217 level=NOTSET
1218 formatter=form1
1219 args=(sys.stdout,)
1220
1221 [formatter_form1]
1222 format=%(levelname)s ++ %(message)s
1223 datefmt=
1224 """
1225
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001226 disable_test = """
1227 [loggers]
1228 keys=root
1229
1230 [handlers]
1231 keys=screen
1232
1233 [formatters]
1234 keys=
1235
1236 [logger_root]
1237 level=DEBUG
1238 handlers=screen
1239
1240 [handler_screen]
1241 level=DEBUG
1242 class=StreamHandler
1243 args=(sys.stdout,)
1244 formatter=
1245 """
1246
1247 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001248 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001249 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001250
1251 def test_config0_ok(self):
1252 # A simple config file which overrides the default settings.
1253 with captured_stdout() as output:
1254 self.apply_config(self.config0)
1255 logger = logging.getLogger()
1256 # Won't output anything
1257 logger.info(self.next_message())
1258 # Outputs a message
1259 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001260 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001261 ('ERROR', '2'),
1262 ], stream=output)
1263 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001264 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001265
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001266 def test_config0_using_cp_ok(self):
1267 # A simple config file which overrides the default settings.
1268 with captured_stdout() as output:
1269 file = io.StringIO(textwrap.dedent(self.config0))
1270 cp = configparser.ConfigParser()
1271 cp.read_file(file)
1272 logging.config.fileConfig(cp)
1273 logger = logging.getLogger()
1274 # Won't output anything
1275 logger.info(self.next_message())
1276 # Outputs a message
1277 logger.error(self.next_message())
1278 self.assert_log_lines([
1279 ('ERROR', '2'),
1280 ], stream=output)
1281 # Original logger output is empty.
1282 self.assert_log_lines([])
1283
Georg Brandl3dbca812008-07-23 16:10:53 +00001284 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001285 # A config file defining a sub-parser as well.
1286 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001287 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001288 logger = logging.getLogger("compiler.parser")
1289 # Both will output a message
1290 logger.info(self.next_message())
1291 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001292 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001293 ('INFO', '1'),
1294 ('ERROR', '2'),
1295 ], stream=output)
1296 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001297 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001298
1299 def test_config2_failure(self):
1300 # A simple config file which overrides the default settings.
1301 self.assertRaises(Exception, self.apply_config, self.config2)
1302
1303 def test_config3_failure(self):
1304 # A simple config file which overrides the default settings.
1305 self.assertRaises(Exception, self.apply_config, self.config3)
1306
1307 def test_config4_ok(self):
1308 # A config file specifying a custom formatter class.
1309 with captured_stdout() as output:
1310 self.apply_config(self.config4)
1311 logger = logging.getLogger()
1312 try:
1313 raise RuntimeError()
1314 except RuntimeError:
1315 logging.exception("just testing")
1316 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001317 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001318 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1319 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001320 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001321
Georg Brandl3dbca812008-07-23 16:10:53 +00001322 def test_config5_ok(self):
1323 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001324
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001325 def test_config6_ok(self):
1326 self.test_config1_ok(config=self.config6)
1327
Vinay Sajip3f84b072011-03-07 17:49:33 +00001328 def test_config7_ok(self):
1329 with captured_stdout() as output:
1330 self.apply_config(self.config1a)
1331 logger = logging.getLogger("compiler.parser")
1332 # See issue #11424. compiler-hyphenated sorts
1333 # between compiler and compiler.xyz and this
1334 # was preventing compiler.xyz from being included
1335 # in the child loggers of compiler because of an
1336 # overzealous loop termination condition.
1337 hyphenated = logging.getLogger('compiler-hyphenated')
1338 # All will output a message
1339 logger.info(self.next_message())
1340 logger.error(self.next_message())
1341 hyphenated.critical(self.next_message())
1342 self.assert_log_lines([
1343 ('INFO', '1'),
1344 ('ERROR', '2'),
1345 ('CRITICAL', '3'),
1346 ], stream=output)
1347 # Original logger output is empty.
1348 self.assert_log_lines([])
1349 with captured_stdout() as output:
1350 self.apply_config(self.config7)
1351 logger = logging.getLogger("compiler.parser")
1352 self.assertFalse(logger.disabled)
1353 # Both will output a message
1354 logger.info(self.next_message())
1355 logger.error(self.next_message())
1356 logger = logging.getLogger("compiler.lexer")
1357 # Both will output a message
1358 logger.info(self.next_message())
1359 logger.error(self.next_message())
1360 # Will not appear
1361 hyphenated.critical(self.next_message())
1362 self.assert_log_lines([
1363 ('INFO', '4'),
1364 ('ERROR', '5'),
1365 ('INFO', '6'),
1366 ('ERROR', '7'),
1367 ], stream=output)
1368 # Original logger output is empty.
1369 self.assert_log_lines([])
1370
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001371 def test_logger_disabling(self):
1372 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001373 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001374 self.assertFalse(logger.disabled)
1375 self.apply_config(self.disable_test)
1376 self.assertTrue(logger.disabled)
1377 self.apply_config(self.disable_test, disable_existing_loggers=False)
1378 self.assertFalse(logger.disabled)
1379
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001380
Victor Stinner45df8202010-04-28 22:31:17 +00001381@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001382class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001383
Christian Heimes180510d2008-03-03 19:15:45 +00001384 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001385
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001386 if threading:
1387 server_class = TestTCPServer
1388 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001389
Christian Heimes180510d2008-03-03 19:15:45 +00001390 def setUp(self):
1391 """Set up a TCP server to receive log messages, and a SocketHandler
1392 pointing to that server's address and port."""
1393 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001394 self.server = server = self.server_class(self.address,
1395 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001396 server.start()
1397 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001398 hcls = logging.handlers.SocketHandler
1399 if isinstance(server.server_address, tuple):
1400 self.sock_hdlr = hcls('localhost', server.port)
1401 else:
1402 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001403 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001404 self.root_logger.removeHandler(self.root_logger.handlers[0])
1405 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001406 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001407
Christian Heimes180510d2008-03-03 19:15:45 +00001408 def tearDown(self):
1409 """Shutdown the TCP server."""
1410 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001411 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001412 self.root_logger.removeHandler(self.sock_hdlr)
1413 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001414 finally:
1415 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001416
Vinay Sajip7367d082011-05-02 13:17:27 +01001417 def handle_socket(self, request):
1418 conn = request.connection
1419 while True:
1420 chunk = conn.recv(4)
1421 if len(chunk) < 4:
1422 break
1423 slen = struct.unpack(">L", chunk)[0]
1424 chunk = conn.recv(slen)
1425 while len(chunk) < slen:
1426 chunk = chunk + conn.recv(slen - len(chunk))
1427 obj = pickle.loads(chunk)
1428 record = logging.makeLogRecord(obj)
1429 self.log_output += record.msg + '\n'
1430 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001431
Christian Heimes180510d2008-03-03 19:15:45 +00001432 def test_output(self):
1433 # The log message sent to the SocketHandler is properly received.
1434 logger = logging.getLogger("tcp")
1435 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001436 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001437 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001438 self.handled.acquire()
1439 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001440
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001441 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001442 # Avoid timing-related failures due to SocketHandler's own hard-wired
1443 # one-second timeout on socket.create_connection() (issue #16264).
1444 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001445 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001446 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001447 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001448 try:
1449 raise RuntimeError('Deliberate mistake')
1450 except RuntimeError:
1451 self.root_logger.exception('Never sent')
1452 self.root_logger.error('Never sent, either')
1453 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001454 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001455 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1456 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001457
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001458def _get_temp_domain_socket():
1459 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1460 os.close(fd)
1461 # just need a name - file can't be present, or we'll get an
1462 # 'address already in use' error.
1463 os.remove(fn)
1464 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001465
Victor Stinnerec5a8602014-06-02 14:41:51 +02001466@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001467@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001468class UnixSocketHandlerTest(SocketHandlerTest):
1469
1470 """Test for SocketHandler with unix sockets."""
1471
Victor Stinnerec5a8602014-06-02 14:41:51 +02001472 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001473 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001474
1475 def setUp(self):
1476 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001477 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001478 SocketHandlerTest.setUp(self)
1479
1480 def tearDown(self):
1481 SocketHandlerTest.tearDown(self)
1482 os.remove(self.address)
1483
1484@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001485class DatagramHandlerTest(BaseTest):
1486
1487 """Test for DatagramHandler."""
1488
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001489 if threading:
1490 server_class = TestUDPServer
1491 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001492
Vinay Sajip7367d082011-05-02 13:17:27 +01001493 def setUp(self):
1494 """Set up a UDP server to receive log messages, and a DatagramHandler
1495 pointing to that server's address and port."""
1496 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001497 self.server = server = self.server_class(self.address,
1498 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 server.start()
1500 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001501 hcls = logging.handlers.DatagramHandler
1502 if isinstance(server.server_address, tuple):
1503 self.sock_hdlr = hcls('localhost', server.port)
1504 else:
1505 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001506 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
Victor Stinnerec5a8602014-06-02 14:41:51 +02001538@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001539@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001540class UnixDatagramHandlerTest(DatagramHandlerTest):
1541
1542 """Test for DatagramHandler using Unix sockets."""
1543
Victor Stinnerec5a8602014-06-02 14:41:51 +02001544 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001545 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001546
1547 def setUp(self):
1548 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001549 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001550 DatagramHandlerTest.setUp(self)
1551
1552 def tearDown(self):
1553 DatagramHandlerTest.tearDown(self)
1554 os.remove(self.address)
1555
1556@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001557class SysLogHandlerTest(BaseTest):
1558
1559 """Test for SysLogHandler using UDP."""
1560
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001561 if threading:
1562 server_class = TestUDPServer
1563 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001564
Vinay Sajip7367d082011-05-02 13:17:27 +01001565 def setUp(self):
1566 """Set up a UDP server to receive log messages, and a SysLogHandler
1567 pointing to that server's address and port."""
1568 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001569 self.server = server = self.server_class(self.address,
1570 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001571 server.start()
1572 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001573 hcls = logging.handlers.SysLogHandler
1574 if isinstance(server.server_address, tuple):
1575 self.sl_hdlr = hcls(('localhost', server.port))
1576 else:
1577 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001578 self.log_output = ''
1579 self.root_logger.removeHandler(self.root_logger.handlers[0])
1580 self.root_logger.addHandler(self.sl_hdlr)
1581 self.handled = threading.Event()
1582
1583 def tearDown(self):
1584 """Shutdown the UDP server."""
1585 try:
1586 self.server.stop(2.0)
1587 self.root_logger.removeHandler(self.sl_hdlr)
1588 self.sl_hdlr.close()
1589 finally:
1590 BaseTest.tearDown(self)
1591
1592 def handle_datagram(self, request):
1593 self.log_output = request.packet
1594 self.handled.set()
1595
1596 def test_output(self):
1597 # The log message sent to the SysLogHandler is properly received.
1598 logger = logging.getLogger("slh")
1599 logger.error("sp\xe4m")
1600 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001601 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001602 self.handled.clear()
1603 self.sl_hdlr.append_nul = False
1604 logger.error("sp\xe4m")
1605 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001606 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001607 self.handled.clear()
1608 self.sl_hdlr.ident = "h\xe4m-"
1609 logger.error("sp\xe4m")
1610 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001611 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001612
Victor Stinnerec5a8602014-06-02 14:41:51 +02001613@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001614@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001615class UnixSysLogHandlerTest(SysLogHandlerTest):
1616
1617 """Test for SysLogHandler with Unix sockets."""
1618
Victor Stinnerec5a8602014-06-02 14:41:51 +02001619 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001620 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001621
1622 def setUp(self):
1623 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001624 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001625 SysLogHandlerTest.setUp(self)
1626
1627 def tearDown(self):
1628 SysLogHandlerTest.tearDown(self)
1629 os.remove(self.address)
1630
Vinay Sajip5421f352013-09-27 18:18:28 +01001631@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001632class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001633 """Test for HTTPHandler."""
1634
1635 def setUp(self):
1636 """Set up an HTTP server to receive log messages, and a HTTPHandler
1637 pointing to that server's address and port."""
1638 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001639 self.handled = threading.Event()
1640
Vinay Sajip7367d082011-05-02 13:17:27 +01001641 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001642 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001643 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001644 if self.command == 'POST':
1645 try:
1646 rlen = int(request.headers['Content-Length'])
1647 self.post_data = request.rfile.read(rlen)
1648 except:
1649 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001650 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001651 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001652 self.handled.set()
1653
1654 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001655 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001656 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001657 root_logger = self.root_logger
1658 root_logger.removeHandler(self.root_logger.handlers[0])
1659 for secure in (False, True):
1660 addr = ('localhost', 0)
1661 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001662 try:
1663 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001664 except ImportError:
1665 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001666 else:
1667 here = os.path.dirname(__file__)
1668 localhost_cert = os.path.join(here, "keycert.pem")
1669 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1670 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001671
1672 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001673 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001674 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001675 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001676 self.server = server = TestHTTPServer(addr, self.handle_request,
1677 0.01, sslctx=sslctx)
1678 server.start()
1679 server.ready.wait()
1680 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001681 secure_client = secure and sslctx
1682 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001683 secure=secure_client,
1684 context=context)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001685 self.log_data = None
1686 root_logger.addHandler(self.h_hdlr)
1687
1688 for method in ('GET', 'POST'):
1689 self.h_hdlr.method = method
1690 self.handled.clear()
1691 msg = "sp\xe4m"
1692 logger.error(msg)
1693 self.handled.wait()
1694 self.assertEqual(self.log_data.path, '/frob')
1695 self.assertEqual(self.command, method)
1696 if method == 'GET':
1697 d = parse_qs(self.log_data.query)
1698 else:
1699 d = parse_qs(self.post_data.decode('utf-8'))
1700 self.assertEqual(d['name'], ['http'])
1701 self.assertEqual(d['funcName'], ['test_output'])
1702 self.assertEqual(d['msg'], [msg])
1703
1704 self.server.stop(2.0)
1705 self.root_logger.removeHandler(self.h_hdlr)
1706 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001707
Christian Heimes180510d2008-03-03 19:15:45 +00001708class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001709
Christian Heimes180510d2008-03-03 19:15:45 +00001710 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001711
Christian Heimes180510d2008-03-03 19:15:45 +00001712 def setUp(self):
1713 """Create a dict to remember potentially destroyed objects."""
1714 BaseTest.setUp(self)
1715 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001716
Christian Heimes180510d2008-03-03 19:15:45 +00001717 def _watch_for_survival(self, *args):
1718 """Watch the given objects for survival, by creating weakrefs to
1719 them."""
1720 for obj in args:
1721 key = id(obj), repr(obj)
1722 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001723
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001724 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001725 """Assert that all objects watched for survival have survived."""
1726 # Trigger cycle breaking.
1727 gc.collect()
1728 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001729 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001730 if ref() is None:
1731 dead.append(repr_)
1732 if dead:
1733 self.fail("%d objects should have survived "
1734 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001735
Christian Heimes180510d2008-03-03 19:15:45 +00001736 def test_persistent_loggers(self):
1737 # Logger objects are persistent and retain their configuration, even
1738 # if visible references are destroyed.
1739 self.root_logger.setLevel(logging.INFO)
1740 foo = logging.getLogger("foo")
1741 self._watch_for_survival(foo)
1742 foo.setLevel(logging.DEBUG)
1743 self.root_logger.debug(self.next_message())
1744 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001745 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001746 ('foo', 'DEBUG', '2'),
1747 ])
1748 del foo
1749 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001750 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001751 # foo has retained its settings.
1752 bar = logging.getLogger("foo")
1753 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001754 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001755 ('foo', 'DEBUG', '2'),
1756 ('foo', 'DEBUG', '3'),
1757 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001758
Benjamin Petersonf91df042009-02-13 02:50:59 +00001759
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001760class EncodingTest(BaseTest):
1761 def test_encoding_plain_file(self):
1762 # In Python 2.x, a plain file object is treated as having no encoding.
1763 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001764 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1765 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001766 # the non-ascii data we write to the log.
1767 data = "foo\x80"
1768 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001769 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001770 log.addHandler(handler)
1771 try:
1772 # write non-ascii data to the log.
1773 log.warning(data)
1774 finally:
1775 log.removeHandler(handler)
1776 handler.close()
1777 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001778 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001779 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001780 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001781 finally:
1782 f.close()
1783 finally:
1784 if os.path.isfile(fn):
1785 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001786
Benjamin Petersonf91df042009-02-13 02:50:59 +00001787 def test_encoding_cyrillic_unicode(self):
1788 log = logging.getLogger("test")
1789 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1790 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1791 #Ensure it's written in a Cyrillic encoding
1792 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001793 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001794 stream = io.BytesIO()
1795 writer = writer_class(stream, 'strict')
1796 handler = logging.StreamHandler(writer)
1797 log.addHandler(handler)
1798 try:
1799 log.warning(message)
1800 finally:
1801 log.removeHandler(handler)
1802 handler.close()
1803 # check we wrote exactly those bytes, ignoring trailing \n etc
1804 s = stream.getvalue()
1805 #Compare against what the data should be when encoded in CP-1251
1806 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1807
1808
Georg Brandlf9734072008-12-07 15:30:06 +00001809class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001810
Georg Brandlf9734072008-12-07 15:30:06 +00001811 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001812 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001813 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001814 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001815 warnings.filterwarnings("always", category=UserWarning)
1816 stream = io.StringIO()
1817 h = logging.StreamHandler(stream)
1818 logger = logging.getLogger("py.warnings")
1819 logger.addHandler(h)
1820 warnings.warn("I'm warning you...")
1821 logger.removeHandler(h)
1822 s = stream.getvalue()
1823 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001824 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001825
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001826 #See if an explicit file uses the original implementation
1827 a_file = io.StringIO()
1828 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1829 a_file, "Dummy line")
1830 s = a_file.getvalue()
1831 a_file.close()
1832 self.assertEqual(s,
1833 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1834
1835 def test_warnings_no_handlers(self):
1836 with warnings.catch_warnings():
1837 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001838 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001839
1840 # confirm our assumption: no loggers are set
1841 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001842 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001843
1844 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001845 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001846 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001847
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001848
1849def formatFunc(format, datefmt=None):
1850 return logging.Formatter(format, datefmt)
1851
1852def handlerFunc():
1853 return logging.StreamHandler()
1854
1855class CustomHandler(logging.StreamHandler):
1856 pass
1857
1858class ConfigDictTest(BaseTest):
1859
1860 """Reading logging config from a dictionary."""
1861
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001862 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001863
1864 # config0 is a standard configuration.
1865 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001866 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001867 'formatters': {
1868 'form1' : {
1869 'format' : '%(levelname)s ++ %(message)s',
1870 },
1871 },
1872 'handlers' : {
1873 'hand1' : {
1874 'class' : 'logging.StreamHandler',
1875 'formatter' : 'form1',
1876 'level' : 'NOTSET',
1877 'stream' : 'ext://sys.stdout',
1878 },
1879 },
1880 'root' : {
1881 'level' : 'WARNING',
1882 'handlers' : ['hand1'],
1883 },
1884 }
1885
1886 # config1 adds a little to the standard configuration.
1887 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001888 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001889 'formatters': {
1890 'form1' : {
1891 'format' : '%(levelname)s ++ %(message)s',
1892 },
1893 },
1894 'handlers' : {
1895 'hand1' : {
1896 'class' : 'logging.StreamHandler',
1897 'formatter' : 'form1',
1898 'level' : 'NOTSET',
1899 'stream' : 'ext://sys.stdout',
1900 },
1901 },
1902 'loggers' : {
1903 'compiler.parser' : {
1904 'level' : 'DEBUG',
1905 'handlers' : ['hand1'],
1906 },
1907 },
1908 'root' : {
1909 'level' : 'WARNING',
1910 },
1911 }
1912
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001913 # config1a moves the handler to the root. Used with config8a
1914 config1a = {
1915 'version': 1,
1916 'formatters': {
1917 'form1' : {
1918 'format' : '%(levelname)s ++ %(message)s',
1919 },
1920 },
1921 'handlers' : {
1922 'hand1' : {
1923 'class' : 'logging.StreamHandler',
1924 'formatter' : 'form1',
1925 'level' : 'NOTSET',
1926 'stream' : 'ext://sys.stdout',
1927 },
1928 },
1929 'loggers' : {
1930 'compiler.parser' : {
1931 'level' : 'DEBUG',
1932 },
1933 },
1934 'root' : {
1935 'level' : 'WARNING',
1936 'handlers' : ['hand1'],
1937 },
1938 }
1939
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001940 # config2 has a subtle configuration error that should be reported
1941 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001942 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001943 'formatters': {
1944 'form1' : {
1945 'format' : '%(levelname)s ++ %(message)s',
1946 },
1947 },
1948 'handlers' : {
1949 'hand1' : {
1950 'class' : 'logging.StreamHandler',
1951 'formatter' : 'form1',
1952 'level' : 'NOTSET',
1953 'stream' : 'ext://sys.stdbout',
1954 },
1955 },
1956 'loggers' : {
1957 'compiler.parser' : {
1958 'level' : 'DEBUG',
1959 'handlers' : ['hand1'],
1960 },
1961 },
1962 'root' : {
1963 'level' : 'WARNING',
1964 },
1965 }
1966
1967 #As config1 but with a misspelt level on a handler
1968 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001969 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001970 'formatters': {
1971 'form1' : {
1972 'format' : '%(levelname)s ++ %(message)s',
1973 },
1974 },
1975 'handlers' : {
1976 'hand1' : {
1977 'class' : 'logging.StreamHandler',
1978 'formatter' : 'form1',
1979 'level' : 'NTOSET',
1980 'stream' : 'ext://sys.stdout',
1981 },
1982 },
1983 'loggers' : {
1984 'compiler.parser' : {
1985 'level' : 'DEBUG',
1986 'handlers' : ['hand1'],
1987 },
1988 },
1989 'root' : {
1990 'level' : 'WARNING',
1991 },
1992 }
1993
1994
1995 #As config1 but with a misspelt level on a logger
1996 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001997 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001998 'formatters': {
1999 'form1' : {
2000 'format' : '%(levelname)s ++ %(message)s',
2001 },
2002 },
2003 'handlers' : {
2004 'hand1' : {
2005 'class' : 'logging.StreamHandler',
2006 'formatter' : 'form1',
2007 'level' : 'NOTSET',
2008 'stream' : 'ext://sys.stdout',
2009 },
2010 },
2011 'loggers' : {
2012 'compiler.parser' : {
2013 'level' : 'DEBUG',
2014 'handlers' : ['hand1'],
2015 },
2016 },
2017 'root' : {
2018 'level' : 'WRANING',
2019 },
2020 }
2021
2022 # config3 has a less subtle configuration error
2023 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002024 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002025 'formatters': {
2026 'form1' : {
2027 'format' : '%(levelname)s ++ %(message)s',
2028 },
2029 },
2030 'handlers' : {
2031 'hand1' : {
2032 'class' : 'logging.StreamHandler',
2033 'formatter' : 'misspelled_name',
2034 'level' : 'NOTSET',
2035 'stream' : 'ext://sys.stdout',
2036 },
2037 },
2038 'loggers' : {
2039 'compiler.parser' : {
2040 'level' : 'DEBUG',
2041 'handlers' : ['hand1'],
2042 },
2043 },
2044 'root' : {
2045 'level' : 'WARNING',
2046 },
2047 }
2048
2049 # config4 specifies a custom formatter class to be loaded
2050 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002051 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002052 'formatters': {
2053 'form1' : {
2054 '()' : __name__ + '.ExceptionFormatter',
2055 'format' : '%(levelname)s:%(name)s:%(message)s',
2056 },
2057 },
2058 'handlers' : {
2059 'hand1' : {
2060 'class' : 'logging.StreamHandler',
2061 'formatter' : 'form1',
2062 'level' : 'NOTSET',
2063 'stream' : 'ext://sys.stdout',
2064 },
2065 },
2066 'root' : {
2067 'level' : 'NOTSET',
2068 'handlers' : ['hand1'],
2069 },
2070 }
2071
2072 # As config4 but using an actual callable rather than a string
2073 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002074 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002075 'formatters': {
2076 'form1' : {
2077 '()' : ExceptionFormatter,
2078 'format' : '%(levelname)s:%(name)s:%(message)s',
2079 },
2080 'form2' : {
2081 '()' : __name__ + '.formatFunc',
2082 'format' : '%(levelname)s:%(name)s:%(message)s',
2083 },
2084 'form3' : {
2085 '()' : formatFunc,
2086 'format' : '%(levelname)s:%(name)s:%(message)s',
2087 },
2088 },
2089 'handlers' : {
2090 'hand1' : {
2091 'class' : 'logging.StreamHandler',
2092 'formatter' : 'form1',
2093 'level' : 'NOTSET',
2094 'stream' : 'ext://sys.stdout',
2095 },
2096 'hand2' : {
2097 '()' : handlerFunc,
2098 },
2099 },
2100 'root' : {
2101 'level' : 'NOTSET',
2102 'handlers' : ['hand1'],
2103 },
2104 }
2105
2106 # config5 specifies a custom handler class to be loaded
2107 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002108 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002109 'formatters': {
2110 'form1' : {
2111 'format' : '%(levelname)s ++ %(message)s',
2112 },
2113 },
2114 'handlers' : {
2115 'hand1' : {
2116 'class' : __name__ + '.CustomHandler',
2117 'formatter' : 'form1',
2118 'level' : 'NOTSET',
2119 'stream' : 'ext://sys.stdout',
2120 },
2121 },
2122 'loggers' : {
2123 'compiler.parser' : {
2124 'level' : 'DEBUG',
2125 'handlers' : ['hand1'],
2126 },
2127 },
2128 'root' : {
2129 'level' : 'WARNING',
2130 },
2131 }
2132
2133 # config6 specifies a custom handler class to be loaded
2134 # but has bad arguments
2135 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002136 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002137 'formatters': {
2138 'form1' : {
2139 'format' : '%(levelname)s ++ %(message)s',
2140 },
2141 },
2142 'handlers' : {
2143 'hand1' : {
2144 'class' : __name__ + '.CustomHandler',
2145 'formatter' : 'form1',
2146 'level' : 'NOTSET',
2147 'stream' : 'ext://sys.stdout',
2148 '9' : 'invalid parameter name',
2149 },
2150 },
2151 'loggers' : {
2152 'compiler.parser' : {
2153 'level' : 'DEBUG',
2154 'handlers' : ['hand1'],
2155 },
2156 },
2157 'root' : {
2158 'level' : 'WARNING',
2159 },
2160 }
2161
2162 #config 7 does not define compiler.parser but defines compiler.lexer
2163 #so compiler.parser should be disabled after applying it
2164 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002165 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002166 'formatters': {
2167 'form1' : {
2168 'format' : '%(levelname)s ++ %(message)s',
2169 },
2170 },
2171 'handlers' : {
2172 'hand1' : {
2173 'class' : 'logging.StreamHandler',
2174 'formatter' : 'form1',
2175 'level' : 'NOTSET',
2176 'stream' : 'ext://sys.stdout',
2177 },
2178 },
2179 'loggers' : {
2180 'compiler.lexer' : {
2181 'level' : 'DEBUG',
2182 'handlers' : ['hand1'],
2183 },
2184 },
2185 'root' : {
2186 'level' : 'WARNING',
2187 },
2188 }
2189
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002190 # config8 defines both compiler and compiler.lexer
2191 # so compiler.parser should not be disabled (since
2192 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002193 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002194 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002195 'disable_existing_loggers' : False,
2196 'formatters': {
2197 'form1' : {
2198 'format' : '%(levelname)s ++ %(message)s',
2199 },
2200 },
2201 'handlers' : {
2202 'hand1' : {
2203 'class' : 'logging.StreamHandler',
2204 'formatter' : 'form1',
2205 'level' : 'NOTSET',
2206 'stream' : 'ext://sys.stdout',
2207 },
2208 },
2209 'loggers' : {
2210 'compiler' : {
2211 'level' : 'DEBUG',
2212 'handlers' : ['hand1'],
2213 },
2214 'compiler.lexer' : {
2215 },
2216 },
2217 'root' : {
2218 'level' : 'WARNING',
2219 },
2220 }
2221
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002222 # config8a disables existing loggers
2223 config8a = {
2224 'version': 1,
2225 'disable_existing_loggers' : True,
2226 'formatters': {
2227 'form1' : {
2228 'format' : '%(levelname)s ++ %(message)s',
2229 },
2230 },
2231 'handlers' : {
2232 'hand1' : {
2233 'class' : 'logging.StreamHandler',
2234 'formatter' : 'form1',
2235 'level' : 'NOTSET',
2236 'stream' : 'ext://sys.stdout',
2237 },
2238 },
2239 'loggers' : {
2240 'compiler' : {
2241 'level' : 'DEBUG',
2242 'handlers' : ['hand1'],
2243 },
2244 'compiler.lexer' : {
2245 },
2246 },
2247 'root' : {
2248 'level' : 'WARNING',
2249 },
2250 }
2251
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002252 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002253 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002254 'formatters': {
2255 'form1' : {
2256 'format' : '%(levelname)s ++ %(message)s',
2257 },
2258 },
2259 'handlers' : {
2260 'hand1' : {
2261 'class' : 'logging.StreamHandler',
2262 'formatter' : 'form1',
2263 'level' : 'WARNING',
2264 'stream' : 'ext://sys.stdout',
2265 },
2266 },
2267 'loggers' : {
2268 'compiler.parser' : {
2269 'level' : 'WARNING',
2270 'handlers' : ['hand1'],
2271 },
2272 },
2273 'root' : {
2274 'level' : 'NOTSET',
2275 },
2276 }
2277
2278 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002279 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002280 'incremental' : True,
2281 'handlers' : {
2282 'hand1' : {
2283 'level' : 'WARNING',
2284 },
2285 },
2286 'loggers' : {
2287 'compiler.parser' : {
2288 'level' : 'INFO',
2289 },
2290 },
2291 }
2292
2293 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002294 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002295 'incremental' : True,
2296 'handlers' : {
2297 'hand1' : {
2298 'level' : 'INFO',
2299 },
2300 },
2301 'loggers' : {
2302 'compiler.parser' : {
2303 'level' : 'INFO',
2304 },
2305 },
2306 }
2307
2308 #As config1 but with a filter added
2309 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002310 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002311 'formatters': {
2312 'form1' : {
2313 'format' : '%(levelname)s ++ %(message)s',
2314 },
2315 },
2316 'filters' : {
2317 'filt1' : {
2318 'name' : 'compiler.parser',
2319 },
2320 },
2321 'handlers' : {
2322 'hand1' : {
2323 'class' : 'logging.StreamHandler',
2324 'formatter' : 'form1',
2325 'level' : 'NOTSET',
2326 'stream' : 'ext://sys.stdout',
2327 'filters' : ['filt1'],
2328 },
2329 },
2330 'loggers' : {
2331 'compiler.parser' : {
2332 'level' : 'DEBUG',
2333 'filters' : ['filt1'],
2334 },
2335 },
2336 'root' : {
2337 'level' : 'WARNING',
2338 'handlers' : ['hand1'],
2339 },
2340 }
2341
2342 #As config1 but using cfg:// references
2343 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002344 'version': 1,
2345 'true_formatters': {
2346 'form1' : {
2347 'format' : '%(levelname)s ++ %(message)s',
2348 },
2349 },
2350 'handler_configs': {
2351 'hand1' : {
2352 'class' : 'logging.StreamHandler',
2353 'formatter' : 'form1',
2354 'level' : 'NOTSET',
2355 'stream' : 'ext://sys.stdout',
2356 },
2357 },
2358 'formatters' : 'cfg://true_formatters',
2359 'handlers' : {
2360 'hand1' : 'cfg://handler_configs[hand1]',
2361 },
2362 'loggers' : {
2363 'compiler.parser' : {
2364 'level' : 'DEBUG',
2365 'handlers' : ['hand1'],
2366 },
2367 },
2368 'root' : {
2369 'level' : 'WARNING',
2370 },
2371 }
2372
2373 #As config11 but missing the version key
2374 config12 = {
2375 'true_formatters': {
2376 'form1' : {
2377 'format' : '%(levelname)s ++ %(message)s',
2378 },
2379 },
2380 'handler_configs': {
2381 'hand1' : {
2382 'class' : 'logging.StreamHandler',
2383 'formatter' : 'form1',
2384 'level' : 'NOTSET',
2385 'stream' : 'ext://sys.stdout',
2386 },
2387 },
2388 'formatters' : 'cfg://true_formatters',
2389 'handlers' : {
2390 'hand1' : 'cfg://handler_configs[hand1]',
2391 },
2392 'loggers' : {
2393 'compiler.parser' : {
2394 'level' : 'DEBUG',
2395 'handlers' : ['hand1'],
2396 },
2397 },
2398 'root' : {
2399 'level' : 'WARNING',
2400 },
2401 }
2402
2403 #As config11 but using an unsupported version
2404 config13 = {
2405 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002406 'true_formatters': {
2407 'form1' : {
2408 'format' : '%(levelname)s ++ %(message)s',
2409 },
2410 },
2411 'handler_configs': {
2412 'hand1' : {
2413 'class' : 'logging.StreamHandler',
2414 'formatter' : 'form1',
2415 'level' : 'NOTSET',
2416 'stream' : 'ext://sys.stdout',
2417 },
2418 },
2419 'formatters' : 'cfg://true_formatters',
2420 'handlers' : {
2421 'hand1' : 'cfg://handler_configs[hand1]',
2422 },
2423 'loggers' : {
2424 'compiler.parser' : {
2425 'level' : 'DEBUG',
2426 'handlers' : ['hand1'],
2427 },
2428 },
2429 'root' : {
2430 'level' : 'WARNING',
2431 },
2432 }
2433
Vinay Sajip8d270232012-11-15 14:20:18 +00002434 # As config0, but with properties
2435 config14 = {
2436 'version': 1,
2437 'formatters': {
2438 'form1' : {
2439 'format' : '%(levelname)s ++ %(message)s',
2440 },
2441 },
2442 'handlers' : {
2443 'hand1' : {
2444 'class' : 'logging.StreamHandler',
2445 'formatter' : 'form1',
2446 'level' : 'NOTSET',
2447 'stream' : 'ext://sys.stdout',
2448 '.': {
2449 'foo': 'bar',
2450 'terminator': '!\n',
2451 }
2452 },
2453 },
2454 'root' : {
2455 'level' : 'WARNING',
2456 'handlers' : ['hand1'],
2457 },
2458 }
2459
Vinay Sajip3f885b52013-03-22 15:19:54 +00002460 out_of_order = {
2461 "version": 1,
2462 "formatters": {
2463 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002464 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2465 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002466 }
2467 },
2468 "handlers": {
2469 "fileGlobal": {
2470 "class": "logging.StreamHandler",
2471 "level": "DEBUG",
2472 "formatter": "mySimpleFormatter"
2473 },
2474 "bufferGlobal": {
2475 "class": "logging.handlers.MemoryHandler",
2476 "capacity": 5,
2477 "formatter": "mySimpleFormatter",
2478 "target": "fileGlobal",
2479 "level": "DEBUG"
2480 }
2481 },
2482 "loggers": {
2483 "mymodule": {
2484 "level": "DEBUG",
2485 "handlers": ["bufferGlobal"],
2486 "propagate": "true"
2487 }
2488 }
2489 }
2490
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002491 def apply_config(self, conf):
2492 logging.config.dictConfig(conf)
2493
2494 def test_config0_ok(self):
2495 # A simple config which overrides the default settings.
2496 with captured_stdout() as output:
2497 self.apply_config(self.config0)
2498 logger = logging.getLogger()
2499 # Won't output anything
2500 logger.info(self.next_message())
2501 # Outputs a message
2502 logger.error(self.next_message())
2503 self.assert_log_lines([
2504 ('ERROR', '2'),
2505 ], stream=output)
2506 # Original logger output is empty.
2507 self.assert_log_lines([])
2508
2509 def test_config1_ok(self, config=config1):
2510 # A config defining a sub-parser as well.
2511 with captured_stdout() as output:
2512 self.apply_config(config)
2513 logger = logging.getLogger("compiler.parser")
2514 # Both will output a message
2515 logger.info(self.next_message())
2516 logger.error(self.next_message())
2517 self.assert_log_lines([
2518 ('INFO', '1'),
2519 ('ERROR', '2'),
2520 ], stream=output)
2521 # Original logger output is empty.
2522 self.assert_log_lines([])
2523
2524 def test_config2_failure(self):
2525 # A simple config which overrides the default settings.
2526 self.assertRaises(Exception, self.apply_config, self.config2)
2527
2528 def test_config2a_failure(self):
2529 # A simple config which overrides the default settings.
2530 self.assertRaises(Exception, self.apply_config, self.config2a)
2531
2532 def test_config2b_failure(self):
2533 # A simple config which overrides the default settings.
2534 self.assertRaises(Exception, self.apply_config, self.config2b)
2535
2536 def test_config3_failure(self):
2537 # A simple config which overrides the default settings.
2538 self.assertRaises(Exception, self.apply_config, self.config3)
2539
2540 def test_config4_ok(self):
2541 # A config specifying a custom formatter class.
2542 with captured_stdout() as output:
2543 self.apply_config(self.config4)
2544 #logger = logging.getLogger()
2545 try:
2546 raise RuntimeError()
2547 except RuntimeError:
2548 logging.exception("just testing")
2549 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002550 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002551 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2552 # Original logger output is empty
2553 self.assert_log_lines([])
2554
2555 def test_config4a_ok(self):
2556 # A config specifying a custom formatter class.
2557 with captured_stdout() as output:
2558 self.apply_config(self.config4a)
2559 #logger = logging.getLogger()
2560 try:
2561 raise RuntimeError()
2562 except RuntimeError:
2563 logging.exception("just testing")
2564 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002565 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002566 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2567 # Original logger output is empty
2568 self.assert_log_lines([])
2569
2570 def test_config5_ok(self):
2571 self.test_config1_ok(config=self.config5)
2572
2573 def test_config6_failure(self):
2574 self.assertRaises(Exception, self.apply_config, self.config6)
2575
2576 def test_config7_ok(self):
2577 with captured_stdout() as output:
2578 self.apply_config(self.config1)
2579 logger = logging.getLogger("compiler.parser")
2580 # Both will output a message
2581 logger.info(self.next_message())
2582 logger.error(self.next_message())
2583 self.assert_log_lines([
2584 ('INFO', '1'),
2585 ('ERROR', '2'),
2586 ], stream=output)
2587 # Original logger output is empty.
2588 self.assert_log_lines([])
2589 with captured_stdout() as output:
2590 self.apply_config(self.config7)
2591 logger = logging.getLogger("compiler.parser")
2592 self.assertTrue(logger.disabled)
2593 logger = logging.getLogger("compiler.lexer")
2594 # Both will output a message
2595 logger.info(self.next_message())
2596 logger.error(self.next_message())
2597 self.assert_log_lines([
2598 ('INFO', '3'),
2599 ('ERROR', '4'),
2600 ], stream=output)
2601 # Original logger output is empty.
2602 self.assert_log_lines([])
2603
2604 #Same as test_config_7_ok but don't disable old loggers.
2605 def test_config_8_ok(self):
2606 with captured_stdout() as output:
2607 self.apply_config(self.config1)
2608 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002609 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002610 logger.info(self.next_message())
2611 logger.error(self.next_message())
2612 self.assert_log_lines([
2613 ('INFO', '1'),
2614 ('ERROR', '2'),
2615 ], stream=output)
2616 # Original logger output is empty.
2617 self.assert_log_lines([])
2618 with captured_stdout() as output:
2619 self.apply_config(self.config8)
2620 logger = logging.getLogger("compiler.parser")
2621 self.assertFalse(logger.disabled)
2622 # Both will output a message
2623 logger.info(self.next_message())
2624 logger.error(self.next_message())
2625 logger = logging.getLogger("compiler.lexer")
2626 # Both will output a message
2627 logger.info(self.next_message())
2628 logger.error(self.next_message())
2629 self.assert_log_lines([
2630 ('INFO', '3'),
2631 ('ERROR', '4'),
2632 ('INFO', '5'),
2633 ('ERROR', '6'),
2634 ], stream=output)
2635 # Original logger output is empty.
2636 self.assert_log_lines([])
2637
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002638 def test_config_8a_ok(self):
2639 with captured_stdout() as output:
2640 self.apply_config(self.config1a)
2641 logger = logging.getLogger("compiler.parser")
2642 # See issue #11424. compiler-hyphenated sorts
2643 # between compiler and compiler.xyz and this
2644 # was preventing compiler.xyz from being included
2645 # in the child loggers of compiler because of an
2646 # overzealous loop termination condition.
2647 hyphenated = logging.getLogger('compiler-hyphenated')
2648 # All will output a message
2649 logger.info(self.next_message())
2650 logger.error(self.next_message())
2651 hyphenated.critical(self.next_message())
2652 self.assert_log_lines([
2653 ('INFO', '1'),
2654 ('ERROR', '2'),
2655 ('CRITICAL', '3'),
2656 ], stream=output)
2657 # Original logger output is empty.
2658 self.assert_log_lines([])
2659 with captured_stdout() as output:
2660 self.apply_config(self.config8a)
2661 logger = logging.getLogger("compiler.parser")
2662 self.assertFalse(logger.disabled)
2663 # Both will output a message
2664 logger.info(self.next_message())
2665 logger.error(self.next_message())
2666 logger = logging.getLogger("compiler.lexer")
2667 # Both will output a message
2668 logger.info(self.next_message())
2669 logger.error(self.next_message())
2670 # Will not appear
2671 hyphenated.critical(self.next_message())
2672 self.assert_log_lines([
2673 ('INFO', '4'),
2674 ('ERROR', '5'),
2675 ('INFO', '6'),
2676 ('ERROR', '7'),
2677 ], stream=output)
2678 # Original logger output is empty.
2679 self.assert_log_lines([])
2680
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002681 def test_config_9_ok(self):
2682 with captured_stdout() as output:
2683 self.apply_config(self.config9)
2684 logger = logging.getLogger("compiler.parser")
2685 #Nothing will be output since both handler and logger are set to WARNING
2686 logger.info(self.next_message())
2687 self.assert_log_lines([], stream=output)
2688 self.apply_config(self.config9a)
2689 #Nothing will be output since both handler is still set to WARNING
2690 logger.info(self.next_message())
2691 self.assert_log_lines([], stream=output)
2692 self.apply_config(self.config9b)
2693 #Message should now be output
2694 logger.info(self.next_message())
2695 self.assert_log_lines([
2696 ('INFO', '3'),
2697 ], stream=output)
2698
2699 def test_config_10_ok(self):
2700 with captured_stdout() as output:
2701 self.apply_config(self.config10)
2702 logger = logging.getLogger("compiler.parser")
2703 logger.warning(self.next_message())
2704 logger = logging.getLogger('compiler')
2705 #Not output, because filtered
2706 logger.warning(self.next_message())
2707 logger = logging.getLogger('compiler.lexer')
2708 #Not output, because filtered
2709 logger.warning(self.next_message())
2710 logger = logging.getLogger("compiler.parser.codegen")
2711 #Output, as not filtered
2712 logger.error(self.next_message())
2713 self.assert_log_lines([
2714 ('WARNING', '1'),
2715 ('ERROR', '4'),
2716 ], stream=output)
2717
2718 def test_config11_ok(self):
2719 self.test_config1_ok(self.config11)
2720
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002721 def test_config12_failure(self):
2722 self.assertRaises(Exception, self.apply_config, self.config12)
2723
2724 def test_config13_failure(self):
2725 self.assertRaises(Exception, self.apply_config, self.config13)
2726
Vinay Sajip8d270232012-11-15 14:20:18 +00002727 def test_config14_ok(self):
2728 with captured_stdout() as output:
2729 self.apply_config(self.config14)
2730 h = logging._handlers['hand1']
2731 self.assertEqual(h.foo, 'bar')
2732 self.assertEqual(h.terminator, '!\n')
2733 logging.warning('Exclamation')
2734 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2735
Victor Stinner45df8202010-04-28 22:31:17 +00002736 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002737 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002738 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002739 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002740 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002741 t.start()
2742 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002743 # Now get the port allocated
2744 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002745 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002746 try:
2747 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2748 sock.settimeout(2.0)
2749 sock.connect(('localhost', port))
2750
2751 slen = struct.pack('>L', len(text))
2752 s = slen + text
2753 sentsofar = 0
2754 left = len(s)
2755 while left > 0:
2756 sent = sock.send(s[sentsofar:])
2757 sentsofar += sent
2758 left -= sent
2759 sock.close()
2760 finally:
2761 t.ready.wait(2.0)
2762 logging.config.stopListening()
2763 t.join(2.0)
2764
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002765 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002766 def test_listen_config_10_ok(self):
2767 with captured_stdout() as output:
2768 self.setup_via_listener(json.dumps(self.config10))
2769 logger = logging.getLogger("compiler.parser")
2770 logger.warning(self.next_message())
2771 logger = logging.getLogger('compiler')
2772 #Not output, because filtered
2773 logger.warning(self.next_message())
2774 logger = logging.getLogger('compiler.lexer')
2775 #Not output, because filtered
2776 logger.warning(self.next_message())
2777 logger = logging.getLogger("compiler.parser.codegen")
2778 #Output, as not filtered
2779 logger.error(self.next_message())
2780 self.assert_log_lines([
2781 ('WARNING', '1'),
2782 ('ERROR', '4'),
2783 ], stream=output)
2784
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002785 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002786 def test_listen_config_1_ok(self):
2787 with captured_stdout() as output:
2788 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2789 logger = logging.getLogger("compiler.parser")
2790 # Both will output a message
2791 logger.info(self.next_message())
2792 logger.error(self.next_message())
2793 self.assert_log_lines([
2794 ('INFO', '1'),
2795 ('ERROR', '2'),
2796 ], stream=output)
2797 # Original logger output is empty.
2798 self.assert_log_lines([])
2799
Vinay Sajip4ded5512012-10-02 15:56:16 +01002800 @unittest.skipUnless(threading, 'Threading required for this test.')
2801 def test_listen_verify(self):
2802
2803 def verify_fail(stuff):
2804 return None
2805
2806 def verify_reverse(stuff):
2807 return stuff[::-1]
2808
2809 logger = logging.getLogger("compiler.parser")
2810 to_send = textwrap.dedent(ConfigFileTest.config1)
2811 # First, specify a verification function that will fail.
2812 # We expect to see no output, since our configuration
2813 # never took effect.
2814 with captured_stdout() as output:
2815 self.setup_via_listener(to_send, verify_fail)
2816 # Both will output a message
2817 logger.info(self.next_message())
2818 logger.error(self.next_message())
2819 self.assert_log_lines([], stream=output)
2820 # Original logger output has the stuff we logged.
2821 self.assert_log_lines([
2822 ('INFO', '1'),
2823 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002824 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002825
2826 # Now, perform no verification. Our configuration
2827 # should take effect.
2828
2829 with captured_stdout() as output:
2830 self.setup_via_listener(to_send) # no verify callable specified
2831 logger = logging.getLogger("compiler.parser")
2832 # Both will output a message
2833 logger.info(self.next_message())
2834 logger.error(self.next_message())
2835 self.assert_log_lines([
2836 ('INFO', '3'),
2837 ('ERROR', '4'),
2838 ], stream=output)
2839 # Original logger output still has the stuff we logged before.
2840 self.assert_log_lines([
2841 ('INFO', '1'),
2842 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002843 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002844
2845 # Now, perform verification which transforms the bytes.
2846
2847 with captured_stdout() as output:
2848 self.setup_via_listener(to_send[::-1], verify_reverse)
2849 logger = logging.getLogger("compiler.parser")
2850 # Both will output a message
2851 logger.info(self.next_message())
2852 logger.error(self.next_message())
2853 self.assert_log_lines([
2854 ('INFO', '5'),
2855 ('ERROR', '6'),
2856 ], stream=output)
2857 # Original logger output still has the stuff we logged before.
2858 self.assert_log_lines([
2859 ('INFO', '1'),
2860 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002861 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002862
Vinay Sajip3f885b52013-03-22 15:19:54 +00002863 def test_out_of_order(self):
2864 self.apply_config(self.out_of_order)
2865 handler = logging.getLogger('mymodule').handlers[0]
2866 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002867 self.assertIsInstance(handler.formatter._style,
2868 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002869
Vinay Sajip373baef2011-04-26 20:05:24 +01002870 def test_baseconfig(self):
2871 d = {
2872 'atuple': (1, 2, 3),
2873 'alist': ['a', 'b', 'c'],
2874 'adict': {'d': 'e', 'f': 3 },
2875 'nest1': ('g', ('h', 'i'), 'j'),
2876 'nest2': ['k', ['l', 'm'], 'n'],
2877 'nest3': ['o', 'cfg://alist', 'p'],
2878 }
2879 bc = logging.config.BaseConfigurator(d)
2880 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2881 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2882 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2883 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2884 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2885 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2886 v = bc.convert('cfg://nest3')
2887 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2888 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2889 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2890 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002891
2892class ManagerTest(BaseTest):
2893 def test_manager_loggerclass(self):
2894 logged = []
2895
2896 class MyLogger(logging.Logger):
2897 def _log(self, level, msg, args, exc_info=None, extra=None):
2898 logged.append(msg)
2899
2900 man = logging.Manager(None)
2901 self.assertRaises(TypeError, man.setLoggerClass, int)
2902 man.setLoggerClass(MyLogger)
2903 logger = man.getLogger('test')
2904 logger.warning('should appear in logged')
2905 logging.warning('should not appear in logged')
2906
2907 self.assertEqual(logged, ['should appear in logged'])
2908
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002909 def test_set_log_record_factory(self):
2910 man = logging.Manager(None)
2911 expected = object()
2912 man.setLogRecordFactory(expected)
2913 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002914
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002915class ChildLoggerTest(BaseTest):
2916 def test_child_loggers(self):
2917 r = logging.getLogger()
2918 l1 = logging.getLogger('abc')
2919 l2 = logging.getLogger('def.ghi')
2920 c1 = r.getChild('xyz')
2921 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002922 self.assertIs(c1, logging.getLogger('xyz'))
2923 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002924 c1 = l1.getChild('def')
2925 c2 = c1.getChild('ghi')
2926 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002927 self.assertIs(c1, logging.getLogger('abc.def'))
2928 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2929 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002930
2931
Vinay Sajip6fac8172010-10-19 20:44:14 +00002932class DerivedLogRecord(logging.LogRecord):
2933 pass
2934
Vinay Sajip61561522010-12-03 11:50:38 +00002935class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002936
2937 def setUp(self):
2938 class CheckingFilter(logging.Filter):
2939 def __init__(self, cls):
2940 self.cls = cls
2941
2942 def filter(self, record):
2943 t = type(record)
2944 if t is not self.cls:
2945 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2946 self.cls)
2947 raise TypeError(msg)
2948 return True
2949
2950 BaseTest.setUp(self)
2951 self.filter = CheckingFilter(DerivedLogRecord)
2952 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002953 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002954
2955 def tearDown(self):
2956 self.root_logger.removeFilter(self.filter)
2957 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002958 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959
2960 def test_logrecord_class(self):
2961 self.assertRaises(TypeError, self.root_logger.warning,
2962 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002963 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002964 self.root_logger.error(self.next_message())
2965 self.assert_log_lines([
2966 ('root', 'ERROR', '2'),
2967 ])
2968
2969
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002970class QueueHandlerTest(BaseTest):
2971 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002972 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002973
2974 def setUp(self):
2975 BaseTest.setUp(self)
2976 self.queue = queue.Queue(-1)
2977 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2978 self.que_logger = logging.getLogger('que')
2979 self.que_logger.propagate = False
2980 self.que_logger.setLevel(logging.WARNING)
2981 self.que_logger.addHandler(self.que_hdlr)
2982
2983 def tearDown(self):
2984 self.que_hdlr.close()
2985 BaseTest.tearDown(self)
2986
2987 def test_queue_handler(self):
2988 self.que_logger.debug(self.next_message())
2989 self.assertRaises(queue.Empty, self.queue.get_nowait)
2990 self.que_logger.info(self.next_message())
2991 self.assertRaises(queue.Empty, self.queue.get_nowait)
2992 msg = self.next_message()
2993 self.que_logger.warning(msg)
2994 data = self.queue.get_nowait()
2995 self.assertTrue(isinstance(data, logging.LogRecord))
2996 self.assertEqual(data.name, self.que_logger.name)
2997 self.assertEqual((data.msg, data.args), (msg, None))
2998
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002999 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3000 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003001 def test_queue_listener(self):
3002 handler = TestHandler(Matcher())
3003 listener = logging.handlers.QueueListener(self.queue, handler)
3004 listener.start()
3005 try:
3006 self.que_logger.warning(self.next_message())
3007 self.que_logger.error(self.next_message())
3008 self.que_logger.critical(self.next_message())
3009 finally:
3010 listener.stop()
3011 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3012 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3013 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3014
Vinay Sajip37eb3382011-04-26 20:26:41 +01003015ZERO = datetime.timedelta(0)
3016
3017class UTC(datetime.tzinfo):
3018 def utcoffset(self, dt):
3019 return ZERO
3020
3021 dst = utcoffset
3022
3023 def tzname(self, dt):
3024 return 'UTC'
3025
3026utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003027
Vinay Sajipa39c5712010-10-25 13:57:39 +00003028class FormatterTest(unittest.TestCase):
3029 def setUp(self):
3030 self.common = {
3031 'name': 'formatter.test',
3032 'level': logging.DEBUG,
3033 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3034 'lineno': 42,
3035 'exc_info': None,
3036 'func': None,
3037 'msg': 'Message with %d %s',
3038 'args': (2, 'placeholders'),
3039 }
3040 self.variants = {
3041 }
3042
3043 def get_record(self, name=None):
3044 result = dict(self.common)
3045 if name is not None:
3046 result.update(self.variants[name])
3047 return logging.makeLogRecord(result)
3048
3049 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003050 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003051 r = self.get_record()
3052 f = logging.Formatter('${%(message)s}')
3053 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3054 f = logging.Formatter('%(random)s')
3055 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003056 self.assertFalse(f.usesTime())
3057 f = logging.Formatter('%(asctime)s')
3058 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003059 f = logging.Formatter('%(asctime)-15s')
3060 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003061 f = logging.Formatter('asctime')
3062 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003063
3064 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003065 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003066 r = self.get_record()
3067 f = logging.Formatter('$%{message}%$', style='{')
3068 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3069 f = logging.Formatter('{random}', style='{')
3070 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003071 self.assertFalse(f.usesTime())
3072 f = logging.Formatter('{asctime}', style='{')
3073 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003074 f = logging.Formatter('{asctime!s:15}', style='{')
3075 self.assertTrue(f.usesTime())
3076 f = logging.Formatter('{asctime:15}', style='{')
3077 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003078 f = logging.Formatter('asctime', style='{')
3079 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003080
3081 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003082 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003083 r = self.get_record()
3084 f = logging.Formatter('$message', style='$')
3085 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3086 f = logging.Formatter('$$%${message}%$$', style='$')
3087 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3088 f = logging.Formatter('${random}', style='$')
3089 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003090 self.assertFalse(f.usesTime())
3091 f = logging.Formatter('${asctime}', style='$')
3092 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003093 f = logging.Formatter('${asctime', style='$')
3094 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003095 f = logging.Formatter('$asctime', style='$')
3096 self.assertTrue(f.usesTime())
3097 f = logging.Formatter('asctime', style='$')
3098 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003099
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003100 def test_invalid_style(self):
3101 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3102
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003103 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003104 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003105 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3106 # We use None to indicate we want the local timezone
3107 # We're essentially converting a UTC time to local time
3108 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003109 r.msecs = 123
3110 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003111 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003112 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3113 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003114 f.format(r)
3115 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3116
3117class TestBufferingFormatter(logging.BufferingFormatter):
3118 def formatHeader(self, records):
3119 return '[(%d)' % len(records)
3120
3121 def formatFooter(self, records):
3122 return '(%d)]' % len(records)
3123
3124class BufferingFormatterTest(unittest.TestCase):
3125 def setUp(self):
3126 self.records = [
3127 logging.makeLogRecord({'msg': 'one'}),
3128 logging.makeLogRecord({'msg': 'two'}),
3129 ]
3130
3131 def test_default(self):
3132 f = logging.BufferingFormatter()
3133 self.assertEqual('', f.format([]))
3134 self.assertEqual('onetwo', f.format(self.records))
3135
3136 def test_custom(self):
3137 f = TestBufferingFormatter()
3138 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3139 lf = logging.Formatter('<%(message)s>')
3140 f = TestBufferingFormatter(lf)
3141 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003142
3143class ExceptionTest(BaseTest):
3144 def test_formatting(self):
3145 r = self.root_logger
3146 h = RecordingHandler()
3147 r.addHandler(h)
3148 try:
3149 raise RuntimeError('deliberate mistake')
3150 except:
3151 logging.exception('failed', stack_info=True)
3152 r.removeHandler(h)
3153 h.close()
3154 r = h.records[0]
3155 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3156 'call last):\n'))
3157 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3158 'deliberate mistake'))
3159 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3160 'call last):\n'))
3161 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3162 'stack_info=True)'))
3163
3164
Vinay Sajip5a27d402010-12-10 11:42:57 +00003165class LastResortTest(BaseTest):
3166 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003167 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003168 root = self.root_logger
3169 root.removeHandler(self.root_hdlr)
3170 old_stderr = sys.stderr
3171 old_lastresort = logging.lastResort
3172 old_raise_exceptions = logging.raiseExceptions
3173 try:
3174 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003175 root.debug('This should not appear')
3176 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003177 root.warning('This is your final chance!')
3178 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3179 #No handlers and no last resort, so 'No handlers' message
3180 logging.lastResort = None
3181 sys.stderr = sio = io.StringIO()
3182 root.warning('This is your final chance!')
3183 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3184 # 'No handlers' message only printed once
3185 sys.stderr = sio = io.StringIO()
3186 root.warning('This is your final chance!')
3187 self.assertEqual(sio.getvalue(), '')
3188 root.manager.emittedNoHandlerWarning = False
3189 #If raiseExceptions is False, no message is printed
3190 logging.raiseExceptions = False
3191 sys.stderr = sio = io.StringIO()
3192 root.warning('This is your final chance!')
3193 self.assertEqual(sio.getvalue(), '')
3194 finally:
3195 sys.stderr = old_stderr
3196 root.addHandler(self.root_hdlr)
3197 logging.lastResort = old_lastresort
3198 logging.raiseExceptions = old_raise_exceptions
3199
3200
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003201class FakeHandler:
3202
3203 def __init__(self, identifier, called):
3204 for method in ('acquire', 'flush', 'close', 'release'):
3205 setattr(self, method, self.record_call(identifier, method, called))
3206
3207 def record_call(self, identifier, method_name, called):
3208 def inner():
3209 called.append('{} - {}'.format(identifier, method_name))
3210 return inner
3211
3212
3213class RecordingHandler(logging.NullHandler):
3214
3215 def __init__(self, *args, **kwargs):
3216 super(RecordingHandler, self).__init__(*args, **kwargs)
3217 self.records = []
3218
3219 def handle(self, record):
3220 """Keep track of all the emitted records."""
3221 self.records.append(record)
3222
3223
3224class ShutdownTest(BaseTest):
3225
Vinay Sajip5e66b162011-04-20 15:41:14 +01003226 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003227
3228 def setUp(self):
3229 super(ShutdownTest, self).setUp()
3230 self.called = []
3231
3232 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003233 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003234
3235 def raise_error(self, error):
3236 def inner():
3237 raise error()
3238 return inner
3239
3240 def test_no_failure(self):
3241 # create some fake handlers
3242 handler0 = FakeHandler(0, self.called)
3243 handler1 = FakeHandler(1, self.called)
3244 handler2 = FakeHandler(2, self.called)
3245
3246 # create live weakref to those handlers
3247 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3248
3249 logging.shutdown(handlerList=list(handlers))
3250
3251 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3252 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3253 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3254 self.assertEqual(expected, self.called)
3255
3256 def _test_with_failure_in_method(self, method, error):
3257 handler = FakeHandler(0, self.called)
3258 setattr(handler, method, self.raise_error(error))
3259 handlers = [logging.weakref.ref(handler)]
3260
3261 logging.shutdown(handlerList=list(handlers))
3262
3263 self.assertEqual('0 - release', self.called[-1])
3264
3265 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003266 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003267
3268 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003269 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003270
3271 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003272 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003273
3274 def test_with_valueerror_in_acquire(self):
3275 self._test_with_failure_in_method('acquire', ValueError)
3276
3277 def test_with_valueerror_in_flush(self):
3278 self._test_with_failure_in_method('flush', ValueError)
3279
3280 def test_with_valueerror_in_close(self):
3281 self._test_with_failure_in_method('close', ValueError)
3282
3283 def test_with_other_error_in_acquire_without_raise(self):
3284 logging.raiseExceptions = False
3285 self._test_with_failure_in_method('acquire', IndexError)
3286
3287 def test_with_other_error_in_flush_without_raise(self):
3288 logging.raiseExceptions = False
3289 self._test_with_failure_in_method('flush', IndexError)
3290
3291 def test_with_other_error_in_close_without_raise(self):
3292 logging.raiseExceptions = False
3293 self._test_with_failure_in_method('close', IndexError)
3294
3295 def test_with_other_error_in_acquire_with_raise(self):
3296 logging.raiseExceptions = True
3297 self.assertRaises(IndexError, self._test_with_failure_in_method,
3298 'acquire', IndexError)
3299
3300 def test_with_other_error_in_flush_with_raise(self):
3301 logging.raiseExceptions = True
3302 self.assertRaises(IndexError, self._test_with_failure_in_method,
3303 'flush', IndexError)
3304
3305 def test_with_other_error_in_close_with_raise(self):
3306 logging.raiseExceptions = True
3307 self.assertRaises(IndexError, self._test_with_failure_in_method,
3308 'close', IndexError)
3309
3310
3311class ModuleLevelMiscTest(BaseTest):
3312
Vinay Sajip5e66b162011-04-20 15:41:14 +01003313 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003314
3315 def test_disable(self):
3316 old_disable = logging.root.manager.disable
3317 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003318 self.assertEqual(old_disable, 0)
3319 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003320
3321 logging.disable(83)
3322 self.assertEqual(logging.root.manager.disable, 83)
3323
3324 def _test_log(self, method, level=None):
3325 called = []
3326 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003327 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003328
3329 recording = RecordingHandler()
3330 logging.root.addHandler(recording)
3331
3332 log_method = getattr(logging, method)
3333 if level is not None:
3334 log_method(level, "test me: %r", recording)
3335 else:
3336 log_method("test me: %r", recording)
3337
3338 self.assertEqual(len(recording.records), 1)
3339 record = recording.records[0]
3340 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3341
3342 expected_level = level if level is not None else getattr(logging, method.upper())
3343 self.assertEqual(record.levelno, expected_level)
3344
3345 # basicConfig was not called!
3346 self.assertEqual(called, [])
3347
3348 def test_log(self):
3349 self._test_log('log', logging.ERROR)
3350
3351 def test_debug(self):
3352 self._test_log('debug')
3353
3354 def test_info(self):
3355 self._test_log('info')
3356
3357 def test_warning(self):
3358 self._test_log('warning')
3359
3360 def test_error(self):
3361 self._test_log('error')
3362
3363 def test_critical(self):
3364 self._test_log('critical')
3365
3366 def test_set_logger_class(self):
3367 self.assertRaises(TypeError, logging.setLoggerClass, object)
3368
3369 class MyLogger(logging.Logger):
3370 pass
3371
3372 logging.setLoggerClass(MyLogger)
3373 self.assertEqual(logging.getLoggerClass(), MyLogger)
3374
3375 logging.setLoggerClass(logging.Logger)
3376 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3377
Antoine Pitrou712cb732013-12-21 15:51:54 +01003378 def test_logging_at_shutdown(self):
3379 # Issue #20037
3380 code = """if 1:
3381 import logging
3382
3383 class A:
3384 def __del__(self):
3385 try:
3386 raise ValueError("some error")
3387 except Exception:
3388 logging.exception("exception in __del__")
3389
3390 a = A()"""
3391 rc, out, err = assert_python_ok("-c", code)
3392 err = err.decode()
3393 self.assertIn("exception in __del__", err)
3394 self.assertIn("ValueError: some error", err)
3395
3396
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003397class LogRecordTest(BaseTest):
3398 def test_str_rep(self):
3399 r = logging.makeLogRecord({})
3400 s = str(r)
3401 self.assertTrue(s.startswith('<LogRecord: '))
3402 self.assertTrue(s.endswith('>'))
3403
3404 def test_dict_arg(self):
3405 h = RecordingHandler()
3406 r = logging.getLogger()
3407 r.addHandler(h)
3408 d = {'less' : 'more' }
3409 logging.warning('less is %(less)s', d)
3410 self.assertIs(h.records[0].args, d)
3411 self.assertEqual(h.records[0].message, 'less is more')
3412 r.removeHandler(h)
3413 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003414
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003415 def test_multiprocessing(self):
3416 r = logging.makeLogRecord({})
3417 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003418 try:
3419 import multiprocessing as mp
3420 r = logging.makeLogRecord({})
3421 self.assertEqual(r.processName, mp.current_process().name)
3422 except ImportError:
3423 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003424
3425 def test_optional(self):
3426 r = logging.makeLogRecord({})
3427 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003428 if threading:
3429 NOT_NONE(r.thread)
3430 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003431 NOT_NONE(r.process)
3432 NOT_NONE(r.processName)
3433 log_threads = logging.logThreads
3434 log_processes = logging.logProcesses
3435 log_multiprocessing = logging.logMultiprocessing
3436 try:
3437 logging.logThreads = False
3438 logging.logProcesses = False
3439 logging.logMultiprocessing = False
3440 r = logging.makeLogRecord({})
3441 NONE = self.assertIsNone
3442 NONE(r.thread)
3443 NONE(r.threadName)
3444 NONE(r.process)
3445 NONE(r.processName)
3446 finally:
3447 logging.logThreads = log_threads
3448 logging.logProcesses = log_processes
3449 logging.logMultiprocessing = log_multiprocessing
3450
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003451class BasicConfigTest(unittest.TestCase):
3452
Vinay Sajip95bf5042011-04-20 11:50:56 +01003453 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003454
3455 def setUp(self):
3456 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003457 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003458 self.saved_handlers = logging._handlers.copy()
3459 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003460 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003461 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003462 logging.root.handlers = []
3463
3464 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003465 for h in logging.root.handlers[:]:
3466 logging.root.removeHandler(h)
3467 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003468 super(BasicConfigTest, self).tearDown()
3469
Vinay Sajip3def7e02011-04-20 10:58:06 +01003470 def cleanup(self):
3471 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003472 logging._handlers.clear()
3473 logging._handlers.update(self.saved_handlers)
3474 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003475 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003476
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003477 def test_no_kwargs(self):
3478 logging.basicConfig()
3479
3480 # handler defaults to a StreamHandler to sys.stderr
3481 self.assertEqual(len(logging.root.handlers), 1)
3482 handler = logging.root.handlers[0]
3483 self.assertIsInstance(handler, logging.StreamHandler)
3484 self.assertEqual(handler.stream, sys.stderr)
3485
3486 formatter = handler.formatter
3487 # format defaults to logging.BASIC_FORMAT
3488 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3489 # datefmt defaults to None
3490 self.assertIsNone(formatter.datefmt)
3491 # style defaults to %
3492 self.assertIsInstance(formatter._style, logging.PercentStyle)
3493
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003494 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003495 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003496
Vinay Sajip1fd12022014-01-13 21:59:56 +00003497 def test_strformatstyle(self):
3498 with captured_stdout() as output:
3499 logging.basicConfig(stream=sys.stdout, style="{")
3500 logging.error("Log an error")
3501 sys.stdout.seek(0)
3502 self.assertEqual(output.getvalue().strip(),
3503 "ERROR:root:Log an error")
3504
3505 def test_stringtemplatestyle(self):
3506 with captured_stdout() as output:
3507 logging.basicConfig(stream=sys.stdout, style="$")
3508 logging.error("Log an error")
3509 sys.stdout.seek(0)
3510 self.assertEqual(output.getvalue().strip(),
3511 "ERROR:root:Log an error")
3512
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003513 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003514
3515 def cleanup(h1, h2, fn):
3516 h1.close()
3517 h2.close()
3518 os.remove(fn)
3519
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003520 logging.basicConfig(filename='test.log')
3521
3522 self.assertEqual(len(logging.root.handlers), 1)
3523 handler = logging.root.handlers[0]
3524 self.assertIsInstance(handler, logging.FileHandler)
3525
3526 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003527 self.assertEqual(handler.stream.mode, expected.stream.mode)
3528 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003529 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003530
3531 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003532
3533 def cleanup(h1, h2, fn):
3534 h1.close()
3535 h2.close()
3536 os.remove(fn)
3537
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003538 logging.basicConfig(filename='test.log', filemode='wb')
3539
3540 handler = logging.root.handlers[0]
3541 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003542 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003543 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003544
3545 def test_stream(self):
3546 stream = io.StringIO()
3547 self.addCleanup(stream.close)
3548 logging.basicConfig(stream=stream)
3549
3550 self.assertEqual(len(logging.root.handlers), 1)
3551 handler = logging.root.handlers[0]
3552 self.assertIsInstance(handler, logging.StreamHandler)
3553 self.assertEqual(handler.stream, stream)
3554
3555 def test_format(self):
3556 logging.basicConfig(format='foo')
3557
3558 formatter = logging.root.handlers[0].formatter
3559 self.assertEqual(formatter._style._fmt, 'foo')
3560
3561 def test_datefmt(self):
3562 logging.basicConfig(datefmt='bar')
3563
3564 formatter = logging.root.handlers[0].formatter
3565 self.assertEqual(formatter.datefmt, 'bar')
3566
3567 def test_style(self):
3568 logging.basicConfig(style='$')
3569
3570 formatter = logging.root.handlers[0].formatter
3571 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3572
3573 def test_level(self):
3574 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003575 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003576
3577 logging.basicConfig(level=57)
3578 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003579 # Test that second call has no effect
3580 logging.basicConfig(level=58)
3581 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003582
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003583 def test_incompatible(self):
3584 assertRaises = self.assertRaises
3585 handlers = [logging.StreamHandler()]
3586 stream = sys.stderr
3587 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3588 stream=stream)
3589 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3590 handlers=handlers)
3591 assertRaises(ValueError, logging.basicConfig, stream=stream,
3592 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003593 # Issue 23207: test for invalid kwargs
3594 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3595 # Should pop both filename and filemode even if filename is None
3596 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003597
3598 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003599 handlers = [
3600 logging.StreamHandler(),
3601 logging.StreamHandler(sys.stdout),
3602 logging.StreamHandler(),
3603 ]
3604 f = logging.Formatter()
3605 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003606 logging.basicConfig(handlers=handlers)
3607 self.assertIs(handlers[0], logging.root.handlers[0])
3608 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003609 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003610 self.assertIsNotNone(handlers[0].formatter)
3611 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003612 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003613 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3614
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003615 def _test_log(self, method, level=None):
3616 # logging.root has no handlers so basicConfig should be called
3617 called = []
3618
3619 old_basic_config = logging.basicConfig
3620 def my_basic_config(*a, **kw):
3621 old_basic_config()
3622 old_level = logging.root.level
3623 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003624 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003625 called.append((a, kw))
3626
3627 patch(self, logging, 'basicConfig', my_basic_config)
3628
3629 log_method = getattr(logging, method)
3630 if level is not None:
3631 log_method(level, "test me")
3632 else:
3633 log_method("test me")
3634
3635 # basicConfig was called with no arguments
3636 self.assertEqual(called, [((), {})])
3637
3638 def test_log(self):
3639 self._test_log('log', logging.WARNING)
3640
3641 def test_debug(self):
3642 self._test_log('debug')
3643
3644 def test_info(self):
3645 self._test_log('info')
3646
3647 def test_warning(self):
3648 self._test_log('warning')
3649
3650 def test_error(self):
3651 self._test_log('error')
3652
3653 def test_critical(self):
3654 self._test_log('critical')
3655
3656
3657class LoggerAdapterTest(unittest.TestCase):
3658
3659 def setUp(self):
3660 super(LoggerAdapterTest, self).setUp()
3661 old_handler_list = logging._handlerList[:]
3662
3663 self.recording = RecordingHandler()
3664 self.logger = logging.root
3665 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003666 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003667 self.addCleanup(self.recording.close)
3668
3669 def cleanup():
3670 logging._handlerList[:] = old_handler_list
3671
3672 self.addCleanup(cleanup)
3673 self.addCleanup(logging.shutdown)
3674 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3675
3676 def test_exception(self):
3677 msg = 'testing exception: %r'
3678 exc = None
3679 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003680 1 / 0
3681 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003682 exc = e
3683 self.adapter.exception(msg, self.recording)
3684
3685 self.assertEqual(len(self.recording.records), 1)
3686 record = self.recording.records[0]
3687 self.assertEqual(record.levelno, logging.ERROR)
3688 self.assertEqual(record.msg, msg)
3689 self.assertEqual(record.args, (self.recording,))
3690 self.assertEqual(record.exc_info,
3691 (exc.__class__, exc, exc.__traceback__))
3692
3693 def test_critical(self):
3694 msg = 'critical test! %r'
3695 self.adapter.critical(msg, self.recording)
3696
3697 self.assertEqual(len(self.recording.records), 1)
3698 record = self.recording.records[0]
3699 self.assertEqual(record.levelno, logging.CRITICAL)
3700 self.assertEqual(record.msg, msg)
3701 self.assertEqual(record.args, (self.recording,))
3702
3703 def test_is_enabled_for(self):
3704 old_disable = self.adapter.logger.manager.disable
3705 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003706 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3707 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003708 self.assertFalse(self.adapter.isEnabledFor(32))
3709
3710 def test_has_handlers(self):
3711 self.assertTrue(self.adapter.hasHandlers())
3712
3713 for handler in self.logger.handlers:
3714 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003715
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003716 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003717 self.assertFalse(self.adapter.hasHandlers())
3718
3719
3720class LoggerTest(BaseTest):
3721
3722 def setUp(self):
3723 super(LoggerTest, self).setUp()
3724 self.recording = RecordingHandler()
3725 self.logger = logging.Logger(name='blah')
3726 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003727 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003728 self.addCleanup(self.recording.close)
3729 self.addCleanup(logging.shutdown)
3730
3731 def test_set_invalid_level(self):
3732 self.assertRaises(TypeError, self.logger.setLevel, object())
3733
3734 def test_exception(self):
3735 msg = 'testing exception: %r'
3736 exc = None
3737 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003738 1 / 0
3739 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003740 exc = e
3741 self.logger.exception(msg, self.recording)
3742
3743 self.assertEqual(len(self.recording.records), 1)
3744 record = self.recording.records[0]
3745 self.assertEqual(record.levelno, logging.ERROR)
3746 self.assertEqual(record.msg, msg)
3747 self.assertEqual(record.args, (self.recording,))
3748 self.assertEqual(record.exc_info,
3749 (exc.__class__, exc, exc.__traceback__))
3750
3751 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003752 with swap_attr(logging, 'raiseExceptions', True):
3753 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003754
3755 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003756 with swap_attr(logging, 'raiseExceptions', False):
3757 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003758
3759 def test_find_caller_with_stack_info(self):
3760 called = []
3761 patch(self, logging.traceback, 'print_stack',
3762 lambda f, file: called.append(file.getvalue()))
3763
3764 self.logger.findCaller(stack_info=True)
3765
3766 self.assertEqual(len(called), 1)
3767 self.assertEqual('Stack (most recent call last):\n', called[0])
3768
3769 def test_make_record_with_extra_overwrite(self):
3770 name = 'my record'
3771 level = 13
3772 fn = lno = msg = args = exc_info = func = sinfo = None
3773 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3774 exc_info, func, sinfo)
3775
3776 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3777 extra = {key: 'some value'}
3778 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3779 fn, lno, msg, args, exc_info,
3780 extra=extra, sinfo=sinfo)
3781
3782 def test_make_record_with_extra_no_overwrite(self):
3783 name = 'my record'
3784 level = 13
3785 fn = lno = msg = args = exc_info = func = sinfo = None
3786 extra = {'valid_key': 'some value'}
3787 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3788 exc_info, extra=extra, sinfo=sinfo)
3789 self.assertIn('valid_key', result.__dict__)
3790
3791 def test_has_handlers(self):
3792 self.assertTrue(self.logger.hasHandlers())
3793
3794 for handler in self.logger.handlers:
3795 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003796 self.assertFalse(self.logger.hasHandlers())
3797
3798 def test_has_handlers_no_propagate(self):
3799 child_logger = logging.getLogger('blah.child')
3800 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003801 self.assertFalse(child_logger.hasHandlers())
3802
3803 def test_is_enabled_for(self):
3804 old_disable = self.logger.manager.disable
3805 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003806 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003807 self.assertFalse(self.logger.isEnabledFor(22))
3808
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003809 def test_root_logger_aliases(self):
3810 root = logging.getLogger()
3811 self.assertIs(root, logging.root)
3812 self.assertIs(root, logging.getLogger(None))
3813 self.assertIs(root, logging.getLogger(''))
3814 self.assertIs(root, logging.getLogger('foo').root)
3815 self.assertIs(root, logging.getLogger('foo.bar').root)
3816 self.assertIs(root, logging.getLogger('foo').parent)
3817
3818 self.assertIsNot(root, logging.getLogger('\0'))
3819 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3820
3821 def test_invalid_names(self):
3822 self.assertRaises(TypeError, logging.getLogger, any)
3823 self.assertRaises(TypeError, logging.getLogger, b'foo')
3824
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003825
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003826class BaseFileTest(BaseTest):
3827 "Base class for handler tests that write log files"
3828
3829 def setUp(self):
3830 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003831 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3832 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003833 self.rmfiles = []
3834
3835 def tearDown(self):
3836 for fn in self.rmfiles:
3837 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003838 if os.path.exists(self.fn):
3839 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003840 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003841
3842 def assertLogFile(self, filename):
3843 "Assert a log file is there and register it for deletion"
3844 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003845 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003846 self.rmfiles.append(filename)
3847
3848
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003849class FileHandlerTest(BaseFileTest):
3850 def test_delay(self):
3851 os.unlink(self.fn)
3852 fh = logging.FileHandler(self.fn, delay=True)
3853 self.assertIsNone(fh.stream)
3854 self.assertFalse(os.path.exists(self.fn))
3855 fh.handle(logging.makeLogRecord({}))
3856 self.assertIsNotNone(fh.stream)
3857 self.assertTrue(os.path.exists(self.fn))
3858 fh.close()
3859
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003860class RotatingFileHandlerTest(BaseFileTest):
3861 def next_rec(self):
3862 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3863 self.next_message(), None, None, None)
3864
3865 def test_should_not_rollover(self):
3866 # If maxbytes is zero rollover never occurs
3867 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3868 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003869 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003870
3871 def test_should_rollover(self):
3872 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3873 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003874 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003875
3876 def test_file_created(self):
3877 # checks that the file is created and assumes it was created
3878 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003879 rh = logging.handlers.RotatingFileHandler(self.fn)
3880 rh.emit(self.next_rec())
3881 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003882 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003883
3884 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003885 def namer(name):
3886 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003887 rh = logging.handlers.RotatingFileHandler(
3888 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003889 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003890 rh.emit(self.next_rec())
3891 self.assertLogFile(self.fn)
3892 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003893 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003894 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003895 self.assertLogFile(namer(self.fn + ".2"))
3896 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3897 rh.close()
3898
Eric V. Smith851cad72012-03-11 22:46:04 -07003899 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003900 def test_rotator(self):
3901 def namer(name):
3902 return name + ".gz"
3903
3904 def rotator(source, dest):
3905 with open(source, "rb") as sf:
3906 data = sf.read()
3907 compressed = zlib.compress(data, 9)
3908 with open(dest, "wb") as df:
3909 df.write(compressed)
3910 os.remove(source)
3911
3912 rh = logging.handlers.RotatingFileHandler(
3913 self.fn, backupCount=2, maxBytes=1)
3914 rh.rotator = rotator
3915 rh.namer = namer
3916 m1 = self.next_rec()
3917 rh.emit(m1)
3918 self.assertLogFile(self.fn)
3919 m2 = self.next_rec()
3920 rh.emit(m2)
3921 fn = namer(self.fn + ".1")
3922 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003923 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003924 with open(fn, "rb") as f:
3925 compressed = f.read()
3926 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003927 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003928 rh.emit(self.next_rec())
3929 fn = namer(self.fn + ".2")
3930 self.assertLogFile(fn)
3931 with open(fn, "rb") as f:
3932 compressed = f.read()
3933 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003934 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003935 rh.emit(self.next_rec())
3936 fn = namer(self.fn + ".2")
3937 with open(fn, "rb") as f:
3938 compressed = f.read()
3939 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003940 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003941 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003942 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003943
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003944class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003945 # other test methods added below
3946 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003947 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3948 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003949 fmt = logging.Formatter('%(asctime)s %(message)s')
3950 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003951 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003952 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003953 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003954 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003955 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003956 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003957 fh.close()
3958 # At this point, we should have a recent rotated file which we
3959 # can test for the existence of. However, in practice, on some
3960 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003961 # in time to go to look for the log file. So, we go back a fair
3962 # bit, and stop as soon as we see a rotated file. In theory this
3963 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003964 found = False
3965 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003966 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003967 for secs in range(GO_BACK):
3968 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003969 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3970 found = os.path.exists(fn)
3971 if found:
3972 self.rmfiles.append(fn)
3973 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003974 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3975 if not found:
3976 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003977 dn, fn = os.path.split(self.fn)
3978 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003979 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3980 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003981 for f in files:
3982 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003983 path = os.path.join(dn, f)
3984 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003985 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003986 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003987
Vinay Sajip0372e102011-05-05 12:59:14 +01003988 def test_invalid(self):
3989 assertRaises = self.assertRaises
3990 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003991 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003992 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003993 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003994 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003995 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003996
Vinay Sajipa7130792013-04-12 17:04:23 +01003997 def test_compute_rollover_daily_attime(self):
3998 currentTime = 0
3999 atTime = datetime.time(12, 0, 0)
4000 rh = logging.handlers.TimedRotatingFileHandler(
4001 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4002 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004003 try:
4004 actual = rh.computeRollover(currentTime)
4005 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004006
Vinay Sajipd86ac962013-04-14 12:20:46 +01004007 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4008 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4009 finally:
4010 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004011
Vinay Sajip10e8c492013-05-18 10:19:54 -07004012 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004013 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004014 currentTime = int(time.time())
4015 today = currentTime - currentTime % 86400
4016
Vinay Sajipa7130792013-04-12 17:04:23 +01004017 atTime = datetime.time(12, 0, 0)
4018
Vinay Sajip10e8c492013-05-18 10:19:54 -07004019 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004020 for day in range(7):
4021 rh = logging.handlers.TimedRotatingFileHandler(
4022 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4023 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004024 try:
4025 if wday > day:
4026 # The rollover day has already passed this week, so we
4027 # go over into next week
4028 expected = (7 - wday + day)
4029 else:
4030 expected = (day - wday)
4031 # At this point expected is in days from now, convert to seconds
4032 expected *= 24 * 60 * 60
4033 # Add in the rollover time
4034 expected += 12 * 60 * 60
4035 # Add in adjustment for today
4036 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004037 actual = rh.computeRollover(today)
4038 if actual != expected:
4039 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004040 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004041 self.assertEqual(actual, expected)
4042 if day == wday:
4043 # goes into following week
4044 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004045 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004046 if actual != expected:
4047 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004048 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004049 self.assertEqual(actual, expected)
4050 finally:
4051 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004052
4053
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004054def secs(**kw):
4055 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4056
4057for when, exp in (('S', 1),
4058 ('M', 60),
4059 ('H', 60 * 60),
4060 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004061 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004062 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004063 ('W0', secs(days=4, hours=24)),
4064 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004065 def test_compute_rollover(self, when=when, exp=exp):
4066 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004067 self.fn, when=when, interval=1, backupCount=0, utc=True)
4068 currentTime = 0.0
4069 actual = rh.computeRollover(currentTime)
4070 if exp != actual:
4071 # Failures occur on some systems for MIDNIGHT and W0.
4072 # Print detailed calculation for MIDNIGHT so we can try to see
4073 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004074 if when == 'MIDNIGHT':
4075 try:
4076 if rh.utc:
4077 t = time.gmtime(currentTime)
4078 else:
4079 t = time.localtime(currentTime)
4080 currentHour = t[3]
4081 currentMinute = t[4]
4082 currentSecond = t[5]
4083 # r is the number of seconds left between now and midnight
4084 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4085 currentMinute) * 60 +
4086 currentSecond)
4087 result = currentTime + r
4088 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4089 print('currentHour: %s' % currentHour, file=sys.stderr)
4090 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4091 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4092 print('r: %s' % r, file=sys.stderr)
4093 print('result: %s' % result, file=sys.stderr)
4094 except Exception:
4095 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4096 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004097 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004098 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4099
Vinay Sajip60ccd822011-05-09 17:32:09 +01004100
4101@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4102class NTEventLogHandlerTest(BaseTest):
4103 def test_basic(self):
4104 logtype = 'Application'
4105 elh = win32evtlog.OpenEventLog(None, logtype)
4106 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4107 h = logging.handlers.NTEventLogHandler('test_logging')
4108 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4109 h.handle(r)
4110 h.close()
4111 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004112 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004113 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4114 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4115 found = False
4116 GO_BACK = 100
4117 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4118 for e in events:
4119 if e.SourceName != 'test_logging':
4120 continue
4121 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4122 if msg != 'Test Log Message\r\n':
4123 continue
4124 found = True
4125 break
4126 msg = 'Record not found in event log, went back %d records' % GO_BACK
4127 self.assertTrue(found, msg=msg)
4128
Christian Heimes180510d2008-03-03 19:15:45 +00004129# Set the locale to the platform-dependent default. I have no idea
4130# why the test does this, but in any case we save the current locale
4131# first and restore it at the end.
4132@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004133def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004134 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004135 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004136 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4137 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4138 ManagerTest, FormatterTest, BufferingFormatterTest,
4139 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4140 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4141 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4142 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004143 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004144 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004145 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4146 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004147 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004148
Christian Heimes180510d2008-03-03 19:15:45 +00004149if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004150 test_main()