blob: 3adeaec644d907fe178f71419f43f4962a42f6a5 [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajip66b8b082012-04-24 23:25:30 +01003# Copyright 2001-2012 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 Sajip66b8b082012-04-24 23:25:30 +010021Copyright (C) 2001-2012 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 Sajip19ec67a2010-09-17 18:57:36 +000029import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000038import select
Christian Heimes180510d2008-03-03 19:15:45 +000039import socket
Christian Heimes180510d2008-03-03 19:15:45 +000040import struct
41import sys
42import tempfile
Eric V. Smith851cad72012-03-11 22:46:04 -070043from test.support import (captured_stdout, run_with_locale, run_unittest,
44 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000045import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010046import time
Christian Heimes180510d2008-03-03 19:15:45 +000047import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000048import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000049import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000050try:
51 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010053 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 import asynchat
55 import asyncore
56 import errno
57 from http.server import HTTPServer, BaseHTTPRequestHandler
58 import smtpd
59 from urllib.parse import urlparse, parse_qs
60 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
61 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000062except ImportError:
63 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010064try:
65 import win32evtlog
66except ImportError:
67 win32evtlog = None
68try:
69 import win32evtlogutil
70except ImportError:
71 win32evtlogutil = None
72 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070073try:
74 import zlib
75except ImportError:
76 pass
Christian Heimes18c66892008-02-17 13:31:39 +000077
78
Christian Heimes180510d2008-03-03 19:15:45 +000079class BaseTest(unittest.TestCase):
80
81 """Base class for logging tests."""
82
83 log_format = "%(name)s -> %(levelname)s: %(message)s"
84 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
85 message_num = 0
86
87 def setUp(self):
88 """Setup the default logging stream to an internal StringIO instance,
89 so that we can examine log output as we want."""
90 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000091 logging._acquireLock()
92 try:
Christian Heimes180510d2008-03-03 19:15:45 +000093 self.saved_handlers = logging._handlers.copy()
94 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000095 self.saved_loggers = saved_loggers = logger_dict.copy()
Christian Heimes180510d2008-03-03 19:15:45 +000096 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000097 self.logger_states = logger_states = {}
98 for name in saved_loggers:
99 logger_states[name] = getattr(saved_loggers[name],
100 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000101 finally:
102 logging._releaseLock()
103
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100104 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000105 self.logger1 = logging.getLogger("\xab\xd7\xbb")
106 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000107
Christian Heimes180510d2008-03-03 19:15:45 +0000108 self.root_logger = logging.getLogger("")
109 self.original_logging_level = self.root_logger.getEffectiveLevel()
110
111 self.stream = io.StringIO()
112 self.root_logger.setLevel(logging.DEBUG)
113 self.root_hdlr = logging.StreamHandler(self.stream)
114 self.root_formatter = logging.Formatter(self.log_format)
115 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000116 if self.logger1.hasHandlers():
117 hlist = self.logger1.handlers + self.root_logger.handlers
118 raise AssertionError('Unexpected handlers: %s' % hlist)
119 if self.logger2.hasHandlers():
120 hlist = self.logger2.handlers + self.root_logger.handlers
121 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000122 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000123 self.assertTrue(self.logger1.hasHandlers())
124 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000125
126 def tearDown(self):
127 """Remove our logging stream, and restore the original logging
128 level."""
129 self.stream.close()
130 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000131 while self.root_logger.handlers:
132 h = self.root_logger.handlers[0]
133 self.root_logger.removeHandler(h)
134 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000135 self.root_logger.setLevel(self.original_logging_level)
136 logging._acquireLock()
137 try:
138 logging._levelNames.clear()
139 logging._levelNames.update(self.saved_level_names)
140 logging._handlers.clear()
141 logging._handlers.update(self.saved_handlers)
142 logging._handlerList[:] = self.saved_handler_list
143 loggerDict = logging.getLogger().manager.loggerDict
144 loggerDict.clear()
145 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000146 logger_states = self.logger_states
147 for name in self.logger_states:
148 if logger_states[name] is not None:
149 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000150 finally:
151 logging._releaseLock()
152
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000153 def assert_log_lines(self, expected_values, stream=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000154 """Match the collected log lines against the regular expression
155 self.expected_log_pat, and compare the extracted group values to
156 the expected_values list of tuples."""
157 stream = stream or self.stream
158 pat = re.compile(self.expected_log_pat)
159 try:
160 stream.reset()
161 actual_lines = stream.readlines()
162 except AttributeError:
163 # StringIO.StringIO lacks a reset() method.
164 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.
438 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
439
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()
568 except socket.error: # syslogd might not be available
569 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 Sajipa5798de2012-04-24 23:33:33 +0100585 @unittest.skipUnless(threading, 'Threading required for this test.')
586 def test_race(self):
587 # Issue #14632 refers.
588 def remove_loop(fname, tries):
589 for _ in range(tries):
590 try:
591 os.unlink(fname)
592 except OSError:
593 pass
594 time.sleep(0.004 * random.randint(0, 4))
595
Vinay Sajipc94871a2012-04-25 10:51:35 +0100596 del_count = 500
597 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100598
Vinay Sajipa5798de2012-04-24 23:33:33 +0100599 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100600 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
601 os.close(fd)
602 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
603 remover.daemon = True
604 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100605 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100606 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
607 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100608 try:
609 for _ in range(log_count):
610 time.sleep(0.005)
611 r = logging.makeLogRecord({'msg': 'testing' })
612 h.handle(r)
613 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100614 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100615 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100616 if os.path.exists(fn):
617 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100618
619
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100620class BadStream(object):
621 def write(self, data):
622 raise RuntimeError('deliberate mistake')
623
624class TestStreamHandler(logging.StreamHandler):
625 def handleError(self, record):
626 self.error_record = record
627
628class StreamHandlerTest(BaseTest):
629 def test_error_handling(self):
630 h = TestStreamHandler(BadStream())
631 r = logging.makeLogRecord({})
632 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100633 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100634 try:
635 h.handle(r)
636 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100637 h = logging.StreamHandler(BadStream())
638 sys.stderr = sio = io.StringIO()
639 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100640 self.assertIn('\nRuntimeError: deliberate mistake\n',
641 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100642 logging.raiseExceptions = False
643 sys.stderr = sio = io.StringIO()
644 h.handle(r)
645 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100646 finally:
647 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100648 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100649
Vinay Sajip7367d082011-05-02 13:17:27 +0100650# -- The following section could be moved into a server_helper.py module
651# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100652
Vinay Sajipce7c9782011-05-17 07:15:53 +0100653if threading:
654 class TestSMTPChannel(smtpd.SMTPChannel):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100655 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100656 This derived class has had to be created because smtpd does not
657 support use of custom channel maps, although they are allowed by
658 asyncore's design. Issue #11959 has been raised to address this,
659 and if resolved satisfactorily, some of this code can be removed.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100660 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100661 def __init__(self, server, conn, addr, sockmap):
662 asynchat.async_chat.__init__(self, conn, sockmap)
663 self.smtp_server = server
664 self.conn = conn
665 self.addr = addr
666 self.received_lines = []
667 self.smtp_state = self.COMMAND
668 self.seen_greeting = ''
669 self.mailfrom = None
670 self.rcpttos = []
671 self.received_data = ''
672 self.fqdn = socket.getfqdn()
673 self.num_bytes = 0
674 try:
675 self.peer = conn.getpeername()
676 except socket.error as err:
677 # a race condition may occur if the other end is closing
678 # before we can get the peername
679 self.close()
680 if err.args[0] != errno.ENOTCONN:
681 raise
682 return
683 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
684 self.set_terminator(b'\r\n')
Vinay Sajipa463d252011-04-30 21:52:48 +0100685
Vinay Sajip314b92b2011-05-02 14:31:16 +0100686
Vinay Sajipce7c9782011-05-17 07:15:53 +0100687 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100688 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100690
Vinay Sajipce7c9782011-05-17 07:15:53 +0100691 :param addr: A (host, port) tuple which the server listens on.
692 You can specify a port value of zero: the server's
693 *port* attribute will hold the actual port number
694 used, which can be used in client connections.
695 :param handler: A callable which will be called to process
696 incoming messages. The handler will be passed
697 the client address tuple, who the message is from,
698 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100699 :param poll_interval: The interval, in seconds, used in the underlying
700 :func:`select` or :func:`poll` call by
701 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702 :param sockmap: A dictionary which will be used to hold
703 :class:`asyncore.dispatcher` instances used by
704 :func:`asyncore.loop`. This avoids changing the
705 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100706 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100707 channel_class = TestSMTPChannel
708
709 def __init__(self, addr, handler, poll_interval, sockmap):
710 self._localaddr = addr
711 self._remoteaddr = None
712 self.sockmap = sockmap
713 asyncore.dispatcher.__init__(self, map=sockmap)
714 try:
715 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
716 sock.setblocking(0)
717 self.set_socket(sock, map=sockmap)
718 # try to re-use a server port if possible
719 self.set_reuse_addr()
720 self.bind(addr)
721 self.port = sock.getsockname()[1]
722 self.listen(5)
723 except:
724 self.close()
Vinay Sajipe73afad2011-05-10 07:48:28 +0100725 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100726 self._handler = handler
727 self._thread = None
728 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100729
Vinay Sajipce7c9782011-05-17 07:15:53 +0100730 def handle_accepted(self, conn, addr):
731 """
732 Redefined only because the base class does not pass in a
733 map, forcing use of a global in :mod:`asyncore`.
734 """
735 channel = self.channel_class(self, conn, addr, self.sockmap)
Vinay Sajip314b92b2011-05-02 14:31:16 +0100736
Vinay Sajipce7c9782011-05-17 07:15:53 +0100737 def process_message(self, peer, mailfrom, rcpttos, data):
738 """
739 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100740
Vinay Sajipce7c9782011-05-17 07:15:53 +0100741 Typically, this will be a test case method.
742 :param peer: The client (host, port) tuple.
743 :param mailfrom: The address of the sender.
744 :param rcpttos: The addresses of the recipients.
745 :param data: The message.
746 """
747 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100748
Vinay Sajipce7c9782011-05-17 07:15:53 +0100749 def start(self):
750 """
751 Start the server running on a separate daemon thread.
752 """
753 self._thread = t = threading.Thread(target=self.serve_forever,
754 args=(self.poll_interval,))
755 t.setDaemon(True)
756 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100757
Vinay Sajipce7c9782011-05-17 07:15:53 +0100758 def serve_forever(self, poll_interval):
759 """
760 Run the :mod:`asyncore` loop until normal termination
761 conditions arise.
762 :param poll_interval: The interval, in seconds, used in the underlying
763 :func:`select` or :func:`poll` call by
764 :func:`asyncore.loop`.
765 """
766 try:
767 asyncore.loop(poll_interval, map=self.sockmap)
768 except select.error:
769 # On FreeBSD 8, closing the server repeatably
770 # raises this error. We swallow it if the
771 # server has been closed.
772 if self.connected or self.accepting:
773 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100774
Vinay Sajipce7c9782011-05-17 07:15:53 +0100775 def stop(self, timeout=None):
776 """
777 Stop the thread by closing the server instance.
778 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100779
Vinay Sajipce7c9782011-05-17 07:15:53 +0100780 :param timeout: How long to wait for the server thread
781 to terminate.
782 """
783 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100784 self._thread.join(timeout)
785 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100786
Vinay Sajipce7c9782011-05-17 07:15:53 +0100787 class ControlMixin(object):
788 """
789 This mixin is used to start a server on a separate thread, and
790 shut it down programmatically. Request handling is simplified - instead
791 of needing to derive a suitable RequestHandler subclass, you just
792 provide a callable which will be passed each received request to be
793 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100794
Vinay Sajipce7c9782011-05-17 07:15:53 +0100795 :param handler: A handler callable which will be called with a
796 single parameter - the request - in order to
797 process the request. This handler is called on the
798 server thread, effectively meaning that requests are
799 processed serially. While not quite Web scale ;-),
800 this should be fine for testing applications.
801 :param poll_interval: The polling interval in seconds.
802 """
803 def __init__(self, handler, poll_interval):
804 self._thread = None
805 self.poll_interval = poll_interval
806 self._handler = handler
807 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100808
Vinay Sajipce7c9782011-05-17 07:15:53 +0100809 def start(self):
810 """
811 Create a daemon thread to run the server, and start it.
812 """
813 self._thread = t = threading.Thread(target=self.serve_forever,
814 args=(self.poll_interval,))
815 t.setDaemon(True)
816 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100817
Vinay Sajipce7c9782011-05-17 07:15:53 +0100818 def serve_forever(self, poll_interval):
819 """
820 Run the server. Set the ready flag before entering the
821 service loop.
822 """
823 self.ready.set()
824 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100825
Vinay Sajipce7c9782011-05-17 07:15:53 +0100826 def stop(self, timeout=None):
827 """
828 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100829
Vinay Sajipce7c9782011-05-17 07:15:53 +0100830 :param timeout: How long to wait for the server thread
831 to terminate.
832 """
833 self.shutdown()
834 if self._thread is not None:
835 self._thread.join(timeout)
836 self._thread = None
837 self.server_close()
838 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100839
Vinay Sajipce7c9782011-05-17 07:15:53 +0100840 class TestHTTPServer(ControlMixin, HTTPServer):
841 """
842 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100843
Vinay Sajipce7c9782011-05-17 07:15:53 +0100844 :param addr: A tuple with the IP address and port to listen on.
845 :param handler: A handler callable which will be called with a
846 single parameter - the request - in order to
847 process the request.
848 :param poll_interval: The polling interval in seconds.
849 :param log: Pass ``True`` to enable log messages.
850 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100851 def __init__(self, addr, handler, poll_interval=0.5,
852 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100853 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
854 def __getattr__(self, name, default=None):
855 if name.startswith('do_'):
856 return self.process_request
857 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100858
Vinay Sajipce7c9782011-05-17 07:15:53 +0100859 def process_request(self):
860 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100861
Vinay Sajipce7c9782011-05-17 07:15:53 +0100862 def log_message(self, format, *args):
863 if log:
864 super(DelegatingHTTPRequestHandler,
865 self).log_message(format, *args)
866 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
867 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100868 self.sslctx = sslctx
869
870 def get_request(self):
871 try:
872 sock, addr = self.socket.accept()
873 if self.sslctx:
874 sock = self.sslctx.wrap_socket(sock, server_side=True)
875 except socket.error as e:
876 # socket errors are silenced by the caller, print them here
877 sys.stderr.write("Got an error:\n%s\n" % e)
878 raise
879 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100880
Vinay Sajipce7c9782011-05-17 07:15:53 +0100881 class TestTCPServer(ControlMixin, ThreadingTCPServer):
882 """
883 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100884
Vinay Sajipce7c9782011-05-17 07:15:53 +0100885 :param addr: A tuple with the IP address and port to listen on.
886 :param handler: A handler callable which will be called with a single
887 parameter - the request - in order to process the request.
888 :param poll_interval: The polling interval in seconds.
889 :bind_and_activate: If True (the default), binds the server and starts it
890 listening. If False, you need to call
891 :meth:`server_bind` and :meth:`server_activate` at
892 some later time before calling :meth:`start`, so that
893 the server will set up the socket and listen on it.
894 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100895
Vinay Sajipce7c9782011-05-17 07:15:53 +0100896 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100897
Vinay Sajipce7c9782011-05-17 07:15:53 +0100898 def __init__(self, addr, handler, poll_interval=0.5,
899 bind_and_activate=True):
900 class DelegatingTCPRequestHandler(StreamRequestHandler):
901
902 def handle(self):
903 self.server._handler(self)
904 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
905 bind_and_activate)
906 ControlMixin.__init__(self, handler, poll_interval)
907
908 def server_bind(self):
909 super(TestTCPServer, self).server_bind()
910 self.port = self.socket.getsockname()[1]
911
912 class TestUDPServer(ControlMixin, ThreadingUDPServer):
913 """
914 A UDP server which is controllable using :class:`ControlMixin`.
915
916 :param addr: A tuple with the IP address and port to listen on.
917 :param handler: A handler callable which will be called with a
918 single parameter - the request - in order to
919 process the request.
920 :param poll_interval: The polling interval for shutdown requests,
921 in seconds.
922 :bind_and_activate: If True (the default), binds the server and
923 starts it listening. If False, you need to
924 call :meth:`server_bind` and
925 :meth:`server_activate` at some later time
926 before calling :meth:`start`, so that the server will
927 set up the socket and listen on it.
928 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100929 def __init__(self, addr, handler, poll_interval=0.5,
930 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100931 class DelegatingUDPRequestHandler(DatagramRequestHandler):
932
933 def handle(self):
934 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100935
936 def finish(self):
937 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100938 if data:
939 try:
940 super(DelegatingUDPRequestHandler, self).finish()
941 except socket.error:
942 if not self.server._closed:
943 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100944
Vinay Sajip3ef12292011-05-23 23:00:42 +0100945 ThreadingUDPServer.__init__(self, addr,
946 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100947 bind_and_activate)
948 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100949 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100950
951 def server_bind(self):
952 super(TestUDPServer, self).server_bind()
953 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100954
Vinay Sajipba980db2011-05-23 21:37:54 +0100955 def server_close(self):
956 super(TestUDPServer, self).server_close()
957 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100958
959# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100960
Vinay Sajipce7c9782011-05-17 07:15:53 +0100961@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100962class SMTPHandlerTest(BaseTest):
963 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100964 sockmap = {}
965 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
966 sockmap)
967 server.start()
968 addr = ('localhost', server.port)
Vinay Sajip4c3f4782012-04-22 18:19:50 +0100969 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log', timeout=5.0)
Vinay Sajipa463d252011-04-30 21:52:48 +0100970 self.assertEqual(h.toaddrs, ['you'])
971 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100972 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100973 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100974 h.handle(r)
Vinay Sajip17160fd2012-03-15 12:02:08 +0000975 self.handled.wait(5.0) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100976 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000977 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100978 self.assertEqual(len(self.messages), 1)
979 peer, mailfrom, rcpttos, data = self.messages[0]
980 self.assertEqual(mailfrom, 'me')
981 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100982 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100983 self.assertTrue(data.endswith('\n\nHello'))
984 h.close()
985
986 def process_message(self, *args):
987 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100988 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100989
Christian Heimes180510d2008-03-03 19:15:45 +0000990class MemoryHandlerTest(BaseTest):
991
992 """Tests for the MemoryHandler."""
993
994 # Do not bother with a logger name group.
995 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
996
997 def setUp(self):
998 BaseTest.setUp(self)
999 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1000 self.root_hdlr)
1001 self.mem_logger = logging.getLogger('mem')
1002 self.mem_logger.propagate = 0
1003 self.mem_logger.addHandler(self.mem_hdlr)
1004
1005 def tearDown(self):
1006 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001007 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001008
1009 def test_flush(self):
1010 # The memory handler flushes to its target handler based on specific
1011 # criteria (message count and message level).
1012 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001013 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001014 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001015 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001016 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001017 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001018 lines = [
1019 ('DEBUG', '1'),
1020 ('INFO', '2'),
1021 ('WARNING', '3'),
1022 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001023 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001024 for n in (4, 14):
1025 for i in range(9):
1026 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001027 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001028 # This will flush because it's the 10th message since the last
1029 # flush.
1030 self.mem_logger.debug(self.next_message())
1031 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001032 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001033
1034 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001035 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001036
1037
1038class ExceptionFormatter(logging.Formatter):
1039 """A special exception formatter."""
1040 def formatException(self, ei):
1041 return "Got a [%s]" % ei[0].__name__
1042
1043
1044class ConfigFileTest(BaseTest):
1045
1046 """Reading logging config from a .ini-style config file."""
1047
1048 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1049
1050 # config0 is a standard configuration.
1051 config0 = """
1052 [loggers]
1053 keys=root
1054
1055 [handlers]
1056 keys=hand1
1057
1058 [formatters]
1059 keys=form1
1060
1061 [logger_root]
1062 level=WARNING
1063 handlers=hand1
1064
1065 [handler_hand1]
1066 class=StreamHandler
1067 level=NOTSET
1068 formatter=form1
1069 args=(sys.stdout,)
1070
1071 [formatter_form1]
1072 format=%(levelname)s ++ %(message)s
1073 datefmt=
1074 """
1075
1076 # config1 adds a little to the standard configuration.
1077 config1 = """
1078 [loggers]
1079 keys=root,parser
1080
1081 [handlers]
1082 keys=hand1
1083
1084 [formatters]
1085 keys=form1
1086
1087 [logger_root]
1088 level=WARNING
1089 handlers=
1090
1091 [logger_parser]
1092 level=DEBUG
1093 handlers=hand1
1094 propagate=1
1095 qualname=compiler.parser
1096
1097 [handler_hand1]
1098 class=StreamHandler
1099 level=NOTSET
1100 formatter=form1
1101 args=(sys.stdout,)
1102
1103 [formatter_form1]
1104 format=%(levelname)s ++ %(message)s
1105 datefmt=
1106 """
1107
Vinay Sajip3f84b072011-03-07 17:49:33 +00001108 # config1a moves the handler to the root.
1109 config1a = """
1110 [loggers]
1111 keys=root,parser
1112
1113 [handlers]
1114 keys=hand1
1115
1116 [formatters]
1117 keys=form1
1118
1119 [logger_root]
1120 level=WARNING
1121 handlers=hand1
1122
1123 [logger_parser]
1124 level=DEBUG
1125 handlers=
1126 propagate=1
1127 qualname=compiler.parser
1128
1129 [handler_hand1]
1130 class=StreamHandler
1131 level=NOTSET
1132 formatter=form1
1133 args=(sys.stdout,)
1134
1135 [formatter_form1]
1136 format=%(levelname)s ++ %(message)s
1137 datefmt=
1138 """
1139
Christian Heimes180510d2008-03-03 19:15:45 +00001140 # config2 has a subtle configuration error that should be reported
1141 config2 = config1.replace("sys.stdout", "sys.stbout")
1142
1143 # config3 has a less subtle configuration error
1144 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1145
1146 # config4 specifies a custom formatter class to be loaded
1147 config4 = """
1148 [loggers]
1149 keys=root
1150
1151 [handlers]
1152 keys=hand1
1153
1154 [formatters]
1155 keys=form1
1156
1157 [logger_root]
1158 level=NOTSET
1159 handlers=hand1
1160
1161 [handler_hand1]
1162 class=StreamHandler
1163 level=NOTSET
1164 formatter=form1
1165 args=(sys.stdout,)
1166
1167 [formatter_form1]
1168 class=""" + __name__ + """.ExceptionFormatter
1169 format=%(levelname)s:%(name)s:%(message)s
1170 datefmt=
1171 """
1172
Georg Brandl3dbca812008-07-23 16:10:53 +00001173 # config5 specifies a custom handler class to be loaded
1174 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1175
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001176 # config6 uses ', ' delimiters in the handlers and formatters sections
1177 config6 = """
1178 [loggers]
1179 keys=root,parser
1180
1181 [handlers]
1182 keys=hand1, hand2
1183
1184 [formatters]
1185 keys=form1, form2
1186
1187 [logger_root]
1188 level=WARNING
1189 handlers=
1190
1191 [logger_parser]
1192 level=DEBUG
1193 handlers=hand1
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 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001204 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001205 level=NOTSET
1206 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001207 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001208
1209 [formatter_form1]
1210 format=%(levelname)s ++ %(message)s
1211 datefmt=
1212
1213 [formatter_form2]
1214 format=%(message)s
1215 datefmt=
1216 """
1217
Vinay Sajip3f84b072011-03-07 17:49:33 +00001218 # config7 adds a compiler logger.
1219 config7 = """
1220 [loggers]
1221 keys=root,parser,compiler
1222
1223 [handlers]
1224 keys=hand1
1225
1226 [formatters]
1227 keys=form1
1228
1229 [logger_root]
1230 level=WARNING
1231 handlers=hand1
1232
1233 [logger_compiler]
1234 level=DEBUG
1235 handlers=
1236 propagate=1
1237 qualname=compiler
1238
1239 [logger_parser]
1240 level=DEBUG
1241 handlers=
1242 propagate=1
1243 qualname=compiler.parser
1244
1245 [handler_hand1]
1246 class=StreamHandler
1247 level=NOTSET
1248 formatter=form1
1249 args=(sys.stdout,)
1250
1251 [formatter_form1]
1252 format=%(levelname)s ++ %(message)s
1253 datefmt=
1254 """
1255
Christian Heimes180510d2008-03-03 19:15:45 +00001256 def apply_config(self, conf):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001257 file = io.StringIO(textwrap.dedent(conf))
1258 logging.config.fileConfig(file)
Christian Heimes180510d2008-03-03 19:15:45 +00001259
1260 def test_config0_ok(self):
1261 # A simple config file which overrides the default settings.
1262 with captured_stdout() as output:
1263 self.apply_config(self.config0)
1264 logger = logging.getLogger()
1265 # Won't output anything
1266 logger.info(self.next_message())
1267 # Outputs a message
1268 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001269 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001270 ('ERROR', '2'),
1271 ], stream=output)
1272 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001273 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001274
Georg Brandl3dbca812008-07-23 16:10:53 +00001275 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001276 # A config file defining a sub-parser as well.
1277 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001278 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001279 logger = logging.getLogger("compiler.parser")
1280 # Both will output a message
1281 logger.info(self.next_message())
1282 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001283 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001284 ('INFO', '1'),
1285 ('ERROR', '2'),
1286 ], stream=output)
1287 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001288 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001289
1290 def test_config2_failure(self):
1291 # A simple config file which overrides the default settings.
1292 self.assertRaises(Exception, self.apply_config, self.config2)
1293
1294 def test_config3_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config3)
1297
1298 def test_config4_ok(self):
1299 # A config file specifying a custom formatter class.
1300 with captured_stdout() as output:
1301 self.apply_config(self.config4)
1302 logger = logging.getLogger()
1303 try:
1304 raise RuntimeError()
1305 except RuntimeError:
1306 logging.exception("just testing")
1307 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001308 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001309 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1310 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001311 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001312
Georg Brandl3dbca812008-07-23 16:10:53 +00001313 def test_config5_ok(self):
1314 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001315
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001316 def test_config6_ok(self):
1317 self.test_config1_ok(config=self.config6)
1318
Vinay Sajip3f84b072011-03-07 17:49:33 +00001319 def test_config7_ok(self):
1320 with captured_stdout() as output:
1321 self.apply_config(self.config1a)
1322 logger = logging.getLogger("compiler.parser")
1323 # See issue #11424. compiler-hyphenated sorts
1324 # between compiler and compiler.xyz and this
1325 # was preventing compiler.xyz from being included
1326 # in the child loggers of compiler because of an
1327 # overzealous loop termination condition.
1328 hyphenated = logging.getLogger('compiler-hyphenated')
1329 # All will output a message
1330 logger.info(self.next_message())
1331 logger.error(self.next_message())
1332 hyphenated.critical(self.next_message())
1333 self.assert_log_lines([
1334 ('INFO', '1'),
1335 ('ERROR', '2'),
1336 ('CRITICAL', '3'),
1337 ], stream=output)
1338 # Original logger output is empty.
1339 self.assert_log_lines([])
1340 with captured_stdout() as output:
1341 self.apply_config(self.config7)
1342 logger = logging.getLogger("compiler.parser")
1343 self.assertFalse(logger.disabled)
1344 # Both will output a message
1345 logger.info(self.next_message())
1346 logger.error(self.next_message())
1347 logger = logging.getLogger("compiler.lexer")
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 # Will not appear
1352 hyphenated.critical(self.next_message())
1353 self.assert_log_lines([
1354 ('INFO', '4'),
1355 ('ERROR', '5'),
1356 ('INFO', '6'),
1357 ('ERROR', '7'),
1358 ], stream=output)
1359 # Original logger output is empty.
1360 self.assert_log_lines([])
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
Christian Heimes180510d2008-03-03 19:15:45 +00001368 def setUp(self):
1369 """Set up a TCP server to receive log messages, and a SocketHandler
1370 pointing to that server's address and port."""
1371 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001372 addr = ('localhost', 0)
1373 self.server = server = TestTCPServer(addr, self.handle_socket,
1374 0.01)
1375 server.start()
1376 server.ready.wait()
1377 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1378 server.port)
1379 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001380 self.root_logger.removeHandler(self.root_logger.handlers[0])
1381 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001382 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001383
Christian Heimes180510d2008-03-03 19:15:45 +00001384 def tearDown(self):
1385 """Shutdown the TCP server."""
1386 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001387 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001388 self.root_logger.removeHandler(self.sock_hdlr)
1389 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001390 finally:
1391 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001392
Vinay Sajip7367d082011-05-02 13:17:27 +01001393 def handle_socket(self, request):
1394 conn = request.connection
1395 while True:
1396 chunk = conn.recv(4)
1397 if len(chunk) < 4:
1398 break
1399 slen = struct.unpack(">L", chunk)[0]
1400 chunk = conn.recv(slen)
1401 while len(chunk) < slen:
1402 chunk = chunk + conn.recv(slen - len(chunk))
1403 obj = pickle.loads(chunk)
1404 record = logging.makeLogRecord(obj)
1405 self.log_output += record.msg + '\n'
1406 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001407
Christian Heimes180510d2008-03-03 19:15:45 +00001408 def test_output(self):
1409 # The log message sent to the SocketHandler is properly received.
1410 logger = logging.getLogger("tcp")
1411 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001412 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001413 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001414 self.handled.acquire()
1415 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001416
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001417 def test_noserver(self):
1418 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001419 self.server.stop(2.0)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001420 #The logging call should try to connect, which should fail
1421 try:
1422 raise RuntimeError('Deliberate mistake')
1423 except RuntimeError:
1424 self.root_logger.exception('Never sent')
1425 self.root_logger.error('Never sent, either')
1426 now = time.time()
1427 self.assertTrue(self.sock_hdlr.retryTime > now)
1428 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1429 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001430
Vinay Sajip7367d082011-05-02 13:17:27 +01001431
1432@unittest.skipUnless(threading, 'Threading required for this test.')
1433class DatagramHandlerTest(BaseTest):
1434
1435 """Test for DatagramHandler."""
1436
1437 def setUp(self):
1438 """Set up a UDP server to receive log messages, and a DatagramHandler
1439 pointing to that server's address and port."""
1440 BaseTest.setUp(self)
1441 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001442 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001443 server.start()
1444 server.ready.wait()
1445 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1446 server.port)
1447 self.log_output = ''
1448 self.root_logger.removeHandler(self.root_logger.handlers[0])
1449 self.root_logger.addHandler(self.sock_hdlr)
1450 self.handled = threading.Event()
1451
1452 def tearDown(self):
1453 """Shutdown the UDP server."""
1454 try:
1455 self.server.stop(2.0)
1456 self.root_logger.removeHandler(self.sock_hdlr)
1457 self.sock_hdlr.close()
1458 finally:
1459 BaseTest.tearDown(self)
1460
1461 def handle_datagram(self, request):
1462 slen = struct.pack('>L', 0) # length of prefix
1463 packet = request.packet[len(slen):]
1464 obj = pickle.loads(packet)
1465 record = logging.makeLogRecord(obj)
1466 self.log_output += record.msg + '\n'
1467 self.handled.set()
1468
1469 def test_output(self):
1470 # The log message sent to the DatagramHandler is properly received.
1471 logger = logging.getLogger("udp")
1472 logger.error("spam")
1473 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001474 self.handled.clear()
1475 logger.error("eggs")
1476 self.handled.wait()
1477 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001478
1479
1480@unittest.skipUnless(threading, 'Threading required for this test.')
1481class SysLogHandlerTest(BaseTest):
1482
1483 """Test for SysLogHandler using UDP."""
1484
1485 def setUp(self):
1486 """Set up a UDP server to receive log messages, and a SysLogHandler
1487 pointing to that server's address and port."""
1488 BaseTest.setUp(self)
1489 addr = ('localhost', 0)
1490 self.server = server = TestUDPServer(addr, self.handle_datagram,
1491 0.01)
1492 server.start()
1493 server.ready.wait()
1494 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1495 server.port))
1496 self.log_output = ''
1497 self.root_logger.removeHandler(self.root_logger.handlers[0])
1498 self.root_logger.addHandler(self.sl_hdlr)
1499 self.handled = threading.Event()
1500
1501 def tearDown(self):
1502 """Shutdown the UDP server."""
1503 try:
1504 self.server.stop(2.0)
1505 self.root_logger.removeHandler(self.sl_hdlr)
1506 self.sl_hdlr.close()
1507 finally:
1508 BaseTest.tearDown(self)
1509
1510 def handle_datagram(self, request):
1511 self.log_output = request.packet
1512 self.handled.set()
1513
1514 def test_output(self):
1515 # The log message sent to the SysLogHandler is properly received.
1516 logger = logging.getLogger("slh")
1517 logger.error("sp\xe4m")
1518 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001519 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001520 self.handled.clear()
1521 self.sl_hdlr.append_nul = False
1522 logger.error("sp\xe4m")
1523 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001524 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001525 self.handled.clear()
1526 self.sl_hdlr.ident = "h\xe4m-"
1527 logger.error("sp\xe4m")
1528 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001529 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001530
1531
1532@unittest.skipUnless(threading, 'Threading required for this test.')
1533class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001534 """Test for HTTPHandler."""
1535
Vinay Sajip9ba87612011-05-21 11:32:15 +01001536 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1537MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1538zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1539aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1540AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15410tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15425LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1543piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15442z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1545i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1546PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1547E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1548rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1549/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1550-----END RSA PRIVATE KEY-----
1551-----BEGIN CERTIFICATE-----
1552MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1553BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1554EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1555xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1556l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1557vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1558BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1559S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1560BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15614f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15621c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1563IRbTpvlHWPjsSvHz0ZOH
1564-----END CERTIFICATE-----"""
1565
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 def setUp(self):
1567 """Set up an HTTP server to receive log messages, and a HTTPHandler
1568 pointing to that server's address and port."""
1569 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001570 self.handled = threading.Event()
1571
Vinay Sajip7367d082011-05-02 13:17:27 +01001572 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001573 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001574 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001575 if self.command == 'POST':
1576 try:
1577 rlen = int(request.headers['Content-Length'])
1578 self.post_data = request.rfile.read(rlen)
1579 except:
1580 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001581 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001582 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001583 self.handled.set()
1584
1585 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001586 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001587 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001588 root_logger = self.root_logger
1589 root_logger.removeHandler(self.root_logger.handlers[0])
1590 for secure in (False, True):
1591 addr = ('localhost', 0)
1592 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001593 try:
1594 import ssl
1595 fd, fn = tempfile.mkstemp()
1596 os.close(fd)
1597 with open(fn, 'w') as f:
1598 f.write(self.PEMFILE)
1599 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1600 sslctx.load_cert_chain(fn)
1601 os.unlink(fn)
1602 except ImportError:
1603 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001604 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001605 sslctx = None
1606 self.server = server = TestHTTPServer(addr, self.handle_request,
1607 0.01, sslctx=sslctx)
1608 server.start()
1609 server.ready.wait()
1610 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001611 secure_client = secure and sslctx
1612 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1613 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001614 self.log_data = None
1615 root_logger.addHandler(self.h_hdlr)
1616
1617 for method in ('GET', 'POST'):
1618 self.h_hdlr.method = method
1619 self.handled.clear()
1620 msg = "sp\xe4m"
1621 logger.error(msg)
1622 self.handled.wait()
1623 self.assertEqual(self.log_data.path, '/frob')
1624 self.assertEqual(self.command, method)
1625 if method == 'GET':
1626 d = parse_qs(self.log_data.query)
1627 else:
1628 d = parse_qs(self.post_data.decode('utf-8'))
1629 self.assertEqual(d['name'], ['http'])
1630 self.assertEqual(d['funcName'], ['test_output'])
1631 self.assertEqual(d['msg'], [msg])
1632
1633 self.server.stop(2.0)
1634 self.root_logger.removeHandler(self.h_hdlr)
1635 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001636
Christian Heimes180510d2008-03-03 19:15:45 +00001637class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001638
Christian Heimes180510d2008-03-03 19:15:45 +00001639 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001640
Christian Heimes180510d2008-03-03 19:15:45 +00001641 def setUp(self):
1642 """Create a dict to remember potentially destroyed objects."""
1643 BaseTest.setUp(self)
1644 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001645
Christian Heimes180510d2008-03-03 19:15:45 +00001646 def _watch_for_survival(self, *args):
1647 """Watch the given objects for survival, by creating weakrefs to
1648 them."""
1649 for obj in args:
1650 key = id(obj), repr(obj)
1651 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001652
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001653 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001654 """Assert that all objects watched for survival have survived."""
1655 # Trigger cycle breaking.
1656 gc.collect()
1657 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001658 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001659 if ref() is None:
1660 dead.append(repr_)
1661 if dead:
1662 self.fail("%d objects should have survived "
1663 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001664
Christian Heimes180510d2008-03-03 19:15:45 +00001665 def test_persistent_loggers(self):
1666 # Logger objects are persistent and retain their configuration, even
1667 # if visible references are destroyed.
1668 self.root_logger.setLevel(logging.INFO)
1669 foo = logging.getLogger("foo")
1670 self._watch_for_survival(foo)
1671 foo.setLevel(logging.DEBUG)
1672 self.root_logger.debug(self.next_message())
1673 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001674 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001675 ('foo', 'DEBUG', '2'),
1676 ])
1677 del foo
1678 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001679 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001680 # foo has retained its settings.
1681 bar = logging.getLogger("foo")
1682 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001683 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001684 ('foo', 'DEBUG', '2'),
1685 ('foo', 'DEBUG', '3'),
1686 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001687
Benjamin Petersonf91df042009-02-13 02:50:59 +00001688
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001689class EncodingTest(BaseTest):
1690 def test_encoding_plain_file(self):
1691 # In Python 2.x, a plain file object is treated as having no encoding.
1692 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001693 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1694 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001695 # the non-ascii data we write to the log.
1696 data = "foo\x80"
1697 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001698 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001699 log.addHandler(handler)
1700 try:
1701 # write non-ascii data to the log.
1702 log.warning(data)
1703 finally:
1704 log.removeHandler(handler)
1705 handler.close()
1706 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001707 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001708 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001709 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001710 finally:
1711 f.close()
1712 finally:
1713 if os.path.isfile(fn):
1714 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001715
Benjamin Petersonf91df042009-02-13 02:50:59 +00001716 def test_encoding_cyrillic_unicode(self):
1717 log = logging.getLogger("test")
1718 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1719 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1720 #Ensure it's written in a Cyrillic encoding
1721 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001722 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001723 stream = io.BytesIO()
1724 writer = writer_class(stream, 'strict')
1725 handler = logging.StreamHandler(writer)
1726 log.addHandler(handler)
1727 try:
1728 log.warning(message)
1729 finally:
1730 log.removeHandler(handler)
1731 handler.close()
1732 # check we wrote exactly those bytes, ignoring trailing \n etc
1733 s = stream.getvalue()
1734 #Compare against what the data should be when encoded in CP-1251
1735 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1736
1737
Georg Brandlf9734072008-12-07 15:30:06 +00001738class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001739
Georg Brandlf9734072008-12-07 15:30:06 +00001740 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001741 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001742 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001743 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001744 warnings.filterwarnings("always", category=UserWarning)
1745 stream = io.StringIO()
1746 h = logging.StreamHandler(stream)
1747 logger = logging.getLogger("py.warnings")
1748 logger.addHandler(h)
1749 warnings.warn("I'm warning you...")
1750 logger.removeHandler(h)
1751 s = stream.getvalue()
1752 h.close()
1753 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001754
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001755 #See if an explicit file uses the original implementation
1756 a_file = io.StringIO()
1757 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1758 a_file, "Dummy line")
1759 s = a_file.getvalue()
1760 a_file.close()
1761 self.assertEqual(s,
1762 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1763
1764 def test_warnings_no_handlers(self):
1765 with warnings.catch_warnings():
1766 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001767 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001768
1769 # confirm our assumption: no loggers are set
1770 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001771 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001772
1773 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001774 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001775 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001776
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001777
1778def formatFunc(format, datefmt=None):
1779 return logging.Formatter(format, datefmt)
1780
1781def handlerFunc():
1782 return logging.StreamHandler()
1783
1784class CustomHandler(logging.StreamHandler):
1785 pass
1786
1787class ConfigDictTest(BaseTest):
1788
1789 """Reading logging config from a dictionary."""
1790
1791 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1792
1793 # config0 is a standard configuration.
1794 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001795 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001796 'formatters': {
1797 'form1' : {
1798 'format' : '%(levelname)s ++ %(message)s',
1799 },
1800 },
1801 'handlers' : {
1802 'hand1' : {
1803 'class' : 'logging.StreamHandler',
1804 'formatter' : 'form1',
1805 'level' : 'NOTSET',
1806 'stream' : 'ext://sys.stdout',
1807 },
1808 },
1809 'root' : {
1810 'level' : 'WARNING',
1811 'handlers' : ['hand1'],
1812 },
1813 }
1814
1815 # config1 adds a little to the standard configuration.
1816 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001817 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001818 'formatters': {
1819 'form1' : {
1820 'format' : '%(levelname)s ++ %(message)s',
1821 },
1822 },
1823 'handlers' : {
1824 'hand1' : {
1825 'class' : 'logging.StreamHandler',
1826 'formatter' : 'form1',
1827 'level' : 'NOTSET',
1828 'stream' : 'ext://sys.stdout',
1829 },
1830 },
1831 'loggers' : {
1832 'compiler.parser' : {
1833 'level' : 'DEBUG',
1834 'handlers' : ['hand1'],
1835 },
1836 },
1837 'root' : {
1838 'level' : 'WARNING',
1839 },
1840 }
1841
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001842 # config1a moves the handler to the root. Used with config8a
1843 config1a = {
1844 'version': 1,
1845 'formatters': {
1846 'form1' : {
1847 'format' : '%(levelname)s ++ %(message)s',
1848 },
1849 },
1850 'handlers' : {
1851 'hand1' : {
1852 'class' : 'logging.StreamHandler',
1853 'formatter' : 'form1',
1854 'level' : 'NOTSET',
1855 'stream' : 'ext://sys.stdout',
1856 },
1857 },
1858 'loggers' : {
1859 'compiler.parser' : {
1860 'level' : 'DEBUG',
1861 },
1862 },
1863 'root' : {
1864 'level' : 'WARNING',
1865 'handlers' : ['hand1'],
1866 },
1867 }
1868
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001869 # config2 has a subtle configuration error that should be reported
1870 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001871 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001872 'formatters': {
1873 'form1' : {
1874 'format' : '%(levelname)s ++ %(message)s',
1875 },
1876 },
1877 'handlers' : {
1878 'hand1' : {
1879 'class' : 'logging.StreamHandler',
1880 'formatter' : 'form1',
1881 'level' : 'NOTSET',
1882 'stream' : 'ext://sys.stdbout',
1883 },
1884 },
1885 'loggers' : {
1886 'compiler.parser' : {
1887 'level' : 'DEBUG',
1888 'handlers' : ['hand1'],
1889 },
1890 },
1891 'root' : {
1892 'level' : 'WARNING',
1893 },
1894 }
1895
1896 #As config1 but with a misspelt level on a handler
1897 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001898 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001899 'formatters': {
1900 'form1' : {
1901 'format' : '%(levelname)s ++ %(message)s',
1902 },
1903 },
1904 'handlers' : {
1905 'hand1' : {
1906 'class' : 'logging.StreamHandler',
1907 'formatter' : 'form1',
1908 'level' : 'NTOSET',
1909 'stream' : 'ext://sys.stdout',
1910 },
1911 },
1912 'loggers' : {
1913 'compiler.parser' : {
1914 'level' : 'DEBUG',
1915 'handlers' : ['hand1'],
1916 },
1917 },
1918 'root' : {
1919 'level' : 'WARNING',
1920 },
1921 }
1922
1923
1924 #As config1 but with a misspelt level on a logger
1925 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001926 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001927 'formatters': {
1928 'form1' : {
1929 'format' : '%(levelname)s ++ %(message)s',
1930 },
1931 },
1932 'handlers' : {
1933 'hand1' : {
1934 'class' : 'logging.StreamHandler',
1935 'formatter' : 'form1',
1936 'level' : 'NOTSET',
1937 'stream' : 'ext://sys.stdout',
1938 },
1939 },
1940 'loggers' : {
1941 'compiler.parser' : {
1942 'level' : 'DEBUG',
1943 'handlers' : ['hand1'],
1944 },
1945 },
1946 'root' : {
1947 'level' : 'WRANING',
1948 },
1949 }
1950
1951 # config3 has a less subtle configuration error
1952 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001953 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001954 'formatters': {
1955 'form1' : {
1956 'format' : '%(levelname)s ++ %(message)s',
1957 },
1958 },
1959 'handlers' : {
1960 'hand1' : {
1961 'class' : 'logging.StreamHandler',
1962 'formatter' : 'misspelled_name',
1963 'level' : 'NOTSET',
1964 'stream' : 'ext://sys.stdout',
1965 },
1966 },
1967 'loggers' : {
1968 'compiler.parser' : {
1969 'level' : 'DEBUG',
1970 'handlers' : ['hand1'],
1971 },
1972 },
1973 'root' : {
1974 'level' : 'WARNING',
1975 },
1976 }
1977
1978 # config4 specifies a custom formatter class to be loaded
1979 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001980 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001981 'formatters': {
1982 'form1' : {
1983 '()' : __name__ + '.ExceptionFormatter',
1984 'format' : '%(levelname)s:%(name)s:%(message)s',
1985 },
1986 },
1987 'handlers' : {
1988 'hand1' : {
1989 'class' : 'logging.StreamHandler',
1990 'formatter' : 'form1',
1991 'level' : 'NOTSET',
1992 'stream' : 'ext://sys.stdout',
1993 },
1994 },
1995 'root' : {
1996 'level' : 'NOTSET',
1997 'handlers' : ['hand1'],
1998 },
1999 }
2000
2001 # As config4 but using an actual callable rather than a string
2002 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002003 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002004 'formatters': {
2005 'form1' : {
2006 '()' : ExceptionFormatter,
2007 'format' : '%(levelname)s:%(name)s:%(message)s',
2008 },
2009 'form2' : {
2010 '()' : __name__ + '.formatFunc',
2011 'format' : '%(levelname)s:%(name)s:%(message)s',
2012 },
2013 'form3' : {
2014 '()' : formatFunc,
2015 'format' : '%(levelname)s:%(name)s:%(message)s',
2016 },
2017 },
2018 'handlers' : {
2019 'hand1' : {
2020 'class' : 'logging.StreamHandler',
2021 'formatter' : 'form1',
2022 'level' : 'NOTSET',
2023 'stream' : 'ext://sys.stdout',
2024 },
2025 'hand2' : {
2026 '()' : handlerFunc,
2027 },
2028 },
2029 'root' : {
2030 'level' : 'NOTSET',
2031 'handlers' : ['hand1'],
2032 },
2033 }
2034
2035 # config5 specifies a custom handler class to be loaded
2036 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002037 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002038 'formatters': {
2039 'form1' : {
2040 'format' : '%(levelname)s ++ %(message)s',
2041 },
2042 },
2043 'handlers' : {
2044 'hand1' : {
2045 'class' : __name__ + '.CustomHandler',
2046 'formatter' : 'form1',
2047 'level' : 'NOTSET',
2048 'stream' : 'ext://sys.stdout',
2049 },
2050 },
2051 'loggers' : {
2052 'compiler.parser' : {
2053 'level' : 'DEBUG',
2054 'handlers' : ['hand1'],
2055 },
2056 },
2057 'root' : {
2058 'level' : 'WARNING',
2059 },
2060 }
2061
2062 # config6 specifies a custom handler class to be loaded
2063 # but has bad arguments
2064 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002065 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002066 'formatters': {
2067 'form1' : {
2068 'format' : '%(levelname)s ++ %(message)s',
2069 },
2070 },
2071 'handlers' : {
2072 'hand1' : {
2073 'class' : __name__ + '.CustomHandler',
2074 'formatter' : 'form1',
2075 'level' : 'NOTSET',
2076 'stream' : 'ext://sys.stdout',
2077 '9' : 'invalid parameter name',
2078 },
2079 },
2080 'loggers' : {
2081 'compiler.parser' : {
2082 'level' : 'DEBUG',
2083 'handlers' : ['hand1'],
2084 },
2085 },
2086 'root' : {
2087 'level' : 'WARNING',
2088 },
2089 }
2090
2091 #config 7 does not define compiler.parser but defines compiler.lexer
2092 #so compiler.parser should be disabled after applying it
2093 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002094 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002095 'formatters': {
2096 'form1' : {
2097 'format' : '%(levelname)s ++ %(message)s',
2098 },
2099 },
2100 'handlers' : {
2101 'hand1' : {
2102 'class' : 'logging.StreamHandler',
2103 'formatter' : 'form1',
2104 'level' : 'NOTSET',
2105 'stream' : 'ext://sys.stdout',
2106 },
2107 },
2108 'loggers' : {
2109 'compiler.lexer' : {
2110 'level' : 'DEBUG',
2111 'handlers' : ['hand1'],
2112 },
2113 },
2114 'root' : {
2115 'level' : 'WARNING',
2116 },
2117 }
2118
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002119 # config8 defines both compiler and compiler.lexer
2120 # so compiler.parser should not be disabled (since
2121 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002122 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002123 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002124 'disable_existing_loggers' : False,
2125 'formatters': {
2126 'form1' : {
2127 'format' : '%(levelname)s ++ %(message)s',
2128 },
2129 },
2130 'handlers' : {
2131 'hand1' : {
2132 'class' : 'logging.StreamHandler',
2133 'formatter' : 'form1',
2134 'level' : 'NOTSET',
2135 'stream' : 'ext://sys.stdout',
2136 },
2137 },
2138 'loggers' : {
2139 'compiler' : {
2140 'level' : 'DEBUG',
2141 'handlers' : ['hand1'],
2142 },
2143 'compiler.lexer' : {
2144 },
2145 },
2146 'root' : {
2147 'level' : 'WARNING',
2148 },
2149 }
2150
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002151 # config8a disables existing loggers
2152 config8a = {
2153 'version': 1,
2154 'disable_existing_loggers' : True,
2155 'formatters': {
2156 'form1' : {
2157 'format' : '%(levelname)s ++ %(message)s',
2158 },
2159 },
2160 'handlers' : {
2161 'hand1' : {
2162 'class' : 'logging.StreamHandler',
2163 'formatter' : 'form1',
2164 'level' : 'NOTSET',
2165 'stream' : 'ext://sys.stdout',
2166 },
2167 },
2168 'loggers' : {
2169 'compiler' : {
2170 'level' : 'DEBUG',
2171 'handlers' : ['hand1'],
2172 },
2173 'compiler.lexer' : {
2174 },
2175 },
2176 'root' : {
2177 'level' : 'WARNING',
2178 },
2179 }
2180
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002181 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002182 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002183 'formatters': {
2184 'form1' : {
2185 'format' : '%(levelname)s ++ %(message)s',
2186 },
2187 },
2188 'handlers' : {
2189 'hand1' : {
2190 'class' : 'logging.StreamHandler',
2191 'formatter' : 'form1',
2192 'level' : 'WARNING',
2193 'stream' : 'ext://sys.stdout',
2194 },
2195 },
2196 'loggers' : {
2197 'compiler.parser' : {
2198 'level' : 'WARNING',
2199 'handlers' : ['hand1'],
2200 },
2201 },
2202 'root' : {
2203 'level' : 'NOTSET',
2204 },
2205 }
2206
2207 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002208 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002209 'incremental' : True,
2210 'handlers' : {
2211 'hand1' : {
2212 'level' : 'WARNING',
2213 },
2214 },
2215 'loggers' : {
2216 'compiler.parser' : {
2217 'level' : 'INFO',
2218 },
2219 },
2220 }
2221
2222 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002223 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002224 'incremental' : True,
2225 'handlers' : {
2226 'hand1' : {
2227 'level' : 'INFO',
2228 },
2229 },
2230 'loggers' : {
2231 'compiler.parser' : {
2232 'level' : 'INFO',
2233 },
2234 },
2235 }
2236
2237 #As config1 but with a filter added
2238 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002239 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002240 'formatters': {
2241 'form1' : {
2242 'format' : '%(levelname)s ++ %(message)s',
2243 },
2244 },
2245 'filters' : {
2246 'filt1' : {
2247 'name' : 'compiler.parser',
2248 },
2249 },
2250 'handlers' : {
2251 'hand1' : {
2252 'class' : 'logging.StreamHandler',
2253 'formatter' : 'form1',
2254 'level' : 'NOTSET',
2255 'stream' : 'ext://sys.stdout',
2256 'filters' : ['filt1'],
2257 },
2258 },
2259 'loggers' : {
2260 'compiler.parser' : {
2261 'level' : 'DEBUG',
2262 'filters' : ['filt1'],
2263 },
2264 },
2265 'root' : {
2266 'level' : 'WARNING',
2267 'handlers' : ['hand1'],
2268 },
2269 }
2270
2271 #As config1 but using cfg:// references
2272 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002273 'version': 1,
2274 'true_formatters': {
2275 'form1' : {
2276 'format' : '%(levelname)s ++ %(message)s',
2277 },
2278 },
2279 'handler_configs': {
2280 'hand1' : {
2281 'class' : 'logging.StreamHandler',
2282 'formatter' : 'form1',
2283 'level' : 'NOTSET',
2284 'stream' : 'ext://sys.stdout',
2285 },
2286 },
2287 'formatters' : 'cfg://true_formatters',
2288 'handlers' : {
2289 'hand1' : 'cfg://handler_configs[hand1]',
2290 },
2291 'loggers' : {
2292 'compiler.parser' : {
2293 'level' : 'DEBUG',
2294 'handlers' : ['hand1'],
2295 },
2296 },
2297 'root' : {
2298 'level' : 'WARNING',
2299 },
2300 }
2301
2302 #As config11 but missing the version key
2303 config12 = {
2304 'true_formatters': {
2305 'form1' : {
2306 'format' : '%(levelname)s ++ %(message)s',
2307 },
2308 },
2309 'handler_configs': {
2310 'hand1' : {
2311 'class' : 'logging.StreamHandler',
2312 'formatter' : 'form1',
2313 'level' : 'NOTSET',
2314 'stream' : 'ext://sys.stdout',
2315 },
2316 },
2317 'formatters' : 'cfg://true_formatters',
2318 'handlers' : {
2319 'hand1' : 'cfg://handler_configs[hand1]',
2320 },
2321 'loggers' : {
2322 'compiler.parser' : {
2323 'level' : 'DEBUG',
2324 'handlers' : ['hand1'],
2325 },
2326 },
2327 'root' : {
2328 'level' : 'WARNING',
2329 },
2330 }
2331
2332 #As config11 but using an unsupported version
2333 config13 = {
2334 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002335 'true_formatters': {
2336 'form1' : {
2337 'format' : '%(levelname)s ++ %(message)s',
2338 },
2339 },
2340 'handler_configs': {
2341 'hand1' : {
2342 'class' : 'logging.StreamHandler',
2343 'formatter' : 'form1',
2344 'level' : 'NOTSET',
2345 'stream' : 'ext://sys.stdout',
2346 },
2347 },
2348 'formatters' : 'cfg://true_formatters',
2349 'handlers' : {
2350 'hand1' : 'cfg://handler_configs[hand1]',
2351 },
2352 'loggers' : {
2353 'compiler.parser' : {
2354 'level' : 'DEBUG',
2355 'handlers' : ['hand1'],
2356 },
2357 },
2358 'root' : {
2359 'level' : 'WARNING',
2360 },
2361 }
2362
2363 def apply_config(self, conf):
2364 logging.config.dictConfig(conf)
2365
2366 def test_config0_ok(self):
2367 # A simple config which overrides the default settings.
2368 with captured_stdout() as output:
2369 self.apply_config(self.config0)
2370 logger = logging.getLogger()
2371 # Won't output anything
2372 logger.info(self.next_message())
2373 # Outputs a message
2374 logger.error(self.next_message())
2375 self.assert_log_lines([
2376 ('ERROR', '2'),
2377 ], stream=output)
2378 # Original logger output is empty.
2379 self.assert_log_lines([])
2380
2381 def test_config1_ok(self, config=config1):
2382 # A config defining a sub-parser as well.
2383 with captured_stdout() as output:
2384 self.apply_config(config)
2385 logger = logging.getLogger("compiler.parser")
2386 # Both will output a message
2387 logger.info(self.next_message())
2388 logger.error(self.next_message())
2389 self.assert_log_lines([
2390 ('INFO', '1'),
2391 ('ERROR', '2'),
2392 ], stream=output)
2393 # Original logger output is empty.
2394 self.assert_log_lines([])
2395
2396 def test_config2_failure(self):
2397 # A simple config which overrides the default settings.
2398 self.assertRaises(Exception, self.apply_config, self.config2)
2399
2400 def test_config2a_failure(self):
2401 # A simple config which overrides the default settings.
2402 self.assertRaises(Exception, self.apply_config, self.config2a)
2403
2404 def test_config2b_failure(self):
2405 # A simple config which overrides the default settings.
2406 self.assertRaises(Exception, self.apply_config, self.config2b)
2407
2408 def test_config3_failure(self):
2409 # A simple config which overrides the default settings.
2410 self.assertRaises(Exception, self.apply_config, self.config3)
2411
2412 def test_config4_ok(self):
2413 # A config specifying a custom formatter class.
2414 with captured_stdout() as output:
2415 self.apply_config(self.config4)
2416 #logger = logging.getLogger()
2417 try:
2418 raise RuntimeError()
2419 except RuntimeError:
2420 logging.exception("just testing")
2421 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002422 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002423 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2424 # Original logger output is empty
2425 self.assert_log_lines([])
2426
2427 def test_config4a_ok(self):
2428 # A config specifying a custom formatter class.
2429 with captured_stdout() as output:
2430 self.apply_config(self.config4a)
2431 #logger = logging.getLogger()
2432 try:
2433 raise RuntimeError()
2434 except RuntimeError:
2435 logging.exception("just testing")
2436 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002437 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002438 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2439 # Original logger output is empty
2440 self.assert_log_lines([])
2441
2442 def test_config5_ok(self):
2443 self.test_config1_ok(config=self.config5)
2444
2445 def test_config6_failure(self):
2446 self.assertRaises(Exception, self.apply_config, self.config6)
2447
2448 def test_config7_ok(self):
2449 with captured_stdout() as output:
2450 self.apply_config(self.config1)
2451 logger = logging.getLogger("compiler.parser")
2452 # Both will output a message
2453 logger.info(self.next_message())
2454 logger.error(self.next_message())
2455 self.assert_log_lines([
2456 ('INFO', '1'),
2457 ('ERROR', '2'),
2458 ], stream=output)
2459 # Original logger output is empty.
2460 self.assert_log_lines([])
2461 with captured_stdout() as output:
2462 self.apply_config(self.config7)
2463 logger = logging.getLogger("compiler.parser")
2464 self.assertTrue(logger.disabled)
2465 logger = logging.getLogger("compiler.lexer")
2466 # Both will output a message
2467 logger.info(self.next_message())
2468 logger.error(self.next_message())
2469 self.assert_log_lines([
2470 ('INFO', '3'),
2471 ('ERROR', '4'),
2472 ], stream=output)
2473 # Original logger output is empty.
2474 self.assert_log_lines([])
2475
2476 #Same as test_config_7_ok but don't disable old loggers.
2477 def test_config_8_ok(self):
2478 with captured_stdout() as output:
2479 self.apply_config(self.config1)
2480 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002481 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002482 logger.info(self.next_message())
2483 logger.error(self.next_message())
2484 self.assert_log_lines([
2485 ('INFO', '1'),
2486 ('ERROR', '2'),
2487 ], stream=output)
2488 # Original logger output is empty.
2489 self.assert_log_lines([])
2490 with captured_stdout() as output:
2491 self.apply_config(self.config8)
2492 logger = logging.getLogger("compiler.parser")
2493 self.assertFalse(logger.disabled)
2494 # Both will output a message
2495 logger.info(self.next_message())
2496 logger.error(self.next_message())
2497 logger = logging.getLogger("compiler.lexer")
2498 # Both will output a message
2499 logger.info(self.next_message())
2500 logger.error(self.next_message())
2501 self.assert_log_lines([
2502 ('INFO', '3'),
2503 ('ERROR', '4'),
2504 ('INFO', '5'),
2505 ('ERROR', '6'),
2506 ], stream=output)
2507 # Original logger output is empty.
2508 self.assert_log_lines([])
2509
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002510 def test_config_8a_ok(self):
2511 with captured_stdout() as output:
2512 self.apply_config(self.config1a)
2513 logger = logging.getLogger("compiler.parser")
2514 # See issue #11424. compiler-hyphenated sorts
2515 # between compiler and compiler.xyz and this
2516 # was preventing compiler.xyz from being included
2517 # in the child loggers of compiler because of an
2518 # overzealous loop termination condition.
2519 hyphenated = logging.getLogger('compiler-hyphenated')
2520 # All will output a message
2521 logger.info(self.next_message())
2522 logger.error(self.next_message())
2523 hyphenated.critical(self.next_message())
2524 self.assert_log_lines([
2525 ('INFO', '1'),
2526 ('ERROR', '2'),
2527 ('CRITICAL', '3'),
2528 ], stream=output)
2529 # Original logger output is empty.
2530 self.assert_log_lines([])
2531 with captured_stdout() as output:
2532 self.apply_config(self.config8a)
2533 logger = logging.getLogger("compiler.parser")
2534 self.assertFalse(logger.disabled)
2535 # Both will output a message
2536 logger.info(self.next_message())
2537 logger.error(self.next_message())
2538 logger = logging.getLogger("compiler.lexer")
2539 # Both will output a message
2540 logger.info(self.next_message())
2541 logger.error(self.next_message())
2542 # Will not appear
2543 hyphenated.critical(self.next_message())
2544 self.assert_log_lines([
2545 ('INFO', '4'),
2546 ('ERROR', '5'),
2547 ('INFO', '6'),
2548 ('ERROR', '7'),
2549 ], stream=output)
2550 # Original logger output is empty.
2551 self.assert_log_lines([])
2552
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002553 def test_config_9_ok(self):
2554 with captured_stdout() as output:
2555 self.apply_config(self.config9)
2556 logger = logging.getLogger("compiler.parser")
2557 #Nothing will be output since both handler and logger are set to WARNING
2558 logger.info(self.next_message())
2559 self.assert_log_lines([], stream=output)
2560 self.apply_config(self.config9a)
2561 #Nothing will be output since both handler is still set to WARNING
2562 logger.info(self.next_message())
2563 self.assert_log_lines([], stream=output)
2564 self.apply_config(self.config9b)
2565 #Message should now be output
2566 logger.info(self.next_message())
2567 self.assert_log_lines([
2568 ('INFO', '3'),
2569 ], stream=output)
2570
2571 def test_config_10_ok(self):
2572 with captured_stdout() as output:
2573 self.apply_config(self.config10)
2574 logger = logging.getLogger("compiler.parser")
2575 logger.warning(self.next_message())
2576 logger = logging.getLogger('compiler')
2577 #Not output, because filtered
2578 logger.warning(self.next_message())
2579 logger = logging.getLogger('compiler.lexer')
2580 #Not output, because filtered
2581 logger.warning(self.next_message())
2582 logger = logging.getLogger("compiler.parser.codegen")
2583 #Output, as not filtered
2584 logger.error(self.next_message())
2585 self.assert_log_lines([
2586 ('WARNING', '1'),
2587 ('ERROR', '4'),
2588 ], stream=output)
2589
2590 def test_config11_ok(self):
2591 self.test_config1_ok(self.config11)
2592
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002593 def test_config12_failure(self):
2594 self.assertRaises(Exception, self.apply_config, self.config12)
2595
2596 def test_config13_failure(self):
2597 self.assertRaises(Exception, self.apply_config, self.config13)
2598
Victor Stinner45df8202010-04-28 22:31:17 +00002599 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002600 def setup_via_listener(self, text):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002601 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002602 # Ask for a randomly assigned port (by using port 0)
2603 t = logging.config.listen(0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002604 t.start()
2605 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002606 # Now get the port allocated
2607 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002608 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002609 try:
2610 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2611 sock.settimeout(2.0)
2612 sock.connect(('localhost', port))
2613
2614 slen = struct.pack('>L', len(text))
2615 s = slen + text
2616 sentsofar = 0
2617 left = len(s)
2618 while left > 0:
2619 sent = sock.send(s[sentsofar:])
2620 sentsofar += sent
2621 left -= sent
2622 sock.close()
2623 finally:
2624 t.ready.wait(2.0)
2625 logging.config.stopListening()
2626 t.join(2.0)
2627
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002628 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002629 def test_listen_config_10_ok(self):
2630 with captured_stdout() as output:
2631 self.setup_via_listener(json.dumps(self.config10))
2632 logger = logging.getLogger("compiler.parser")
2633 logger.warning(self.next_message())
2634 logger = logging.getLogger('compiler')
2635 #Not output, because filtered
2636 logger.warning(self.next_message())
2637 logger = logging.getLogger('compiler.lexer')
2638 #Not output, because filtered
2639 logger.warning(self.next_message())
2640 logger = logging.getLogger("compiler.parser.codegen")
2641 #Output, as not filtered
2642 logger.error(self.next_message())
2643 self.assert_log_lines([
2644 ('WARNING', '1'),
2645 ('ERROR', '4'),
2646 ], stream=output)
2647
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002648 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002649 def test_listen_config_1_ok(self):
2650 with captured_stdout() as output:
2651 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2652 logger = logging.getLogger("compiler.parser")
2653 # Both will output a message
2654 logger.info(self.next_message())
2655 logger.error(self.next_message())
2656 self.assert_log_lines([
2657 ('INFO', '1'),
2658 ('ERROR', '2'),
2659 ], stream=output)
2660 # Original logger output is empty.
2661 self.assert_log_lines([])
2662
Vinay Sajip373baef2011-04-26 20:05:24 +01002663 def test_baseconfig(self):
2664 d = {
2665 'atuple': (1, 2, 3),
2666 'alist': ['a', 'b', 'c'],
2667 'adict': {'d': 'e', 'f': 3 },
2668 'nest1': ('g', ('h', 'i'), 'j'),
2669 'nest2': ['k', ['l', 'm'], 'n'],
2670 'nest3': ['o', 'cfg://alist', 'p'],
2671 }
2672 bc = logging.config.BaseConfigurator(d)
2673 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2674 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2675 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2676 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2677 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2678 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2679 v = bc.convert('cfg://nest3')
2680 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2681 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2682 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2683 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002684
2685class ManagerTest(BaseTest):
2686 def test_manager_loggerclass(self):
2687 logged = []
2688
2689 class MyLogger(logging.Logger):
2690 def _log(self, level, msg, args, exc_info=None, extra=None):
2691 logged.append(msg)
2692
2693 man = logging.Manager(None)
2694 self.assertRaises(TypeError, man.setLoggerClass, int)
2695 man.setLoggerClass(MyLogger)
2696 logger = man.getLogger('test')
2697 logger.warning('should appear in logged')
2698 logging.warning('should not appear in logged')
2699
2700 self.assertEqual(logged, ['should appear in logged'])
2701
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002702 def test_set_log_record_factory(self):
2703 man = logging.Manager(None)
2704 expected = object()
2705 man.setLogRecordFactory(expected)
2706 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002707
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002708class ChildLoggerTest(BaseTest):
2709 def test_child_loggers(self):
2710 r = logging.getLogger()
2711 l1 = logging.getLogger('abc')
2712 l2 = logging.getLogger('def.ghi')
2713 c1 = r.getChild('xyz')
2714 c2 = r.getChild('uvw.xyz')
2715 self.assertTrue(c1 is logging.getLogger('xyz'))
2716 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
2717 c1 = l1.getChild('def')
2718 c2 = c1.getChild('ghi')
2719 c3 = l1.getChild('def.ghi')
2720 self.assertTrue(c1 is logging.getLogger('abc.def'))
2721 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
2722 self.assertTrue(c2 is c3)
2723
2724
Vinay Sajip6fac8172010-10-19 20:44:14 +00002725class DerivedLogRecord(logging.LogRecord):
2726 pass
2727
Vinay Sajip61561522010-12-03 11:50:38 +00002728class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002729
2730 def setUp(self):
2731 class CheckingFilter(logging.Filter):
2732 def __init__(self, cls):
2733 self.cls = cls
2734
2735 def filter(self, record):
2736 t = type(record)
2737 if t is not self.cls:
2738 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2739 self.cls)
2740 raise TypeError(msg)
2741 return True
2742
2743 BaseTest.setUp(self)
2744 self.filter = CheckingFilter(DerivedLogRecord)
2745 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002746 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002747
2748 def tearDown(self):
2749 self.root_logger.removeFilter(self.filter)
2750 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002751 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002752
2753 def test_logrecord_class(self):
2754 self.assertRaises(TypeError, self.root_logger.warning,
2755 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002756 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002757 self.root_logger.error(self.next_message())
2758 self.assert_log_lines([
2759 ('root', 'ERROR', '2'),
2760 ])
2761
2762
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002763class QueueHandlerTest(BaseTest):
2764 # Do not bother with a logger name group.
2765 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
2766
2767 def setUp(self):
2768 BaseTest.setUp(self)
2769 self.queue = queue.Queue(-1)
2770 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2771 self.que_logger = logging.getLogger('que')
2772 self.que_logger.propagate = False
2773 self.que_logger.setLevel(logging.WARNING)
2774 self.que_logger.addHandler(self.que_hdlr)
2775
2776 def tearDown(self):
2777 self.que_hdlr.close()
2778 BaseTest.tearDown(self)
2779
2780 def test_queue_handler(self):
2781 self.que_logger.debug(self.next_message())
2782 self.assertRaises(queue.Empty, self.queue.get_nowait)
2783 self.que_logger.info(self.next_message())
2784 self.assertRaises(queue.Empty, self.queue.get_nowait)
2785 msg = self.next_message()
2786 self.que_logger.warning(msg)
2787 data = self.queue.get_nowait()
2788 self.assertTrue(isinstance(data, logging.LogRecord))
2789 self.assertEqual(data.name, self.que_logger.name)
2790 self.assertEqual((data.msg, data.args), (msg, None))
2791
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002792 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2793 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002794 def test_queue_listener(self):
2795 handler = TestHandler(Matcher())
2796 listener = logging.handlers.QueueListener(self.queue, handler)
2797 listener.start()
2798 try:
2799 self.que_logger.warning(self.next_message())
2800 self.que_logger.error(self.next_message())
2801 self.que_logger.critical(self.next_message())
2802 finally:
2803 listener.stop()
2804 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2805 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2806 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2807
Vinay Sajip37eb3382011-04-26 20:26:41 +01002808ZERO = datetime.timedelta(0)
2809
2810class UTC(datetime.tzinfo):
2811 def utcoffset(self, dt):
2812 return ZERO
2813
2814 dst = utcoffset
2815
2816 def tzname(self, dt):
2817 return 'UTC'
2818
2819utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002820
Vinay Sajipa39c5712010-10-25 13:57:39 +00002821class FormatterTest(unittest.TestCase):
2822 def setUp(self):
2823 self.common = {
2824 'name': 'formatter.test',
2825 'level': logging.DEBUG,
2826 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2827 'lineno': 42,
2828 'exc_info': None,
2829 'func': None,
2830 'msg': 'Message with %d %s',
2831 'args': (2, 'placeholders'),
2832 }
2833 self.variants = {
2834 }
2835
2836 def get_record(self, name=None):
2837 result = dict(self.common)
2838 if name is not None:
2839 result.update(self.variants[name])
2840 return logging.makeLogRecord(result)
2841
2842 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002843 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002844 r = self.get_record()
2845 f = logging.Formatter('${%(message)s}')
2846 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2847 f = logging.Formatter('%(random)s')
2848 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002849 self.assertFalse(f.usesTime())
2850 f = logging.Formatter('%(asctime)s')
2851 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002852 f = logging.Formatter('%(asctime)-15s')
2853 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002854 f = logging.Formatter('asctime')
2855 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002856
2857 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002858 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002859 r = self.get_record()
2860 f = logging.Formatter('$%{message}%$', style='{')
2861 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2862 f = logging.Formatter('{random}', style='{')
2863 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002864 self.assertFalse(f.usesTime())
2865 f = logging.Formatter('{asctime}', style='{')
2866 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002867 f = logging.Formatter('{asctime!s:15}', style='{')
2868 self.assertTrue(f.usesTime())
2869 f = logging.Formatter('{asctime:15}', style='{')
2870 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002871 f = logging.Formatter('asctime', style='{')
2872 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002873
2874 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002875 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002876 r = self.get_record()
2877 f = logging.Formatter('$message', style='$')
2878 self.assertEqual(f.format(r), 'Message with 2 placeholders')
2879 f = logging.Formatter('$$%${message}%$$', style='$')
2880 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2881 f = logging.Formatter('${random}', style='$')
2882 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002883 self.assertFalse(f.usesTime())
2884 f = logging.Formatter('${asctime}', style='$')
2885 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002886 f = logging.Formatter('${asctime', style='$')
2887 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002888 f = logging.Formatter('$asctime', style='$')
2889 self.assertTrue(f.usesTime())
2890 f = logging.Formatter('asctime', style='$')
2891 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002892
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002893 def test_invalid_style(self):
2894 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
2895
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002896 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002897 r = self.get_record()
Vinay Sajip37eb3382011-04-26 20:26:41 +01002898 dt = datetime.datetime(1993,4,21,8,3,0,0,utc)
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002899 r.created = time.mktime(dt.timetuple()) - time.timezone
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002900 r.msecs = 123
2901 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01002902 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002903 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
2904 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01002905 f.format(r)
2906 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
2907
2908class TestBufferingFormatter(logging.BufferingFormatter):
2909 def formatHeader(self, records):
2910 return '[(%d)' % len(records)
2911
2912 def formatFooter(self, records):
2913 return '(%d)]' % len(records)
2914
2915class BufferingFormatterTest(unittest.TestCase):
2916 def setUp(self):
2917 self.records = [
2918 logging.makeLogRecord({'msg': 'one'}),
2919 logging.makeLogRecord({'msg': 'two'}),
2920 ]
2921
2922 def test_default(self):
2923 f = logging.BufferingFormatter()
2924 self.assertEqual('', f.format([]))
2925 self.assertEqual('onetwo', f.format(self.records))
2926
2927 def test_custom(self):
2928 f = TestBufferingFormatter()
2929 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
2930 lf = logging.Formatter('<%(message)s>')
2931 f = TestBufferingFormatter(lf)
2932 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002933
2934class ExceptionTest(BaseTest):
2935 def test_formatting(self):
2936 r = self.root_logger
2937 h = RecordingHandler()
2938 r.addHandler(h)
2939 try:
2940 raise RuntimeError('deliberate mistake')
2941 except:
2942 logging.exception('failed', stack_info=True)
2943 r.removeHandler(h)
2944 h.close()
2945 r = h.records[0]
2946 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
2947 'call last):\n'))
2948 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
2949 'deliberate mistake'))
2950 self.assertTrue(r.stack_info.startswith('Stack (most recent '
2951 'call last):\n'))
2952 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
2953 'stack_info=True)'))
2954
2955
Vinay Sajip5a27d402010-12-10 11:42:57 +00002956class LastResortTest(BaseTest):
2957 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002958 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00002959 root = self.root_logger
2960 root.removeHandler(self.root_hdlr)
2961 old_stderr = sys.stderr
2962 old_lastresort = logging.lastResort
2963 old_raise_exceptions = logging.raiseExceptions
2964 try:
2965 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01002966 root.debug('This should not appear')
2967 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00002968 root.warning('This is your final chance!')
2969 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
2970 #No handlers and no last resort, so 'No handlers' message
2971 logging.lastResort = None
2972 sys.stderr = sio = io.StringIO()
2973 root.warning('This is your final chance!')
2974 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
2975 # 'No handlers' message only printed once
2976 sys.stderr = sio = io.StringIO()
2977 root.warning('This is your final chance!')
2978 self.assertEqual(sio.getvalue(), '')
2979 root.manager.emittedNoHandlerWarning = False
2980 #If raiseExceptions is False, no message is printed
2981 logging.raiseExceptions = False
2982 sys.stderr = sio = io.StringIO()
2983 root.warning('This is your final chance!')
2984 self.assertEqual(sio.getvalue(), '')
2985 finally:
2986 sys.stderr = old_stderr
2987 root.addHandler(self.root_hdlr)
2988 logging.lastResort = old_lastresort
2989 logging.raiseExceptions = old_raise_exceptions
2990
2991
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002992class FakeHandler:
2993
2994 def __init__(self, identifier, called):
2995 for method in ('acquire', 'flush', 'close', 'release'):
2996 setattr(self, method, self.record_call(identifier, method, called))
2997
2998 def record_call(self, identifier, method_name, called):
2999 def inner():
3000 called.append('{} - {}'.format(identifier, method_name))
3001 return inner
3002
3003
3004class RecordingHandler(logging.NullHandler):
3005
3006 def __init__(self, *args, **kwargs):
3007 super(RecordingHandler, self).__init__(*args, **kwargs)
3008 self.records = []
3009
3010 def handle(self, record):
3011 """Keep track of all the emitted records."""
3012 self.records.append(record)
3013
3014
3015class ShutdownTest(BaseTest):
3016
Vinay Sajip5e66b162011-04-20 15:41:14 +01003017 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003018
3019 def setUp(self):
3020 super(ShutdownTest, self).setUp()
3021 self.called = []
3022
3023 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003024 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003025
3026 def raise_error(self, error):
3027 def inner():
3028 raise error()
3029 return inner
3030
3031 def test_no_failure(self):
3032 # create some fake handlers
3033 handler0 = FakeHandler(0, self.called)
3034 handler1 = FakeHandler(1, self.called)
3035 handler2 = FakeHandler(2, self.called)
3036
3037 # create live weakref to those handlers
3038 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3039
3040 logging.shutdown(handlerList=list(handlers))
3041
3042 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3043 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3044 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3045 self.assertEqual(expected, self.called)
3046
3047 def _test_with_failure_in_method(self, method, error):
3048 handler = FakeHandler(0, self.called)
3049 setattr(handler, method, self.raise_error(error))
3050 handlers = [logging.weakref.ref(handler)]
3051
3052 logging.shutdown(handlerList=list(handlers))
3053
3054 self.assertEqual('0 - release', self.called[-1])
3055
3056 def test_with_ioerror_in_acquire(self):
3057 self._test_with_failure_in_method('acquire', IOError)
3058
3059 def test_with_ioerror_in_flush(self):
3060 self._test_with_failure_in_method('flush', IOError)
3061
3062 def test_with_ioerror_in_close(self):
3063 self._test_with_failure_in_method('close', IOError)
3064
3065 def test_with_valueerror_in_acquire(self):
3066 self._test_with_failure_in_method('acquire', ValueError)
3067
3068 def test_with_valueerror_in_flush(self):
3069 self._test_with_failure_in_method('flush', ValueError)
3070
3071 def test_with_valueerror_in_close(self):
3072 self._test_with_failure_in_method('close', ValueError)
3073
3074 def test_with_other_error_in_acquire_without_raise(self):
3075 logging.raiseExceptions = False
3076 self._test_with_failure_in_method('acquire', IndexError)
3077
3078 def test_with_other_error_in_flush_without_raise(self):
3079 logging.raiseExceptions = False
3080 self._test_with_failure_in_method('flush', IndexError)
3081
3082 def test_with_other_error_in_close_without_raise(self):
3083 logging.raiseExceptions = False
3084 self._test_with_failure_in_method('close', IndexError)
3085
3086 def test_with_other_error_in_acquire_with_raise(self):
3087 logging.raiseExceptions = True
3088 self.assertRaises(IndexError, self._test_with_failure_in_method,
3089 'acquire', IndexError)
3090
3091 def test_with_other_error_in_flush_with_raise(self):
3092 logging.raiseExceptions = True
3093 self.assertRaises(IndexError, self._test_with_failure_in_method,
3094 'flush', IndexError)
3095
3096 def test_with_other_error_in_close_with_raise(self):
3097 logging.raiseExceptions = True
3098 self.assertRaises(IndexError, self._test_with_failure_in_method,
3099 'close', IndexError)
3100
3101
3102class ModuleLevelMiscTest(BaseTest):
3103
Vinay Sajip5e66b162011-04-20 15:41:14 +01003104 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003105
3106 def test_disable(self):
3107 old_disable = logging.root.manager.disable
3108 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003109 self.assertEqual(old_disable, 0)
3110 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003111
3112 logging.disable(83)
3113 self.assertEqual(logging.root.manager.disable, 83)
3114
3115 def _test_log(self, method, level=None):
3116 called = []
3117 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003118 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003119
3120 recording = RecordingHandler()
3121 logging.root.addHandler(recording)
3122
3123 log_method = getattr(logging, method)
3124 if level is not None:
3125 log_method(level, "test me: %r", recording)
3126 else:
3127 log_method("test me: %r", recording)
3128
3129 self.assertEqual(len(recording.records), 1)
3130 record = recording.records[0]
3131 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3132
3133 expected_level = level if level is not None else getattr(logging, method.upper())
3134 self.assertEqual(record.levelno, expected_level)
3135
3136 # basicConfig was not called!
3137 self.assertEqual(called, [])
3138
3139 def test_log(self):
3140 self._test_log('log', logging.ERROR)
3141
3142 def test_debug(self):
3143 self._test_log('debug')
3144
3145 def test_info(self):
3146 self._test_log('info')
3147
3148 def test_warning(self):
3149 self._test_log('warning')
3150
3151 def test_error(self):
3152 self._test_log('error')
3153
3154 def test_critical(self):
3155 self._test_log('critical')
3156
3157 def test_set_logger_class(self):
3158 self.assertRaises(TypeError, logging.setLoggerClass, object)
3159
3160 class MyLogger(logging.Logger):
3161 pass
3162
3163 logging.setLoggerClass(MyLogger)
3164 self.assertEqual(logging.getLoggerClass(), MyLogger)
3165
3166 logging.setLoggerClass(logging.Logger)
3167 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3168
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003169class LogRecordTest(BaseTest):
3170 def test_str_rep(self):
3171 r = logging.makeLogRecord({})
3172 s = str(r)
3173 self.assertTrue(s.startswith('<LogRecord: '))
3174 self.assertTrue(s.endswith('>'))
3175
3176 def test_dict_arg(self):
3177 h = RecordingHandler()
3178 r = logging.getLogger()
3179 r.addHandler(h)
3180 d = {'less' : 'more' }
3181 logging.warning('less is %(less)s', d)
3182 self.assertIs(h.records[0].args, d)
3183 self.assertEqual(h.records[0].message, 'less is more')
3184 r.removeHandler(h)
3185 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003186
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003187 def test_multiprocessing(self):
3188 r = logging.makeLogRecord({})
3189 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003190 try:
3191 import multiprocessing as mp
3192 r = logging.makeLogRecord({})
3193 self.assertEqual(r.processName, mp.current_process().name)
3194 except ImportError:
3195 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003196
3197 def test_optional(self):
3198 r = logging.makeLogRecord({})
3199 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003200 if threading:
3201 NOT_NONE(r.thread)
3202 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003203 NOT_NONE(r.process)
3204 NOT_NONE(r.processName)
3205 log_threads = logging.logThreads
3206 log_processes = logging.logProcesses
3207 log_multiprocessing = logging.logMultiprocessing
3208 try:
3209 logging.logThreads = False
3210 logging.logProcesses = False
3211 logging.logMultiprocessing = False
3212 r = logging.makeLogRecord({})
3213 NONE = self.assertIsNone
3214 NONE(r.thread)
3215 NONE(r.threadName)
3216 NONE(r.process)
3217 NONE(r.processName)
3218 finally:
3219 logging.logThreads = log_threads
3220 logging.logProcesses = log_processes
3221 logging.logMultiprocessing = log_multiprocessing
3222
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003223class BasicConfigTest(unittest.TestCase):
3224
Vinay Sajip95bf5042011-04-20 11:50:56 +01003225 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003226
3227 def setUp(self):
3228 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003229 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003230 self.saved_handlers = logging._handlers.copy()
3231 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003232 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003233 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003234 logging.root.handlers = []
3235
3236 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003237 for h in logging.root.handlers[:]:
3238 logging.root.removeHandler(h)
3239 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003240 super(BasicConfigTest, self).tearDown()
3241
Vinay Sajip3def7e02011-04-20 10:58:06 +01003242 def cleanup(self):
3243 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003244 logging._handlers.clear()
3245 logging._handlers.update(self.saved_handlers)
3246 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003247 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003248
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003249 def test_no_kwargs(self):
3250 logging.basicConfig()
3251
3252 # handler defaults to a StreamHandler to sys.stderr
3253 self.assertEqual(len(logging.root.handlers), 1)
3254 handler = logging.root.handlers[0]
3255 self.assertIsInstance(handler, logging.StreamHandler)
3256 self.assertEqual(handler.stream, sys.stderr)
3257
3258 formatter = handler.formatter
3259 # format defaults to logging.BASIC_FORMAT
3260 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3261 # datefmt defaults to None
3262 self.assertIsNone(formatter.datefmt)
3263 # style defaults to %
3264 self.assertIsInstance(formatter._style, logging.PercentStyle)
3265
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003266 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003267 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003268
3269 def test_filename(self):
3270 logging.basicConfig(filename='test.log')
3271
3272 self.assertEqual(len(logging.root.handlers), 1)
3273 handler = logging.root.handlers[0]
3274 self.assertIsInstance(handler, logging.FileHandler)
3275
3276 expected = logging.FileHandler('test.log', 'a')
3277 self.addCleanup(expected.close)
3278 self.assertEqual(handler.stream.mode, expected.stream.mode)
3279 self.assertEqual(handler.stream.name, expected.stream.name)
3280
3281 def test_filemode(self):
3282 logging.basicConfig(filename='test.log', filemode='wb')
3283
3284 handler = logging.root.handlers[0]
3285 expected = logging.FileHandler('test.log', 'wb')
3286 self.addCleanup(expected.close)
3287 self.assertEqual(handler.stream.mode, expected.stream.mode)
3288
3289 def test_stream(self):
3290 stream = io.StringIO()
3291 self.addCleanup(stream.close)
3292 logging.basicConfig(stream=stream)
3293
3294 self.assertEqual(len(logging.root.handlers), 1)
3295 handler = logging.root.handlers[0]
3296 self.assertIsInstance(handler, logging.StreamHandler)
3297 self.assertEqual(handler.stream, stream)
3298
3299 def test_format(self):
3300 logging.basicConfig(format='foo')
3301
3302 formatter = logging.root.handlers[0].formatter
3303 self.assertEqual(formatter._style._fmt, 'foo')
3304
3305 def test_datefmt(self):
3306 logging.basicConfig(datefmt='bar')
3307
3308 formatter = logging.root.handlers[0].formatter
3309 self.assertEqual(formatter.datefmt, 'bar')
3310
3311 def test_style(self):
3312 logging.basicConfig(style='$')
3313
3314 formatter = logging.root.handlers[0].formatter
3315 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3316
3317 def test_level(self):
3318 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003319 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003320
3321 logging.basicConfig(level=57)
3322 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003323 # Test that second call has no effect
3324 logging.basicConfig(level=58)
3325 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003326
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003327 def test_incompatible(self):
3328 assertRaises = self.assertRaises
3329 handlers = [logging.StreamHandler()]
3330 stream = sys.stderr
3331 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3332 stream=stream)
3333 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3334 handlers=handlers)
3335 assertRaises(ValueError, logging.basicConfig, stream=stream,
3336 handlers=handlers)
3337
3338 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003339 handlers = [
3340 logging.StreamHandler(),
3341 logging.StreamHandler(sys.stdout),
3342 logging.StreamHandler(),
3343 ]
3344 f = logging.Formatter()
3345 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003346 logging.basicConfig(handlers=handlers)
3347 self.assertIs(handlers[0], logging.root.handlers[0])
3348 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003349 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003350 self.assertIsNotNone(handlers[0].formatter)
3351 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003352 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003353 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3354
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003355 def _test_log(self, method, level=None):
3356 # logging.root has no handlers so basicConfig should be called
3357 called = []
3358
3359 old_basic_config = logging.basicConfig
3360 def my_basic_config(*a, **kw):
3361 old_basic_config()
3362 old_level = logging.root.level
3363 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003364 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003365 called.append((a, kw))
3366
3367 patch(self, logging, 'basicConfig', my_basic_config)
3368
3369 log_method = getattr(logging, method)
3370 if level is not None:
3371 log_method(level, "test me")
3372 else:
3373 log_method("test me")
3374
3375 # basicConfig was called with no arguments
3376 self.assertEqual(called, [((), {})])
3377
3378 def test_log(self):
3379 self._test_log('log', logging.WARNING)
3380
3381 def test_debug(self):
3382 self._test_log('debug')
3383
3384 def test_info(self):
3385 self._test_log('info')
3386
3387 def test_warning(self):
3388 self._test_log('warning')
3389
3390 def test_error(self):
3391 self._test_log('error')
3392
3393 def test_critical(self):
3394 self._test_log('critical')
3395
3396
3397class LoggerAdapterTest(unittest.TestCase):
3398
3399 def setUp(self):
3400 super(LoggerAdapterTest, self).setUp()
3401 old_handler_list = logging._handlerList[:]
3402
3403 self.recording = RecordingHandler()
3404 self.logger = logging.root
3405 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003406 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003407 self.addCleanup(self.recording.close)
3408
3409 def cleanup():
3410 logging._handlerList[:] = old_handler_list
3411
3412 self.addCleanup(cleanup)
3413 self.addCleanup(logging.shutdown)
3414 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3415
3416 def test_exception(self):
3417 msg = 'testing exception: %r'
3418 exc = None
3419 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003420 1 / 0
3421 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003422 exc = e
3423 self.adapter.exception(msg, self.recording)
3424
3425 self.assertEqual(len(self.recording.records), 1)
3426 record = self.recording.records[0]
3427 self.assertEqual(record.levelno, logging.ERROR)
3428 self.assertEqual(record.msg, msg)
3429 self.assertEqual(record.args, (self.recording,))
3430 self.assertEqual(record.exc_info,
3431 (exc.__class__, exc, exc.__traceback__))
3432
3433 def test_critical(self):
3434 msg = 'critical test! %r'
3435 self.adapter.critical(msg, self.recording)
3436
3437 self.assertEqual(len(self.recording.records), 1)
3438 record = self.recording.records[0]
3439 self.assertEqual(record.levelno, logging.CRITICAL)
3440 self.assertEqual(record.msg, msg)
3441 self.assertEqual(record.args, (self.recording,))
3442
3443 def test_is_enabled_for(self):
3444 old_disable = self.adapter.logger.manager.disable
3445 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003446 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3447 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003448 self.assertFalse(self.adapter.isEnabledFor(32))
3449
3450 def test_has_handlers(self):
3451 self.assertTrue(self.adapter.hasHandlers())
3452
3453 for handler in self.logger.handlers:
3454 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003455
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003456 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003457 self.assertFalse(self.adapter.hasHandlers())
3458
3459
3460class LoggerTest(BaseTest):
3461
3462 def setUp(self):
3463 super(LoggerTest, self).setUp()
3464 self.recording = RecordingHandler()
3465 self.logger = logging.Logger(name='blah')
3466 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003467 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003468 self.addCleanup(self.recording.close)
3469 self.addCleanup(logging.shutdown)
3470
3471 def test_set_invalid_level(self):
3472 self.assertRaises(TypeError, self.logger.setLevel, object())
3473
3474 def test_exception(self):
3475 msg = 'testing exception: %r'
3476 exc = None
3477 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003478 1 / 0
3479 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003480 exc = e
3481 self.logger.exception(msg, self.recording)
3482
3483 self.assertEqual(len(self.recording.records), 1)
3484 record = self.recording.records[0]
3485 self.assertEqual(record.levelno, logging.ERROR)
3486 self.assertEqual(record.msg, msg)
3487 self.assertEqual(record.args, (self.recording,))
3488 self.assertEqual(record.exc_info,
3489 (exc.__class__, exc, exc.__traceback__))
3490
3491 def test_log_invalid_level_with_raise(self):
3492 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003493 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003494
3495 logging.raiseExceptions = True
3496 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3497
3498 def test_log_invalid_level_no_raise(self):
3499 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003500 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003501
3502 logging.raiseExceptions = False
3503 self.logger.log('10', 'test message') # no exception happens
3504
3505 def test_find_caller_with_stack_info(self):
3506 called = []
3507 patch(self, logging.traceback, 'print_stack',
3508 lambda f, file: called.append(file.getvalue()))
3509
3510 self.logger.findCaller(stack_info=True)
3511
3512 self.assertEqual(len(called), 1)
3513 self.assertEqual('Stack (most recent call last):\n', called[0])
3514
3515 def test_make_record_with_extra_overwrite(self):
3516 name = 'my record'
3517 level = 13
3518 fn = lno = msg = args = exc_info = func = sinfo = None
3519 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3520 exc_info, func, sinfo)
3521
3522 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3523 extra = {key: 'some value'}
3524 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3525 fn, lno, msg, args, exc_info,
3526 extra=extra, sinfo=sinfo)
3527
3528 def test_make_record_with_extra_no_overwrite(self):
3529 name = 'my record'
3530 level = 13
3531 fn = lno = msg = args = exc_info = func = sinfo = None
3532 extra = {'valid_key': 'some value'}
3533 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3534 exc_info, extra=extra, sinfo=sinfo)
3535 self.assertIn('valid_key', result.__dict__)
3536
3537 def test_has_handlers(self):
3538 self.assertTrue(self.logger.hasHandlers())
3539
3540 for handler in self.logger.handlers:
3541 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003542 self.assertFalse(self.logger.hasHandlers())
3543
3544 def test_has_handlers_no_propagate(self):
3545 child_logger = logging.getLogger('blah.child')
3546 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003547 self.assertFalse(child_logger.hasHandlers())
3548
3549 def test_is_enabled_for(self):
3550 old_disable = self.logger.manager.disable
3551 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003552 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003553 self.assertFalse(self.logger.isEnabledFor(22))
3554
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003555 def test_root_logger_aliases(self):
3556 root = logging.getLogger()
3557 self.assertIs(root, logging.root)
3558 self.assertIs(root, logging.getLogger(None))
3559 self.assertIs(root, logging.getLogger(''))
3560 self.assertIs(root, logging.getLogger('foo').root)
3561 self.assertIs(root, logging.getLogger('foo.bar').root)
3562 self.assertIs(root, logging.getLogger('foo').parent)
3563
3564 self.assertIsNot(root, logging.getLogger('\0'))
3565 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3566
3567 def test_invalid_names(self):
3568 self.assertRaises(TypeError, logging.getLogger, any)
3569 self.assertRaises(TypeError, logging.getLogger, b'foo')
3570
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003571
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003572class BaseFileTest(BaseTest):
3573 "Base class for handler tests that write log files"
3574
3575 def setUp(self):
3576 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003577 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3578 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003579 self.rmfiles = []
3580
3581 def tearDown(self):
3582 for fn in self.rmfiles:
3583 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003584 if os.path.exists(self.fn):
3585 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003586 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003587
3588 def assertLogFile(self, filename):
3589 "Assert a log file is there and register it for deletion"
3590 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003591 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003592 self.rmfiles.append(filename)
3593
3594
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003595class FileHandlerTest(BaseFileTest):
3596 def test_delay(self):
3597 os.unlink(self.fn)
3598 fh = logging.FileHandler(self.fn, delay=True)
3599 self.assertIsNone(fh.stream)
3600 self.assertFalse(os.path.exists(self.fn))
3601 fh.handle(logging.makeLogRecord({}))
3602 self.assertIsNotNone(fh.stream)
3603 self.assertTrue(os.path.exists(self.fn))
3604 fh.close()
3605
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003606class RotatingFileHandlerTest(BaseFileTest):
3607 def next_rec(self):
3608 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3609 self.next_message(), None, None, None)
3610
3611 def test_should_not_rollover(self):
3612 # If maxbytes is zero rollover never occurs
3613 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3614 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003615 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003616
3617 def test_should_rollover(self):
3618 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3619 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003620 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003621
3622 def test_file_created(self):
3623 # checks that the file is created and assumes it was created
3624 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003625 rh = logging.handlers.RotatingFileHandler(self.fn)
3626 rh.emit(self.next_rec())
3627 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003628 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003629
3630 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003631 def namer(name):
3632 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003633 rh = logging.handlers.RotatingFileHandler(
3634 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003635 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003636 rh.emit(self.next_rec())
3637 self.assertLogFile(self.fn)
3638 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003639 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003640 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003641 self.assertLogFile(namer(self.fn + ".2"))
3642 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3643 rh.close()
3644
Eric V. Smith851cad72012-03-11 22:46:04 -07003645 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003646 def test_rotator(self):
3647 def namer(name):
3648 return name + ".gz"
3649
3650 def rotator(source, dest):
3651 with open(source, "rb") as sf:
3652 data = sf.read()
3653 compressed = zlib.compress(data, 9)
3654 with open(dest, "wb") as df:
3655 df.write(compressed)
3656 os.remove(source)
3657
3658 rh = logging.handlers.RotatingFileHandler(
3659 self.fn, backupCount=2, maxBytes=1)
3660 rh.rotator = rotator
3661 rh.namer = namer
3662 m1 = self.next_rec()
3663 rh.emit(m1)
3664 self.assertLogFile(self.fn)
3665 m2 = self.next_rec()
3666 rh.emit(m2)
3667 fn = namer(self.fn + ".1")
3668 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003669 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003670 with open(fn, "rb") as f:
3671 compressed = f.read()
3672 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003673 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003674 rh.emit(self.next_rec())
3675 fn = namer(self.fn + ".2")
3676 self.assertLogFile(fn)
3677 with open(fn, "rb") as f:
3678 compressed = f.read()
3679 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003680 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003681 rh.emit(self.next_rec())
3682 fn = namer(self.fn + ".2")
3683 with open(fn, "rb") as f:
3684 compressed = f.read()
3685 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003686 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003687 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003688 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003689
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003690class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003691 # other test methods added below
3692 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003693 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3694 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003695 fmt = logging.Formatter('%(asctime)s %(message)s')
3696 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003697 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003698 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003699 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003700 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003701 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003702 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003703 fh.close()
3704 # At this point, we should have a recent rotated file which we
3705 # can test for the existence of. However, in practice, on some
3706 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003707 # in time to go to look for the log file. So, we go back a fair
3708 # bit, and stop as soon as we see a rotated file. In theory this
3709 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003710 found = False
3711 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003712 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003713 for secs in range(GO_BACK):
3714 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003715 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3716 found = os.path.exists(fn)
3717 if found:
3718 self.rmfiles.append(fn)
3719 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003720 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3721 if not found:
3722 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003723 dn, fn = os.path.split(self.fn)
3724 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003725 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3726 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003727 for f in files:
3728 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003729 path = os.path.join(dn, f)
3730 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003731 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003732 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003733
Vinay Sajip0372e102011-05-05 12:59:14 +01003734 def test_invalid(self):
3735 assertRaises = self.assertRaises
3736 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003737 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003738 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003739 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003740 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003741 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003742
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003743def secs(**kw):
3744 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3745
3746for when, exp in (('S', 1),
3747 ('M', 60),
3748 ('H', 60 * 60),
3749 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003750 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003751 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003752 ('W0', secs(days=4, hours=24)),
3753 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003754 def test_compute_rollover(self, when=when, exp=exp):
3755 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003756 self.fn, when=when, interval=1, backupCount=0, utc=True)
3757 currentTime = 0.0
3758 actual = rh.computeRollover(currentTime)
3759 if exp != actual:
3760 # Failures occur on some systems for MIDNIGHT and W0.
3761 # Print detailed calculation for MIDNIGHT so we can try to see
3762 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00003763 if when == 'MIDNIGHT':
3764 try:
3765 if rh.utc:
3766 t = time.gmtime(currentTime)
3767 else:
3768 t = time.localtime(currentTime)
3769 currentHour = t[3]
3770 currentMinute = t[4]
3771 currentSecond = t[5]
3772 # r is the number of seconds left between now and midnight
3773 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3774 currentMinute) * 60 +
3775 currentSecond)
3776 result = currentTime + r
3777 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3778 print('currentHour: %s' % currentHour, file=sys.stderr)
3779 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3780 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3781 print('r: %s' % r, file=sys.stderr)
3782 print('result: %s' % result, file=sys.stderr)
3783 except Exception:
3784 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3785 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003786 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003787 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3788
Vinay Sajip60ccd822011-05-09 17:32:09 +01003789
3790@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
3791class NTEventLogHandlerTest(BaseTest):
3792 def test_basic(self):
3793 logtype = 'Application'
3794 elh = win32evtlog.OpenEventLog(None, logtype)
3795 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
3796 h = logging.handlers.NTEventLogHandler('test_logging')
3797 r = logging.makeLogRecord({'msg': 'Test Log Message'})
3798 h.handle(r)
3799 h.close()
3800 # Now see if the event is recorded
3801 self.assertTrue(num_recs < win32evtlog.GetNumberOfEventLogRecords(elh))
3802 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
3803 win32evtlog.EVENTLOG_SEQUENTIAL_READ
3804 found = False
3805 GO_BACK = 100
3806 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
3807 for e in events:
3808 if e.SourceName != 'test_logging':
3809 continue
3810 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
3811 if msg != 'Test Log Message\r\n':
3812 continue
3813 found = True
3814 break
3815 msg = 'Record not found in event log, went back %d records' % GO_BACK
3816 self.assertTrue(found, msg=msg)
3817
Christian Heimes180510d2008-03-03 19:15:45 +00003818# Set the locale to the platform-dependent default. I have no idea
3819# why the test does this, but in any case we save the current locale
3820# first and restore it at the end.
3821@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00003822def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00003823 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003824 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01003825 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
3826 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
3827 ManagerTest, FormatterTest, BufferingFormatterTest,
3828 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
3829 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
3830 BasicConfigTest, LoggerAdapterTest, LoggerTest,
3831 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003832 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01003833 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00003834 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00003835 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00003836
Christian Heimes180510d2008-03-03 19:15:45 +00003837if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00003838 test_main()