blob: ffd0c8bf2b54337975e557e95b8f0dc30e7d28f7 [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajip3f885b52013-03-22 15:19:54 +00003# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00004#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose and without fee is hereby granted,
7# provided that the above copyright notice appear in all copies and that
8# both that copyright notice and this permission notice appear in
9# supporting documentation, and that the name of Vinay Sajip
10# not be used in advertising or publicity pertaining to distribution
11# of the software without specific, written prior permission.
12# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
16# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19"""Test harness for the logging module. Run all tests.
20
Vinay Sajip3f885b52013-03-22 15:19:54 +000021Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000022"""
23
Christian Heimes180510d2008-03-03 19:15:45 +000024import logging
25import logging.handlers
26import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000027
Benjamin Petersonf91df042009-02-13 02:50:59 +000028import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010029import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000030import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000031import pickle
32import io
33import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000034import json
Christian Heimes180510d2008-03-03 19:15:45 +000035import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000036import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010037import random
Christian Heimes180510d2008-03-03 19:15:45 +000038import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000039import select
Christian Heimes180510d2008-03-03 19:15:45 +000040import socket
Christian Heimes180510d2008-03-03 19:15:45 +000041import struct
42import sys
43import tempfile
Eric V. Smith851cad72012-03-11 22:46:04 -070044from test.support import (captured_stdout, run_with_locale, run_unittest,
45 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000046import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010047import time
Christian Heimes180510d2008-03-03 19:15:45 +000048import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000049import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000050import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000051try:
52 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010054 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010055 import asynchat
56 import asyncore
57 import errno
58 from http.server import HTTPServer, BaseHTTPRequestHandler
59 import smtpd
60 from urllib.parse import urlparse, parse_qs
61 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
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
317
318class BasicFilterTest(BaseTest):
319
320 """Test the bundled Filter class."""
321
322 def test_filter(self):
323 # Only messages satisfying the specified criteria pass through the
324 # filter.
325 filter_ = logging.Filter("spam.eggs")
326 handler = self.root_logger.handlers[0]
327 try:
328 handler.addFilter(filter_)
329 spam = logging.getLogger("spam")
330 spam_eggs = logging.getLogger("spam.eggs")
331 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
332 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
333
334 spam.info(self.next_message())
335 spam_eggs.info(self.next_message()) # Good.
336 spam_eggs_fish.info(self.next_message()) # Good.
337 spam_bakedbeans.info(self.next_message())
338
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000339 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000340 ('spam.eggs', 'INFO', '2'),
341 ('spam.eggs.fish', 'INFO', '3'),
342 ])
343 finally:
344 handler.removeFilter(filter_)
345
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000346 def test_callable_filter(self):
347 # Only messages satisfying the specified criteria pass through the
348 # filter.
349
350 def filterfunc(record):
351 parts = record.name.split('.')
352 prefix = '.'.join(parts[:2])
353 return prefix == 'spam.eggs'
354
355 handler = self.root_logger.handlers[0]
356 try:
357 handler.addFilter(filterfunc)
358 spam = logging.getLogger("spam")
359 spam_eggs = logging.getLogger("spam.eggs")
360 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
361 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
362
363 spam.info(self.next_message())
364 spam_eggs.info(self.next_message()) # Good.
365 spam_eggs_fish.info(self.next_message()) # Good.
366 spam_bakedbeans.info(self.next_message())
367
368 self.assert_log_lines([
369 ('spam.eggs', 'INFO', '2'),
370 ('spam.eggs.fish', 'INFO', '3'),
371 ])
372 finally:
373 handler.removeFilter(filterfunc)
374
Vinay Sajip985ef872011-04-26 19:34:04 +0100375 def test_empty_filter(self):
376 f = logging.Filter()
377 r = logging.makeLogRecord({'name': 'spam.eggs'})
378 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000379
380#
381# First, we define our levels. There can be as many as you want - the only
382# limitations are that they should be integers, the lowest should be > 0 and
383# larger values mean less information being logged. If you need specific
384# level values which do not fit into these limitations, you can use a
385# mapping dictionary to convert between your application levels and the
386# logging system.
387#
388SILENT = 120
389TACITURN = 119
390TERSE = 118
391EFFUSIVE = 117
392SOCIABLE = 116
393VERBOSE = 115
394TALKATIVE = 114
395GARRULOUS = 113
396CHATTERBOX = 112
397BORING = 111
398
399LEVEL_RANGE = range(BORING, SILENT + 1)
400
401#
402# Next, we define names for our levels. You don't need to do this - in which
403# case the system will use "Level n" to denote the text for the level.
404#
405my_logging_levels = {
406 SILENT : 'Silent',
407 TACITURN : 'Taciturn',
408 TERSE : 'Terse',
409 EFFUSIVE : 'Effusive',
410 SOCIABLE : 'Sociable',
411 VERBOSE : 'Verbose',
412 TALKATIVE : 'Talkative',
413 GARRULOUS : 'Garrulous',
414 CHATTERBOX : 'Chatterbox',
415 BORING : 'Boring',
416}
417
418class GarrulousFilter(logging.Filter):
419
420 """A filter which blocks garrulous messages."""
421
422 def filter(self, record):
423 return record.levelno != GARRULOUS
424
425class VerySpecificFilter(logging.Filter):
426
427 """A filter which blocks sociable and taciturn messages."""
428
429 def filter(self, record):
430 return record.levelno not in [SOCIABLE, TACITURN]
431
432
433class CustomLevelsAndFiltersTest(BaseTest):
434
435 """Test various filtering possibilities with custom logging levels."""
436
437 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300438 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000439
440 def setUp(self):
441 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000442 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000443 logging.addLevelName(k, v)
444
445 def log_at_all_levels(self, logger):
446 for lvl in LEVEL_RANGE:
447 logger.log(lvl, self.next_message())
448
449 def test_logger_filter(self):
450 # Filter at logger level.
451 self.root_logger.setLevel(VERBOSE)
452 # Levels >= 'Verbose' are good.
453 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000454 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000455 ('Verbose', '5'),
456 ('Sociable', '6'),
457 ('Effusive', '7'),
458 ('Terse', '8'),
459 ('Taciturn', '9'),
460 ('Silent', '10'),
461 ])
462
463 def test_handler_filter(self):
464 # Filter at handler level.
465 self.root_logger.handlers[0].setLevel(SOCIABLE)
466 try:
467 # Levels >= 'Sociable' are good.
468 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000469 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000470 ('Sociable', '6'),
471 ('Effusive', '7'),
472 ('Terse', '8'),
473 ('Taciturn', '9'),
474 ('Silent', '10'),
475 ])
476 finally:
477 self.root_logger.handlers[0].setLevel(logging.NOTSET)
478
479 def test_specific_filters(self):
480 # Set a specific filter object on the handler, and then add another
481 # filter object on the logger itself.
482 handler = self.root_logger.handlers[0]
483 specific_filter = None
484 garr = GarrulousFilter()
485 handler.addFilter(garr)
486 try:
487 self.log_at_all_levels(self.root_logger)
488 first_lines = [
489 # Notice how 'Garrulous' is missing
490 ('Boring', '1'),
491 ('Chatterbox', '2'),
492 ('Talkative', '4'),
493 ('Verbose', '5'),
494 ('Sociable', '6'),
495 ('Effusive', '7'),
496 ('Terse', '8'),
497 ('Taciturn', '9'),
498 ('Silent', '10'),
499 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000500 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000501
502 specific_filter = VerySpecificFilter()
503 self.root_logger.addFilter(specific_filter)
504 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000505 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000506 # Not only 'Garrulous' is still missing, but also 'Sociable'
507 # and 'Taciturn'
508 ('Boring', '11'),
509 ('Chatterbox', '12'),
510 ('Talkative', '14'),
511 ('Verbose', '15'),
512 ('Effusive', '17'),
513 ('Terse', '18'),
514 ('Silent', '20'),
515 ])
516 finally:
517 if specific_filter:
518 self.root_logger.removeFilter(specific_filter)
519 handler.removeFilter(garr)
520
521
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100522class HandlerTest(BaseTest):
523 def test_name(self):
524 h = logging.Handler()
525 h.name = 'generic'
526 self.assertEqual(h.name, 'generic')
527 h.name = 'anothergeneric'
528 self.assertEqual(h.name, 'anothergeneric')
529 self.assertRaises(NotImplementedError, h.emit, None)
530
Vinay Sajip5a35b062011-04-27 11:31:14 +0100531 def test_builtin_handlers(self):
532 # We can't actually *use* too many handlers in the tests,
533 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200534 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100535 for existing in (True, False):
536 fd, fn = tempfile.mkstemp()
537 os.close(fd)
538 if not existing:
539 os.unlink(fn)
540 h = logging.handlers.WatchedFileHandler(fn, delay=True)
541 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100542 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100543 self.assertEqual(dev, -1)
544 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100545 r = logging.makeLogRecord({'msg': 'Test'})
546 h.handle(r)
547 # Now remove the file.
548 os.unlink(fn)
549 self.assertFalse(os.path.exists(fn))
550 # The next call should recreate the file.
551 h.handle(r)
552 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100553 else:
554 self.assertEqual(h.dev, -1)
555 self.assertEqual(h.ino, -1)
556 h.close()
557 if existing:
558 os.unlink(fn)
559 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100560 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100561 else:
562 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100563 try:
564 h = logging.handlers.SysLogHandler(sockname)
565 self.assertEqual(h.facility, h.LOG_USER)
566 self.assertTrue(h.unixsocket)
567 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200568 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100569 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100570 for method in ('GET', 'POST', 'PUT'):
571 if method == 'PUT':
572 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
573 'localhost', '/log', method)
574 else:
575 h = logging.handlers.HTTPHandler('localhost', '/log', method)
576 h.close()
577 h = logging.handlers.BufferingHandler(0)
578 r = logging.makeLogRecord({})
579 self.assertTrue(h.shouldFlush(r))
580 h.close()
581 h = logging.handlers.BufferingHandler(1)
582 self.assertFalse(h.shouldFlush(r))
583 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100584
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100585 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100586 @unittest.skipUnless(threading, 'Threading required for this test.')
587 def test_race(self):
588 # Issue #14632 refers.
589 def remove_loop(fname, tries):
590 for _ in range(tries):
591 try:
592 os.unlink(fname)
593 except OSError:
594 pass
595 time.sleep(0.004 * random.randint(0, 4))
596
Vinay Sajipc94871a2012-04-25 10:51:35 +0100597 del_count = 500
598 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100599
Vinay Sajipa5798de2012-04-24 23:33:33 +0100600 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100601 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
602 os.close(fd)
603 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
604 remover.daemon = True
605 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100606 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100607 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
608 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100609 try:
610 for _ in range(log_count):
611 time.sleep(0.005)
612 r = logging.makeLogRecord({'msg': 'testing' })
613 h.handle(r)
614 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100615 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100616 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100617 if os.path.exists(fn):
618 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100619
620
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100621class BadStream(object):
622 def write(self, data):
623 raise RuntimeError('deliberate mistake')
624
625class TestStreamHandler(logging.StreamHandler):
626 def handleError(self, record):
627 self.error_record = record
628
629class StreamHandlerTest(BaseTest):
630 def test_error_handling(self):
631 h = TestStreamHandler(BadStream())
632 r = logging.makeLogRecord({})
633 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100634 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100635 try:
636 h.handle(r)
637 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100638 h = logging.StreamHandler(BadStream())
639 sys.stderr = sio = io.StringIO()
640 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100641 self.assertIn('\nRuntimeError: deliberate mistake\n',
642 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100643 logging.raiseExceptions = False
644 sys.stderr = sio = io.StringIO()
645 h.handle(r)
646 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100647 finally:
648 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100649 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100650
Vinay Sajip7367d082011-05-02 13:17:27 +0100651# -- The following section could be moved into a server_helper.py module
652# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100653
Vinay Sajipce7c9782011-05-17 07:15:53 +0100654if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100655 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100656 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100657 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100658
Vinay Sajipce7c9782011-05-17 07:15:53 +0100659 :param addr: A (host, port) tuple which the server listens on.
660 You can specify a port value of zero: the server's
661 *port* attribute will hold the actual port number
662 used, which can be used in client connections.
663 :param handler: A callable which will be called to process
664 incoming messages. The handler will be passed
665 the client address tuple, who the message is from,
666 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100667 :param poll_interval: The interval, in seconds, used in the underlying
668 :func:`select` or :func:`poll` call by
669 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100670 :param sockmap: A dictionary which will be used to hold
671 :class:`asyncore.dispatcher` instances used by
672 :func:`asyncore.loop`. This avoids changing the
673 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100674 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100675
676 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100677 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
678 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100679 self._handler = handler
680 self._thread = None
681 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100682
Vinay Sajipce7c9782011-05-17 07:15:53 +0100683 def process_message(self, peer, mailfrom, rcpttos, data):
684 """
685 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100686
Vinay Sajipce7c9782011-05-17 07:15:53 +0100687 Typically, this will be a test case method.
688 :param peer: The client (host, port) tuple.
689 :param mailfrom: The address of the sender.
690 :param rcpttos: The addresses of the recipients.
691 :param data: The message.
692 """
693 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100694
Vinay Sajipce7c9782011-05-17 07:15:53 +0100695 def start(self):
696 """
697 Start the server running on a separate daemon thread.
698 """
699 self._thread = t = threading.Thread(target=self.serve_forever,
700 args=(self.poll_interval,))
701 t.setDaemon(True)
702 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100703
Vinay Sajipce7c9782011-05-17 07:15:53 +0100704 def serve_forever(self, poll_interval):
705 """
706 Run the :mod:`asyncore` loop until normal termination
707 conditions arise.
708 :param poll_interval: The interval, in seconds, used in the underlying
709 :func:`select` or :func:`poll` call by
710 :func:`asyncore.loop`.
711 """
712 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100713 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200714 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100715 # On FreeBSD 8, closing the server repeatably
716 # raises this error. We swallow it if the
717 # server has been closed.
718 if self.connected or self.accepting:
719 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100720
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 def stop(self, timeout=None):
722 """
723 Stop the thread by closing the server instance.
724 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100725
Vinay Sajipce7c9782011-05-17 07:15:53 +0100726 :param timeout: How long to wait for the server thread
727 to terminate.
728 """
729 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100730 self._thread.join(timeout)
731 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100732
Vinay Sajipce7c9782011-05-17 07:15:53 +0100733 class ControlMixin(object):
734 """
735 This mixin is used to start a server on a separate thread, and
736 shut it down programmatically. Request handling is simplified - instead
737 of needing to derive a suitable RequestHandler subclass, you just
738 provide a callable which will be passed each received request to be
739 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100740
Vinay Sajipce7c9782011-05-17 07:15:53 +0100741 :param handler: A handler callable which will be called with a
742 single parameter - the request - in order to
743 process the request. This handler is called on the
744 server thread, effectively meaning that requests are
745 processed serially. While not quite Web scale ;-),
746 this should be fine for testing applications.
747 :param poll_interval: The polling interval in seconds.
748 """
749 def __init__(self, handler, poll_interval):
750 self._thread = None
751 self.poll_interval = poll_interval
752 self._handler = handler
753 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100754
Vinay Sajipce7c9782011-05-17 07:15:53 +0100755 def start(self):
756 """
757 Create a daemon thread to run the server, and start it.
758 """
759 self._thread = t = threading.Thread(target=self.serve_forever,
760 args=(self.poll_interval,))
761 t.setDaemon(True)
762 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100763
Vinay Sajipce7c9782011-05-17 07:15:53 +0100764 def serve_forever(self, poll_interval):
765 """
766 Run the server. Set the ready flag before entering the
767 service loop.
768 """
769 self.ready.set()
770 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100771
Vinay Sajipce7c9782011-05-17 07:15:53 +0100772 def stop(self, timeout=None):
773 """
774 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100775
Vinay Sajipce7c9782011-05-17 07:15:53 +0100776 :param timeout: How long to wait for the server thread
777 to terminate.
778 """
779 self.shutdown()
780 if self._thread is not None:
781 self._thread.join(timeout)
782 self._thread = None
783 self.server_close()
784 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 class TestHTTPServer(ControlMixin, HTTPServer):
787 """
788 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100789
Vinay Sajipce7c9782011-05-17 07:15:53 +0100790 :param addr: A tuple with the IP address and port to listen on.
791 :param handler: A handler callable which will be called with a
792 single parameter - the request - in order to
793 process the request.
794 :param poll_interval: The polling interval in seconds.
795 :param log: Pass ``True`` to enable log messages.
796 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100797 def __init__(self, addr, handler, poll_interval=0.5,
798 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100799 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
800 def __getattr__(self, name, default=None):
801 if name.startswith('do_'):
802 return self.process_request
803 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100804
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 def process_request(self):
806 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100807
Vinay Sajipce7c9782011-05-17 07:15:53 +0100808 def log_message(self, format, *args):
809 if log:
810 super(DelegatingHTTPRequestHandler,
811 self).log_message(format, *args)
812 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
813 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100814 self.sslctx = sslctx
815
816 def get_request(self):
817 try:
818 sock, addr = self.socket.accept()
819 if self.sslctx:
820 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200821 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100822 # socket errors are silenced by the caller, print them here
823 sys.stderr.write("Got an error:\n%s\n" % e)
824 raise
825 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100826
Vinay Sajipce7c9782011-05-17 07:15:53 +0100827 class TestTCPServer(ControlMixin, ThreadingTCPServer):
828 """
829 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100830
Vinay Sajipce7c9782011-05-17 07:15:53 +0100831 :param addr: A tuple with the IP address and port to listen on.
832 :param handler: A handler callable which will be called with a single
833 parameter - the request - in order to process the request.
834 :param poll_interval: The polling interval in seconds.
835 :bind_and_activate: If True (the default), binds the server and starts it
836 listening. If False, you need to call
837 :meth:`server_bind` and :meth:`server_activate` at
838 some later time before calling :meth:`start`, so that
839 the server will set up the socket and listen on it.
840 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100841
Vinay Sajipce7c9782011-05-17 07:15:53 +0100842 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100843
Vinay Sajipce7c9782011-05-17 07:15:53 +0100844 def __init__(self, addr, handler, poll_interval=0.5,
845 bind_and_activate=True):
846 class DelegatingTCPRequestHandler(StreamRequestHandler):
847
848 def handle(self):
849 self.server._handler(self)
850 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
851 bind_and_activate)
852 ControlMixin.__init__(self, handler, poll_interval)
853
854 def server_bind(self):
855 super(TestTCPServer, self).server_bind()
856 self.port = self.socket.getsockname()[1]
857
Vinay Sajip5421f352013-09-27 18:18:28 +0100858 class TestUnixStreamServer(TestTCPServer):
859 address_family = socket.AF_UNIX
860
Vinay Sajipce7c9782011-05-17 07:15:53 +0100861 class TestUDPServer(ControlMixin, ThreadingUDPServer):
862 """
863 A UDP server which is controllable using :class:`ControlMixin`.
864
865 :param addr: A tuple with the IP address and port to listen on.
866 :param handler: A handler callable which will be called with a
867 single parameter - the request - in order to
868 process the request.
869 :param poll_interval: The polling interval for shutdown requests,
870 in seconds.
871 :bind_and_activate: If True (the default), binds the server and
872 starts it listening. If False, you need to
873 call :meth:`server_bind` and
874 :meth:`server_activate` at some later time
875 before calling :meth:`start`, so that the server will
876 set up the socket and listen on it.
877 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100878 def __init__(self, addr, handler, poll_interval=0.5,
879 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100880 class DelegatingUDPRequestHandler(DatagramRequestHandler):
881
882 def handle(self):
883 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100884
885 def finish(self):
886 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100887 if data:
888 try:
889 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200890 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100891 if not self.server._closed:
892 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100893
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 ThreadingUDPServer.__init__(self, addr,
895 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100896 bind_and_activate)
897 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100898 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100899
900 def server_bind(self):
901 super(TestUDPServer, self).server_bind()
902 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100903
Vinay Sajipba980db2011-05-23 21:37:54 +0100904 def server_close(self):
905 super(TestUDPServer, self).server_close()
906 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Vinay Sajip5421f352013-09-27 18:18:28 +0100908 class TestUnixDatagramServer(TestUDPServer):
909 address_family = socket.AF_UNIX
910
Vinay Sajip7367d082011-05-02 13:17:27 +0100911# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100912
Vinay Sajipce7c9782011-05-17 07:15:53 +0100913@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100914class SMTPHandlerTest(BaseTest):
915 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100916 sockmap = {}
917 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
918 sockmap)
919 server.start()
920 addr = ('localhost', server.port)
Vinay Sajip4c3f4782012-04-22 18:19:50 +0100921 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
Vinay Sajipa463d252011-04-30 21:52:48 +0100922 self.assertEqual(h.toaddrs, ['you'])
923 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100924 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100925 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100926 h.handle(r)
Vinay Sajip17160fd2012-03-15 12:02:08 +0000927 self.handled.wait(5.0) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100928 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000929 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100930 self.assertEqual(len(self.messages), 1)
931 peer, mailfrom, rcpttos, data = self.messages[0]
932 self.assertEqual(mailfrom, 'me')
933 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100934 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 self.assertTrue(data.endswith('\n\nHello'))
936 h.close()
937
938 def process_message(self, *args):
939 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100940 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100941
Christian Heimes180510d2008-03-03 19:15:45 +0000942class MemoryHandlerTest(BaseTest):
943
944 """Tests for the MemoryHandler."""
945
946 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300947 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000948
949 def setUp(self):
950 BaseTest.setUp(self)
951 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
952 self.root_hdlr)
953 self.mem_logger = logging.getLogger('mem')
954 self.mem_logger.propagate = 0
955 self.mem_logger.addHandler(self.mem_hdlr)
956
957 def tearDown(self):
958 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000959 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000960
961 def test_flush(self):
962 # The memory handler flushes to its target handler based on specific
963 # criteria (message count and message level).
964 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000965 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000966 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000967 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000968 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100969 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000970 lines = [
971 ('DEBUG', '1'),
972 ('INFO', '2'),
973 ('WARNING', '3'),
974 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000975 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000976 for n in (4, 14):
977 for i in range(9):
978 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000979 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000980 # This will flush because it's the 10th message since the last
981 # flush.
982 self.mem_logger.debug(self.next_message())
983 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000984 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000985
986 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000987 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000988
989
990class ExceptionFormatter(logging.Formatter):
991 """A special exception formatter."""
992 def formatException(self, ei):
993 return "Got a [%s]" % ei[0].__name__
994
995
996class ConfigFileTest(BaseTest):
997
998 """Reading logging config from a .ini-style config file."""
999
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001000 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001001
1002 # config0 is a standard configuration.
1003 config0 = """
1004 [loggers]
1005 keys=root
1006
1007 [handlers]
1008 keys=hand1
1009
1010 [formatters]
1011 keys=form1
1012
1013 [logger_root]
1014 level=WARNING
1015 handlers=hand1
1016
1017 [handler_hand1]
1018 class=StreamHandler
1019 level=NOTSET
1020 formatter=form1
1021 args=(sys.stdout,)
1022
1023 [formatter_form1]
1024 format=%(levelname)s ++ %(message)s
1025 datefmt=
1026 """
1027
1028 # config1 adds a little to the standard configuration.
1029 config1 = """
1030 [loggers]
1031 keys=root,parser
1032
1033 [handlers]
1034 keys=hand1
1035
1036 [formatters]
1037 keys=form1
1038
1039 [logger_root]
1040 level=WARNING
1041 handlers=
1042
1043 [logger_parser]
1044 level=DEBUG
1045 handlers=hand1
1046 propagate=1
1047 qualname=compiler.parser
1048
1049 [handler_hand1]
1050 class=StreamHandler
1051 level=NOTSET
1052 formatter=form1
1053 args=(sys.stdout,)
1054
1055 [formatter_form1]
1056 format=%(levelname)s ++ %(message)s
1057 datefmt=
1058 """
1059
Vinay Sajip3f84b072011-03-07 17:49:33 +00001060 # config1a moves the handler to the root.
1061 config1a = """
1062 [loggers]
1063 keys=root,parser
1064
1065 [handlers]
1066 keys=hand1
1067
1068 [formatters]
1069 keys=form1
1070
1071 [logger_root]
1072 level=WARNING
1073 handlers=hand1
1074
1075 [logger_parser]
1076 level=DEBUG
1077 handlers=
1078 propagate=1
1079 qualname=compiler.parser
1080
1081 [handler_hand1]
1082 class=StreamHandler
1083 level=NOTSET
1084 formatter=form1
1085 args=(sys.stdout,)
1086
1087 [formatter_form1]
1088 format=%(levelname)s ++ %(message)s
1089 datefmt=
1090 """
1091
Christian Heimes180510d2008-03-03 19:15:45 +00001092 # config2 has a subtle configuration error that should be reported
1093 config2 = config1.replace("sys.stdout", "sys.stbout")
1094
1095 # config3 has a less subtle configuration error
1096 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1097
1098 # config4 specifies a custom formatter class to be loaded
1099 config4 = """
1100 [loggers]
1101 keys=root
1102
1103 [handlers]
1104 keys=hand1
1105
1106 [formatters]
1107 keys=form1
1108
1109 [logger_root]
1110 level=NOTSET
1111 handlers=hand1
1112
1113 [handler_hand1]
1114 class=StreamHandler
1115 level=NOTSET
1116 formatter=form1
1117 args=(sys.stdout,)
1118
1119 [formatter_form1]
1120 class=""" + __name__ + """.ExceptionFormatter
1121 format=%(levelname)s:%(name)s:%(message)s
1122 datefmt=
1123 """
1124
Georg Brandl3dbca812008-07-23 16:10:53 +00001125 # config5 specifies a custom handler class to be loaded
1126 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1127
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001128 # config6 uses ', ' delimiters in the handlers and formatters sections
1129 config6 = """
1130 [loggers]
1131 keys=root,parser
1132
1133 [handlers]
1134 keys=hand1, hand2
1135
1136 [formatters]
1137 keys=form1, form2
1138
1139 [logger_root]
1140 level=WARNING
1141 handlers=
1142
1143 [logger_parser]
1144 level=DEBUG
1145 handlers=hand1
1146 propagate=1
1147 qualname=compiler.parser
1148
1149 [handler_hand1]
1150 class=StreamHandler
1151 level=NOTSET
1152 formatter=form1
1153 args=(sys.stdout,)
1154
1155 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001156 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001157 level=NOTSET
1158 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001159 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001160
1161 [formatter_form1]
1162 format=%(levelname)s ++ %(message)s
1163 datefmt=
1164
1165 [formatter_form2]
1166 format=%(message)s
1167 datefmt=
1168 """
1169
Vinay Sajip3f84b072011-03-07 17:49:33 +00001170 # config7 adds a compiler logger.
1171 config7 = """
1172 [loggers]
1173 keys=root,parser,compiler
1174
1175 [handlers]
1176 keys=hand1
1177
1178 [formatters]
1179 keys=form1
1180
1181 [logger_root]
1182 level=WARNING
1183 handlers=hand1
1184
1185 [logger_compiler]
1186 level=DEBUG
1187 handlers=
1188 propagate=1
1189 qualname=compiler
1190
1191 [logger_parser]
1192 level=DEBUG
1193 handlers=
1194 propagate=1
1195 qualname=compiler.parser
1196
1197 [handler_hand1]
1198 class=StreamHandler
1199 level=NOTSET
1200 formatter=form1
1201 args=(sys.stdout,)
1202
1203 [formatter_form1]
1204 format=%(levelname)s ++ %(message)s
1205 datefmt=
1206 """
1207
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001208 disable_test = """
1209 [loggers]
1210 keys=root
1211
1212 [handlers]
1213 keys=screen
1214
1215 [formatters]
1216 keys=
1217
1218 [logger_root]
1219 level=DEBUG
1220 handlers=screen
1221
1222 [handler_screen]
1223 level=DEBUG
1224 class=StreamHandler
1225 args=(sys.stdout,)
1226 formatter=
1227 """
1228
1229 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001230 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001231 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001232
1233 def test_config0_ok(self):
1234 # A simple config file which overrides the default settings.
1235 with captured_stdout() as output:
1236 self.apply_config(self.config0)
1237 logger = logging.getLogger()
1238 # Won't output anything
1239 logger.info(self.next_message())
1240 # Outputs a message
1241 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001242 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001243 ('ERROR', '2'),
1244 ], stream=output)
1245 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001246 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001247
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001248 def test_config0_using_cp_ok(self):
1249 # A simple config file which overrides the default settings.
1250 with captured_stdout() as output:
1251 file = io.StringIO(textwrap.dedent(self.config0))
1252 cp = configparser.ConfigParser()
1253 cp.read_file(file)
1254 logging.config.fileConfig(cp)
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())
1260 self.assert_log_lines([
1261 ('ERROR', '2'),
1262 ], stream=output)
1263 # Original logger output is empty.
1264 self.assert_log_lines([])
1265
Georg Brandl3dbca812008-07-23 16:10:53 +00001266 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001267 # A config file defining a sub-parser as well.
1268 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001269 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001270 logger = logging.getLogger("compiler.parser")
1271 # Both will output a message
1272 logger.info(self.next_message())
1273 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001274 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001275 ('INFO', '1'),
1276 ('ERROR', '2'),
1277 ], stream=output)
1278 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001279 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001280
1281 def test_config2_failure(self):
1282 # A simple config file which overrides the default settings.
1283 self.assertRaises(Exception, self.apply_config, self.config2)
1284
1285 def test_config3_failure(self):
1286 # A simple config file which overrides the default settings.
1287 self.assertRaises(Exception, self.apply_config, self.config3)
1288
1289 def test_config4_ok(self):
1290 # A config file specifying a custom formatter class.
1291 with captured_stdout() as output:
1292 self.apply_config(self.config4)
1293 logger = logging.getLogger()
1294 try:
1295 raise RuntimeError()
1296 except RuntimeError:
1297 logging.exception("just testing")
1298 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001299 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001300 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1301 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001302 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001303
Georg Brandl3dbca812008-07-23 16:10:53 +00001304 def test_config5_ok(self):
1305 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001306
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001307 def test_config6_ok(self):
1308 self.test_config1_ok(config=self.config6)
1309
Vinay Sajip3f84b072011-03-07 17:49:33 +00001310 def test_config7_ok(self):
1311 with captured_stdout() as output:
1312 self.apply_config(self.config1a)
1313 logger = logging.getLogger("compiler.parser")
1314 # See issue #11424. compiler-hyphenated sorts
1315 # between compiler and compiler.xyz and this
1316 # was preventing compiler.xyz from being included
1317 # in the child loggers of compiler because of an
1318 # overzealous loop termination condition.
1319 hyphenated = logging.getLogger('compiler-hyphenated')
1320 # All will output a message
1321 logger.info(self.next_message())
1322 logger.error(self.next_message())
1323 hyphenated.critical(self.next_message())
1324 self.assert_log_lines([
1325 ('INFO', '1'),
1326 ('ERROR', '2'),
1327 ('CRITICAL', '3'),
1328 ], stream=output)
1329 # Original logger output is empty.
1330 self.assert_log_lines([])
1331 with captured_stdout() as output:
1332 self.apply_config(self.config7)
1333 logger = logging.getLogger("compiler.parser")
1334 self.assertFalse(logger.disabled)
1335 # Both will output a message
1336 logger.info(self.next_message())
1337 logger.error(self.next_message())
1338 logger = logging.getLogger("compiler.lexer")
1339 # Both will output a message
1340 logger.info(self.next_message())
1341 logger.error(self.next_message())
1342 # Will not appear
1343 hyphenated.critical(self.next_message())
1344 self.assert_log_lines([
1345 ('INFO', '4'),
1346 ('ERROR', '5'),
1347 ('INFO', '6'),
1348 ('ERROR', '7'),
1349 ], stream=output)
1350 # Original logger output is empty.
1351 self.assert_log_lines([])
1352
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001353 def test_logger_disabling(self):
1354 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001355 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001356 self.assertFalse(logger.disabled)
1357 self.apply_config(self.disable_test)
1358 self.assertTrue(logger.disabled)
1359 self.apply_config(self.disable_test, disable_existing_loggers=False)
1360 self.assertFalse(logger.disabled)
1361
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001362
Victor Stinner45df8202010-04-28 22:31:17 +00001363@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001364class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001365
Christian Heimes180510d2008-03-03 19:15:45 +00001366 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001367
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001368 if threading:
1369 server_class = TestTCPServer
1370 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001371
Christian Heimes180510d2008-03-03 19:15:45 +00001372 def setUp(self):
1373 """Set up a TCP server to receive log messages, and a SocketHandler
1374 pointing to that server's address and port."""
1375 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001376 self.server = server = self.server_class(self.address,
1377 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001378 server.start()
1379 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001380 hcls = logging.handlers.SocketHandler
1381 if isinstance(server.server_address, tuple):
1382 self.sock_hdlr = hcls('localhost', server.port)
1383 else:
1384 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001385 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001386 self.root_logger.removeHandler(self.root_logger.handlers[0])
1387 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001388 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001389
Christian Heimes180510d2008-03-03 19:15:45 +00001390 def tearDown(self):
1391 """Shutdown the TCP server."""
1392 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001393 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001394 self.root_logger.removeHandler(self.sock_hdlr)
1395 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001396 finally:
1397 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001398
Vinay Sajip7367d082011-05-02 13:17:27 +01001399 def handle_socket(self, request):
1400 conn = request.connection
1401 while True:
1402 chunk = conn.recv(4)
1403 if len(chunk) < 4:
1404 break
1405 slen = struct.unpack(">L", chunk)[0]
1406 chunk = conn.recv(slen)
1407 while len(chunk) < slen:
1408 chunk = chunk + conn.recv(slen - len(chunk))
1409 obj = pickle.loads(chunk)
1410 record = logging.makeLogRecord(obj)
1411 self.log_output += record.msg + '\n'
1412 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001413
Christian Heimes180510d2008-03-03 19:15:45 +00001414 def test_output(self):
1415 # The log message sent to the SocketHandler is properly received.
1416 logger = logging.getLogger("tcp")
1417 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001418 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001419 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001420 self.handled.acquire()
1421 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001422
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001423 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001424 # Avoid timing-related failures due to SocketHandler's own hard-wired
1425 # one-second timeout on socket.create_connection() (issue #16264).
1426 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001427 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001428 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001429 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001430 try:
1431 raise RuntimeError('Deliberate mistake')
1432 except RuntimeError:
1433 self.root_logger.exception('Never sent')
1434 self.root_logger.error('Never sent, either')
1435 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001436 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001437 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1438 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001439
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001440def _get_temp_domain_socket():
1441 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1442 os.close(fd)
1443 # just need a name - file can't be present, or we'll get an
1444 # 'address already in use' error.
1445 os.remove(fn)
1446 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001447
1448@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001449class UnixSocketHandlerTest(SocketHandlerTest):
1450
1451 """Test for SocketHandler with unix sockets."""
1452
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001453 if threading:
1454 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001455
1456 def setUp(self):
1457 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001458 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001459 SocketHandlerTest.setUp(self)
1460
1461 def tearDown(self):
1462 SocketHandlerTest.tearDown(self)
1463 os.remove(self.address)
1464
1465@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001466class DatagramHandlerTest(BaseTest):
1467
1468 """Test for DatagramHandler."""
1469
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001470 if threading:
1471 server_class = TestUDPServer
1472 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001473
Vinay Sajip7367d082011-05-02 13:17:27 +01001474 def setUp(self):
1475 """Set up a UDP server to receive log messages, and a DatagramHandler
1476 pointing to that server's address and port."""
1477 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001478 self.server = server = self.server_class(self.address,
1479 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001480 server.start()
1481 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001482 hcls = logging.handlers.DatagramHandler
1483 if isinstance(server.server_address, tuple):
1484 self.sock_hdlr = hcls('localhost', server.port)
1485 else:
1486 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001487 self.log_output = ''
1488 self.root_logger.removeHandler(self.root_logger.handlers[0])
1489 self.root_logger.addHandler(self.sock_hdlr)
1490 self.handled = threading.Event()
1491
1492 def tearDown(self):
1493 """Shutdown the UDP server."""
1494 try:
1495 self.server.stop(2.0)
1496 self.root_logger.removeHandler(self.sock_hdlr)
1497 self.sock_hdlr.close()
1498 finally:
1499 BaseTest.tearDown(self)
1500
1501 def handle_datagram(self, request):
1502 slen = struct.pack('>L', 0) # length of prefix
1503 packet = request.packet[len(slen):]
1504 obj = pickle.loads(packet)
1505 record = logging.makeLogRecord(obj)
1506 self.log_output += record.msg + '\n'
1507 self.handled.set()
1508
1509 def test_output(self):
1510 # The log message sent to the DatagramHandler is properly received.
1511 logger = logging.getLogger("udp")
1512 logger.error("spam")
1513 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001514 self.handled.clear()
1515 logger.error("eggs")
1516 self.handled.wait()
1517 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001518
1519
1520@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001521class UnixDatagramHandlerTest(DatagramHandlerTest):
1522
1523 """Test for DatagramHandler using Unix sockets."""
1524
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001525 if threading:
1526 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001527
1528 def setUp(self):
1529 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001530 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001531 DatagramHandlerTest.setUp(self)
1532
1533 def tearDown(self):
1534 DatagramHandlerTest.tearDown(self)
1535 os.remove(self.address)
1536
1537@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001538class SysLogHandlerTest(BaseTest):
1539
1540 """Test for SysLogHandler using UDP."""
1541
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001542 if threading:
1543 server_class = TestUDPServer
1544 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001545
Vinay Sajip7367d082011-05-02 13:17:27 +01001546 def setUp(self):
1547 """Set up a UDP server to receive log messages, and a SysLogHandler
1548 pointing to that server's address and port."""
1549 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001550 self.server = server = self.server_class(self.address,
1551 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001552 server.start()
1553 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001554 hcls = logging.handlers.SysLogHandler
1555 if isinstance(server.server_address, tuple):
1556 self.sl_hdlr = hcls(('localhost', server.port))
1557 else:
1558 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001559 self.log_output = ''
1560 self.root_logger.removeHandler(self.root_logger.handlers[0])
1561 self.root_logger.addHandler(self.sl_hdlr)
1562 self.handled = threading.Event()
1563
1564 def tearDown(self):
1565 """Shutdown the UDP server."""
1566 try:
1567 self.server.stop(2.0)
1568 self.root_logger.removeHandler(self.sl_hdlr)
1569 self.sl_hdlr.close()
1570 finally:
1571 BaseTest.tearDown(self)
1572
1573 def handle_datagram(self, request):
1574 self.log_output = request.packet
1575 self.handled.set()
1576
1577 def test_output(self):
1578 # The log message sent to the SysLogHandler is properly received.
1579 logger = logging.getLogger("slh")
1580 logger.error("sp\xe4m")
1581 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001582 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001583 self.handled.clear()
1584 self.sl_hdlr.append_nul = False
1585 logger.error("sp\xe4m")
1586 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001587 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001588 self.handled.clear()
1589 self.sl_hdlr.ident = "h\xe4m-"
1590 logger.error("sp\xe4m")
1591 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001592 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001593
1594
1595@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001596class UnixSysLogHandlerTest(SysLogHandlerTest):
1597
1598 """Test for SysLogHandler with Unix sockets."""
1599
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001600 if threading:
1601 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001602
1603 def setUp(self):
1604 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001605 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001606 SysLogHandlerTest.setUp(self)
1607
1608 def tearDown(self):
1609 SysLogHandlerTest.tearDown(self)
1610 os.remove(self.address)
1611
Vinay Sajip5421f352013-09-27 18:18:28 +01001612@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001613class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001614 """Test for HTTPHandler."""
1615
Vinay Sajip9ba87612011-05-21 11:32:15 +01001616 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1617MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1618zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1619aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1620AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16210tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16225LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1623piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16242z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1625i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1626PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1627E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1628rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1629/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1630-----END RSA PRIVATE KEY-----
1631-----BEGIN CERTIFICATE-----
1632MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1633BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1634EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1635xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1636l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1637vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1638BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1639S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1640BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16414f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16421c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1643IRbTpvlHWPjsSvHz0ZOH
1644-----END CERTIFICATE-----"""
1645
Vinay Sajip7367d082011-05-02 13:17:27 +01001646 def setUp(self):
1647 """Set up an HTTP server to receive log messages, and a HTTPHandler
1648 pointing to that server's address and port."""
1649 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001650 self.handled = threading.Event()
1651
Vinay Sajip7367d082011-05-02 13:17:27 +01001652 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001653 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001654 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001655 if self.command == 'POST':
1656 try:
1657 rlen = int(request.headers['Content-Length'])
1658 self.post_data = request.rfile.read(rlen)
1659 except:
1660 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001661 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001662 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001663 self.handled.set()
1664
1665 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001666 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001667 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001668 root_logger = self.root_logger
1669 root_logger.removeHandler(self.root_logger.handlers[0])
1670 for secure in (False, True):
1671 addr = ('localhost', 0)
1672 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001673 try:
1674 import ssl
1675 fd, fn = tempfile.mkstemp()
1676 os.close(fd)
1677 with open(fn, 'w') as f:
1678 f.write(self.PEMFILE)
1679 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1680 sslctx.load_cert_chain(fn)
1681 os.unlink(fn)
1682 except ImportError:
1683 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001684 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001685 sslctx = None
1686 self.server = server = TestHTTPServer(addr, self.handle_request,
1687 0.01, sslctx=sslctx)
1688 server.start()
1689 server.ready.wait()
1690 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001691 secure_client = secure and sslctx
1692 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1693 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001694 self.log_data = None
1695 root_logger.addHandler(self.h_hdlr)
1696
1697 for method in ('GET', 'POST'):
1698 self.h_hdlr.method = method
1699 self.handled.clear()
1700 msg = "sp\xe4m"
1701 logger.error(msg)
1702 self.handled.wait()
1703 self.assertEqual(self.log_data.path, '/frob')
1704 self.assertEqual(self.command, method)
1705 if method == 'GET':
1706 d = parse_qs(self.log_data.query)
1707 else:
1708 d = parse_qs(self.post_data.decode('utf-8'))
1709 self.assertEqual(d['name'], ['http'])
1710 self.assertEqual(d['funcName'], ['test_output'])
1711 self.assertEqual(d['msg'], [msg])
1712
1713 self.server.stop(2.0)
1714 self.root_logger.removeHandler(self.h_hdlr)
1715 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001716
Christian Heimes180510d2008-03-03 19:15:45 +00001717class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001718
Christian Heimes180510d2008-03-03 19:15:45 +00001719 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001720
Christian Heimes180510d2008-03-03 19:15:45 +00001721 def setUp(self):
1722 """Create a dict to remember potentially destroyed objects."""
1723 BaseTest.setUp(self)
1724 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001725
Christian Heimes180510d2008-03-03 19:15:45 +00001726 def _watch_for_survival(self, *args):
1727 """Watch the given objects for survival, by creating weakrefs to
1728 them."""
1729 for obj in args:
1730 key = id(obj), repr(obj)
1731 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001732
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001733 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001734 """Assert that all objects watched for survival have survived."""
1735 # Trigger cycle breaking.
1736 gc.collect()
1737 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001738 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001739 if ref() is None:
1740 dead.append(repr_)
1741 if dead:
1742 self.fail("%d objects should have survived "
1743 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001744
Christian Heimes180510d2008-03-03 19:15:45 +00001745 def test_persistent_loggers(self):
1746 # Logger objects are persistent and retain their configuration, even
1747 # if visible references are destroyed.
1748 self.root_logger.setLevel(logging.INFO)
1749 foo = logging.getLogger("foo")
1750 self._watch_for_survival(foo)
1751 foo.setLevel(logging.DEBUG)
1752 self.root_logger.debug(self.next_message())
1753 foo.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 ])
1757 del foo
1758 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001759 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001760 # foo has retained its settings.
1761 bar = logging.getLogger("foo")
1762 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001763 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001764 ('foo', 'DEBUG', '2'),
1765 ('foo', 'DEBUG', '3'),
1766 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001767
Benjamin Petersonf91df042009-02-13 02:50:59 +00001768
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001769class EncodingTest(BaseTest):
1770 def test_encoding_plain_file(self):
1771 # In Python 2.x, a plain file object is treated as having no encoding.
1772 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001773 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1774 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001775 # the non-ascii data we write to the log.
1776 data = "foo\x80"
1777 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001778 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001779 log.addHandler(handler)
1780 try:
1781 # write non-ascii data to the log.
1782 log.warning(data)
1783 finally:
1784 log.removeHandler(handler)
1785 handler.close()
1786 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001787 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001788 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001789 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001790 finally:
1791 f.close()
1792 finally:
1793 if os.path.isfile(fn):
1794 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001795
Benjamin Petersonf91df042009-02-13 02:50:59 +00001796 def test_encoding_cyrillic_unicode(self):
1797 log = logging.getLogger("test")
1798 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1799 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1800 #Ensure it's written in a Cyrillic encoding
1801 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001802 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001803 stream = io.BytesIO()
1804 writer = writer_class(stream, 'strict')
1805 handler = logging.StreamHandler(writer)
1806 log.addHandler(handler)
1807 try:
1808 log.warning(message)
1809 finally:
1810 log.removeHandler(handler)
1811 handler.close()
1812 # check we wrote exactly those bytes, ignoring trailing \n etc
1813 s = stream.getvalue()
1814 #Compare against what the data should be when encoded in CP-1251
1815 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1816
1817
Georg Brandlf9734072008-12-07 15:30:06 +00001818class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001819
Georg Brandlf9734072008-12-07 15:30:06 +00001820 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001821 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001822 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001823 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001824 warnings.filterwarnings("always", category=UserWarning)
1825 stream = io.StringIO()
1826 h = logging.StreamHandler(stream)
1827 logger = logging.getLogger("py.warnings")
1828 logger.addHandler(h)
1829 warnings.warn("I'm warning you...")
1830 logger.removeHandler(h)
1831 s = stream.getvalue()
1832 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001833 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001834
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001835 #See if an explicit file uses the original implementation
1836 a_file = io.StringIO()
1837 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1838 a_file, "Dummy line")
1839 s = a_file.getvalue()
1840 a_file.close()
1841 self.assertEqual(s,
1842 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1843
1844 def test_warnings_no_handlers(self):
1845 with warnings.catch_warnings():
1846 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001847 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001848
1849 # confirm our assumption: no loggers are set
1850 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001851 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001852
1853 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001854 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001855 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001856
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001857
1858def formatFunc(format, datefmt=None):
1859 return logging.Formatter(format, datefmt)
1860
1861def handlerFunc():
1862 return logging.StreamHandler()
1863
1864class CustomHandler(logging.StreamHandler):
1865 pass
1866
1867class ConfigDictTest(BaseTest):
1868
1869 """Reading logging config from a dictionary."""
1870
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001871 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001872
1873 # config0 is a standard configuration.
1874 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001875 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001876 'formatters': {
1877 'form1' : {
1878 'format' : '%(levelname)s ++ %(message)s',
1879 },
1880 },
1881 'handlers' : {
1882 'hand1' : {
1883 'class' : 'logging.StreamHandler',
1884 'formatter' : 'form1',
1885 'level' : 'NOTSET',
1886 'stream' : 'ext://sys.stdout',
1887 },
1888 },
1889 'root' : {
1890 'level' : 'WARNING',
1891 'handlers' : ['hand1'],
1892 },
1893 }
1894
1895 # config1 adds a little to the standard configuration.
1896 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001897 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001898 'formatters': {
1899 'form1' : {
1900 'format' : '%(levelname)s ++ %(message)s',
1901 },
1902 },
1903 'handlers' : {
1904 'hand1' : {
1905 'class' : 'logging.StreamHandler',
1906 'formatter' : 'form1',
1907 'level' : 'NOTSET',
1908 'stream' : 'ext://sys.stdout',
1909 },
1910 },
1911 'loggers' : {
1912 'compiler.parser' : {
1913 'level' : 'DEBUG',
1914 'handlers' : ['hand1'],
1915 },
1916 },
1917 'root' : {
1918 'level' : 'WARNING',
1919 },
1920 }
1921
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001922 # config1a moves the handler to the root. Used with config8a
1923 config1a = {
1924 'version': 1,
1925 'formatters': {
1926 'form1' : {
1927 'format' : '%(levelname)s ++ %(message)s',
1928 },
1929 },
1930 'handlers' : {
1931 'hand1' : {
1932 'class' : 'logging.StreamHandler',
1933 'formatter' : 'form1',
1934 'level' : 'NOTSET',
1935 'stream' : 'ext://sys.stdout',
1936 },
1937 },
1938 'loggers' : {
1939 'compiler.parser' : {
1940 'level' : 'DEBUG',
1941 },
1942 },
1943 'root' : {
1944 'level' : 'WARNING',
1945 'handlers' : ['hand1'],
1946 },
1947 }
1948
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001949 # config2 has a subtle configuration error that should be reported
1950 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001951 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001952 'formatters': {
1953 'form1' : {
1954 'format' : '%(levelname)s ++ %(message)s',
1955 },
1956 },
1957 'handlers' : {
1958 'hand1' : {
1959 'class' : 'logging.StreamHandler',
1960 'formatter' : 'form1',
1961 'level' : 'NOTSET',
1962 'stream' : 'ext://sys.stdbout',
1963 },
1964 },
1965 'loggers' : {
1966 'compiler.parser' : {
1967 'level' : 'DEBUG',
1968 'handlers' : ['hand1'],
1969 },
1970 },
1971 'root' : {
1972 'level' : 'WARNING',
1973 },
1974 }
1975
1976 #As config1 but with a misspelt level on a handler
1977 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001978 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001979 'formatters': {
1980 'form1' : {
1981 'format' : '%(levelname)s ++ %(message)s',
1982 },
1983 },
1984 'handlers' : {
1985 'hand1' : {
1986 'class' : 'logging.StreamHandler',
1987 'formatter' : 'form1',
1988 'level' : 'NTOSET',
1989 'stream' : 'ext://sys.stdout',
1990 },
1991 },
1992 'loggers' : {
1993 'compiler.parser' : {
1994 'level' : 'DEBUG',
1995 'handlers' : ['hand1'],
1996 },
1997 },
1998 'root' : {
1999 'level' : 'WARNING',
2000 },
2001 }
2002
2003
2004 #As config1 but with a misspelt level on a logger
2005 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002006 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002007 'formatters': {
2008 'form1' : {
2009 'format' : '%(levelname)s ++ %(message)s',
2010 },
2011 },
2012 'handlers' : {
2013 'hand1' : {
2014 'class' : 'logging.StreamHandler',
2015 'formatter' : 'form1',
2016 'level' : 'NOTSET',
2017 'stream' : 'ext://sys.stdout',
2018 },
2019 },
2020 'loggers' : {
2021 'compiler.parser' : {
2022 'level' : 'DEBUG',
2023 'handlers' : ['hand1'],
2024 },
2025 },
2026 'root' : {
2027 'level' : 'WRANING',
2028 },
2029 }
2030
2031 # config3 has a less subtle configuration error
2032 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002033 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002034 'formatters': {
2035 'form1' : {
2036 'format' : '%(levelname)s ++ %(message)s',
2037 },
2038 },
2039 'handlers' : {
2040 'hand1' : {
2041 'class' : 'logging.StreamHandler',
2042 'formatter' : 'misspelled_name',
2043 'level' : 'NOTSET',
2044 'stream' : 'ext://sys.stdout',
2045 },
2046 },
2047 'loggers' : {
2048 'compiler.parser' : {
2049 'level' : 'DEBUG',
2050 'handlers' : ['hand1'],
2051 },
2052 },
2053 'root' : {
2054 'level' : 'WARNING',
2055 },
2056 }
2057
2058 # config4 specifies a custom formatter class to be loaded
2059 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002060 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002061 'formatters': {
2062 'form1' : {
2063 '()' : __name__ + '.ExceptionFormatter',
2064 'format' : '%(levelname)s:%(name)s:%(message)s',
2065 },
2066 },
2067 'handlers' : {
2068 'hand1' : {
2069 'class' : 'logging.StreamHandler',
2070 'formatter' : 'form1',
2071 'level' : 'NOTSET',
2072 'stream' : 'ext://sys.stdout',
2073 },
2074 },
2075 'root' : {
2076 'level' : 'NOTSET',
2077 'handlers' : ['hand1'],
2078 },
2079 }
2080
2081 # As config4 but using an actual callable rather than a string
2082 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002083 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002084 'formatters': {
2085 'form1' : {
2086 '()' : ExceptionFormatter,
2087 'format' : '%(levelname)s:%(name)s:%(message)s',
2088 },
2089 'form2' : {
2090 '()' : __name__ + '.formatFunc',
2091 'format' : '%(levelname)s:%(name)s:%(message)s',
2092 },
2093 'form3' : {
2094 '()' : formatFunc,
2095 'format' : '%(levelname)s:%(name)s:%(message)s',
2096 },
2097 },
2098 'handlers' : {
2099 'hand1' : {
2100 'class' : 'logging.StreamHandler',
2101 'formatter' : 'form1',
2102 'level' : 'NOTSET',
2103 'stream' : 'ext://sys.stdout',
2104 },
2105 'hand2' : {
2106 '()' : handlerFunc,
2107 },
2108 },
2109 'root' : {
2110 'level' : 'NOTSET',
2111 'handlers' : ['hand1'],
2112 },
2113 }
2114
2115 # config5 specifies a custom handler class to be loaded
2116 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002117 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002118 'formatters': {
2119 'form1' : {
2120 'format' : '%(levelname)s ++ %(message)s',
2121 },
2122 },
2123 'handlers' : {
2124 'hand1' : {
2125 'class' : __name__ + '.CustomHandler',
2126 'formatter' : 'form1',
2127 'level' : 'NOTSET',
2128 'stream' : 'ext://sys.stdout',
2129 },
2130 },
2131 'loggers' : {
2132 'compiler.parser' : {
2133 'level' : 'DEBUG',
2134 'handlers' : ['hand1'],
2135 },
2136 },
2137 'root' : {
2138 'level' : 'WARNING',
2139 },
2140 }
2141
2142 # config6 specifies a custom handler class to be loaded
2143 # but has bad arguments
2144 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002145 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002146 'formatters': {
2147 'form1' : {
2148 'format' : '%(levelname)s ++ %(message)s',
2149 },
2150 },
2151 'handlers' : {
2152 'hand1' : {
2153 'class' : __name__ + '.CustomHandler',
2154 'formatter' : 'form1',
2155 'level' : 'NOTSET',
2156 'stream' : 'ext://sys.stdout',
2157 '9' : 'invalid parameter name',
2158 },
2159 },
2160 'loggers' : {
2161 'compiler.parser' : {
2162 'level' : 'DEBUG',
2163 'handlers' : ['hand1'],
2164 },
2165 },
2166 'root' : {
2167 'level' : 'WARNING',
2168 },
2169 }
2170
2171 #config 7 does not define compiler.parser but defines compiler.lexer
2172 #so compiler.parser should be disabled after applying it
2173 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002174 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002175 'formatters': {
2176 'form1' : {
2177 'format' : '%(levelname)s ++ %(message)s',
2178 },
2179 },
2180 'handlers' : {
2181 'hand1' : {
2182 'class' : 'logging.StreamHandler',
2183 'formatter' : 'form1',
2184 'level' : 'NOTSET',
2185 'stream' : 'ext://sys.stdout',
2186 },
2187 },
2188 'loggers' : {
2189 'compiler.lexer' : {
2190 'level' : 'DEBUG',
2191 'handlers' : ['hand1'],
2192 },
2193 },
2194 'root' : {
2195 'level' : 'WARNING',
2196 },
2197 }
2198
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002199 # config8 defines both compiler and compiler.lexer
2200 # so compiler.parser should not be disabled (since
2201 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002202 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002203 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002204 'disable_existing_loggers' : False,
2205 'formatters': {
2206 'form1' : {
2207 'format' : '%(levelname)s ++ %(message)s',
2208 },
2209 },
2210 'handlers' : {
2211 'hand1' : {
2212 'class' : 'logging.StreamHandler',
2213 'formatter' : 'form1',
2214 'level' : 'NOTSET',
2215 'stream' : 'ext://sys.stdout',
2216 },
2217 },
2218 'loggers' : {
2219 'compiler' : {
2220 'level' : 'DEBUG',
2221 'handlers' : ['hand1'],
2222 },
2223 'compiler.lexer' : {
2224 },
2225 },
2226 'root' : {
2227 'level' : 'WARNING',
2228 },
2229 }
2230
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002231 # config8a disables existing loggers
2232 config8a = {
2233 'version': 1,
2234 'disable_existing_loggers' : True,
2235 'formatters': {
2236 'form1' : {
2237 'format' : '%(levelname)s ++ %(message)s',
2238 },
2239 },
2240 'handlers' : {
2241 'hand1' : {
2242 'class' : 'logging.StreamHandler',
2243 'formatter' : 'form1',
2244 'level' : 'NOTSET',
2245 'stream' : 'ext://sys.stdout',
2246 },
2247 },
2248 'loggers' : {
2249 'compiler' : {
2250 'level' : 'DEBUG',
2251 'handlers' : ['hand1'],
2252 },
2253 'compiler.lexer' : {
2254 },
2255 },
2256 'root' : {
2257 'level' : 'WARNING',
2258 },
2259 }
2260
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002261 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002262 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002263 'formatters': {
2264 'form1' : {
2265 'format' : '%(levelname)s ++ %(message)s',
2266 },
2267 },
2268 'handlers' : {
2269 'hand1' : {
2270 'class' : 'logging.StreamHandler',
2271 'formatter' : 'form1',
2272 'level' : 'WARNING',
2273 'stream' : 'ext://sys.stdout',
2274 },
2275 },
2276 'loggers' : {
2277 'compiler.parser' : {
2278 'level' : 'WARNING',
2279 'handlers' : ['hand1'],
2280 },
2281 },
2282 'root' : {
2283 'level' : 'NOTSET',
2284 },
2285 }
2286
2287 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002288 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002289 'incremental' : True,
2290 'handlers' : {
2291 'hand1' : {
2292 'level' : 'WARNING',
2293 },
2294 },
2295 'loggers' : {
2296 'compiler.parser' : {
2297 'level' : 'INFO',
2298 },
2299 },
2300 }
2301
2302 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002303 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002304 'incremental' : True,
2305 'handlers' : {
2306 'hand1' : {
2307 'level' : 'INFO',
2308 },
2309 },
2310 'loggers' : {
2311 'compiler.parser' : {
2312 'level' : 'INFO',
2313 },
2314 },
2315 }
2316
2317 #As config1 but with a filter added
2318 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002319 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002320 'formatters': {
2321 'form1' : {
2322 'format' : '%(levelname)s ++ %(message)s',
2323 },
2324 },
2325 'filters' : {
2326 'filt1' : {
2327 'name' : 'compiler.parser',
2328 },
2329 },
2330 'handlers' : {
2331 'hand1' : {
2332 'class' : 'logging.StreamHandler',
2333 'formatter' : 'form1',
2334 'level' : 'NOTSET',
2335 'stream' : 'ext://sys.stdout',
2336 'filters' : ['filt1'],
2337 },
2338 },
2339 'loggers' : {
2340 'compiler.parser' : {
2341 'level' : 'DEBUG',
2342 'filters' : ['filt1'],
2343 },
2344 },
2345 'root' : {
2346 'level' : 'WARNING',
2347 'handlers' : ['hand1'],
2348 },
2349 }
2350
2351 #As config1 but using cfg:// references
2352 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002353 'version': 1,
2354 'true_formatters': {
2355 'form1' : {
2356 'format' : '%(levelname)s ++ %(message)s',
2357 },
2358 },
2359 'handler_configs': {
2360 'hand1' : {
2361 'class' : 'logging.StreamHandler',
2362 'formatter' : 'form1',
2363 'level' : 'NOTSET',
2364 'stream' : 'ext://sys.stdout',
2365 },
2366 },
2367 'formatters' : 'cfg://true_formatters',
2368 'handlers' : {
2369 'hand1' : 'cfg://handler_configs[hand1]',
2370 },
2371 'loggers' : {
2372 'compiler.parser' : {
2373 'level' : 'DEBUG',
2374 'handlers' : ['hand1'],
2375 },
2376 },
2377 'root' : {
2378 'level' : 'WARNING',
2379 },
2380 }
2381
2382 #As config11 but missing the version key
2383 config12 = {
2384 'true_formatters': {
2385 'form1' : {
2386 'format' : '%(levelname)s ++ %(message)s',
2387 },
2388 },
2389 'handler_configs': {
2390 'hand1' : {
2391 'class' : 'logging.StreamHandler',
2392 'formatter' : 'form1',
2393 'level' : 'NOTSET',
2394 'stream' : 'ext://sys.stdout',
2395 },
2396 },
2397 'formatters' : 'cfg://true_formatters',
2398 'handlers' : {
2399 'hand1' : 'cfg://handler_configs[hand1]',
2400 },
2401 'loggers' : {
2402 'compiler.parser' : {
2403 'level' : 'DEBUG',
2404 'handlers' : ['hand1'],
2405 },
2406 },
2407 'root' : {
2408 'level' : 'WARNING',
2409 },
2410 }
2411
2412 #As config11 but using an unsupported version
2413 config13 = {
2414 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002415 'true_formatters': {
2416 'form1' : {
2417 'format' : '%(levelname)s ++ %(message)s',
2418 },
2419 },
2420 'handler_configs': {
2421 'hand1' : {
2422 'class' : 'logging.StreamHandler',
2423 'formatter' : 'form1',
2424 'level' : 'NOTSET',
2425 'stream' : 'ext://sys.stdout',
2426 },
2427 },
2428 'formatters' : 'cfg://true_formatters',
2429 'handlers' : {
2430 'hand1' : 'cfg://handler_configs[hand1]',
2431 },
2432 'loggers' : {
2433 'compiler.parser' : {
2434 'level' : 'DEBUG',
2435 'handlers' : ['hand1'],
2436 },
2437 },
2438 'root' : {
2439 'level' : 'WARNING',
2440 },
2441 }
2442
Vinay Sajip8d270232012-11-15 14:20:18 +00002443 # As config0, but with properties
2444 config14 = {
2445 'version': 1,
2446 'formatters': {
2447 'form1' : {
2448 'format' : '%(levelname)s ++ %(message)s',
2449 },
2450 },
2451 'handlers' : {
2452 'hand1' : {
2453 'class' : 'logging.StreamHandler',
2454 'formatter' : 'form1',
2455 'level' : 'NOTSET',
2456 'stream' : 'ext://sys.stdout',
2457 '.': {
2458 'foo': 'bar',
2459 'terminator': '!\n',
2460 }
2461 },
2462 },
2463 'root' : {
2464 'level' : 'WARNING',
2465 'handlers' : ['hand1'],
2466 },
2467 }
2468
Vinay Sajip3f885b52013-03-22 15:19:54 +00002469 out_of_order = {
2470 "version": 1,
2471 "formatters": {
2472 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002473 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2474 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002475 }
2476 },
2477 "handlers": {
2478 "fileGlobal": {
2479 "class": "logging.StreamHandler",
2480 "level": "DEBUG",
2481 "formatter": "mySimpleFormatter"
2482 },
2483 "bufferGlobal": {
2484 "class": "logging.handlers.MemoryHandler",
2485 "capacity": 5,
2486 "formatter": "mySimpleFormatter",
2487 "target": "fileGlobal",
2488 "level": "DEBUG"
2489 }
2490 },
2491 "loggers": {
2492 "mymodule": {
2493 "level": "DEBUG",
2494 "handlers": ["bufferGlobal"],
2495 "propagate": "true"
2496 }
2497 }
2498 }
2499
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002500 def apply_config(self, conf):
2501 logging.config.dictConfig(conf)
2502
2503 def test_config0_ok(self):
2504 # A simple config which overrides the default settings.
2505 with captured_stdout() as output:
2506 self.apply_config(self.config0)
2507 logger = logging.getLogger()
2508 # Won't output anything
2509 logger.info(self.next_message())
2510 # Outputs a message
2511 logger.error(self.next_message())
2512 self.assert_log_lines([
2513 ('ERROR', '2'),
2514 ], stream=output)
2515 # Original logger output is empty.
2516 self.assert_log_lines([])
2517
2518 def test_config1_ok(self, config=config1):
2519 # A config defining a sub-parser as well.
2520 with captured_stdout() as output:
2521 self.apply_config(config)
2522 logger = logging.getLogger("compiler.parser")
2523 # Both will output a message
2524 logger.info(self.next_message())
2525 logger.error(self.next_message())
2526 self.assert_log_lines([
2527 ('INFO', '1'),
2528 ('ERROR', '2'),
2529 ], stream=output)
2530 # Original logger output is empty.
2531 self.assert_log_lines([])
2532
2533 def test_config2_failure(self):
2534 # A simple config which overrides the default settings.
2535 self.assertRaises(Exception, self.apply_config, self.config2)
2536
2537 def test_config2a_failure(self):
2538 # A simple config which overrides the default settings.
2539 self.assertRaises(Exception, self.apply_config, self.config2a)
2540
2541 def test_config2b_failure(self):
2542 # A simple config which overrides the default settings.
2543 self.assertRaises(Exception, self.apply_config, self.config2b)
2544
2545 def test_config3_failure(self):
2546 # A simple config which overrides the default settings.
2547 self.assertRaises(Exception, self.apply_config, self.config3)
2548
2549 def test_config4_ok(self):
2550 # A config specifying a custom formatter class.
2551 with captured_stdout() as output:
2552 self.apply_config(self.config4)
2553 #logger = logging.getLogger()
2554 try:
2555 raise RuntimeError()
2556 except RuntimeError:
2557 logging.exception("just testing")
2558 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002559 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002560 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2561 # Original logger output is empty
2562 self.assert_log_lines([])
2563
2564 def test_config4a_ok(self):
2565 # A config specifying a custom formatter class.
2566 with captured_stdout() as output:
2567 self.apply_config(self.config4a)
2568 #logger = logging.getLogger()
2569 try:
2570 raise RuntimeError()
2571 except RuntimeError:
2572 logging.exception("just testing")
2573 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002574 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002575 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2576 # Original logger output is empty
2577 self.assert_log_lines([])
2578
2579 def test_config5_ok(self):
2580 self.test_config1_ok(config=self.config5)
2581
2582 def test_config6_failure(self):
2583 self.assertRaises(Exception, self.apply_config, self.config6)
2584
2585 def test_config7_ok(self):
2586 with captured_stdout() as output:
2587 self.apply_config(self.config1)
2588 logger = logging.getLogger("compiler.parser")
2589 # Both will output a message
2590 logger.info(self.next_message())
2591 logger.error(self.next_message())
2592 self.assert_log_lines([
2593 ('INFO', '1'),
2594 ('ERROR', '2'),
2595 ], stream=output)
2596 # Original logger output is empty.
2597 self.assert_log_lines([])
2598 with captured_stdout() as output:
2599 self.apply_config(self.config7)
2600 logger = logging.getLogger("compiler.parser")
2601 self.assertTrue(logger.disabled)
2602 logger = logging.getLogger("compiler.lexer")
2603 # Both will output a message
2604 logger.info(self.next_message())
2605 logger.error(self.next_message())
2606 self.assert_log_lines([
2607 ('INFO', '3'),
2608 ('ERROR', '4'),
2609 ], stream=output)
2610 # Original logger output is empty.
2611 self.assert_log_lines([])
2612
2613 #Same as test_config_7_ok but don't disable old loggers.
2614 def test_config_8_ok(self):
2615 with captured_stdout() as output:
2616 self.apply_config(self.config1)
2617 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002618 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002619 logger.info(self.next_message())
2620 logger.error(self.next_message())
2621 self.assert_log_lines([
2622 ('INFO', '1'),
2623 ('ERROR', '2'),
2624 ], stream=output)
2625 # Original logger output is empty.
2626 self.assert_log_lines([])
2627 with captured_stdout() as output:
2628 self.apply_config(self.config8)
2629 logger = logging.getLogger("compiler.parser")
2630 self.assertFalse(logger.disabled)
2631 # Both will output a message
2632 logger.info(self.next_message())
2633 logger.error(self.next_message())
2634 logger = logging.getLogger("compiler.lexer")
2635 # Both will output a message
2636 logger.info(self.next_message())
2637 logger.error(self.next_message())
2638 self.assert_log_lines([
2639 ('INFO', '3'),
2640 ('ERROR', '4'),
2641 ('INFO', '5'),
2642 ('ERROR', '6'),
2643 ], stream=output)
2644 # Original logger output is empty.
2645 self.assert_log_lines([])
2646
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002647 def test_config_8a_ok(self):
2648 with captured_stdout() as output:
2649 self.apply_config(self.config1a)
2650 logger = logging.getLogger("compiler.parser")
2651 # See issue #11424. compiler-hyphenated sorts
2652 # between compiler and compiler.xyz and this
2653 # was preventing compiler.xyz from being included
2654 # in the child loggers of compiler because of an
2655 # overzealous loop termination condition.
2656 hyphenated = logging.getLogger('compiler-hyphenated')
2657 # All will output a message
2658 logger.info(self.next_message())
2659 logger.error(self.next_message())
2660 hyphenated.critical(self.next_message())
2661 self.assert_log_lines([
2662 ('INFO', '1'),
2663 ('ERROR', '2'),
2664 ('CRITICAL', '3'),
2665 ], stream=output)
2666 # Original logger output is empty.
2667 self.assert_log_lines([])
2668 with captured_stdout() as output:
2669 self.apply_config(self.config8a)
2670 logger = logging.getLogger("compiler.parser")
2671 self.assertFalse(logger.disabled)
2672 # Both will output a message
2673 logger.info(self.next_message())
2674 logger.error(self.next_message())
2675 logger = logging.getLogger("compiler.lexer")
2676 # Both will output a message
2677 logger.info(self.next_message())
2678 logger.error(self.next_message())
2679 # Will not appear
2680 hyphenated.critical(self.next_message())
2681 self.assert_log_lines([
2682 ('INFO', '4'),
2683 ('ERROR', '5'),
2684 ('INFO', '6'),
2685 ('ERROR', '7'),
2686 ], stream=output)
2687 # Original logger output is empty.
2688 self.assert_log_lines([])
2689
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002690 def test_config_9_ok(self):
2691 with captured_stdout() as output:
2692 self.apply_config(self.config9)
2693 logger = logging.getLogger("compiler.parser")
2694 #Nothing will be output since both handler and logger are set to WARNING
2695 logger.info(self.next_message())
2696 self.assert_log_lines([], stream=output)
2697 self.apply_config(self.config9a)
2698 #Nothing will be output since both handler is still set to WARNING
2699 logger.info(self.next_message())
2700 self.assert_log_lines([], stream=output)
2701 self.apply_config(self.config9b)
2702 #Message should now be output
2703 logger.info(self.next_message())
2704 self.assert_log_lines([
2705 ('INFO', '3'),
2706 ], stream=output)
2707
2708 def test_config_10_ok(self):
2709 with captured_stdout() as output:
2710 self.apply_config(self.config10)
2711 logger = logging.getLogger("compiler.parser")
2712 logger.warning(self.next_message())
2713 logger = logging.getLogger('compiler')
2714 #Not output, because filtered
2715 logger.warning(self.next_message())
2716 logger = logging.getLogger('compiler.lexer')
2717 #Not output, because filtered
2718 logger.warning(self.next_message())
2719 logger = logging.getLogger("compiler.parser.codegen")
2720 #Output, as not filtered
2721 logger.error(self.next_message())
2722 self.assert_log_lines([
2723 ('WARNING', '1'),
2724 ('ERROR', '4'),
2725 ], stream=output)
2726
2727 def test_config11_ok(self):
2728 self.test_config1_ok(self.config11)
2729
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002730 def test_config12_failure(self):
2731 self.assertRaises(Exception, self.apply_config, self.config12)
2732
2733 def test_config13_failure(self):
2734 self.assertRaises(Exception, self.apply_config, self.config13)
2735
Vinay Sajip8d270232012-11-15 14:20:18 +00002736 def test_config14_ok(self):
2737 with captured_stdout() as output:
2738 self.apply_config(self.config14)
2739 h = logging._handlers['hand1']
2740 self.assertEqual(h.foo, 'bar')
2741 self.assertEqual(h.terminator, '!\n')
2742 logging.warning('Exclamation')
2743 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2744
Victor Stinner45df8202010-04-28 22:31:17 +00002745 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002746 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002747 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002748 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002749 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002750 t.start()
2751 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002752 # Now get the port allocated
2753 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002754 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002755 try:
2756 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2757 sock.settimeout(2.0)
2758 sock.connect(('localhost', port))
2759
2760 slen = struct.pack('>L', len(text))
2761 s = slen + text
2762 sentsofar = 0
2763 left = len(s)
2764 while left > 0:
2765 sent = sock.send(s[sentsofar:])
2766 sentsofar += sent
2767 left -= sent
2768 sock.close()
2769 finally:
2770 t.ready.wait(2.0)
2771 logging.config.stopListening()
2772 t.join(2.0)
2773
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002774 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002775 def test_listen_config_10_ok(self):
2776 with captured_stdout() as output:
2777 self.setup_via_listener(json.dumps(self.config10))
2778 logger = logging.getLogger("compiler.parser")
2779 logger.warning(self.next_message())
2780 logger = logging.getLogger('compiler')
2781 #Not output, because filtered
2782 logger.warning(self.next_message())
2783 logger = logging.getLogger('compiler.lexer')
2784 #Not output, because filtered
2785 logger.warning(self.next_message())
2786 logger = logging.getLogger("compiler.parser.codegen")
2787 #Output, as not filtered
2788 logger.error(self.next_message())
2789 self.assert_log_lines([
2790 ('WARNING', '1'),
2791 ('ERROR', '4'),
2792 ], stream=output)
2793
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002794 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002795 def test_listen_config_1_ok(self):
2796 with captured_stdout() as output:
2797 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2798 logger = logging.getLogger("compiler.parser")
2799 # Both will output a message
2800 logger.info(self.next_message())
2801 logger.error(self.next_message())
2802 self.assert_log_lines([
2803 ('INFO', '1'),
2804 ('ERROR', '2'),
2805 ], stream=output)
2806 # Original logger output is empty.
2807 self.assert_log_lines([])
2808
Vinay Sajip4ded5512012-10-02 15:56:16 +01002809 @unittest.skipUnless(threading, 'Threading required for this test.')
2810 def test_listen_verify(self):
2811
2812 def verify_fail(stuff):
2813 return None
2814
2815 def verify_reverse(stuff):
2816 return stuff[::-1]
2817
2818 logger = logging.getLogger("compiler.parser")
2819 to_send = textwrap.dedent(ConfigFileTest.config1)
2820 # First, specify a verification function that will fail.
2821 # We expect to see no output, since our configuration
2822 # never took effect.
2823 with captured_stdout() as output:
2824 self.setup_via_listener(to_send, verify_fail)
2825 # Both will output a message
2826 logger.info(self.next_message())
2827 logger.error(self.next_message())
2828 self.assert_log_lines([], stream=output)
2829 # Original logger output has the stuff we logged.
2830 self.assert_log_lines([
2831 ('INFO', '1'),
2832 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002833 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002834
2835 # Now, perform no verification. Our configuration
2836 # should take effect.
2837
2838 with captured_stdout() as output:
2839 self.setup_via_listener(to_send) # no verify callable specified
2840 logger = logging.getLogger("compiler.parser")
2841 # Both will output a message
2842 logger.info(self.next_message())
2843 logger.error(self.next_message())
2844 self.assert_log_lines([
2845 ('INFO', '3'),
2846 ('ERROR', '4'),
2847 ], stream=output)
2848 # Original logger output still has the stuff we logged before.
2849 self.assert_log_lines([
2850 ('INFO', '1'),
2851 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002852 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002853
2854 # Now, perform verification which transforms the bytes.
2855
2856 with captured_stdout() as output:
2857 self.setup_via_listener(to_send[::-1], verify_reverse)
2858 logger = logging.getLogger("compiler.parser")
2859 # Both will output a message
2860 logger.info(self.next_message())
2861 logger.error(self.next_message())
2862 self.assert_log_lines([
2863 ('INFO', '5'),
2864 ('ERROR', '6'),
2865 ], stream=output)
2866 # Original logger output still has the stuff we logged before.
2867 self.assert_log_lines([
2868 ('INFO', '1'),
2869 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002870 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002871
Vinay Sajip3f885b52013-03-22 15:19:54 +00002872 def test_out_of_order(self):
2873 self.apply_config(self.out_of_order)
2874 handler = logging.getLogger('mymodule').handlers[0]
2875 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002876 self.assertIsInstance(handler.formatter._style,
2877 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002878
Vinay Sajip373baef2011-04-26 20:05:24 +01002879 def test_baseconfig(self):
2880 d = {
2881 'atuple': (1, 2, 3),
2882 'alist': ['a', 'b', 'c'],
2883 'adict': {'d': 'e', 'f': 3 },
2884 'nest1': ('g', ('h', 'i'), 'j'),
2885 'nest2': ['k', ['l', 'm'], 'n'],
2886 'nest3': ['o', 'cfg://alist', 'p'],
2887 }
2888 bc = logging.config.BaseConfigurator(d)
2889 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2890 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2891 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2892 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2893 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2894 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2895 v = bc.convert('cfg://nest3')
2896 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2897 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2898 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2899 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002900
2901class ManagerTest(BaseTest):
2902 def test_manager_loggerclass(self):
2903 logged = []
2904
2905 class MyLogger(logging.Logger):
2906 def _log(self, level, msg, args, exc_info=None, extra=None):
2907 logged.append(msg)
2908
2909 man = logging.Manager(None)
2910 self.assertRaises(TypeError, man.setLoggerClass, int)
2911 man.setLoggerClass(MyLogger)
2912 logger = man.getLogger('test')
2913 logger.warning('should appear in logged')
2914 logging.warning('should not appear in logged')
2915
2916 self.assertEqual(logged, ['should appear in logged'])
2917
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002918 def test_set_log_record_factory(self):
2919 man = logging.Manager(None)
2920 expected = object()
2921 man.setLogRecordFactory(expected)
2922 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002923
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002924class ChildLoggerTest(BaseTest):
2925 def test_child_loggers(self):
2926 r = logging.getLogger()
2927 l1 = logging.getLogger('abc')
2928 l2 = logging.getLogger('def.ghi')
2929 c1 = r.getChild('xyz')
2930 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002931 self.assertIs(c1, logging.getLogger('xyz'))
2932 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002933 c1 = l1.getChild('def')
2934 c2 = c1.getChild('ghi')
2935 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002936 self.assertIs(c1, logging.getLogger('abc.def'))
2937 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2938 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002939
2940
Vinay Sajip6fac8172010-10-19 20:44:14 +00002941class DerivedLogRecord(logging.LogRecord):
2942 pass
2943
Vinay Sajip61561522010-12-03 11:50:38 +00002944class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002945
2946 def setUp(self):
2947 class CheckingFilter(logging.Filter):
2948 def __init__(self, cls):
2949 self.cls = cls
2950
2951 def filter(self, record):
2952 t = type(record)
2953 if t is not self.cls:
2954 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2955 self.cls)
2956 raise TypeError(msg)
2957 return True
2958
2959 BaseTest.setUp(self)
2960 self.filter = CheckingFilter(DerivedLogRecord)
2961 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002962 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002963
2964 def tearDown(self):
2965 self.root_logger.removeFilter(self.filter)
2966 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002967 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002968
2969 def test_logrecord_class(self):
2970 self.assertRaises(TypeError, self.root_logger.warning,
2971 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002972 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002973 self.root_logger.error(self.next_message())
2974 self.assert_log_lines([
2975 ('root', 'ERROR', '2'),
2976 ])
2977
2978
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002979class QueueHandlerTest(BaseTest):
2980 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002981 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002982
2983 def setUp(self):
2984 BaseTest.setUp(self)
2985 self.queue = queue.Queue(-1)
2986 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2987 self.que_logger = logging.getLogger('que')
2988 self.que_logger.propagate = False
2989 self.que_logger.setLevel(logging.WARNING)
2990 self.que_logger.addHandler(self.que_hdlr)
2991
2992 def tearDown(self):
2993 self.que_hdlr.close()
2994 BaseTest.tearDown(self)
2995
2996 def test_queue_handler(self):
2997 self.que_logger.debug(self.next_message())
2998 self.assertRaises(queue.Empty, self.queue.get_nowait)
2999 self.que_logger.info(self.next_message())
3000 self.assertRaises(queue.Empty, self.queue.get_nowait)
3001 msg = self.next_message()
3002 self.que_logger.warning(msg)
3003 data = self.queue.get_nowait()
3004 self.assertTrue(isinstance(data, logging.LogRecord))
3005 self.assertEqual(data.name, self.que_logger.name)
3006 self.assertEqual((data.msg, data.args), (msg, None))
3007
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003008 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3009 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003010 def test_queue_listener(self):
3011 handler = TestHandler(Matcher())
3012 listener = logging.handlers.QueueListener(self.queue, handler)
3013 listener.start()
3014 try:
3015 self.que_logger.warning(self.next_message())
3016 self.que_logger.error(self.next_message())
3017 self.que_logger.critical(self.next_message())
3018 finally:
3019 listener.stop()
3020 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3021 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3022 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3023
Vinay Sajip37eb3382011-04-26 20:26:41 +01003024ZERO = datetime.timedelta(0)
3025
3026class UTC(datetime.tzinfo):
3027 def utcoffset(self, dt):
3028 return ZERO
3029
3030 dst = utcoffset
3031
3032 def tzname(self, dt):
3033 return 'UTC'
3034
3035utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003036
Vinay Sajipa39c5712010-10-25 13:57:39 +00003037class FormatterTest(unittest.TestCase):
3038 def setUp(self):
3039 self.common = {
3040 'name': 'formatter.test',
3041 'level': logging.DEBUG,
3042 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3043 'lineno': 42,
3044 'exc_info': None,
3045 'func': None,
3046 'msg': 'Message with %d %s',
3047 'args': (2, 'placeholders'),
3048 }
3049 self.variants = {
3050 }
3051
3052 def get_record(self, name=None):
3053 result = dict(self.common)
3054 if name is not None:
3055 result.update(self.variants[name])
3056 return logging.makeLogRecord(result)
3057
3058 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003059 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003060 r = self.get_record()
3061 f = logging.Formatter('${%(message)s}')
3062 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3063 f = logging.Formatter('%(random)s')
3064 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003065 self.assertFalse(f.usesTime())
3066 f = logging.Formatter('%(asctime)s')
3067 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003068 f = logging.Formatter('%(asctime)-15s')
3069 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003070 f = logging.Formatter('asctime')
3071 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003072
3073 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003074 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003075 r = self.get_record()
3076 f = logging.Formatter('$%{message}%$', style='{')
3077 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3078 f = logging.Formatter('{random}', style='{')
3079 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003080 self.assertFalse(f.usesTime())
3081 f = logging.Formatter('{asctime}', style='{')
3082 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003083 f = logging.Formatter('{asctime!s:15}', style='{')
3084 self.assertTrue(f.usesTime())
3085 f = logging.Formatter('{asctime:15}', style='{')
3086 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003087 f = logging.Formatter('asctime', style='{')
3088 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003089
3090 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003091 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003092 r = self.get_record()
3093 f = logging.Formatter('$message', style='$')
3094 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3095 f = logging.Formatter('$$%${message}%$$', style='$')
3096 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3097 f = logging.Formatter('${random}', style='$')
3098 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003099 self.assertFalse(f.usesTime())
3100 f = logging.Formatter('${asctime}', style='$')
3101 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003102 f = logging.Formatter('${asctime', style='$')
3103 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003104 f = logging.Formatter('$asctime', style='$')
3105 self.assertTrue(f.usesTime())
3106 f = logging.Formatter('asctime', style='$')
3107 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003108
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003109 def test_invalid_style(self):
3110 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3111
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003112 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003113 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003114 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3115 # We use None to indicate we want the local timezone
3116 # We're essentially converting a UTC time to local time
3117 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003118 r.msecs = 123
3119 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003120 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003121 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3122 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003123 f.format(r)
3124 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3125
3126class TestBufferingFormatter(logging.BufferingFormatter):
3127 def formatHeader(self, records):
3128 return '[(%d)' % len(records)
3129
3130 def formatFooter(self, records):
3131 return '(%d)]' % len(records)
3132
3133class BufferingFormatterTest(unittest.TestCase):
3134 def setUp(self):
3135 self.records = [
3136 logging.makeLogRecord({'msg': 'one'}),
3137 logging.makeLogRecord({'msg': 'two'}),
3138 ]
3139
3140 def test_default(self):
3141 f = logging.BufferingFormatter()
3142 self.assertEqual('', f.format([]))
3143 self.assertEqual('onetwo', f.format(self.records))
3144
3145 def test_custom(self):
3146 f = TestBufferingFormatter()
3147 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3148 lf = logging.Formatter('<%(message)s>')
3149 f = TestBufferingFormatter(lf)
3150 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003151
3152class ExceptionTest(BaseTest):
3153 def test_formatting(self):
3154 r = self.root_logger
3155 h = RecordingHandler()
3156 r.addHandler(h)
3157 try:
3158 raise RuntimeError('deliberate mistake')
3159 except:
3160 logging.exception('failed', stack_info=True)
3161 r.removeHandler(h)
3162 h.close()
3163 r = h.records[0]
3164 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3165 'call last):\n'))
3166 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3167 'deliberate mistake'))
3168 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3169 'call last):\n'))
3170 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3171 'stack_info=True)'))
3172
3173
Vinay Sajip5a27d402010-12-10 11:42:57 +00003174class LastResortTest(BaseTest):
3175 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003176 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003177 root = self.root_logger
3178 root.removeHandler(self.root_hdlr)
3179 old_stderr = sys.stderr
3180 old_lastresort = logging.lastResort
3181 old_raise_exceptions = logging.raiseExceptions
3182 try:
3183 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003184 root.debug('This should not appear')
3185 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003186 root.warning('This is your final chance!')
3187 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3188 #No handlers and no last resort, so 'No handlers' message
3189 logging.lastResort = None
3190 sys.stderr = sio = io.StringIO()
3191 root.warning('This is your final chance!')
3192 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3193 # 'No handlers' message only printed once
3194 sys.stderr = sio = io.StringIO()
3195 root.warning('This is your final chance!')
3196 self.assertEqual(sio.getvalue(), '')
3197 root.manager.emittedNoHandlerWarning = False
3198 #If raiseExceptions is False, no message is printed
3199 logging.raiseExceptions = False
3200 sys.stderr = sio = io.StringIO()
3201 root.warning('This is your final chance!')
3202 self.assertEqual(sio.getvalue(), '')
3203 finally:
3204 sys.stderr = old_stderr
3205 root.addHandler(self.root_hdlr)
3206 logging.lastResort = old_lastresort
3207 logging.raiseExceptions = old_raise_exceptions
3208
3209
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003210class FakeHandler:
3211
3212 def __init__(self, identifier, called):
3213 for method in ('acquire', 'flush', 'close', 'release'):
3214 setattr(self, method, self.record_call(identifier, method, called))
3215
3216 def record_call(self, identifier, method_name, called):
3217 def inner():
3218 called.append('{} - {}'.format(identifier, method_name))
3219 return inner
3220
3221
3222class RecordingHandler(logging.NullHandler):
3223
3224 def __init__(self, *args, **kwargs):
3225 super(RecordingHandler, self).__init__(*args, **kwargs)
3226 self.records = []
3227
3228 def handle(self, record):
3229 """Keep track of all the emitted records."""
3230 self.records.append(record)
3231
3232
3233class ShutdownTest(BaseTest):
3234
Vinay Sajip5e66b162011-04-20 15:41:14 +01003235 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003236
3237 def setUp(self):
3238 super(ShutdownTest, self).setUp()
3239 self.called = []
3240
3241 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003242 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003243
3244 def raise_error(self, error):
3245 def inner():
3246 raise error()
3247 return inner
3248
3249 def test_no_failure(self):
3250 # create some fake handlers
3251 handler0 = FakeHandler(0, self.called)
3252 handler1 = FakeHandler(1, self.called)
3253 handler2 = FakeHandler(2, self.called)
3254
3255 # create live weakref to those handlers
3256 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3257
3258 logging.shutdown(handlerList=list(handlers))
3259
3260 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3261 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3262 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3263 self.assertEqual(expected, self.called)
3264
3265 def _test_with_failure_in_method(self, method, error):
3266 handler = FakeHandler(0, self.called)
3267 setattr(handler, method, self.raise_error(error))
3268 handlers = [logging.weakref.ref(handler)]
3269
3270 logging.shutdown(handlerList=list(handlers))
3271
3272 self.assertEqual('0 - release', self.called[-1])
3273
3274 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003275 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003276
3277 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003278 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003279
3280 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003281 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003282
3283 def test_with_valueerror_in_acquire(self):
3284 self._test_with_failure_in_method('acquire', ValueError)
3285
3286 def test_with_valueerror_in_flush(self):
3287 self._test_with_failure_in_method('flush', ValueError)
3288
3289 def test_with_valueerror_in_close(self):
3290 self._test_with_failure_in_method('close', ValueError)
3291
3292 def test_with_other_error_in_acquire_without_raise(self):
3293 logging.raiseExceptions = False
3294 self._test_with_failure_in_method('acquire', IndexError)
3295
3296 def test_with_other_error_in_flush_without_raise(self):
3297 logging.raiseExceptions = False
3298 self._test_with_failure_in_method('flush', IndexError)
3299
3300 def test_with_other_error_in_close_without_raise(self):
3301 logging.raiseExceptions = False
3302 self._test_with_failure_in_method('close', IndexError)
3303
3304 def test_with_other_error_in_acquire_with_raise(self):
3305 logging.raiseExceptions = True
3306 self.assertRaises(IndexError, self._test_with_failure_in_method,
3307 'acquire', IndexError)
3308
3309 def test_with_other_error_in_flush_with_raise(self):
3310 logging.raiseExceptions = True
3311 self.assertRaises(IndexError, self._test_with_failure_in_method,
3312 'flush', IndexError)
3313
3314 def test_with_other_error_in_close_with_raise(self):
3315 logging.raiseExceptions = True
3316 self.assertRaises(IndexError, self._test_with_failure_in_method,
3317 'close', IndexError)
3318
3319
3320class ModuleLevelMiscTest(BaseTest):
3321
Vinay Sajip5e66b162011-04-20 15:41:14 +01003322 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003323
3324 def test_disable(self):
3325 old_disable = logging.root.manager.disable
3326 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003327 self.assertEqual(old_disable, 0)
3328 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003329
3330 logging.disable(83)
3331 self.assertEqual(logging.root.manager.disable, 83)
3332
3333 def _test_log(self, method, level=None):
3334 called = []
3335 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003336 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003337
3338 recording = RecordingHandler()
3339 logging.root.addHandler(recording)
3340
3341 log_method = getattr(logging, method)
3342 if level is not None:
3343 log_method(level, "test me: %r", recording)
3344 else:
3345 log_method("test me: %r", recording)
3346
3347 self.assertEqual(len(recording.records), 1)
3348 record = recording.records[0]
3349 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3350
3351 expected_level = level if level is not None else getattr(logging, method.upper())
3352 self.assertEqual(record.levelno, expected_level)
3353
3354 # basicConfig was not called!
3355 self.assertEqual(called, [])
3356
3357 def test_log(self):
3358 self._test_log('log', logging.ERROR)
3359
3360 def test_debug(self):
3361 self._test_log('debug')
3362
3363 def test_info(self):
3364 self._test_log('info')
3365
3366 def test_warning(self):
3367 self._test_log('warning')
3368
3369 def test_error(self):
3370 self._test_log('error')
3371
3372 def test_critical(self):
3373 self._test_log('critical')
3374
3375 def test_set_logger_class(self):
3376 self.assertRaises(TypeError, logging.setLoggerClass, object)
3377
3378 class MyLogger(logging.Logger):
3379 pass
3380
3381 logging.setLoggerClass(MyLogger)
3382 self.assertEqual(logging.getLoggerClass(), MyLogger)
3383
3384 logging.setLoggerClass(logging.Logger)
3385 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3386
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003387class LogRecordTest(BaseTest):
3388 def test_str_rep(self):
3389 r = logging.makeLogRecord({})
3390 s = str(r)
3391 self.assertTrue(s.startswith('<LogRecord: '))
3392 self.assertTrue(s.endswith('>'))
3393
3394 def test_dict_arg(self):
3395 h = RecordingHandler()
3396 r = logging.getLogger()
3397 r.addHandler(h)
3398 d = {'less' : 'more' }
3399 logging.warning('less is %(less)s', d)
3400 self.assertIs(h.records[0].args, d)
3401 self.assertEqual(h.records[0].message, 'less is more')
3402 r.removeHandler(h)
3403 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003404
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003405 def test_multiprocessing(self):
3406 r = logging.makeLogRecord({})
3407 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003408 try:
3409 import multiprocessing as mp
3410 r = logging.makeLogRecord({})
3411 self.assertEqual(r.processName, mp.current_process().name)
3412 except ImportError:
3413 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003414
3415 def test_optional(self):
3416 r = logging.makeLogRecord({})
3417 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003418 if threading:
3419 NOT_NONE(r.thread)
3420 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003421 NOT_NONE(r.process)
3422 NOT_NONE(r.processName)
3423 log_threads = logging.logThreads
3424 log_processes = logging.logProcesses
3425 log_multiprocessing = logging.logMultiprocessing
3426 try:
3427 logging.logThreads = False
3428 logging.logProcesses = False
3429 logging.logMultiprocessing = False
3430 r = logging.makeLogRecord({})
3431 NONE = self.assertIsNone
3432 NONE(r.thread)
3433 NONE(r.threadName)
3434 NONE(r.process)
3435 NONE(r.processName)
3436 finally:
3437 logging.logThreads = log_threads
3438 logging.logProcesses = log_processes
3439 logging.logMultiprocessing = log_multiprocessing
3440
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003441class BasicConfigTest(unittest.TestCase):
3442
Vinay Sajip95bf5042011-04-20 11:50:56 +01003443 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003444
3445 def setUp(self):
3446 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003447 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003448 self.saved_handlers = logging._handlers.copy()
3449 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003450 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003451 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003452 logging.root.handlers = []
3453
3454 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003455 for h in logging.root.handlers[:]:
3456 logging.root.removeHandler(h)
3457 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003458 super(BasicConfigTest, self).tearDown()
3459
Vinay Sajip3def7e02011-04-20 10:58:06 +01003460 def cleanup(self):
3461 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003462 logging._handlers.clear()
3463 logging._handlers.update(self.saved_handlers)
3464 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003465 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003466
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003467 def test_no_kwargs(self):
3468 logging.basicConfig()
3469
3470 # handler defaults to a StreamHandler to sys.stderr
3471 self.assertEqual(len(logging.root.handlers), 1)
3472 handler = logging.root.handlers[0]
3473 self.assertIsInstance(handler, logging.StreamHandler)
3474 self.assertEqual(handler.stream, sys.stderr)
3475
3476 formatter = handler.formatter
3477 # format defaults to logging.BASIC_FORMAT
3478 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3479 # datefmt defaults to None
3480 self.assertIsNone(formatter.datefmt)
3481 # style defaults to %
3482 self.assertIsInstance(formatter._style, logging.PercentStyle)
3483
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003484 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003485 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003486
3487 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003488
3489 def cleanup(h1, h2, fn):
3490 h1.close()
3491 h2.close()
3492 os.remove(fn)
3493
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494 logging.basicConfig(filename='test.log')
3495
3496 self.assertEqual(len(logging.root.handlers), 1)
3497 handler = logging.root.handlers[0]
3498 self.assertIsInstance(handler, logging.FileHandler)
3499
3500 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003501 self.assertEqual(handler.stream.mode, expected.stream.mode)
3502 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003503 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003504
3505 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003506
3507 def cleanup(h1, h2, fn):
3508 h1.close()
3509 h2.close()
3510 os.remove(fn)
3511
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003512 logging.basicConfig(filename='test.log', filemode='wb')
3513
3514 handler = logging.root.handlers[0]
3515 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003516 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003517 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518
3519 def test_stream(self):
3520 stream = io.StringIO()
3521 self.addCleanup(stream.close)
3522 logging.basicConfig(stream=stream)
3523
3524 self.assertEqual(len(logging.root.handlers), 1)
3525 handler = logging.root.handlers[0]
3526 self.assertIsInstance(handler, logging.StreamHandler)
3527 self.assertEqual(handler.stream, stream)
3528
3529 def test_format(self):
3530 logging.basicConfig(format='foo')
3531
3532 formatter = logging.root.handlers[0].formatter
3533 self.assertEqual(formatter._style._fmt, 'foo')
3534
3535 def test_datefmt(self):
3536 logging.basicConfig(datefmt='bar')
3537
3538 formatter = logging.root.handlers[0].formatter
3539 self.assertEqual(formatter.datefmt, 'bar')
3540
3541 def test_style(self):
3542 logging.basicConfig(style='$')
3543
3544 formatter = logging.root.handlers[0].formatter
3545 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3546
3547 def test_level(self):
3548 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003549 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003550
3551 logging.basicConfig(level=57)
3552 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003553 # Test that second call has no effect
3554 logging.basicConfig(level=58)
3555 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003556
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003557 def test_incompatible(self):
3558 assertRaises = self.assertRaises
3559 handlers = [logging.StreamHandler()]
3560 stream = sys.stderr
3561 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3562 stream=stream)
3563 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3564 handlers=handlers)
3565 assertRaises(ValueError, logging.basicConfig, stream=stream,
3566 handlers=handlers)
3567
3568 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003569 handlers = [
3570 logging.StreamHandler(),
3571 logging.StreamHandler(sys.stdout),
3572 logging.StreamHandler(),
3573 ]
3574 f = logging.Formatter()
3575 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003576 logging.basicConfig(handlers=handlers)
3577 self.assertIs(handlers[0], logging.root.handlers[0])
3578 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003579 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003580 self.assertIsNotNone(handlers[0].formatter)
3581 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003582 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003583 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3584
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003585 def _test_log(self, method, level=None):
3586 # logging.root has no handlers so basicConfig should be called
3587 called = []
3588
3589 old_basic_config = logging.basicConfig
3590 def my_basic_config(*a, **kw):
3591 old_basic_config()
3592 old_level = logging.root.level
3593 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003594 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003595 called.append((a, kw))
3596
3597 patch(self, logging, 'basicConfig', my_basic_config)
3598
3599 log_method = getattr(logging, method)
3600 if level is not None:
3601 log_method(level, "test me")
3602 else:
3603 log_method("test me")
3604
3605 # basicConfig was called with no arguments
3606 self.assertEqual(called, [((), {})])
3607
3608 def test_log(self):
3609 self._test_log('log', logging.WARNING)
3610
3611 def test_debug(self):
3612 self._test_log('debug')
3613
3614 def test_info(self):
3615 self._test_log('info')
3616
3617 def test_warning(self):
3618 self._test_log('warning')
3619
3620 def test_error(self):
3621 self._test_log('error')
3622
3623 def test_critical(self):
3624 self._test_log('critical')
3625
3626
3627class LoggerAdapterTest(unittest.TestCase):
3628
3629 def setUp(self):
3630 super(LoggerAdapterTest, self).setUp()
3631 old_handler_list = logging._handlerList[:]
3632
3633 self.recording = RecordingHandler()
3634 self.logger = logging.root
3635 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003636 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003637 self.addCleanup(self.recording.close)
3638
3639 def cleanup():
3640 logging._handlerList[:] = old_handler_list
3641
3642 self.addCleanup(cleanup)
3643 self.addCleanup(logging.shutdown)
3644 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3645
3646 def test_exception(self):
3647 msg = 'testing exception: %r'
3648 exc = None
3649 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003650 1 / 0
3651 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003652 exc = e
3653 self.adapter.exception(msg, self.recording)
3654
3655 self.assertEqual(len(self.recording.records), 1)
3656 record = self.recording.records[0]
3657 self.assertEqual(record.levelno, logging.ERROR)
3658 self.assertEqual(record.msg, msg)
3659 self.assertEqual(record.args, (self.recording,))
3660 self.assertEqual(record.exc_info,
3661 (exc.__class__, exc, exc.__traceback__))
3662
3663 def test_critical(self):
3664 msg = 'critical test! %r'
3665 self.adapter.critical(msg, self.recording)
3666
3667 self.assertEqual(len(self.recording.records), 1)
3668 record = self.recording.records[0]
3669 self.assertEqual(record.levelno, logging.CRITICAL)
3670 self.assertEqual(record.msg, msg)
3671 self.assertEqual(record.args, (self.recording,))
3672
3673 def test_is_enabled_for(self):
3674 old_disable = self.adapter.logger.manager.disable
3675 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003676 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3677 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003678 self.assertFalse(self.adapter.isEnabledFor(32))
3679
3680 def test_has_handlers(self):
3681 self.assertTrue(self.adapter.hasHandlers())
3682
3683 for handler in self.logger.handlers:
3684 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003685
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003686 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003687 self.assertFalse(self.adapter.hasHandlers())
3688
3689
3690class LoggerTest(BaseTest):
3691
3692 def setUp(self):
3693 super(LoggerTest, self).setUp()
3694 self.recording = RecordingHandler()
3695 self.logger = logging.Logger(name='blah')
3696 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003697 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003698 self.addCleanup(self.recording.close)
3699 self.addCleanup(logging.shutdown)
3700
3701 def test_set_invalid_level(self):
3702 self.assertRaises(TypeError, self.logger.setLevel, object())
3703
3704 def test_exception(self):
3705 msg = 'testing exception: %r'
3706 exc = None
3707 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003708 1 / 0
3709 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003710 exc = e
3711 self.logger.exception(msg, self.recording)
3712
3713 self.assertEqual(len(self.recording.records), 1)
3714 record = self.recording.records[0]
3715 self.assertEqual(record.levelno, logging.ERROR)
3716 self.assertEqual(record.msg, msg)
3717 self.assertEqual(record.args, (self.recording,))
3718 self.assertEqual(record.exc_info,
3719 (exc.__class__, exc, exc.__traceback__))
3720
3721 def test_log_invalid_level_with_raise(self):
3722 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003723 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003724
3725 logging.raiseExceptions = True
3726 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3727
3728 def test_log_invalid_level_no_raise(self):
3729 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003730 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003731
3732 logging.raiseExceptions = False
3733 self.logger.log('10', 'test message') # no exception happens
3734
3735 def test_find_caller_with_stack_info(self):
3736 called = []
3737 patch(self, logging.traceback, 'print_stack',
3738 lambda f, file: called.append(file.getvalue()))
3739
3740 self.logger.findCaller(stack_info=True)
3741
3742 self.assertEqual(len(called), 1)
3743 self.assertEqual('Stack (most recent call last):\n', called[0])
3744
3745 def test_make_record_with_extra_overwrite(self):
3746 name = 'my record'
3747 level = 13
3748 fn = lno = msg = args = exc_info = func = sinfo = None
3749 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3750 exc_info, func, sinfo)
3751
3752 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3753 extra = {key: 'some value'}
3754 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3755 fn, lno, msg, args, exc_info,
3756 extra=extra, sinfo=sinfo)
3757
3758 def test_make_record_with_extra_no_overwrite(self):
3759 name = 'my record'
3760 level = 13
3761 fn = lno = msg = args = exc_info = func = sinfo = None
3762 extra = {'valid_key': 'some value'}
3763 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3764 exc_info, extra=extra, sinfo=sinfo)
3765 self.assertIn('valid_key', result.__dict__)
3766
3767 def test_has_handlers(self):
3768 self.assertTrue(self.logger.hasHandlers())
3769
3770 for handler in self.logger.handlers:
3771 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003772 self.assertFalse(self.logger.hasHandlers())
3773
3774 def test_has_handlers_no_propagate(self):
3775 child_logger = logging.getLogger('blah.child')
3776 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003777 self.assertFalse(child_logger.hasHandlers())
3778
3779 def test_is_enabled_for(self):
3780 old_disable = self.logger.manager.disable
3781 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003782 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003783 self.assertFalse(self.logger.isEnabledFor(22))
3784
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003785 def test_root_logger_aliases(self):
3786 root = logging.getLogger()
3787 self.assertIs(root, logging.root)
3788 self.assertIs(root, logging.getLogger(None))
3789 self.assertIs(root, logging.getLogger(''))
3790 self.assertIs(root, logging.getLogger('foo').root)
3791 self.assertIs(root, logging.getLogger('foo.bar').root)
3792 self.assertIs(root, logging.getLogger('foo').parent)
3793
3794 self.assertIsNot(root, logging.getLogger('\0'))
3795 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3796
3797 def test_invalid_names(self):
3798 self.assertRaises(TypeError, logging.getLogger, any)
3799 self.assertRaises(TypeError, logging.getLogger, b'foo')
3800
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003801
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003802class BaseFileTest(BaseTest):
3803 "Base class for handler tests that write log files"
3804
3805 def setUp(self):
3806 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003807 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3808 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003809 self.rmfiles = []
3810
3811 def tearDown(self):
3812 for fn in self.rmfiles:
3813 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003814 if os.path.exists(self.fn):
3815 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003816 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003817
3818 def assertLogFile(self, filename):
3819 "Assert a log file is there and register it for deletion"
3820 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003821 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003822 self.rmfiles.append(filename)
3823
3824
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003825class FileHandlerTest(BaseFileTest):
3826 def test_delay(self):
3827 os.unlink(self.fn)
3828 fh = logging.FileHandler(self.fn, delay=True)
3829 self.assertIsNone(fh.stream)
3830 self.assertFalse(os.path.exists(self.fn))
3831 fh.handle(logging.makeLogRecord({}))
3832 self.assertIsNotNone(fh.stream)
3833 self.assertTrue(os.path.exists(self.fn))
3834 fh.close()
3835
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003836class RotatingFileHandlerTest(BaseFileTest):
3837 def next_rec(self):
3838 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3839 self.next_message(), None, None, None)
3840
3841 def test_should_not_rollover(self):
3842 # If maxbytes is zero rollover never occurs
3843 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3844 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003845 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003846
3847 def test_should_rollover(self):
3848 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3849 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003850 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003851
3852 def test_file_created(self):
3853 # checks that the file is created and assumes it was created
3854 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003855 rh = logging.handlers.RotatingFileHandler(self.fn)
3856 rh.emit(self.next_rec())
3857 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003858 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003859
3860 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003861 def namer(name):
3862 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003863 rh = logging.handlers.RotatingFileHandler(
3864 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003865 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003866 rh.emit(self.next_rec())
3867 self.assertLogFile(self.fn)
3868 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003869 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003870 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003871 self.assertLogFile(namer(self.fn + ".2"))
3872 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3873 rh.close()
3874
Eric V. Smith851cad72012-03-11 22:46:04 -07003875 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003876 def test_rotator(self):
3877 def namer(name):
3878 return name + ".gz"
3879
3880 def rotator(source, dest):
3881 with open(source, "rb") as sf:
3882 data = sf.read()
3883 compressed = zlib.compress(data, 9)
3884 with open(dest, "wb") as df:
3885 df.write(compressed)
3886 os.remove(source)
3887
3888 rh = logging.handlers.RotatingFileHandler(
3889 self.fn, backupCount=2, maxBytes=1)
3890 rh.rotator = rotator
3891 rh.namer = namer
3892 m1 = self.next_rec()
3893 rh.emit(m1)
3894 self.assertLogFile(self.fn)
3895 m2 = self.next_rec()
3896 rh.emit(m2)
3897 fn = namer(self.fn + ".1")
3898 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003899 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003900 with open(fn, "rb") as f:
3901 compressed = f.read()
3902 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003903 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003904 rh.emit(self.next_rec())
3905 fn = namer(self.fn + ".2")
3906 self.assertLogFile(fn)
3907 with open(fn, "rb") as f:
3908 compressed = f.read()
3909 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003910 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003911 rh.emit(self.next_rec())
3912 fn = namer(self.fn + ".2")
3913 with open(fn, "rb") as f:
3914 compressed = f.read()
3915 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003916 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003917 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003918 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003919
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003920class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003921 # other test methods added below
3922 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003923 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3924 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003925 fmt = logging.Formatter('%(asctime)s %(message)s')
3926 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003927 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003928 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003929 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003930 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003931 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003932 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003933 fh.close()
3934 # At this point, we should have a recent rotated file which we
3935 # can test for the existence of. However, in practice, on some
3936 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003937 # in time to go to look for the log file. So, we go back a fair
3938 # bit, and stop as soon as we see a rotated file. In theory this
3939 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003940 found = False
3941 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003942 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003943 for secs in range(GO_BACK):
3944 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003945 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3946 found = os.path.exists(fn)
3947 if found:
3948 self.rmfiles.append(fn)
3949 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003950 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3951 if not found:
3952 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003953 dn, fn = os.path.split(self.fn)
3954 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003955 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3956 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003957 for f in files:
3958 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003959 path = os.path.join(dn, f)
3960 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003961 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003962 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003963
Vinay Sajip0372e102011-05-05 12:59:14 +01003964 def test_invalid(self):
3965 assertRaises = self.assertRaises
3966 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003967 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003968 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003969 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003970 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003971 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003972
Vinay Sajipa7130792013-04-12 17:04:23 +01003973 def test_compute_rollover_daily_attime(self):
3974 currentTime = 0
3975 atTime = datetime.time(12, 0, 0)
3976 rh = logging.handlers.TimedRotatingFileHandler(
3977 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
3978 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01003979 try:
3980 actual = rh.computeRollover(currentTime)
3981 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01003982
Vinay Sajipd86ac962013-04-14 12:20:46 +01003983 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
3984 self.assertEqual(actual, currentTime + 36 * 60 * 60)
3985 finally:
3986 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01003987
Vinay Sajip10e8c492013-05-18 10:19:54 -07003988 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01003989 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01003990 currentTime = int(time.time())
3991 today = currentTime - currentTime % 86400
3992
Vinay Sajipa7130792013-04-12 17:04:23 +01003993 atTime = datetime.time(12, 0, 0)
3994
Vinay Sajip10e8c492013-05-18 10:19:54 -07003995 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01003996 for day in range(7):
3997 rh = logging.handlers.TimedRotatingFileHandler(
3998 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
3999 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004000 try:
4001 if wday > day:
4002 # The rollover day has already passed this week, so we
4003 # go over into next week
4004 expected = (7 - wday + day)
4005 else:
4006 expected = (day - wday)
4007 # At this point expected is in days from now, convert to seconds
4008 expected *= 24 * 60 * 60
4009 # Add in the rollover time
4010 expected += 12 * 60 * 60
4011 # Add in adjustment for today
4012 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004013 actual = rh.computeRollover(today)
4014 if actual != expected:
4015 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004016 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004017 self.assertEqual(actual, expected)
4018 if day == wday:
4019 # goes into following week
4020 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004021 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004022 if actual != expected:
4023 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004024 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004025 self.assertEqual(actual, expected)
4026 finally:
4027 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004028
4029
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004030def secs(**kw):
4031 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4032
4033for when, exp in (('S', 1),
4034 ('M', 60),
4035 ('H', 60 * 60),
4036 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004037 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004038 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004039 ('W0', secs(days=4, hours=24)),
4040 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004041 def test_compute_rollover(self, when=when, exp=exp):
4042 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004043 self.fn, when=when, interval=1, backupCount=0, utc=True)
4044 currentTime = 0.0
4045 actual = rh.computeRollover(currentTime)
4046 if exp != actual:
4047 # Failures occur on some systems for MIDNIGHT and W0.
4048 # Print detailed calculation for MIDNIGHT so we can try to see
4049 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004050 if when == 'MIDNIGHT':
4051 try:
4052 if rh.utc:
4053 t = time.gmtime(currentTime)
4054 else:
4055 t = time.localtime(currentTime)
4056 currentHour = t[3]
4057 currentMinute = t[4]
4058 currentSecond = t[5]
4059 # r is the number of seconds left between now and midnight
4060 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4061 currentMinute) * 60 +
4062 currentSecond)
4063 result = currentTime + r
4064 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4065 print('currentHour: %s' % currentHour, file=sys.stderr)
4066 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4067 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4068 print('r: %s' % r, file=sys.stderr)
4069 print('result: %s' % result, file=sys.stderr)
4070 except Exception:
4071 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4072 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004073 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004074 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4075
Vinay Sajip60ccd822011-05-09 17:32:09 +01004076
4077@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4078class NTEventLogHandlerTest(BaseTest):
4079 def test_basic(self):
4080 logtype = 'Application'
4081 elh = win32evtlog.OpenEventLog(None, logtype)
4082 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4083 h = logging.handlers.NTEventLogHandler('test_logging')
4084 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4085 h.handle(r)
4086 h.close()
4087 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004088 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004089 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4090 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4091 found = False
4092 GO_BACK = 100
4093 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4094 for e in events:
4095 if e.SourceName != 'test_logging':
4096 continue
4097 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4098 if msg != 'Test Log Message\r\n':
4099 continue
4100 found = True
4101 break
4102 msg = 'Record not found in event log, went back %d records' % GO_BACK
4103 self.assertTrue(found, msg=msg)
4104
Christian Heimes180510d2008-03-03 19:15:45 +00004105# Set the locale to the platform-dependent default. I have no idea
4106# why the test does this, but in any case we save the current locale
4107# first and restore it at the end.
4108@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004109def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004110 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004111 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004112 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4113 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4114 ManagerTest, FormatterTest, BufferingFormatterTest,
4115 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4116 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4117 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4118 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004119 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004120 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004121 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4122 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004123 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004124
Christian Heimes180510d2008-03-03 19:15:45 +00004125if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004126 test_main()