blob: 1aa0bdb62642c1eaec7efac0cb23bdb6bccf9d91 [file] [log] [blame]
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001#!/usr/bin/env python
Christian Heimes180510d2008-03-03 19:15:45 +00002#
Vinay Sajiped0473c2011-02-26 15:35:38 +00003# Copyright 2001-2011 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 Sajiped0473c2011-02-26 15:35:38 +000021Copyright (C) 2001-2011 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
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000037import select
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Vinay Sajipe6c1eb92011-03-29 17:20:34 +010042from test.support import captured_stdout, run_with_locale, run_unittest, patch
Vinay Sajipe723e962011-04-15 22:27:17 +010043from test.support import TestHandler, Matcher
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010045import time
Christian Heimes180510d2008-03-03 19:15:45 +000046import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000047import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000048import weakref
Vinay Sajip23b94d02012-01-04 12:02:26 +000049import zlib
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
Christian Heimes18c66892008-02-17 13:31:39 +000073
74
Christian Heimes180510d2008-03-03 19:15:45 +000075class BaseTest(unittest.TestCase):
76
77 """Base class for logging tests."""
78
79 log_format = "%(name)s -> %(levelname)s: %(message)s"
80 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
81 message_num = 0
82
83 def setUp(self):
84 """Setup the default logging stream to an internal StringIO instance,
85 so that we can examine log output as we want."""
86 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000087 logging._acquireLock()
88 try:
Christian Heimes180510d2008-03-03 19:15:45 +000089 self.saved_handlers = logging._handlers.copy()
90 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000091 self.saved_loggers = saved_loggers = logger_dict.copy()
Christian Heimes180510d2008-03-03 19:15:45 +000092 self.saved_level_names = logging._levelNames.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000093 self.logger_states = logger_states = {}
94 for name in saved_loggers:
95 logger_states[name] = getattr(saved_loggers[name],
96 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000097 finally:
98 logging._releaseLock()
99
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100100 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000101 self.logger1 = logging.getLogger("\xab\xd7\xbb")
102 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000103
Christian Heimes180510d2008-03-03 19:15:45 +0000104 self.root_logger = logging.getLogger("")
105 self.original_logging_level = self.root_logger.getEffectiveLevel()
106
107 self.stream = io.StringIO()
108 self.root_logger.setLevel(logging.DEBUG)
109 self.root_hdlr = logging.StreamHandler(self.stream)
110 self.root_formatter = logging.Formatter(self.log_format)
111 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000112 if self.logger1.hasHandlers():
113 hlist = self.logger1.handlers + self.root_logger.handlers
114 raise AssertionError('Unexpected handlers: %s' % hlist)
115 if self.logger2.hasHandlers():
116 hlist = self.logger2.handlers + self.root_logger.handlers
117 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000118 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000119 self.assertTrue(self.logger1.hasHandlers())
120 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000121
122 def tearDown(self):
123 """Remove our logging stream, and restore the original logging
124 level."""
125 self.stream.close()
126 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000127 while self.root_logger.handlers:
128 h = self.root_logger.handlers[0]
129 self.root_logger.removeHandler(h)
130 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000131 self.root_logger.setLevel(self.original_logging_level)
132 logging._acquireLock()
133 try:
134 logging._levelNames.clear()
135 logging._levelNames.update(self.saved_level_names)
136 logging._handlers.clear()
137 logging._handlers.update(self.saved_handlers)
138 logging._handlerList[:] = self.saved_handler_list
139 loggerDict = logging.getLogger().manager.loggerDict
140 loggerDict.clear()
141 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000142 logger_states = self.logger_states
143 for name in self.logger_states:
144 if logger_states[name] is not None:
145 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000146 finally:
147 logging._releaseLock()
148
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000149 def assert_log_lines(self, expected_values, stream=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000150 """Match the collected log lines against the regular expression
151 self.expected_log_pat, and compare the extracted group values to
152 the expected_values list of tuples."""
153 stream = stream or self.stream
154 pat = re.compile(self.expected_log_pat)
155 try:
156 stream.reset()
157 actual_lines = stream.readlines()
158 except AttributeError:
159 # StringIO.StringIO lacks a reset() method.
160 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100161 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000162 for actual, expected in zip(actual_lines, expected_values):
163 match = pat.search(actual)
164 if not match:
165 self.fail("Log line does not match expected pattern:\n" +
166 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000167 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000168 s = stream.read()
169 if s:
170 self.fail("Remaining output at end of log stream:\n" + s)
171
172 def next_message(self):
173 """Generate a message consisting solely of an auto-incrementing
174 integer."""
175 self.message_num += 1
176 return "%d" % self.message_num
177
178
179class BuiltinLevelsTest(BaseTest):
180 """Test builtin levels and their inheritance."""
181
182 def test_flat(self):
183 #Logging levels in a flat logger namespace.
184 m = self.next_message
185
186 ERR = logging.getLogger("ERR")
187 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000188 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000189 INF.setLevel(logging.INFO)
190 DEB = logging.getLogger("DEB")
191 DEB.setLevel(logging.DEBUG)
192
193 # These should log.
194 ERR.log(logging.CRITICAL, m())
195 ERR.error(m())
196
197 INF.log(logging.CRITICAL, m())
198 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100199 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000200 INF.info(m())
201
202 DEB.log(logging.CRITICAL, m())
203 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100204 DEB.warning(m())
205 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000206 DEB.debug(m())
207
208 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100209 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000210 ERR.info(m())
211 ERR.debug(m())
212
213 INF.debug(m())
214
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000215 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000216 ('ERR', 'CRITICAL', '1'),
217 ('ERR', 'ERROR', '2'),
218 ('INF', 'CRITICAL', '3'),
219 ('INF', 'ERROR', '4'),
220 ('INF', 'WARNING', '5'),
221 ('INF', 'INFO', '6'),
222 ('DEB', 'CRITICAL', '7'),
223 ('DEB', 'ERROR', '8'),
224 ('DEB', 'WARNING', '9'),
225 ('DEB', 'INFO', '10'),
226 ('DEB', 'DEBUG', '11'),
227 ])
228
229 def test_nested_explicit(self):
230 # Logging levels in a nested namespace, all explicitly set.
231 m = self.next_message
232
233 INF = logging.getLogger("INF")
234 INF.setLevel(logging.INFO)
235 INF_ERR = logging.getLogger("INF.ERR")
236 INF_ERR.setLevel(logging.ERROR)
237
238 # These should log.
239 INF_ERR.log(logging.CRITICAL, m())
240 INF_ERR.error(m())
241
242 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100243 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000244 INF_ERR.info(m())
245 INF_ERR.debug(m())
246
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000247 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000248 ('INF.ERR', 'CRITICAL', '1'),
249 ('INF.ERR', 'ERROR', '2'),
250 ])
251
252 def test_nested_inherited(self):
253 #Logging levels in a nested namespace, inherited from parent loggers.
254 m = self.next_message
255
256 INF = logging.getLogger("INF")
257 INF.setLevel(logging.INFO)
258 INF_ERR = logging.getLogger("INF.ERR")
259 INF_ERR.setLevel(logging.ERROR)
260 INF_UNDEF = logging.getLogger("INF.UNDEF")
261 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
262 UNDEF = logging.getLogger("UNDEF")
263
264 # These should log.
265 INF_UNDEF.log(logging.CRITICAL, m())
266 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100267 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000268 INF_UNDEF.info(m())
269 INF_ERR_UNDEF.log(logging.CRITICAL, m())
270 INF_ERR_UNDEF.error(m())
271
272 # These should not log.
273 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100274 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000275 INF_ERR_UNDEF.info(m())
276 INF_ERR_UNDEF.debug(m())
277
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000278 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000279 ('INF.UNDEF', 'CRITICAL', '1'),
280 ('INF.UNDEF', 'ERROR', '2'),
281 ('INF.UNDEF', 'WARNING', '3'),
282 ('INF.UNDEF', 'INFO', '4'),
283 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
284 ('INF.ERR.UNDEF', 'ERROR', '6'),
285 ])
286
287 def test_nested_with_virtual_parent(self):
288 # Logging levels when some parent does not exist yet.
289 m = self.next_message
290
291 INF = logging.getLogger("INF")
292 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
293 CHILD = logging.getLogger("INF.BADPARENT")
294 INF.setLevel(logging.INFO)
295
296 # These should log.
297 GRANDCHILD.log(logging.FATAL, m())
298 GRANDCHILD.info(m())
299 CHILD.log(logging.FATAL, m())
300 CHILD.info(m())
301
302 # These should not log.
303 GRANDCHILD.debug(m())
304 CHILD.debug(m())
305
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000306 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000307 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
308 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
309 ('INF.BADPARENT', 'CRITICAL', '3'),
310 ('INF.BADPARENT', 'INFO', '4'),
311 ])
312
313
314class BasicFilterTest(BaseTest):
315
316 """Test the bundled Filter class."""
317
318 def test_filter(self):
319 # Only messages satisfying the specified criteria pass through the
320 # filter.
321 filter_ = logging.Filter("spam.eggs")
322 handler = self.root_logger.handlers[0]
323 try:
324 handler.addFilter(filter_)
325 spam = logging.getLogger("spam")
326 spam_eggs = logging.getLogger("spam.eggs")
327 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
328 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
329
330 spam.info(self.next_message())
331 spam_eggs.info(self.next_message()) # Good.
332 spam_eggs_fish.info(self.next_message()) # Good.
333 spam_bakedbeans.info(self.next_message())
334
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000335 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000336 ('spam.eggs', 'INFO', '2'),
337 ('spam.eggs.fish', 'INFO', '3'),
338 ])
339 finally:
340 handler.removeFilter(filter_)
341
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000342 def test_callable_filter(self):
343 # Only messages satisfying the specified criteria pass through the
344 # filter.
345
346 def filterfunc(record):
347 parts = record.name.split('.')
348 prefix = '.'.join(parts[:2])
349 return prefix == 'spam.eggs'
350
351 handler = self.root_logger.handlers[0]
352 try:
353 handler.addFilter(filterfunc)
354 spam = logging.getLogger("spam")
355 spam_eggs = logging.getLogger("spam.eggs")
356 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
357 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
358
359 spam.info(self.next_message())
360 spam_eggs.info(self.next_message()) # Good.
361 spam_eggs_fish.info(self.next_message()) # Good.
362 spam_bakedbeans.info(self.next_message())
363
364 self.assert_log_lines([
365 ('spam.eggs', 'INFO', '2'),
366 ('spam.eggs.fish', 'INFO', '3'),
367 ])
368 finally:
369 handler.removeFilter(filterfunc)
370
Vinay Sajip985ef872011-04-26 19:34:04 +0100371 def test_empty_filter(self):
372 f = logging.Filter()
373 r = logging.makeLogRecord({'name': 'spam.eggs'})
374 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000375
376#
377# First, we define our levels. There can be as many as you want - the only
378# limitations are that they should be integers, the lowest should be > 0 and
379# larger values mean less information being logged. If you need specific
380# level values which do not fit into these limitations, you can use a
381# mapping dictionary to convert between your application levels and the
382# logging system.
383#
384SILENT = 120
385TACITURN = 119
386TERSE = 118
387EFFUSIVE = 117
388SOCIABLE = 116
389VERBOSE = 115
390TALKATIVE = 114
391GARRULOUS = 113
392CHATTERBOX = 112
393BORING = 111
394
395LEVEL_RANGE = range(BORING, SILENT + 1)
396
397#
398# Next, we define names for our levels. You don't need to do this - in which
399# case the system will use "Level n" to denote the text for the level.
400#
401my_logging_levels = {
402 SILENT : 'Silent',
403 TACITURN : 'Taciturn',
404 TERSE : 'Terse',
405 EFFUSIVE : 'Effusive',
406 SOCIABLE : 'Sociable',
407 VERBOSE : 'Verbose',
408 TALKATIVE : 'Talkative',
409 GARRULOUS : 'Garrulous',
410 CHATTERBOX : 'Chatterbox',
411 BORING : 'Boring',
412}
413
414class GarrulousFilter(logging.Filter):
415
416 """A filter which blocks garrulous messages."""
417
418 def filter(self, record):
419 return record.levelno != GARRULOUS
420
421class VerySpecificFilter(logging.Filter):
422
423 """A filter which blocks sociable and taciturn messages."""
424
425 def filter(self, record):
426 return record.levelno not in [SOCIABLE, TACITURN]
427
428
429class CustomLevelsAndFiltersTest(BaseTest):
430
431 """Test various filtering possibilities with custom logging levels."""
432
433 # Skip the logger name group.
434 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
435
436 def setUp(self):
437 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000438 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000439 logging.addLevelName(k, v)
440
441 def log_at_all_levels(self, logger):
442 for lvl in LEVEL_RANGE:
443 logger.log(lvl, self.next_message())
444
445 def test_logger_filter(self):
446 # Filter at logger level.
447 self.root_logger.setLevel(VERBOSE)
448 # Levels >= 'Verbose' are good.
449 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000450 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000451 ('Verbose', '5'),
452 ('Sociable', '6'),
453 ('Effusive', '7'),
454 ('Terse', '8'),
455 ('Taciturn', '9'),
456 ('Silent', '10'),
457 ])
458
459 def test_handler_filter(self):
460 # Filter at handler level.
461 self.root_logger.handlers[0].setLevel(SOCIABLE)
462 try:
463 # Levels >= 'Sociable' are good.
464 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000465 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000466 ('Sociable', '6'),
467 ('Effusive', '7'),
468 ('Terse', '8'),
469 ('Taciturn', '9'),
470 ('Silent', '10'),
471 ])
472 finally:
473 self.root_logger.handlers[0].setLevel(logging.NOTSET)
474
475 def test_specific_filters(self):
476 # Set a specific filter object on the handler, and then add another
477 # filter object on the logger itself.
478 handler = self.root_logger.handlers[0]
479 specific_filter = None
480 garr = GarrulousFilter()
481 handler.addFilter(garr)
482 try:
483 self.log_at_all_levels(self.root_logger)
484 first_lines = [
485 # Notice how 'Garrulous' is missing
486 ('Boring', '1'),
487 ('Chatterbox', '2'),
488 ('Talkative', '4'),
489 ('Verbose', '5'),
490 ('Sociable', '6'),
491 ('Effusive', '7'),
492 ('Terse', '8'),
493 ('Taciturn', '9'),
494 ('Silent', '10'),
495 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000496 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000497
498 specific_filter = VerySpecificFilter()
499 self.root_logger.addFilter(specific_filter)
500 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000501 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000502 # Not only 'Garrulous' is still missing, but also 'Sociable'
503 # and 'Taciturn'
504 ('Boring', '11'),
505 ('Chatterbox', '12'),
506 ('Talkative', '14'),
507 ('Verbose', '15'),
508 ('Effusive', '17'),
509 ('Terse', '18'),
510 ('Silent', '20'),
511 ])
512 finally:
513 if specific_filter:
514 self.root_logger.removeFilter(specific_filter)
515 handler.removeFilter(garr)
516
517
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100518class HandlerTest(BaseTest):
519 def test_name(self):
520 h = logging.Handler()
521 h.name = 'generic'
522 self.assertEqual(h.name, 'generic')
523 h.name = 'anothergeneric'
524 self.assertEqual(h.name, 'anothergeneric')
525 self.assertRaises(NotImplementedError, h.emit, None)
526
Vinay Sajip5a35b062011-04-27 11:31:14 +0100527 def test_builtin_handlers(self):
528 # We can't actually *use* too many handlers in the tests,
529 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200530 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100531 for existing in (True, False):
532 fd, fn = tempfile.mkstemp()
533 os.close(fd)
534 if not existing:
535 os.unlink(fn)
536 h = logging.handlers.WatchedFileHandler(fn, delay=True)
537 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100538 dev, ino = h.dev, h.ino
539 self.assertNotEqual(dev, -1)
540 self.assertNotEqual(ino, -1)
541 r = logging.makeLogRecord({'msg': 'Test'})
542 h.handle(r)
543 # Now remove the file.
544 os.unlink(fn)
545 self.assertFalse(os.path.exists(fn))
546 # The next call should recreate the file.
547 h.handle(r)
548 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100549 else:
550 self.assertEqual(h.dev, -1)
551 self.assertEqual(h.ino, -1)
552 h.close()
553 if existing:
554 os.unlink(fn)
555 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100556 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100557 else:
558 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100559 try:
560 h = logging.handlers.SysLogHandler(sockname)
561 self.assertEqual(h.facility, h.LOG_USER)
562 self.assertTrue(h.unixsocket)
563 h.close()
564 except socket.error: # syslogd might not be available
565 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100566 for method in ('GET', 'POST', 'PUT'):
567 if method == 'PUT':
568 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
569 'localhost', '/log', method)
570 else:
571 h = logging.handlers.HTTPHandler('localhost', '/log', method)
572 h.close()
573 h = logging.handlers.BufferingHandler(0)
574 r = logging.makeLogRecord({})
575 self.assertTrue(h.shouldFlush(r))
576 h.close()
577 h = logging.handlers.BufferingHandler(1)
578 self.assertFalse(h.shouldFlush(r))
579 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100580
581class BadStream(object):
582 def write(self, data):
583 raise RuntimeError('deliberate mistake')
584
585class TestStreamHandler(logging.StreamHandler):
586 def handleError(self, record):
587 self.error_record = record
588
589class StreamHandlerTest(BaseTest):
590 def test_error_handling(self):
591 h = TestStreamHandler(BadStream())
592 r = logging.makeLogRecord({})
593 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100594 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100595 try:
596 h.handle(r)
597 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100598 h = logging.StreamHandler(BadStream())
599 sys.stderr = sio = io.StringIO()
600 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100601 self.assertIn('\nRuntimeError: deliberate mistake\n',
602 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100603 logging.raiseExceptions = False
604 sys.stderr = sio = io.StringIO()
605 h.handle(r)
606 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100607 finally:
608 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100609 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100610
Vinay Sajip7367d082011-05-02 13:17:27 +0100611# -- The following section could be moved into a server_helper.py module
612# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100613
Vinay Sajipce7c9782011-05-17 07:15:53 +0100614if threading:
615 class TestSMTPChannel(smtpd.SMTPChannel):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100616 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100617 This derived class has had to be created because smtpd does not
618 support use of custom channel maps, although they are allowed by
619 asyncore's design. Issue #11959 has been raised to address this,
620 and if resolved satisfactorily, some of this code can be removed.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100621 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100622 def __init__(self, server, conn, addr, sockmap):
623 asynchat.async_chat.__init__(self, conn, sockmap)
624 self.smtp_server = server
625 self.conn = conn
626 self.addr = addr
627 self.received_lines = []
628 self.smtp_state = self.COMMAND
629 self.seen_greeting = ''
630 self.mailfrom = None
631 self.rcpttos = []
632 self.received_data = ''
633 self.fqdn = socket.getfqdn()
634 self.num_bytes = 0
635 try:
636 self.peer = conn.getpeername()
637 except socket.error as err:
638 # a race condition may occur if the other end is closing
639 # before we can get the peername
640 self.close()
641 if err.args[0] != errno.ENOTCONN:
642 raise
643 return
644 self.push('220 %s %s' % (self.fqdn, smtpd.__version__))
645 self.set_terminator(b'\r\n')
Vinay Sajipa463d252011-04-30 21:52:48 +0100646
Vinay Sajip314b92b2011-05-02 14:31:16 +0100647
Vinay Sajipce7c9782011-05-17 07:15:53 +0100648 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100649 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100650 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100651
Vinay Sajipce7c9782011-05-17 07:15:53 +0100652 :param addr: A (host, port) tuple which the server listens on.
653 You can specify a port value of zero: the server's
654 *port* attribute will hold the actual port number
655 used, which can be used in client connections.
656 :param handler: A callable which will be called to process
657 incoming messages. The handler will be passed
658 the client address tuple, who the message is from,
659 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100660 :param poll_interval: The interval, in seconds, used in the underlying
661 :func:`select` or :func:`poll` call by
662 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100663 :param sockmap: A dictionary which will be used to hold
664 :class:`asyncore.dispatcher` instances used by
665 :func:`asyncore.loop`. This avoids changing the
666 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100667 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100668 channel_class = TestSMTPChannel
669
670 def __init__(self, addr, handler, poll_interval, sockmap):
671 self._localaddr = addr
672 self._remoteaddr = None
673 self.sockmap = sockmap
674 asyncore.dispatcher.__init__(self, map=sockmap)
675 try:
676 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
677 sock.setblocking(0)
678 self.set_socket(sock, map=sockmap)
679 # try to re-use a server port if possible
680 self.set_reuse_addr()
681 self.bind(addr)
682 self.port = sock.getsockname()[1]
683 self.listen(5)
684 except:
685 self.close()
Vinay Sajipe73afad2011-05-10 07:48:28 +0100686 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100687 self._handler = handler
688 self._thread = None
689 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100690
Vinay Sajipce7c9782011-05-17 07:15:53 +0100691 def handle_accepted(self, conn, addr):
692 """
693 Redefined only because the base class does not pass in a
694 map, forcing use of a global in :mod:`asyncore`.
695 """
696 channel = self.channel_class(self, conn, addr, self.sockmap)
Vinay Sajip314b92b2011-05-02 14:31:16 +0100697
Vinay Sajipce7c9782011-05-17 07:15:53 +0100698 def process_message(self, peer, mailfrom, rcpttos, data):
699 """
700 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100701
Vinay Sajipce7c9782011-05-17 07:15:53 +0100702 Typically, this will be a test case method.
703 :param peer: The client (host, port) tuple.
704 :param mailfrom: The address of the sender.
705 :param rcpttos: The addresses of the recipients.
706 :param data: The message.
707 """
708 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100709
Vinay Sajipce7c9782011-05-17 07:15:53 +0100710 def start(self):
711 """
712 Start the server running on a separate daemon thread.
713 """
714 self._thread = t = threading.Thread(target=self.serve_forever,
715 args=(self.poll_interval,))
716 t.setDaemon(True)
717 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100718
Vinay Sajipce7c9782011-05-17 07:15:53 +0100719 def serve_forever(self, poll_interval):
720 """
721 Run the :mod:`asyncore` loop until normal termination
722 conditions arise.
723 :param poll_interval: The interval, in seconds, used in the underlying
724 :func:`select` or :func:`poll` call by
725 :func:`asyncore.loop`.
726 """
727 try:
728 asyncore.loop(poll_interval, map=self.sockmap)
729 except select.error:
730 # On FreeBSD 8, closing the server repeatably
731 # raises this error. We swallow it if the
732 # server has been closed.
733 if self.connected or self.accepting:
734 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 def stop(self, timeout=None):
737 """
738 Stop the thread by closing the server instance.
739 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100740
Vinay Sajipce7c9782011-05-17 07:15:53 +0100741 :param timeout: How long to wait for the server thread
742 to terminate.
743 """
744 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100745 self._thread.join(timeout)
746 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100747
Vinay Sajipce7c9782011-05-17 07:15:53 +0100748 class ControlMixin(object):
749 """
750 This mixin is used to start a server on a separate thread, and
751 shut it down programmatically. Request handling is simplified - instead
752 of needing to derive a suitable RequestHandler subclass, you just
753 provide a callable which will be passed each received request to be
754 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100755
Vinay Sajipce7c9782011-05-17 07:15:53 +0100756 :param handler: A handler callable which will be called with a
757 single parameter - the request - in order to
758 process the request. This handler is called on the
759 server thread, effectively meaning that requests are
760 processed serially. While not quite Web scale ;-),
761 this should be fine for testing applications.
762 :param poll_interval: The polling interval in seconds.
763 """
764 def __init__(self, handler, poll_interval):
765 self._thread = None
766 self.poll_interval = poll_interval
767 self._handler = handler
768 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def start(self):
771 """
772 Create a daemon thread to run the server, and start it.
773 """
774 self._thread = t = threading.Thread(target=self.serve_forever,
775 args=(self.poll_interval,))
776 t.setDaemon(True)
777 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100778
Vinay Sajipce7c9782011-05-17 07:15:53 +0100779 def serve_forever(self, poll_interval):
780 """
781 Run the server. Set the ready flag before entering the
782 service loop.
783 """
784 self.ready.set()
785 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100786
Vinay Sajipce7c9782011-05-17 07:15:53 +0100787 def stop(self, timeout=None):
788 """
789 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100790
Vinay Sajipce7c9782011-05-17 07:15:53 +0100791 :param timeout: How long to wait for the server thread
792 to terminate.
793 """
794 self.shutdown()
795 if self._thread is not None:
796 self._thread.join(timeout)
797 self._thread = None
798 self.server_close()
799 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100800
Vinay Sajipce7c9782011-05-17 07:15:53 +0100801 class TestHTTPServer(ControlMixin, HTTPServer):
802 """
803 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100804
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 :param addr: A tuple with the IP address and port to listen on.
806 :param handler: A handler callable which will be called with a
807 single parameter - the request - in order to
808 process the request.
809 :param poll_interval: The polling interval in seconds.
810 :param log: Pass ``True`` to enable log messages.
811 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100812 def __init__(self, addr, handler, poll_interval=0.5,
813 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
815 def __getattr__(self, name, default=None):
816 if name.startswith('do_'):
817 return self.process_request
818 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100819
Vinay Sajipce7c9782011-05-17 07:15:53 +0100820 def process_request(self):
821 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100822
Vinay Sajipce7c9782011-05-17 07:15:53 +0100823 def log_message(self, format, *args):
824 if log:
825 super(DelegatingHTTPRequestHandler,
826 self).log_message(format, *args)
827 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
828 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100829 self.sslctx = sslctx
830
831 def get_request(self):
832 try:
833 sock, addr = self.socket.accept()
834 if self.sslctx:
835 sock = self.sslctx.wrap_socket(sock, server_side=True)
836 except socket.error as e:
837 # socket errors are silenced by the caller, print them here
838 sys.stderr.write("Got an error:\n%s\n" % e)
839 raise
840 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100841
Vinay Sajipce7c9782011-05-17 07:15:53 +0100842 class TestTCPServer(ControlMixin, ThreadingTCPServer):
843 """
844 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100845
Vinay Sajipce7c9782011-05-17 07:15:53 +0100846 :param addr: A tuple with the IP address and port to listen on.
847 :param handler: A handler callable which will be called with a single
848 parameter - the request - in order to process the request.
849 :param poll_interval: The polling interval in seconds.
850 :bind_and_activate: If True (the default), binds the server and starts it
851 listening. If False, you need to call
852 :meth:`server_bind` and :meth:`server_activate` at
853 some later time before calling :meth:`start`, so that
854 the server will set up the socket and listen on it.
855 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100856
Vinay Sajipce7c9782011-05-17 07:15:53 +0100857 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100858
Vinay Sajipce7c9782011-05-17 07:15:53 +0100859 def __init__(self, addr, handler, poll_interval=0.5,
860 bind_and_activate=True):
861 class DelegatingTCPRequestHandler(StreamRequestHandler):
862
863 def handle(self):
864 self.server._handler(self)
865 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
866 bind_and_activate)
867 ControlMixin.__init__(self, handler, poll_interval)
868
869 def server_bind(self):
870 super(TestTCPServer, self).server_bind()
871 self.port = self.socket.getsockname()[1]
872
873 class TestUDPServer(ControlMixin, ThreadingUDPServer):
874 """
875 A UDP server which is controllable using :class:`ControlMixin`.
876
877 :param addr: A tuple with the IP address and port to listen on.
878 :param handler: A handler callable which will be called with a
879 single parameter - the request - in order to
880 process the request.
881 :param poll_interval: The polling interval for shutdown requests,
882 in seconds.
883 :bind_and_activate: If True (the default), binds the server and
884 starts it listening. If False, you need to
885 call :meth:`server_bind` and
886 :meth:`server_activate` at some later time
887 before calling :meth:`start`, so that the server will
888 set up the socket and listen on it.
889 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 def __init__(self, addr, handler, poll_interval=0.5,
891 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100892 class DelegatingUDPRequestHandler(DatagramRequestHandler):
893
894 def handle(self):
895 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100896
897 def finish(self):
898 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100899 if data:
900 try:
901 super(DelegatingUDPRequestHandler, self).finish()
902 except socket.error:
903 if not self.server._closed:
904 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100905
Vinay Sajip3ef12292011-05-23 23:00:42 +0100906 ThreadingUDPServer.__init__(self, addr,
907 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100908 bind_and_activate)
909 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100910 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100911
912 def server_bind(self):
913 super(TestUDPServer, self).server_bind()
914 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100915
Vinay Sajipba980db2011-05-23 21:37:54 +0100916 def server_close(self):
917 super(TestUDPServer, self).server_close()
918 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100919
920# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100921
Vinay Sajipce7c9782011-05-17 07:15:53 +0100922@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100923class SMTPHandlerTest(BaseTest):
924 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100925 sockmap = {}
926 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
927 sockmap)
928 server.start()
929 addr = ('localhost', server.port)
Vinay Sajipa463d252011-04-30 21:52:48 +0100930 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log')
931 self.assertEqual(h.toaddrs, ['you'])
932 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100933 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100934 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 h.handle(r)
Vinay Sajip7367d082011-05-02 13:17:27 +0100936 self.handled.wait()
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 server.stop()
938 self.assertEqual(len(self.messages), 1)
939 peer, mailfrom, rcpttos, data = self.messages[0]
940 self.assertEqual(mailfrom, 'me')
941 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100942 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100943 self.assertTrue(data.endswith('\n\nHello'))
944 h.close()
945
946 def process_message(self, *args):
947 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100948 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100949
Christian Heimes180510d2008-03-03 19:15:45 +0000950class MemoryHandlerTest(BaseTest):
951
952 """Tests for the MemoryHandler."""
953
954 # Do not bother with a logger name group.
955 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
956
957 def setUp(self):
958 BaseTest.setUp(self)
959 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
960 self.root_hdlr)
961 self.mem_logger = logging.getLogger('mem')
962 self.mem_logger.propagate = 0
963 self.mem_logger.addHandler(self.mem_hdlr)
964
965 def tearDown(self):
966 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000967 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000968
969 def test_flush(self):
970 # The memory handler flushes to its target handler based on specific
971 # criteria (message count and message level).
972 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000973 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000974 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000975 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000976 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100977 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000978 lines = [
979 ('DEBUG', '1'),
980 ('INFO', '2'),
981 ('WARNING', '3'),
982 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000983 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000984 for n in (4, 14):
985 for i in range(9):
986 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000987 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000988 # This will flush because it's the 10th message since the last
989 # flush.
990 self.mem_logger.debug(self.next_message())
991 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000992 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000993
994 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000995 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000996
997
998class ExceptionFormatter(logging.Formatter):
999 """A special exception formatter."""
1000 def formatException(self, ei):
1001 return "Got a [%s]" % ei[0].__name__
1002
1003
1004class ConfigFileTest(BaseTest):
1005
1006 """Reading logging config from a .ini-style config file."""
1007
1008 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1009
1010 # config0 is a standard configuration.
1011 config0 = """
1012 [loggers]
1013 keys=root
1014
1015 [handlers]
1016 keys=hand1
1017
1018 [formatters]
1019 keys=form1
1020
1021 [logger_root]
1022 level=WARNING
1023 handlers=hand1
1024
1025 [handler_hand1]
1026 class=StreamHandler
1027 level=NOTSET
1028 formatter=form1
1029 args=(sys.stdout,)
1030
1031 [formatter_form1]
1032 format=%(levelname)s ++ %(message)s
1033 datefmt=
1034 """
1035
1036 # config1 adds a little to the standard configuration.
1037 config1 = """
1038 [loggers]
1039 keys=root,parser
1040
1041 [handlers]
1042 keys=hand1
1043
1044 [formatters]
1045 keys=form1
1046
1047 [logger_root]
1048 level=WARNING
1049 handlers=
1050
1051 [logger_parser]
1052 level=DEBUG
1053 handlers=hand1
1054 propagate=1
1055 qualname=compiler.parser
1056
1057 [handler_hand1]
1058 class=StreamHandler
1059 level=NOTSET
1060 formatter=form1
1061 args=(sys.stdout,)
1062
1063 [formatter_form1]
1064 format=%(levelname)s ++ %(message)s
1065 datefmt=
1066 """
1067
Vinay Sajip3f84b072011-03-07 17:49:33 +00001068 # config1a moves the handler to the root.
1069 config1a = """
1070 [loggers]
1071 keys=root,parser
1072
1073 [handlers]
1074 keys=hand1
1075
1076 [formatters]
1077 keys=form1
1078
1079 [logger_root]
1080 level=WARNING
1081 handlers=hand1
1082
1083 [logger_parser]
1084 level=DEBUG
1085 handlers=
1086 propagate=1
1087 qualname=compiler.parser
1088
1089 [handler_hand1]
1090 class=StreamHandler
1091 level=NOTSET
1092 formatter=form1
1093 args=(sys.stdout,)
1094
1095 [formatter_form1]
1096 format=%(levelname)s ++ %(message)s
1097 datefmt=
1098 """
1099
Christian Heimes180510d2008-03-03 19:15:45 +00001100 # config2 has a subtle configuration error that should be reported
1101 config2 = config1.replace("sys.stdout", "sys.stbout")
1102
1103 # config3 has a less subtle configuration error
1104 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1105
1106 # config4 specifies a custom formatter class to be loaded
1107 config4 = """
1108 [loggers]
1109 keys=root
1110
1111 [handlers]
1112 keys=hand1
1113
1114 [formatters]
1115 keys=form1
1116
1117 [logger_root]
1118 level=NOTSET
1119 handlers=hand1
1120
1121 [handler_hand1]
1122 class=StreamHandler
1123 level=NOTSET
1124 formatter=form1
1125 args=(sys.stdout,)
1126
1127 [formatter_form1]
1128 class=""" + __name__ + """.ExceptionFormatter
1129 format=%(levelname)s:%(name)s:%(message)s
1130 datefmt=
1131 """
1132
Georg Brandl3dbca812008-07-23 16:10:53 +00001133 # config5 specifies a custom handler class to be loaded
1134 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1135
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001136 # config6 uses ', ' delimiters in the handlers and formatters sections
1137 config6 = """
1138 [loggers]
1139 keys=root,parser
1140
1141 [handlers]
1142 keys=hand1, hand2
1143
1144 [formatters]
1145 keys=form1, form2
1146
1147 [logger_root]
1148 level=WARNING
1149 handlers=
1150
1151 [logger_parser]
1152 level=DEBUG
1153 handlers=hand1
1154 propagate=1
1155 qualname=compiler.parser
1156
1157 [handler_hand1]
1158 class=StreamHandler
1159 level=NOTSET
1160 formatter=form1
1161 args=(sys.stdout,)
1162
1163 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001164 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001165 level=NOTSET
1166 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001167 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001168
1169 [formatter_form1]
1170 format=%(levelname)s ++ %(message)s
1171 datefmt=
1172
1173 [formatter_form2]
1174 format=%(message)s
1175 datefmt=
1176 """
1177
Vinay Sajip3f84b072011-03-07 17:49:33 +00001178 # config7 adds a compiler logger.
1179 config7 = """
1180 [loggers]
1181 keys=root,parser,compiler
1182
1183 [handlers]
1184 keys=hand1
1185
1186 [formatters]
1187 keys=form1
1188
1189 [logger_root]
1190 level=WARNING
1191 handlers=hand1
1192
1193 [logger_compiler]
1194 level=DEBUG
1195 handlers=
1196 propagate=1
1197 qualname=compiler
1198
1199 [logger_parser]
1200 level=DEBUG
1201 handlers=
1202 propagate=1
1203 qualname=compiler.parser
1204
1205 [handler_hand1]
1206 class=StreamHandler
1207 level=NOTSET
1208 formatter=form1
1209 args=(sys.stdout,)
1210
1211 [formatter_form1]
1212 format=%(levelname)s ++ %(message)s
1213 datefmt=
1214 """
1215
Christian Heimes180510d2008-03-03 19:15:45 +00001216 def apply_config(self, conf):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001217 file = io.StringIO(textwrap.dedent(conf))
1218 logging.config.fileConfig(file)
Christian Heimes180510d2008-03-03 19:15:45 +00001219
1220 def test_config0_ok(self):
1221 # A simple config file which overrides the default settings.
1222 with captured_stdout() as output:
1223 self.apply_config(self.config0)
1224 logger = logging.getLogger()
1225 # Won't output anything
1226 logger.info(self.next_message())
1227 # Outputs a message
1228 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001229 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001230 ('ERROR', '2'),
1231 ], stream=output)
1232 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001233 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001234
Georg Brandl3dbca812008-07-23 16:10:53 +00001235 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001236 # A config file defining a sub-parser as well.
1237 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001238 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001239 logger = logging.getLogger("compiler.parser")
1240 # Both will output a message
1241 logger.info(self.next_message())
1242 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001243 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001244 ('INFO', '1'),
1245 ('ERROR', '2'),
1246 ], stream=output)
1247 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001248 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001249
1250 def test_config2_failure(self):
1251 # A simple config file which overrides the default settings.
1252 self.assertRaises(Exception, self.apply_config, self.config2)
1253
1254 def test_config3_failure(self):
1255 # A simple config file which overrides the default settings.
1256 self.assertRaises(Exception, self.apply_config, self.config3)
1257
1258 def test_config4_ok(self):
1259 # A config file specifying a custom formatter class.
1260 with captured_stdout() as output:
1261 self.apply_config(self.config4)
1262 logger = logging.getLogger()
1263 try:
1264 raise RuntimeError()
1265 except RuntimeError:
1266 logging.exception("just testing")
1267 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001268 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001269 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1270 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001271 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001272
Georg Brandl3dbca812008-07-23 16:10:53 +00001273 def test_config5_ok(self):
1274 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001275
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001276 def test_config6_ok(self):
1277 self.test_config1_ok(config=self.config6)
1278
Vinay Sajip3f84b072011-03-07 17:49:33 +00001279 def test_config7_ok(self):
1280 with captured_stdout() as output:
1281 self.apply_config(self.config1a)
1282 logger = logging.getLogger("compiler.parser")
1283 # See issue #11424. compiler-hyphenated sorts
1284 # between compiler and compiler.xyz and this
1285 # was preventing compiler.xyz from being included
1286 # in the child loggers of compiler because of an
1287 # overzealous loop termination condition.
1288 hyphenated = logging.getLogger('compiler-hyphenated')
1289 # All will output a message
1290 logger.info(self.next_message())
1291 logger.error(self.next_message())
1292 hyphenated.critical(self.next_message())
1293 self.assert_log_lines([
1294 ('INFO', '1'),
1295 ('ERROR', '2'),
1296 ('CRITICAL', '3'),
1297 ], stream=output)
1298 # Original logger output is empty.
1299 self.assert_log_lines([])
1300 with captured_stdout() as output:
1301 self.apply_config(self.config7)
1302 logger = logging.getLogger("compiler.parser")
1303 self.assertFalse(logger.disabled)
1304 # Both will output a message
1305 logger.info(self.next_message())
1306 logger.error(self.next_message())
1307 logger = logging.getLogger("compiler.lexer")
1308 # Both will output a message
1309 logger.info(self.next_message())
1310 logger.error(self.next_message())
1311 # Will not appear
1312 hyphenated.critical(self.next_message())
1313 self.assert_log_lines([
1314 ('INFO', '4'),
1315 ('ERROR', '5'),
1316 ('INFO', '6'),
1317 ('ERROR', '7'),
1318 ], stream=output)
1319 # Original logger output is empty.
1320 self.assert_log_lines([])
1321
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001322
Victor Stinner45df8202010-04-28 22:31:17 +00001323@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001324class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001325
Christian Heimes180510d2008-03-03 19:15:45 +00001326 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001327
Christian Heimes180510d2008-03-03 19:15:45 +00001328 def setUp(self):
1329 """Set up a TCP server to receive log messages, and a SocketHandler
1330 pointing to that server's address and port."""
1331 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001332 addr = ('localhost', 0)
1333 self.server = server = TestTCPServer(addr, self.handle_socket,
1334 0.01)
1335 server.start()
1336 server.ready.wait()
1337 self.sock_hdlr = logging.handlers.SocketHandler('localhost',
1338 server.port)
1339 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001340 self.root_logger.removeHandler(self.root_logger.handlers[0])
1341 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001342 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001343
Christian Heimes180510d2008-03-03 19:15:45 +00001344 def tearDown(self):
1345 """Shutdown the TCP server."""
1346 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001347 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001348 self.root_logger.removeHandler(self.sock_hdlr)
1349 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001350 finally:
1351 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001352
Vinay Sajip7367d082011-05-02 13:17:27 +01001353 def handle_socket(self, request):
1354 conn = request.connection
1355 while True:
1356 chunk = conn.recv(4)
1357 if len(chunk) < 4:
1358 break
1359 slen = struct.unpack(">L", chunk)[0]
1360 chunk = conn.recv(slen)
1361 while len(chunk) < slen:
1362 chunk = chunk + conn.recv(slen - len(chunk))
1363 obj = pickle.loads(chunk)
1364 record = logging.makeLogRecord(obj)
1365 self.log_output += record.msg + '\n'
1366 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001367
Christian Heimes180510d2008-03-03 19:15:45 +00001368 def test_output(self):
1369 # The log message sent to the SocketHandler is properly received.
1370 logger = logging.getLogger("tcp")
1371 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001372 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001373 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001374 self.handled.acquire()
1375 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001376
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001377 def test_noserver(self):
1378 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001379 self.server.stop(2.0)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001380 #The logging call should try to connect, which should fail
1381 try:
1382 raise RuntimeError('Deliberate mistake')
1383 except RuntimeError:
1384 self.root_logger.exception('Never sent')
1385 self.root_logger.error('Never sent, either')
1386 now = time.time()
1387 self.assertTrue(self.sock_hdlr.retryTime > now)
1388 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1389 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001390
Vinay Sajip7367d082011-05-02 13:17:27 +01001391
1392@unittest.skipUnless(threading, 'Threading required for this test.')
1393class DatagramHandlerTest(BaseTest):
1394
1395 """Test for DatagramHandler."""
1396
1397 def setUp(self):
1398 """Set up a UDP server to receive log messages, and a DatagramHandler
1399 pointing to that server's address and port."""
1400 BaseTest.setUp(self)
1401 addr = ('localhost', 0)
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001402 self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001403 server.start()
1404 server.ready.wait()
1405 self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
1406 server.port)
1407 self.log_output = ''
1408 self.root_logger.removeHandler(self.root_logger.handlers[0])
1409 self.root_logger.addHandler(self.sock_hdlr)
1410 self.handled = threading.Event()
1411
1412 def tearDown(self):
1413 """Shutdown the UDP server."""
1414 try:
1415 self.server.stop(2.0)
1416 self.root_logger.removeHandler(self.sock_hdlr)
1417 self.sock_hdlr.close()
1418 finally:
1419 BaseTest.tearDown(self)
1420
1421 def handle_datagram(self, request):
1422 slen = struct.pack('>L', 0) # length of prefix
1423 packet = request.packet[len(slen):]
1424 obj = pickle.loads(packet)
1425 record = logging.makeLogRecord(obj)
1426 self.log_output += record.msg + '\n'
1427 self.handled.set()
1428
1429 def test_output(self):
1430 # The log message sent to the DatagramHandler is properly received.
1431 logger = logging.getLogger("udp")
1432 logger.error("spam")
1433 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001434 self.handled.clear()
1435 logger.error("eggs")
1436 self.handled.wait()
1437 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001438
1439
1440@unittest.skipUnless(threading, 'Threading required for this test.')
1441class SysLogHandlerTest(BaseTest):
1442
1443 """Test for SysLogHandler using UDP."""
1444
1445 def setUp(self):
1446 """Set up a UDP server to receive log messages, and a SysLogHandler
1447 pointing to that server's address and port."""
1448 BaseTest.setUp(self)
1449 addr = ('localhost', 0)
1450 self.server = server = TestUDPServer(addr, self.handle_datagram,
1451 0.01)
1452 server.start()
1453 server.ready.wait()
1454 self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
1455 server.port))
1456 self.log_output = ''
1457 self.root_logger.removeHandler(self.root_logger.handlers[0])
1458 self.root_logger.addHandler(self.sl_hdlr)
1459 self.handled = threading.Event()
1460
1461 def tearDown(self):
1462 """Shutdown the UDP server."""
1463 try:
1464 self.server.stop(2.0)
1465 self.root_logger.removeHandler(self.sl_hdlr)
1466 self.sl_hdlr.close()
1467 finally:
1468 BaseTest.tearDown(self)
1469
1470 def handle_datagram(self, request):
1471 self.log_output = request.packet
1472 self.handled.set()
1473
1474 def test_output(self):
1475 # The log message sent to the SysLogHandler is properly received.
1476 logger = logging.getLogger("slh")
1477 logger.error("sp\xe4m")
1478 self.handled.wait()
1479 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001480 self.handled.clear()
1481 self.sl_hdlr.append_nul = False
1482 logger.error("sp\xe4m")
1483 self.handled.wait()
1484 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001485 self.handled.clear()
1486 self.sl_hdlr.ident = "h\xe4m-"
1487 logger.error("sp\xe4m")
1488 self.handled.wait()
1489 self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfh\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001490
1491
1492@unittest.skipUnless(threading, 'Threading required for this test.')
1493class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001494 """Test for HTTPHandler."""
1495
Vinay Sajip9ba87612011-05-21 11:32:15 +01001496 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1497MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1498zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1499aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1500AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
15010tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
15025LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1503piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
15042z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1505i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1506PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1507E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1508rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1509/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1510-----END RSA PRIVATE KEY-----
1511-----BEGIN CERTIFICATE-----
1512MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1513BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1514EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1515xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1516l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1517vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1518BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1519S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1520BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
15214f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
15221c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1523IRbTpvlHWPjsSvHz0ZOH
1524-----END CERTIFICATE-----"""
1525
Vinay Sajip7367d082011-05-02 13:17:27 +01001526 def setUp(self):
1527 """Set up an HTTP server to receive log messages, and a HTTPHandler
1528 pointing to that server's address and port."""
1529 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001530 self.handled = threading.Event()
1531
Vinay Sajip7367d082011-05-02 13:17:27 +01001532 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001533 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001534 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001535 if self.command == 'POST':
1536 try:
1537 rlen = int(request.headers['Content-Length'])
1538 self.post_data = request.rfile.read(rlen)
1539 except:
1540 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001541 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001542 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001543 self.handled.set()
1544
1545 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001546 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001547 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001548 root_logger = self.root_logger
1549 root_logger.removeHandler(self.root_logger.handlers[0])
1550 for secure in (False, True):
1551 addr = ('localhost', 0)
1552 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001553 try:
1554 import ssl
1555 fd, fn = tempfile.mkstemp()
1556 os.close(fd)
1557 with open(fn, 'w') as f:
1558 f.write(self.PEMFILE)
1559 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1560 sslctx.load_cert_chain(fn)
1561 os.unlink(fn)
1562 except ImportError:
1563 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001564 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001565 sslctx = None
1566 self.server = server = TestHTTPServer(addr, self.handle_request,
1567 0.01, sslctx=sslctx)
1568 server.start()
1569 server.ready.wait()
1570 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001571 secure_client = secure and sslctx
1572 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1573 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001574 self.log_data = None
1575 root_logger.addHandler(self.h_hdlr)
1576
1577 for method in ('GET', 'POST'):
1578 self.h_hdlr.method = method
1579 self.handled.clear()
1580 msg = "sp\xe4m"
1581 logger.error(msg)
1582 self.handled.wait()
1583 self.assertEqual(self.log_data.path, '/frob')
1584 self.assertEqual(self.command, method)
1585 if method == 'GET':
1586 d = parse_qs(self.log_data.query)
1587 else:
1588 d = parse_qs(self.post_data.decode('utf-8'))
1589 self.assertEqual(d['name'], ['http'])
1590 self.assertEqual(d['funcName'], ['test_output'])
1591 self.assertEqual(d['msg'], [msg])
1592
1593 self.server.stop(2.0)
1594 self.root_logger.removeHandler(self.h_hdlr)
1595 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001596
Christian Heimes180510d2008-03-03 19:15:45 +00001597class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001598
Christian Heimes180510d2008-03-03 19:15:45 +00001599 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001600
Christian Heimes180510d2008-03-03 19:15:45 +00001601 def setUp(self):
1602 """Create a dict to remember potentially destroyed objects."""
1603 BaseTest.setUp(self)
1604 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001605
Christian Heimes180510d2008-03-03 19:15:45 +00001606 def _watch_for_survival(self, *args):
1607 """Watch the given objects for survival, by creating weakrefs to
1608 them."""
1609 for obj in args:
1610 key = id(obj), repr(obj)
1611 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001612
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001613 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001614 """Assert that all objects watched for survival have survived."""
1615 # Trigger cycle breaking.
1616 gc.collect()
1617 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001618 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001619 if ref() is None:
1620 dead.append(repr_)
1621 if dead:
1622 self.fail("%d objects should have survived "
1623 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001624
Christian Heimes180510d2008-03-03 19:15:45 +00001625 def test_persistent_loggers(self):
1626 # Logger objects are persistent and retain their configuration, even
1627 # if visible references are destroyed.
1628 self.root_logger.setLevel(logging.INFO)
1629 foo = logging.getLogger("foo")
1630 self._watch_for_survival(foo)
1631 foo.setLevel(logging.DEBUG)
1632 self.root_logger.debug(self.next_message())
1633 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001634 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001635 ('foo', 'DEBUG', '2'),
1636 ])
1637 del foo
1638 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001639 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001640 # foo has retained its settings.
1641 bar = logging.getLogger("foo")
1642 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001643 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001644 ('foo', 'DEBUG', '2'),
1645 ('foo', 'DEBUG', '3'),
1646 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001647
Benjamin Petersonf91df042009-02-13 02:50:59 +00001648
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001649class EncodingTest(BaseTest):
1650 def test_encoding_plain_file(self):
1651 # In Python 2.x, a plain file object is treated as having no encoding.
1652 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001653 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1654 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001655 # the non-ascii data we write to the log.
1656 data = "foo\x80"
1657 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001658 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001659 log.addHandler(handler)
1660 try:
1661 # write non-ascii data to the log.
1662 log.warning(data)
1663 finally:
1664 log.removeHandler(handler)
1665 handler.close()
1666 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001667 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001668 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001669 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001670 finally:
1671 f.close()
1672 finally:
1673 if os.path.isfile(fn):
1674 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001675
Benjamin Petersonf91df042009-02-13 02:50:59 +00001676 def test_encoding_cyrillic_unicode(self):
1677 log = logging.getLogger("test")
1678 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1679 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1680 #Ensure it's written in a Cyrillic encoding
1681 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001682 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001683 stream = io.BytesIO()
1684 writer = writer_class(stream, 'strict')
1685 handler = logging.StreamHandler(writer)
1686 log.addHandler(handler)
1687 try:
1688 log.warning(message)
1689 finally:
1690 log.removeHandler(handler)
1691 handler.close()
1692 # check we wrote exactly those bytes, ignoring trailing \n etc
1693 s = stream.getvalue()
1694 #Compare against what the data should be when encoded in CP-1251
1695 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1696
1697
Georg Brandlf9734072008-12-07 15:30:06 +00001698class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001699
Georg Brandlf9734072008-12-07 15:30:06 +00001700 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001701 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001702 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001703 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001704 warnings.filterwarnings("always", category=UserWarning)
1705 stream = io.StringIO()
1706 h = logging.StreamHandler(stream)
1707 logger = logging.getLogger("py.warnings")
1708 logger.addHandler(h)
1709 warnings.warn("I'm warning you...")
1710 logger.removeHandler(h)
1711 s = stream.getvalue()
1712 h.close()
1713 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001714
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001715 #See if an explicit file uses the original implementation
1716 a_file = io.StringIO()
1717 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1718 a_file, "Dummy line")
1719 s = a_file.getvalue()
1720 a_file.close()
1721 self.assertEqual(s,
1722 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1723
1724 def test_warnings_no_handlers(self):
1725 with warnings.catch_warnings():
1726 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001727 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001728
1729 # confirm our assumption: no loggers are set
1730 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001731 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001732
1733 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001734 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001735 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001736
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001737
1738def formatFunc(format, datefmt=None):
1739 return logging.Formatter(format, datefmt)
1740
1741def handlerFunc():
1742 return logging.StreamHandler()
1743
1744class CustomHandler(logging.StreamHandler):
1745 pass
1746
1747class ConfigDictTest(BaseTest):
1748
1749 """Reading logging config from a dictionary."""
1750
1751 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1752
1753 # config0 is a standard configuration.
1754 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001755 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001756 'formatters': {
1757 'form1' : {
1758 'format' : '%(levelname)s ++ %(message)s',
1759 },
1760 },
1761 'handlers' : {
1762 'hand1' : {
1763 'class' : 'logging.StreamHandler',
1764 'formatter' : 'form1',
1765 'level' : 'NOTSET',
1766 'stream' : 'ext://sys.stdout',
1767 },
1768 },
1769 'root' : {
1770 'level' : 'WARNING',
1771 'handlers' : ['hand1'],
1772 },
1773 }
1774
1775 # config1 adds a little to the standard configuration.
1776 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001777 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001778 'formatters': {
1779 'form1' : {
1780 'format' : '%(levelname)s ++ %(message)s',
1781 },
1782 },
1783 'handlers' : {
1784 'hand1' : {
1785 'class' : 'logging.StreamHandler',
1786 'formatter' : 'form1',
1787 'level' : 'NOTSET',
1788 'stream' : 'ext://sys.stdout',
1789 },
1790 },
1791 'loggers' : {
1792 'compiler.parser' : {
1793 'level' : 'DEBUG',
1794 'handlers' : ['hand1'],
1795 },
1796 },
1797 'root' : {
1798 'level' : 'WARNING',
1799 },
1800 }
1801
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001802 # config1a moves the handler to the root. Used with config8a
1803 config1a = {
1804 'version': 1,
1805 'formatters': {
1806 'form1' : {
1807 'format' : '%(levelname)s ++ %(message)s',
1808 },
1809 },
1810 'handlers' : {
1811 'hand1' : {
1812 'class' : 'logging.StreamHandler',
1813 'formatter' : 'form1',
1814 'level' : 'NOTSET',
1815 'stream' : 'ext://sys.stdout',
1816 },
1817 },
1818 'loggers' : {
1819 'compiler.parser' : {
1820 'level' : 'DEBUG',
1821 },
1822 },
1823 'root' : {
1824 'level' : 'WARNING',
1825 'handlers' : ['hand1'],
1826 },
1827 }
1828
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001829 # config2 has a subtle configuration error that should be reported
1830 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001831 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001832 'formatters': {
1833 'form1' : {
1834 'format' : '%(levelname)s ++ %(message)s',
1835 },
1836 },
1837 'handlers' : {
1838 'hand1' : {
1839 'class' : 'logging.StreamHandler',
1840 'formatter' : 'form1',
1841 'level' : 'NOTSET',
1842 'stream' : 'ext://sys.stdbout',
1843 },
1844 },
1845 'loggers' : {
1846 'compiler.parser' : {
1847 'level' : 'DEBUG',
1848 'handlers' : ['hand1'],
1849 },
1850 },
1851 'root' : {
1852 'level' : 'WARNING',
1853 },
1854 }
1855
1856 #As config1 but with a misspelt level on a handler
1857 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001858 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001859 'formatters': {
1860 'form1' : {
1861 'format' : '%(levelname)s ++ %(message)s',
1862 },
1863 },
1864 'handlers' : {
1865 'hand1' : {
1866 'class' : 'logging.StreamHandler',
1867 'formatter' : 'form1',
1868 'level' : 'NTOSET',
1869 'stream' : 'ext://sys.stdout',
1870 },
1871 },
1872 'loggers' : {
1873 'compiler.parser' : {
1874 'level' : 'DEBUG',
1875 'handlers' : ['hand1'],
1876 },
1877 },
1878 'root' : {
1879 'level' : 'WARNING',
1880 },
1881 }
1882
1883
1884 #As config1 but with a misspelt level on a logger
1885 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001886 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001887 'formatters': {
1888 'form1' : {
1889 'format' : '%(levelname)s ++ %(message)s',
1890 },
1891 },
1892 'handlers' : {
1893 'hand1' : {
1894 'class' : 'logging.StreamHandler',
1895 'formatter' : 'form1',
1896 'level' : 'NOTSET',
1897 'stream' : 'ext://sys.stdout',
1898 },
1899 },
1900 'loggers' : {
1901 'compiler.parser' : {
1902 'level' : 'DEBUG',
1903 'handlers' : ['hand1'],
1904 },
1905 },
1906 'root' : {
1907 'level' : 'WRANING',
1908 },
1909 }
1910
1911 # config3 has a less subtle configuration error
1912 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001913 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001914 'formatters': {
1915 'form1' : {
1916 'format' : '%(levelname)s ++ %(message)s',
1917 },
1918 },
1919 'handlers' : {
1920 'hand1' : {
1921 'class' : 'logging.StreamHandler',
1922 'formatter' : 'misspelled_name',
1923 'level' : 'NOTSET',
1924 'stream' : 'ext://sys.stdout',
1925 },
1926 },
1927 'loggers' : {
1928 'compiler.parser' : {
1929 'level' : 'DEBUG',
1930 'handlers' : ['hand1'],
1931 },
1932 },
1933 'root' : {
1934 'level' : 'WARNING',
1935 },
1936 }
1937
1938 # config4 specifies a custom formatter class to be loaded
1939 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001940 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001941 'formatters': {
1942 'form1' : {
1943 '()' : __name__ + '.ExceptionFormatter',
1944 'format' : '%(levelname)s:%(name)s:%(message)s',
1945 },
1946 },
1947 'handlers' : {
1948 'hand1' : {
1949 'class' : 'logging.StreamHandler',
1950 'formatter' : 'form1',
1951 'level' : 'NOTSET',
1952 'stream' : 'ext://sys.stdout',
1953 },
1954 },
1955 'root' : {
1956 'level' : 'NOTSET',
1957 'handlers' : ['hand1'],
1958 },
1959 }
1960
1961 # As config4 but using an actual callable rather than a string
1962 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001963 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001964 'formatters': {
1965 'form1' : {
1966 '()' : ExceptionFormatter,
1967 'format' : '%(levelname)s:%(name)s:%(message)s',
1968 },
1969 'form2' : {
1970 '()' : __name__ + '.formatFunc',
1971 'format' : '%(levelname)s:%(name)s:%(message)s',
1972 },
1973 'form3' : {
1974 '()' : formatFunc,
1975 'format' : '%(levelname)s:%(name)s:%(message)s',
1976 },
1977 },
1978 'handlers' : {
1979 'hand1' : {
1980 'class' : 'logging.StreamHandler',
1981 'formatter' : 'form1',
1982 'level' : 'NOTSET',
1983 'stream' : 'ext://sys.stdout',
1984 },
1985 'hand2' : {
1986 '()' : handlerFunc,
1987 },
1988 },
1989 'root' : {
1990 'level' : 'NOTSET',
1991 'handlers' : ['hand1'],
1992 },
1993 }
1994
1995 # config5 specifies a custom handler class to be loaded
1996 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001997 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001998 'formatters': {
1999 'form1' : {
2000 'format' : '%(levelname)s ++ %(message)s',
2001 },
2002 },
2003 'handlers' : {
2004 'hand1' : {
2005 'class' : __name__ + '.CustomHandler',
2006 'formatter' : 'form1',
2007 'level' : 'NOTSET',
2008 'stream' : 'ext://sys.stdout',
2009 },
2010 },
2011 'loggers' : {
2012 'compiler.parser' : {
2013 'level' : 'DEBUG',
2014 'handlers' : ['hand1'],
2015 },
2016 },
2017 'root' : {
2018 'level' : 'WARNING',
2019 },
2020 }
2021
2022 # config6 specifies a custom handler class to be loaded
2023 # but has bad arguments
2024 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002025 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002026 'formatters': {
2027 'form1' : {
2028 'format' : '%(levelname)s ++ %(message)s',
2029 },
2030 },
2031 'handlers' : {
2032 'hand1' : {
2033 'class' : __name__ + '.CustomHandler',
2034 'formatter' : 'form1',
2035 'level' : 'NOTSET',
2036 'stream' : 'ext://sys.stdout',
2037 '9' : 'invalid parameter name',
2038 },
2039 },
2040 'loggers' : {
2041 'compiler.parser' : {
2042 'level' : 'DEBUG',
2043 'handlers' : ['hand1'],
2044 },
2045 },
2046 'root' : {
2047 'level' : 'WARNING',
2048 },
2049 }
2050
2051 #config 7 does not define compiler.parser but defines compiler.lexer
2052 #so compiler.parser should be disabled after applying it
2053 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002054 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002055 'formatters': {
2056 'form1' : {
2057 'format' : '%(levelname)s ++ %(message)s',
2058 },
2059 },
2060 'handlers' : {
2061 'hand1' : {
2062 'class' : 'logging.StreamHandler',
2063 'formatter' : 'form1',
2064 'level' : 'NOTSET',
2065 'stream' : 'ext://sys.stdout',
2066 },
2067 },
2068 'loggers' : {
2069 'compiler.lexer' : {
2070 'level' : 'DEBUG',
2071 'handlers' : ['hand1'],
2072 },
2073 },
2074 'root' : {
2075 'level' : 'WARNING',
2076 },
2077 }
2078
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002079 # config8 defines both compiler and compiler.lexer
2080 # so compiler.parser should not be disabled (since
2081 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002082 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002083 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002084 'disable_existing_loggers' : False,
2085 'formatters': {
2086 'form1' : {
2087 'format' : '%(levelname)s ++ %(message)s',
2088 },
2089 },
2090 'handlers' : {
2091 'hand1' : {
2092 'class' : 'logging.StreamHandler',
2093 'formatter' : 'form1',
2094 'level' : 'NOTSET',
2095 'stream' : 'ext://sys.stdout',
2096 },
2097 },
2098 'loggers' : {
2099 'compiler' : {
2100 'level' : 'DEBUG',
2101 'handlers' : ['hand1'],
2102 },
2103 'compiler.lexer' : {
2104 },
2105 },
2106 'root' : {
2107 'level' : 'WARNING',
2108 },
2109 }
2110
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002111 # config8a disables existing loggers
2112 config8a = {
2113 'version': 1,
2114 'disable_existing_loggers' : True,
2115 'formatters': {
2116 'form1' : {
2117 'format' : '%(levelname)s ++ %(message)s',
2118 },
2119 },
2120 'handlers' : {
2121 'hand1' : {
2122 'class' : 'logging.StreamHandler',
2123 'formatter' : 'form1',
2124 'level' : 'NOTSET',
2125 'stream' : 'ext://sys.stdout',
2126 },
2127 },
2128 'loggers' : {
2129 'compiler' : {
2130 'level' : 'DEBUG',
2131 'handlers' : ['hand1'],
2132 },
2133 'compiler.lexer' : {
2134 },
2135 },
2136 'root' : {
2137 'level' : 'WARNING',
2138 },
2139 }
2140
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002141 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002142 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002143 'formatters': {
2144 'form1' : {
2145 'format' : '%(levelname)s ++ %(message)s',
2146 },
2147 },
2148 'handlers' : {
2149 'hand1' : {
2150 'class' : 'logging.StreamHandler',
2151 'formatter' : 'form1',
2152 'level' : 'WARNING',
2153 'stream' : 'ext://sys.stdout',
2154 },
2155 },
2156 'loggers' : {
2157 'compiler.parser' : {
2158 'level' : 'WARNING',
2159 'handlers' : ['hand1'],
2160 },
2161 },
2162 'root' : {
2163 'level' : 'NOTSET',
2164 },
2165 }
2166
2167 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002168 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002169 'incremental' : True,
2170 'handlers' : {
2171 'hand1' : {
2172 'level' : 'WARNING',
2173 },
2174 },
2175 'loggers' : {
2176 'compiler.parser' : {
2177 'level' : 'INFO',
2178 },
2179 },
2180 }
2181
2182 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002183 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002184 'incremental' : True,
2185 'handlers' : {
2186 'hand1' : {
2187 'level' : 'INFO',
2188 },
2189 },
2190 'loggers' : {
2191 'compiler.parser' : {
2192 'level' : 'INFO',
2193 },
2194 },
2195 }
2196
2197 #As config1 but with a filter added
2198 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002199 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002200 'formatters': {
2201 'form1' : {
2202 'format' : '%(levelname)s ++ %(message)s',
2203 },
2204 },
2205 'filters' : {
2206 'filt1' : {
2207 'name' : 'compiler.parser',
2208 },
2209 },
2210 'handlers' : {
2211 'hand1' : {
2212 'class' : 'logging.StreamHandler',
2213 'formatter' : 'form1',
2214 'level' : 'NOTSET',
2215 'stream' : 'ext://sys.stdout',
2216 'filters' : ['filt1'],
2217 },
2218 },
2219 'loggers' : {
2220 'compiler.parser' : {
2221 'level' : 'DEBUG',
2222 'filters' : ['filt1'],
2223 },
2224 },
2225 'root' : {
2226 'level' : 'WARNING',
2227 'handlers' : ['hand1'],
2228 },
2229 }
2230
2231 #As config1 but using cfg:// references
2232 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002233 'version': 1,
2234 'true_formatters': {
2235 'form1' : {
2236 'format' : '%(levelname)s ++ %(message)s',
2237 },
2238 },
2239 'handler_configs': {
2240 'hand1' : {
2241 'class' : 'logging.StreamHandler',
2242 'formatter' : 'form1',
2243 'level' : 'NOTSET',
2244 'stream' : 'ext://sys.stdout',
2245 },
2246 },
2247 'formatters' : 'cfg://true_formatters',
2248 'handlers' : {
2249 'hand1' : 'cfg://handler_configs[hand1]',
2250 },
2251 'loggers' : {
2252 'compiler.parser' : {
2253 'level' : 'DEBUG',
2254 'handlers' : ['hand1'],
2255 },
2256 },
2257 'root' : {
2258 'level' : 'WARNING',
2259 },
2260 }
2261
2262 #As config11 but missing the version key
2263 config12 = {
2264 'true_formatters': {
2265 'form1' : {
2266 'format' : '%(levelname)s ++ %(message)s',
2267 },
2268 },
2269 'handler_configs': {
2270 'hand1' : {
2271 'class' : 'logging.StreamHandler',
2272 'formatter' : 'form1',
2273 'level' : 'NOTSET',
2274 'stream' : 'ext://sys.stdout',
2275 },
2276 },
2277 'formatters' : 'cfg://true_formatters',
2278 'handlers' : {
2279 'hand1' : 'cfg://handler_configs[hand1]',
2280 },
2281 'loggers' : {
2282 'compiler.parser' : {
2283 'level' : 'DEBUG',
2284 'handlers' : ['hand1'],
2285 },
2286 },
2287 'root' : {
2288 'level' : 'WARNING',
2289 },
2290 }
2291
2292 #As config11 but using an unsupported version
2293 config13 = {
2294 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002295 'true_formatters': {
2296 'form1' : {
2297 'format' : '%(levelname)s ++ %(message)s',
2298 },
2299 },
2300 'handler_configs': {
2301 'hand1' : {
2302 'class' : 'logging.StreamHandler',
2303 'formatter' : 'form1',
2304 'level' : 'NOTSET',
2305 'stream' : 'ext://sys.stdout',
2306 },
2307 },
2308 'formatters' : 'cfg://true_formatters',
2309 'handlers' : {
2310 'hand1' : 'cfg://handler_configs[hand1]',
2311 },
2312 'loggers' : {
2313 'compiler.parser' : {
2314 'level' : 'DEBUG',
2315 'handlers' : ['hand1'],
2316 },
2317 },
2318 'root' : {
2319 'level' : 'WARNING',
2320 },
2321 }
2322
2323 def apply_config(self, conf):
2324 logging.config.dictConfig(conf)
2325
2326 def test_config0_ok(self):
2327 # A simple config which overrides the default settings.
2328 with captured_stdout() as output:
2329 self.apply_config(self.config0)
2330 logger = logging.getLogger()
2331 # Won't output anything
2332 logger.info(self.next_message())
2333 # Outputs a message
2334 logger.error(self.next_message())
2335 self.assert_log_lines([
2336 ('ERROR', '2'),
2337 ], stream=output)
2338 # Original logger output is empty.
2339 self.assert_log_lines([])
2340
2341 def test_config1_ok(self, config=config1):
2342 # A config defining a sub-parser as well.
2343 with captured_stdout() as output:
2344 self.apply_config(config)
2345 logger = logging.getLogger("compiler.parser")
2346 # Both will output a message
2347 logger.info(self.next_message())
2348 logger.error(self.next_message())
2349 self.assert_log_lines([
2350 ('INFO', '1'),
2351 ('ERROR', '2'),
2352 ], stream=output)
2353 # Original logger output is empty.
2354 self.assert_log_lines([])
2355
2356 def test_config2_failure(self):
2357 # A simple config which overrides the default settings.
2358 self.assertRaises(Exception, self.apply_config, self.config2)
2359
2360 def test_config2a_failure(self):
2361 # A simple config which overrides the default settings.
2362 self.assertRaises(Exception, self.apply_config, self.config2a)
2363
2364 def test_config2b_failure(self):
2365 # A simple config which overrides the default settings.
2366 self.assertRaises(Exception, self.apply_config, self.config2b)
2367
2368 def test_config3_failure(self):
2369 # A simple config which overrides the default settings.
2370 self.assertRaises(Exception, self.apply_config, self.config3)
2371
2372 def test_config4_ok(self):
2373 # A config specifying a custom formatter class.
2374 with captured_stdout() as output:
2375 self.apply_config(self.config4)
2376 #logger = logging.getLogger()
2377 try:
2378 raise RuntimeError()
2379 except RuntimeError:
2380 logging.exception("just testing")
2381 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002382 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002383 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2384 # Original logger output is empty
2385 self.assert_log_lines([])
2386
2387 def test_config4a_ok(self):
2388 # A config specifying a custom formatter class.
2389 with captured_stdout() as output:
2390 self.apply_config(self.config4a)
2391 #logger = logging.getLogger()
2392 try:
2393 raise RuntimeError()
2394 except RuntimeError:
2395 logging.exception("just testing")
2396 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002397 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002398 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2399 # Original logger output is empty
2400 self.assert_log_lines([])
2401
2402 def test_config5_ok(self):
2403 self.test_config1_ok(config=self.config5)
2404
2405 def test_config6_failure(self):
2406 self.assertRaises(Exception, self.apply_config, self.config6)
2407
2408 def test_config7_ok(self):
2409 with captured_stdout() as output:
2410 self.apply_config(self.config1)
2411 logger = logging.getLogger("compiler.parser")
2412 # Both will output a message
2413 logger.info(self.next_message())
2414 logger.error(self.next_message())
2415 self.assert_log_lines([
2416 ('INFO', '1'),
2417 ('ERROR', '2'),
2418 ], stream=output)
2419 # Original logger output is empty.
2420 self.assert_log_lines([])
2421 with captured_stdout() as output:
2422 self.apply_config(self.config7)
2423 logger = logging.getLogger("compiler.parser")
2424 self.assertTrue(logger.disabled)
2425 logger = logging.getLogger("compiler.lexer")
2426 # Both will output a message
2427 logger.info(self.next_message())
2428 logger.error(self.next_message())
2429 self.assert_log_lines([
2430 ('INFO', '3'),
2431 ('ERROR', '4'),
2432 ], stream=output)
2433 # Original logger output is empty.
2434 self.assert_log_lines([])
2435
2436 #Same as test_config_7_ok but don't disable old loggers.
2437 def test_config_8_ok(self):
2438 with captured_stdout() as output:
2439 self.apply_config(self.config1)
2440 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002441 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002442 logger.info(self.next_message())
2443 logger.error(self.next_message())
2444 self.assert_log_lines([
2445 ('INFO', '1'),
2446 ('ERROR', '2'),
2447 ], stream=output)
2448 # Original logger output is empty.
2449 self.assert_log_lines([])
2450 with captured_stdout() as output:
2451 self.apply_config(self.config8)
2452 logger = logging.getLogger("compiler.parser")
2453 self.assertFalse(logger.disabled)
2454 # Both will output a message
2455 logger.info(self.next_message())
2456 logger.error(self.next_message())
2457 logger = logging.getLogger("compiler.lexer")
2458 # Both will output a message
2459 logger.info(self.next_message())
2460 logger.error(self.next_message())
2461 self.assert_log_lines([
2462 ('INFO', '3'),
2463 ('ERROR', '4'),
2464 ('INFO', '5'),
2465 ('ERROR', '6'),
2466 ], stream=output)
2467 # Original logger output is empty.
2468 self.assert_log_lines([])
2469
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002470 def test_config_8a_ok(self):
2471 with captured_stdout() as output:
2472 self.apply_config(self.config1a)
2473 logger = logging.getLogger("compiler.parser")
2474 # See issue #11424. compiler-hyphenated sorts
2475 # between compiler and compiler.xyz and this
2476 # was preventing compiler.xyz from being included
2477 # in the child loggers of compiler because of an
2478 # overzealous loop termination condition.
2479 hyphenated = logging.getLogger('compiler-hyphenated')
2480 # All will output a message
2481 logger.info(self.next_message())
2482 logger.error(self.next_message())
2483 hyphenated.critical(self.next_message())
2484 self.assert_log_lines([
2485 ('INFO', '1'),
2486 ('ERROR', '2'),
2487 ('CRITICAL', '3'),
2488 ], stream=output)
2489 # Original logger output is empty.
2490 self.assert_log_lines([])
2491 with captured_stdout() as output:
2492 self.apply_config(self.config8a)
2493 logger = logging.getLogger("compiler.parser")
2494 self.assertFalse(logger.disabled)
2495 # Both will output a message
2496 logger.info(self.next_message())
2497 logger.error(self.next_message())
2498 logger = logging.getLogger("compiler.lexer")
2499 # Both will output a message
2500 logger.info(self.next_message())
2501 logger.error(self.next_message())
2502 # Will not appear
2503 hyphenated.critical(self.next_message())
2504 self.assert_log_lines([
2505 ('INFO', '4'),
2506 ('ERROR', '5'),
2507 ('INFO', '6'),
2508 ('ERROR', '7'),
2509 ], stream=output)
2510 # Original logger output is empty.
2511 self.assert_log_lines([])
2512
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002513 def test_config_9_ok(self):
2514 with captured_stdout() as output:
2515 self.apply_config(self.config9)
2516 logger = logging.getLogger("compiler.parser")
2517 #Nothing will be output since both handler and logger are set to WARNING
2518 logger.info(self.next_message())
2519 self.assert_log_lines([], stream=output)
2520 self.apply_config(self.config9a)
2521 #Nothing will be output since both handler is still set to WARNING
2522 logger.info(self.next_message())
2523 self.assert_log_lines([], stream=output)
2524 self.apply_config(self.config9b)
2525 #Message should now be output
2526 logger.info(self.next_message())
2527 self.assert_log_lines([
2528 ('INFO', '3'),
2529 ], stream=output)
2530
2531 def test_config_10_ok(self):
2532 with captured_stdout() as output:
2533 self.apply_config(self.config10)
2534 logger = logging.getLogger("compiler.parser")
2535 logger.warning(self.next_message())
2536 logger = logging.getLogger('compiler')
2537 #Not output, because filtered
2538 logger.warning(self.next_message())
2539 logger = logging.getLogger('compiler.lexer')
2540 #Not output, because filtered
2541 logger.warning(self.next_message())
2542 logger = logging.getLogger("compiler.parser.codegen")
2543 #Output, as not filtered
2544 logger.error(self.next_message())
2545 self.assert_log_lines([
2546 ('WARNING', '1'),
2547 ('ERROR', '4'),
2548 ], stream=output)
2549
2550 def test_config11_ok(self):
2551 self.test_config1_ok(self.config11)
2552
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002553 def test_config12_failure(self):
2554 self.assertRaises(Exception, self.apply_config, self.config12)
2555
2556 def test_config13_failure(self):
2557 self.assertRaises(Exception, self.apply_config, self.config13)
2558
Victor Stinner45df8202010-04-28 22:31:17 +00002559 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002560 def setup_via_listener(self, text):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002561 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002562 # Ask for a randomly assigned port (by using port 0)
2563 t = logging.config.listen(0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002564 t.start()
2565 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002566 # Now get the port allocated
2567 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002568 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002569 try:
2570 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2571 sock.settimeout(2.0)
2572 sock.connect(('localhost', port))
2573
2574 slen = struct.pack('>L', len(text))
2575 s = slen + text
2576 sentsofar = 0
2577 left = len(s)
2578 while left > 0:
2579 sent = sock.send(s[sentsofar:])
2580 sentsofar += sent
2581 left -= sent
2582 sock.close()
2583 finally:
2584 t.ready.wait(2.0)
2585 logging.config.stopListening()
2586 t.join(2.0)
2587
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002588 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002589 def test_listen_config_10_ok(self):
2590 with captured_stdout() as output:
2591 self.setup_via_listener(json.dumps(self.config10))
2592 logger = logging.getLogger("compiler.parser")
2593 logger.warning(self.next_message())
2594 logger = logging.getLogger('compiler')
2595 #Not output, because filtered
2596 logger.warning(self.next_message())
2597 logger = logging.getLogger('compiler.lexer')
2598 #Not output, because filtered
2599 logger.warning(self.next_message())
2600 logger = logging.getLogger("compiler.parser.codegen")
2601 #Output, as not filtered
2602 logger.error(self.next_message())
2603 self.assert_log_lines([
2604 ('WARNING', '1'),
2605 ('ERROR', '4'),
2606 ], stream=output)
2607
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002608 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002609 def test_listen_config_1_ok(self):
2610 with captured_stdout() as output:
2611 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2612 logger = logging.getLogger("compiler.parser")
2613 # Both will output a message
2614 logger.info(self.next_message())
2615 logger.error(self.next_message())
2616 self.assert_log_lines([
2617 ('INFO', '1'),
2618 ('ERROR', '2'),
2619 ], stream=output)
2620 # Original logger output is empty.
2621 self.assert_log_lines([])
2622
Vinay Sajip373baef2011-04-26 20:05:24 +01002623 def test_baseconfig(self):
2624 d = {
2625 'atuple': (1, 2, 3),
2626 'alist': ['a', 'b', 'c'],
2627 'adict': {'d': 'e', 'f': 3 },
2628 'nest1': ('g', ('h', 'i'), 'j'),
2629 'nest2': ['k', ['l', 'm'], 'n'],
2630 'nest3': ['o', 'cfg://alist', 'p'],
2631 }
2632 bc = logging.config.BaseConfigurator(d)
2633 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2634 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2635 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2636 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2637 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2638 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2639 v = bc.convert('cfg://nest3')
2640 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2641 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2642 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2643 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002644
2645class ManagerTest(BaseTest):
2646 def test_manager_loggerclass(self):
2647 logged = []
2648
2649 class MyLogger(logging.Logger):
2650 def _log(self, level, msg, args, exc_info=None, extra=None):
2651 logged.append(msg)
2652
2653 man = logging.Manager(None)
2654 self.assertRaises(TypeError, man.setLoggerClass, int)
2655 man.setLoggerClass(MyLogger)
2656 logger = man.getLogger('test')
2657 logger.warning('should appear in logged')
2658 logging.warning('should not appear in logged')
2659
2660 self.assertEqual(logged, ['should appear in logged'])
2661
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002662 def test_set_log_record_factory(self):
2663 man = logging.Manager(None)
2664 expected = object()
2665 man.setLogRecordFactory(expected)
2666 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002667
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002668class ChildLoggerTest(BaseTest):
2669 def test_child_loggers(self):
2670 r = logging.getLogger()
2671 l1 = logging.getLogger('abc')
2672 l2 = logging.getLogger('def.ghi')
2673 c1 = r.getChild('xyz')
2674 c2 = r.getChild('uvw.xyz')
2675 self.assertTrue(c1 is logging.getLogger('xyz'))
2676 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
2677 c1 = l1.getChild('def')
2678 c2 = c1.getChild('ghi')
2679 c3 = l1.getChild('def.ghi')
2680 self.assertTrue(c1 is logging.getLogger('abc.def'))
2681 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
2682 self.assertTrue(c2 is c3)
2683
2684
Vinay Sajip6fac8172010-10-19 20:44:14 +00002685class DerivedLogRecord(logging.LogRecord):
2686 pass
2687
Vinay Sajip61561522010-12-03 11:50:38 +00002688class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002689
2690 def setUp(self):
2691 class CheckingFilter(logging.Filter):
2692 def __init__(self, cls):
2693 self.cls = cls
2694
2695 def filter(self, record):
2696 t = type(record)
2697 if t is not self.cls:
2698 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2699 self.cls)
2700 raise TypeError(msg)
2701 return True
2702
2703 BaseTest.setUp(self)
2704 self.filter = CheckingFilter(DerivedLogRecord)
2705 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002706 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002707
2708 def tearDown(self):
2709 self.root_logger.removeFilter(self.filter)
2710 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002711 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002712
2713 def test_logrecord_class(self):
2714 self.assertRaises(TypeError, self.root_logger.warning,
2715 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002716 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002717 self.root_logger.error(self.next_message())
2718 self.assert_log_lines([
2719 ('root', 'ERROR', '2'),
2720 ])
2721
2722
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002723class QueueHandlerTest(BaseTest):
2724 # Do not bother with a logger name group.
2725 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
2726
2727 def setUp(self):
2728 BaseTest.setUp(self)
2729 self.queue = queue.Queue(-1)
2730 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2731 self.que_logger = logging.getLogger('que')
2732 self.que_logger.propagate = False
2733 self.que_logger.setLevel(logging.WARNING)
2734 self.que_logger.addHandler(self.que_hdlr)
2735
2736 def tearDown(self):
2737 self.que_hdlr.close()
2738 BaseTest.tearDown(self)
2739
2740 def test_queue_handler(self):
2741 self.que_logger.debug(self.next_message())
2742 self.assertRaises(queue.Empty, self.queue.get_nowait)
2743 self.que_logger.info(self.next_message())
2744 self.assertRaises(queue.Empty, self.queue.get_nowait)
2745 msg = self.next_message()
2746 self.que_logger.warning(msg)
2747 data = self.queue.get_nowait()
2748 self.assertTrue(isinstance(data, logging.LogRecord))
2749 self.assertEqual(data.name, self.que_logger.name)
2750 self.assertEqual((data.msg, data.args), (msg, None))
2751
Victor Stinnercafa2ef2011-05-02 16:11:28 +02002752 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
2753 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01002754 def test_queue_listener(self):
2755 handler = TestHandler(Matcher())
2756 listener = logging.handlers.QueueListener(self.queue, handler)
2757 listener.start()
2758 try:
2759 self.que_logger.warning(self.next_message())
2760 self.que_logger.error(self.next_message())
2761 self.que_logger.critical(self.next_message())
2762 finally:
2763 listener.stop()
2764 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
2765 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
2766 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
2767
Vinay Sajip37eb3382011-04-26 20:26:41 +01002768ZERO = datetime.timedelta(0)
2769
2770class UTC(datetime.tzinfo):
2771 def utcoffset(self, dt):
2772 return ZERO
2773
2774 dst = utcoffset
2775
2776 def tzname(self, dt):
2777 return 'UTC'
2778
2779utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01002780
Vinay Sajipa39c5712010-10-25 13:57:39 +00002781class FormatterTest(unittest.TestCase):
2782 def setUp(self):
2783 self.common = {
2784 'name': 'formatter.test',
2785 'level': logging.DEBUG,
2786 'pathname': os.path.join('path', 'to', 'dummy.ext'),
2787 'lineno': 42,
2788 'exc_info': None,
2789 'func': None,
2790 'msg': 'Message with %d %s',
2791 'args': (2, 'placeholders'),
2792 }
2793 self.variants = {
2794 }
2795
2796 def get_record(self, name=None):
2797 result = dict(self.common)
2798 if name is not None:
2799 result.update(self.variants[name])
2800 return logging.makeLogRecord(result)
2801
2802 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002803 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002804 r = self.get_record()
2805 f = logging.Formatter('${%(message)s}')
2806 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
2807 f = logging.Formatter('%(random)s')
2808 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002809 self.assertFalse(f.usesTime())
2810 f = logging.Formatter('%(asctime)s')
2811 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002812 f = logging.Formatter('%(asctime)-15s')
2813 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002814 f = logging.Formatter('asctime')
2815 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002816
2817 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002818 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002819 r = self.get_record()
2820 f = logging.Formatter('$%{message}%$', style='{')
2821 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2822 f = logging.Formatter('{random}', style='{')
2823 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002824 self.assertFalse(f.usesTime())
2825 f = logging.Formatter('{asctime}', style='{')
2826 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002827 f = logging.Formatter('{asctime!s:15}', style='{')
2828 self.assertTrue(f.usesTime())
2829 f = logging.Formatter('{asctime:15}', style='{')
2830 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002831 f = logging.Formatter('asctime', style='{')
2832 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002833
2834 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002835 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00002836 r = self.get_record()
2837 f = logging.Formatter('$message', style='$')
2838 self.assertEqual(f.format(r), 'Message with 2 placeholders')
2839 f = logging.Formatter('$$%${message}%$$', style='$')
2840 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
2841 f = logging.Formatter('${random}', style='$')
2842 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002843 self.assertFalse(f.usesTime())
2844 f = logging.Formatter('${asctime}', style='$')
2845 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00002846 f = logging.Formatter('${asctime', style='$')
2847 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00002848 f = logging.Formatter('$asctime', style='$')
2849 self.assertTrue(f.usesTime())
2850 f = logging.Formatter('asctime', style='$')
2851 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00002852
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002853 def test_invalid_style(self):
2854 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
2855
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002856 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002857 r = self.get_record()
Vinay Sajip37eb3382011-04-26 20:26:41 +01002858 dt = datetime.datetime(1993,4,21,8,3,0,0,utc)
Vinay Sajip86a96ce2011-04-27 08:30:30 +01002859 r.created = time.mktime(dt.timetuple()) - time.timezone
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002860 r.msecs = 123
2861 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01002862 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002863 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
2864 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01002865 f.format(r)
2866 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
2867
2868class TestBufferingFormatter(logging.BufferingFormatter):
2869 def formatHeader(self, records):
2870 return '[(%d)' % len(records)
2871
2872 def formatFooter(self, records):
2873 return '(%d)]' % len(records)
2874
2875class BufferingFormatterTest(unittest.TestCase):
2876 def setUp(self):
2877 self.records = [
2878 logging.makeLogRecord({'msg': 'one'}),
2879 logging.makeLogRecord({'msg': 'two'}),
2880 ]
2881
2882 def test_default(self):
2883 f = logging.BufferingFormatter()
2884 self.assertEqual('', f.format([]))
2885 self.assertEqual('onetwo', f.format(self.records))
2886
2887 def test_custom(self):
2888 f = TestBufferingFormatter()
2889 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
2890 lf = logging.Formatter('<%(message)s>')
2891 f = TestBufferingFormatter(lf)
2892 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01002893
2894class ExceptionTest(BaseTest):
2895 def test_formatting(self):
2896 r = self.root_logger
2897 h = RecordingHandler()
2898 r.addHandler(h)
2899 try:
2900 raise RuntimeError('deliberate mistake')
2901 except:
2902 logging.exception('failed', stack_info=True)
2903 r.removeHandler(h)
2904 h.close()
2905 r = h.records[0]
2906 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
2907 'call last):\n'))
2908 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
2909 'deliberate mistake'))
2910 self.assertTrue(r.stack_info.startswith('Stack (most recent '
2911 'call last):\n'))
2912 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
2913 'stack_info=True)'))
2914
2915
Vinay Sajip5a27d402010-12-10 11:42:57 +00002916class LastResortTest(BaseTest):
2917 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00002918 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00002919 root = self.root_logger
2920 root.removeHandler(self.root_hdlr)
2921 old_stderr = sys.stderr
2922 old_lastresort = logging.lastResort
2923 old_raise_exceptions = logging.raiseExceptions
2924 try:
2925 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01002926 root.debug('This should not appear')
2927 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00002928 root.warning('This is your final chance!')
2929 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
2930 #No handlers and no last resort, so 'No handlers' message
2931 logging.lastResort = None
2932 sys.stderr = sio = io.StringIO()
2933 root.warning('This is your final chance!')
2934 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
2935 # 'No handlers' message only printed once
2936 sys.stderr = sio = io.StringIO()
2937 root.warning('This is your final chance!')
2938 self.assertEqual(sio.getvalue(), '')
2939 root.manager.emittedNoHandlerWarning = False
2940 #If raiseExceptions is False, no message is printed
2941 logging.raiseExceptions = False
2942 sys.stderr = sio = io.StringIO()
2943 root.warning('This is your final chance!')
2944 self.assertEqual(sio.getvalue(), '')
2945 finally:
2946 sys.stderr = old_stderr
2947 root.addHandler(self.root_hdlr)
2948 logging.lastResort = old_lastresort
2949 logging.raiseExceptions = old_raise_exceptions
2950
2951
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002952class FakeHandler:
2953
2954 def __init__(self, identifier, called):
2955 for method in ('acquire', 'flush', 'close', 'release'):
2956 setattr(self, method, self.record_call(identifier, method, called))
2957
2958 def record_call(self, identifier, method_name, called):
2959 def inner():
2960 called.append('{} - {}'.format(identifier, method_name))
2961 return inner
2962
2963
2964class RecordingHandler(logging.NullHandler):
2965
2966 def __init__(self, *args, **kwargs):
2967 super(RecordingHandler, self).__init__(*args, **kwargs)
2968 self.records = []
2969
2970 def handle(self, record):
2971 """Keep track of all the emitted records."""
2972 self.records.append(record)
2973
2974
2975class ShutdownTest(BaseTest):
2976
Vinay Sajip5e66b162011-04-20 15:41:14 +01002977 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002978
2979 def setUp(self):
2980 super(ShutdownTest, self).setUp()
2981 self.called = []
2982
2983 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002984 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002985
2986 def raise_error(self, error):
2987 def inner():
2988 raise error()
2989 return inner
2990
2991 def test_no_failure(self):
2992 # create some fake handlers
2993 handler0 = FakeHandler(0, self.called)
2994 handler1 = FakeHandler(1, self.called)
2995 handler2 = FakeHandler(2, self.called)
2996
2997 # create live weakref to those handlers
2998 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
2999
3000 logging.shutdown(handlerList=list(handlers))
3001
3002 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3003 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3004 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3005 self.assertEqual(expected, self.called)
3006
3007 def _test_with_failure_in_method(self, method, error):
3008 handler = FakeHandler(0, self.called)
3009 setattr(handler, method, self.raise_error(error))
3010 handlers = [logging.weakref.ref(handler)]
3011
3012 logging.shutdown(handlerList=list(handlers))
3013
3014 self.assertEqual('0 - release', self.called[-1])
3015
3016 def test_with_ioerror_in_acquire(self):
3017 self._test_with_failure_in_method('acquire', IOError)
3018
3019 def test_with_ioerror_in_flush(self):
3020 self._test_with_failure_in_method('flush', IOError)
3021
3022 def test_with_ioerror_in_close(self):
3023 self._test_with_failure_in_method('close', IOError)
3024
3025 def test_with_valueerror_in_acquire(self):
3026 self._test_with_failure_in_method('acquire', ValueError)
3027
3028 def test_with_valueerror_in_flush(self):
3029 self._test_with_failure_in_method('flush', ValueError)
3030
3031 def test_with_valueerror_in_close(self):
3032 self._test_with_failure_in_method('close', ValueError)
3033
3034 def test_with_other_error_in_acquire_without_raise(self):
3035 logging.raiseExceptions = False
3036 self._test_with_failure_in_method('acquire', IndexError)
3037
3038 def test_with_other_error_in_flush_without_raise(self):
3039 logging.raiseExceptions = False
3040 self._test_with_failure_in_method('flush', IndexError)
3041
3042 def test_with_other_error_in_close_without_raise(self):
3043 logging.raiseExceptions = False
3044 self._test_with_failure_in_method('close', IndexError)
3045
3046 def test_with_other_error_in_acquire_with_raise(self):
3047 logging.raiseExceptions = True
3048 self.assertRaises(IndexError, self._test_with_failure_in_method,
3049 'acquire', IndexError)
3050
3051 def test_with_other_error_in_flush_with_raise(self):
3052 logging.raiseExceptions = True
3053 self.assertRaises(IndexError, self._test_with_failure_in_method,
3054 'flush', IndexError)
3055
3056 def test_with_other_error_in_close_with_raise(self):
3057 logging.raiseExceptions = True
3058 self.assertRaises(IndexError, self._test_with_failure_in_method,
3059 'close', IndexError)
3060
3061
3062class ModuleLevelMiscTest(BaseTest):
3063
Vinay Sajip5e66b162011-04-20 15:41:14 +01003064 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003065
3066 def test_disable(self):
3067 old_disable = logging.root.manager.disable
3068 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003069 self.assertEqual(old_disable, 0)
3070 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003071
3072 logging.disable(83)
3073 self.assertEqual(logging.root.manager.disable, 83)
3074
3075 def _test_log(self, method, level=None):
3076 called = []
3077 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003078 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003079
3080 recording = RecordingHandler()
3081 logging.root.addHandler(recording)
3082
3083 log_method = getattr(logging, method)
3084 if level is not None:
3085 log_method(level, "test me: %r", recording)
3086 else:
3087 log_method("test me: %r", recording)
3088
3089 self.assertEqual(len(recording.records), 1)
3090 record = recording.records[0]
3091 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3092
3093 expected_level = level if level is not None else getattr(logging, method.upper())
3094 self.assertEqual(record.levelno, expected_level)
3095
3096 # basicConfig was not called!
3097 self.assertEqual(called, [])
3098
3099 def test_log(self):
3100 self._test_log('log', logging.ERROR)
3101
3102 def test_debug(self):
3103 self._test_log('debug')
3104
3105 def test_info(self):
3106 self._test_log('info')
3107
3108 def test_warning(self):
3109 self._test_log('warning')
3110
3111 def test_error(self):
3112 self._test_log('error')
3113
3114 def test_critical(self):
3115 self._test_log('critical')
3116
3117 def test_set_logger_class(self):
3118 self.assertRaises(TypeError, logging.setLoggerClass, object)
3119
3120 class MyLogger(logging.Logger):
3121 pass
3122
3123 logging.setLoggerClass(MyLogger)
3124 self.assertEqual(logging.getLoggerClass(), MyLogger)
3125
3126 logging.setLoggerClass(logging.Logger)
3127 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3128
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003129class LogRecordTest(BaseTest):
3130 def test_str_rep(self):
3131 r = logging.makeLogRecord({})
3132 s = str(r)
3133 self.assertTrue(s.startswith('<LogRecord: '))
3134 self.assertTrue(s.endswith('>'))
3135
3136 def test_dict_arg(self):
3137 h = RecordingHandler()
3138 r = logging.getLogger()
3139 r.addHandler(h)
3140 d = {'less' : 'more' }
3141 logging.warning('less is %(less)s', d)
3142 self.assertIs(h.records[0].args, d)
3143 self.assertEqual(h.records[0].message, 'less is more')
3144 r.removeHandler(h)
3145 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003146
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003147 def test_multiprocessing(self):
3148 r = logging.makeLogRecord({})
3149 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003150 try:
3151 import multiprocessing as mp
3152 r = logging.makeLogRecord({})
3153 self.assertEqual(r.processName, mp.current_process().name)
3154 except ImportError:
3155 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003156
3157 def test_optional(self):
3158 r = logging.makeLogRecord({})
3159 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003160 if threading:
3161 NOT_NONE(r.thread)
3162 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003163 NOT_NONE(r.process)
3164 NOT_NONE(r.processName)
3165 log_threads = logging.logThreads
3166 log_processes = logging.logProcesses
3167 log_multiprocessing = logging.logMultiprocessing
3168 try:
3169 logging.logThreads = False
3170 logging.logProcesses = False
3171 logging.logMultiprocessing = False
3172 r = logging.makeLogRecord({})
3173 NONE = self.assertIsNone
3174 NONE(r.thread)
3175 NONE(r.threadName)
3176 NONE(r.process)
3177 NONE(r.processName)
3178 finally:
3179 logging.logThreads = log_threads
3180 logging.logProcesses = log_processes
3181 logging.logMultiprocessing = log_multiprocessing
3182
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003183class BasicConfigTest(unittest.TestCase):
3184
Vinay Sajip95bf5042011-04-20 11:50:56 +01003185 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003186
3187 def setUp(self):
3188 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003189 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003190 self.saved_handlers = logging._handlers.copy()
3191 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003192 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003193 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003194 logging.root.handlers = []
3195
3196 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003197 for h in logging.root.handlers[:]:
3198 logging.root.removeHandler(h)
3199 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003200 super(BasicConfigTest, self).tearDown()
3201
Vinay Sajip3def7e02011-04-20 10:58:06 +01003202 def cleanup(self):
3203 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003204 logging._handlers.clear()
3205 logging._handlers.update(self.saved_handlers)
3206 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003207 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003208
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003209 def test_no_kwargs(self):
3210 logging.basicConfig()
3211
3212 # handler defaults to a StreamHandler to sys.stderr
3213 self.assertEqual(len(logging.root.handlers), 1)
3214 handler = logging.root.handlers[0]
3215 self.assertIsInstance(handler, logging.StreamHandler)
3216 self.assertEqual(handler.stream, sys.stderr)
3217
3218 formatter = handler.formatter
3219 # format defaults to logging.BASIC_FORMAT
3220 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3221 # datefmt defaults to None
3222 self.assertIsNone(formatter.datefmt)
3223 # style defaults to %
3224 self.assertIsInstance(formatter._style, logging.PercentStyle)
3225
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003226 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003227 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003228
3229 def test_filename(self):
3230 logging.basicConfig(filename='test.log')
3231
3232 self.assertEqual(len(logging.root.handlers), 1)
3233 handler = logging.root.handlers[0]
3234 self.assertIsInstance(handler, logging.FileHandler)
3235
3236 expected = logging.FileHandler('test.log', 'a')
3237 self.addCleanup(expected.close)
3238 self.assertEqual(handler.stream.mode, expected.stream.mode)
3239 self.assertEqual(handler.stream.name, expected.stream.name)
3240
3241 def test_filemode(self):
3242 logging.basicConfig(filename='test.log', filemode='wb')
3243
3244 handler = logging.root.handlers[0]
3245 expected = logging.FileHandler('test.log', 'wb')
3246 self.addCleanup(expected.close)
3247 self.assertEqual(handler.stream.mode, expected.stream.mode)
3248
3249 def test_stream(self):
3250 stream = io.StringIO()
3251 self.addCleanup(stream.close)
3252 logging.basicConfig(stream=stream)
3253
3254 self.assertEqual(len(logging.root.handlers), 1)
3255 handler = logging.root.handlers[0]
3256 self.assertIsInstance(handler, logging.StreamHandler)
3257 self.assertEqual(handler.stream, stream)
3258
3259 def test_format(self):
3260 logging.basicConfig(format='foo')
3261
3262 formatter = logging.root.handlers[0].formatter
3263 self.assertEqual(formatter._style._fmt, 'foo')
3264
3265 def test_datefmt(self):
3266 logging.basicConfig(datefmt='bar')
3267
3268 formatter = logging.root.handlers[0].formatter
3269 self.assertEqual(formatter.datefmt, 'bar')
3270
3271 def test_style(self):
3272 logging.basicConfig(style='$')
3273
3274 formatter = logging.root.handlers[0].formatter
3275 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3276
3277 def test_level(self):
3278 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003279 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003280
3281 logging.basicConfig(level=57)
3282 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003283 # Test that second call has no effect
3284 logging.basicConfig(level=58)
3285 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003286
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003287 def test_incompatible(self):
3288 assertRaises = self.assertRaises
3289 handlers = [logging.StreamHandler()]
3290 stream = sys.stderr
3291 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3292 stream=stream)
3293 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3294 handlers=handlers)
3295 assertRaises(ValueError, logging.basicConfig, stream=stream,
3296 handlers=handlers)
3297
3298 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003299 handlers = [
3300 logging.StreamHandler(),
3301 logging.StreamHandler(sys.stdout),
3302 logging.StreamHandler(),
3303 ]
3304 f = logging.Formatter()
3305 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003306 logging.basicConfig(handlers=handlers)
3307 self.assertIs(handlers[0], logging.root.handlers[0])
3308 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003309 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003310 self.assertIsNotNone(handlers[0].formatter)
3311 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003312 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003313 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3314
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003315 def _test_log(self, method, level=None):
3316 # logging.root has no handlers so basicConfig should be called
3317 called = []
3318
3319 old_basic_config = logging.basicConfig
3320 def my_basic_config(*a, **kw):
3321 old_basic_config()
3322 old_level = logging.root.level
3323 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003324 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003325 called.append((a, kw))
3326
3327 patch(self, logging, 'basicConfig', my_basic_config)
3328
3329 log_method = getattr(logging, method)
3330 if level is not None:
3331 log_method(level, "test me")
3332 else:
3333 log_method("test me")
3334
3335 # basicConfig was called with no arguments
3336 self.assertEqual(called, [((), {})])
3337
3338 def test_log(self):
3339 self._test_log('log', logging.WARNING)
3340
3341 def test_debug(self):
3342 self._test_log('debug')
3343
3344 def test_info(self):
3345 self._test_log('info')
3346
3347 def test_warning(self):
3348 self._test_log('warning')
3349
3350 def test_error(self):
3351 self._test_log('error')
3352
3353 def test_critical(self):
3354 self._test_log('critical')
3355
3356
3357class LoggerAdapterTest(unittest.TestCase):
3358
3359 def setUp(self):
3360 super(LoggerAdapterTest, self).setUp()
3361 old_handler_list = logging._handlerList[:]
3362
3363 self.recording = RecordingHandler()
3364 self.logger = logging.root
3365 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003366 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003367 self.addCleanup(self.recording.close)
3368
3369 def cleanup():
3370 logging._handlerList[:] = old_handler_list
3371
3372 self.addCleanup(cleanup)
3373 self.addCleanup(logging.shutdown)
3374 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3375
3376 def test_exception(self):
3377 msg = 'testing exception: %r'
3378 exc = None
3379 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003380 1 / 0
3381 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003382 exc = e
3383 self.adapter.exception(msg, self.recording)
3384
3385 self.assertEqual(len(self.recording.records), 1)
3386 record = self.recording.records[0]
3387 self.assertEqual(record.levelno, logging.ERROR)
3388 self.assertEqual(record.msg, msg)
3389 self.assertEqual(record.args, (self.recording,))
3390 self.assertEqual(record.exc_info,
3391 (exc.__class__, exc, exc.__traceback__))
3392
3393 def test_critical(self):
3394 msg = 'critical test! %r'
3395 self.adapter.critical(msg, self.recording)
3396
3397 self.assertEqual(len(self.recording.records), 1)
3398 record = self.recording.records[0]
3399 self.assertEqual(record.levelno, logging.CRITICAL)
3400 self.assertEqual(record.msg, msg)
3401 self.assertEqual(record.args, (self.recording,))
3402
3403 def test_is_enabled_for(self):
3404 old_disable = self.adapter.logger.manager.disable
3405 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003406 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3407 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003408 self.assertFalse(self.adapter.isEnabledFor(32))
3409
3410 def test_has_handlers(self):
3411 self.assertTrue(self.adapter.hasHandlers())
3412
3413 for handler in self.logger.handlers:
3414 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003415
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003416 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003417 self.assertFalse(self.adapter.hasHandlers())
3418
3419
3420class LoggerTest(BaseTest):
3421
3422 def setUp(self):
3423 super(LoggerTest, self).setUp()
3424 self.recording = RecordingHandler()
3425 self.logger = logging.Logger(name='blah')
3426 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003427 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003428 self.addCleanup(self.recording.close)
3429 self.addCleanup(logging.shutdown)
3430
3431 def test_set_invalid_level(self):
3432 self.assertRaises(TypeError, self.logger.setLevel, object())
3433
3434 def test_exception(self):
3435 msg = 'testing exception: %r'
3436 exc = None
3437 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003438 1 / 0
3439 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003440 exc = e
3441 self.logger.exception(msg, self.recording)
3442
3443 self.assertEqual(len(self.recording.records), 1)
3444 record = self.recording.records[0]
3445 self.assertEqual(record.levelno, logging.ERROR)
3446 self.assertEqual(record.msg, msg)
3447 self.assertEqual(record.args, (self.recording,))
3448 self.assertEqual(record.exc_info,
3449 (exc.__class__, exc, exc.__traceback__))
3450
3451 def test_log_invalid_level_with_raise(self):
3452 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003453 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003454
3455 logging.raiseExceptions = True
3456 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3457
3458 def test_log_invalid_level_no_raise(self):
3459 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003460 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003461
3462 logging.raiseExceptions = False
3463 self.logger.log('10', 'test message') # no exception happens
3464
3465 def test_find_caller_with_stack_info(self):
3466 called = []
3467 patch(self, logging.traceback, 'print_stack',
3468 lambda f, file: called.append(file.getvalue()))
3469
3470 self.logger.findCaller(stack_info=True)
3471
3472 self.assertEqual(len(called), 1)
3473 self.assertEqual('Stack (most recent call last):\n', called[0])
3474
3475 def test_make_record_with_extra_overwrite(self):
3476 name = 'my record'
3477 level = 13
3478 fn = lno = msg = args = exc_info = func = sinfo = None
3479 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3480 exc_info, func, sinfo)
3481
3482 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3483 extra = {key: 'some value'}
3484 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3485 fn, lno, msg, args, exc_info,
3486 extra=extra, sinfo=sinfo)
3487
3488 def test_make_record_with_extra_no_overwrite(self):
3489 name = 'my record'
3490 level = 13
3491 fn = lno = msg = args = exc_info = func = sinfo = None
3492 extra = {'valid_key': 'some value'}
3493 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3494 exc_info, extra=extra, sinfo=sinfo)
3495 self.assertIn('valid_key', result.__dict__)
3496
3497 def test_has_handlers(self):
3498 self.assertTrue(self.logger.hasHandlers())
3499
3500 for handler in self.logger.handlers:
3501 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003502 self.assertFalse(self.logger.hasHandlers())
3503
3504 def test_has_handlers_no_propagate(self):
3505 child_logger = logging.getLogger('blah.child')
3506 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003507 self.assertFalse(child_logger.hasHandlers())
3508
3509 def test_is_enabled_for(self):
3510 old_disable = self.logger.manager.disable
3511 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003512 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003513 self.assertFalse(self.logger.isEnabledFor(22))
3514
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003515 def test_root_logger_aliases(self):
3516 root = logging.getLogger()
3517 self.assertIs(root, logging.root)
3518 self.assertIs(root, logging.getLogger(None))
3519 self.assertIs(root, logging.getLogger(''))
3520 self.assertIs(root, logging.getLogger('foo').root)
3521 self.assertIs(root, logging.getLogger('foo.bar').root)
3522 self.assertIs(root, logging.getLogger('foo').parent)
3523
3524 self.assertIsNot(root, logging.getLogger('\0'))
3525 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3526
3527 def test_invalid_names(self):
3528 self.assertRaises(TypeError, logging.getLogger, any)
3529 self.assertRaises(TypeError, logging.getLogger, b'foo')
3530
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003531
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003532class BaseFileTest(BaseTest):
3533 "Base class for handler tests that write log files"
3534
3535 def setUp(self):
3536 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003537 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3538 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003539 self.rmfiles = []
3540
3541 def tearDown(self):
3542 for fn in self.rmfiles:
3543 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003544 if os.path.exists(self.fn):
3545 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003546 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003547
3548 def assertLogFile(self, filename):
3549 "Assert a log file is there and register it for deletion"
3550 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003551 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003552 self.rmfiles.append(filename)
3553
3554
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003555class FileHandlerTest(BaseFileTest):
3556 def test_delay(self):
3557 os.unlink(self.fn)
3558 fh = logging.FileHandler(self.fn, delay=True)
3559 self.assertIsNone(fh.stream)
3560 self.assertFalse(os.path.exists(self.fn))
3561 fh.handle(logging.makeLogRecord({}))
3562 self.assertIsNotNone(fh.stream)
3563 self.assertTrue(os.path.exists(self.fn))
3564 fh.close()
3565
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003566class RotatingFileHandlerTest(BaseFileTest):
3567 def next_rec(self):
3568 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3569 self.next_message(), None, None, None)
3570
3571 def test_should_not_rollover(self):
3572 # If maxbytes is zero rollover never occurs
3573 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3574 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003575 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003576
3577 def test_should_rollover(self):
3578 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3579 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003580 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003581
3582 def test_file_created(self):
3583 # checks that the file is created and assumes it was created
3584 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003585 rh = logging.handlers.RotatingFileHandler(self.fn)
3586 rh.emit(self.next_rec())
3587 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003588 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003589
3590 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003591 def namer(name):
3592 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003593 rh = logging.handlers.RotatingFileHandler(
3594 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003595 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003596 rh.emit(self.next_rec())
3597 self.assertLogFile(self.fn)
3598 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003599 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003600 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003601 self.assertLogFile(namer(self.fn + ".2"))
3602 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3603 rh.close()
3604
3605 def test_rotator(self):
3606 def namer(name):
3607 return name + ".gz"
3608
3609 def rotator(source, dest):
3610 with open(source, "rb") as sf:
3611 data = sf.read()
3612 compressed = zlib.compress(data, 9)
3613 with open(dest, "wb") as df:
3614 df.write(compressed)
3615 os.remove(source)
3616
3617 rh = logging.handlers.RotatingFileHandler(
3618 self.fn, backupCount=2, maxBytes=1)
3619 rh.rotator = rotator
3620 rh.namer = namer
3621 m1 = self.next_rec()
3622 rh.emit(m1)
3623 self.assertLogFile(self.fn)
3624 m2 = self.next_rec()
3625 rh.emit(m2)
3626 fn = namer(self.fn + ".1")
3627 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003628 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003629 with open(fn, "rb") as f:
3630 compressed = f.read()
3631 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003632 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003633 rh.emit(self.next_rec())
3634 fn = namer(self.fn + ".2")
3635 self.assertLogFile(fn)
3636 with open(fn, "rb") as f:
3637 compressed = f.read()
3638 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003639 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003640 rh.emit(self.next_rec())
3641 fn = namer(self.fn + ".2")
3642 with open(fn, "rb") as f:
3643 compressed = f.read()
3644 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003645 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003646 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003647 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003648
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003649class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003650 # other test methods added below
3651 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003652 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3653 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003654 fmt = logging.Formatter('%(asctime)s %(message)s')
3655 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003656 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
3657 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
3658 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003659 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003660 time.sleep(1.1) # a little over a second ...
3661 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003662 fh.close()
3663 # At this point, we should have a recent rotated file which we
3664 # can test for the existence of. However, in practice, on some
3665 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003666 # in time to go to look for the log file. So, we go back a fair
3667 # bit, and stop as soon as we see a rotated file. In theory this
3668 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003669 found = False
3670 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003671 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003672 for secs in range(GO_BACK):
3673 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003674 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3675 found = os.path.exists(fn)
3676 if found:
3677 self.rmfiles.append(fn)
3678 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003679 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3680 if not found:
3681 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01003682 dn, fn = os.path.split(self.fn)
3683 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02003684 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
3685 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00003686 for f in files:
3687 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00003688 path = os.path.join(dn, f)
3689 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00003690 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01003691 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003692
Vinay Sajip0372e102011-05-05 12:59:14 +01003693 def test_invalid(self):
3694 assertRaises = self.assertRaises
3695 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003696 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003697 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003698 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003699 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01003700 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01003701
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003702def secs(**kw):
3703 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
3704
3705for when, exp in (('S', 1),
3706 ('M', 60),
3707 ('H', 60 * 60),
3708 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00003709 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003710 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00003711 ('W0', secs(days=4, hours=24)),
3712 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003713 def test_compute_rollover(self, when=when, exp=exp):
3714 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00003715 self.fn, when=when, interval=1, backupCount=0, utc=True)
3716 currentTime = 0.0
3717 actual = rh.computeRollover(currentTime)
3718 if exp != actual:
3719 # Failures occur on some systems for MIDNIGHT and W0.
3720 # Print detailed calculation for MIDNIGHT so we can try to see
3721 # what's going on
3722 import time
3723 if when == 'MIDNIGHT':
3724 try:
3725 if rh.utc:
3726 t = time.gmtime(currentTime)
3727 else:
3728 t = time.localtime(currentTime)
3729 currentHour = t[3]
3730 currentMinute = t[4]
3731 currentSecond = t[5]
3732 # r is the number of seconds left between now and midnight
3733 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
3734 currentMinute) * 60 +
3735 currentSecond)
3736 result = currentTime + r
3737 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
3738 print('currentHour: %s' % currentHour, file=sys.stderr)
3739 print('currentMinute: %s' % currentMinute, file=sys.stderr)
3740 print('currentSecond: %s' % currentSecond, file=sys.stderr)
3741 print('r: %s' % r, file=sys.stderr)
3742 print('result: %s' % result, file=sys.stderr)
3743 except Exception:
3744 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
3745 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00003746 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003747 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
3748
Vinay Sajip60ccd822011-05-09 17:32:09 +01003749
3750@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
3751class NTEventLogHandlerTest(BaseTest):
3752 def test_basic(self):
3753 logtype = 'Application'
3754 elh = win32evtlog.OpenEventLog(None, logtype)
3755 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
3756 h = logging.handlers.NTEventLogHandler('test_logging')
3757 r = logging.makeLogRecord({'msg': 'Test Log Message'})
3758 h.handle(r)
3759 h.close()
3760 # Now see if the event is recorded
3761 self.assertTrue(num_recs < win32evtlog.GetNumberOfEventLogRecords(elh))
3762 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
3763 win32evtlog.EVENTLOG_SEQUENTIAL_READ
3764 found = False
3765 GO_BACK = 100
3766 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
3767 for e in events:
3768 if e.SourceName != 'test_logging':
3769 continue
3770 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
3771 if msg != 'Test Log Message\r\n':
3772 continue
3773 found = True
3774 break
3775 msg = 'Record not found in event log, went back %d records' % GO_BACK
3776 self.assertTrue(found, msg=msg)
3777
Christian Heimes180510d2008-03-03 19:15:45 +00003778# Set the locale to the platform-dependent default. I have no idea
3779# why the test does this, but in any case we save the current locale
3780# first and restore it at the end.
3781@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00003782def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00003783 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003784 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01003785 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
3786 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
3787 ManagerTest, FormatterTest, BufferingFormatterTest,
3788 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
3789 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
3790 BasicConfigTest, LoggerAdapterTest, LoggerTest,
3791 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003792 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01003793 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip89807a52011-02-26 16:06:02 +00003794 TimedRotatingFileHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00003795 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00003796
Christian Heimes180510d2008-03-03 19:15:45 +00003797if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00003798 test_main()