blob: e72b036e101343ea898acc0f5e60e6aa1d633324 [file] [log] [blame]
Vinay Sajip3f885b52013-03-22 15:19:54 +00001# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Christian Heimes180510d2008-03-03 19:15:45 +00002#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose and without fee is hereby granted,
5# provided that the above copyright notice appear in all copies and that
6# both that copyright notice and this permission notice appear in
7# supporting documentation, and that the name of Vinay Sajip
8# not be used in advertising or publicity pertaining to distribution
9# of the software without specific, written prior permission.
10# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17"""Test harness for the logging module. Run all tests.
18
Vinay Sajip3f885b52013-03-22 15:19:54 +000019Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Christian Heimes180510d2008-03-03 19:15:45 +000022import logging
23import logging.handlers
24import logging.config
Christian Heimes18c66892008-02-17 13:31:39 +000025
Benjamin Petersonf91df042009-02-13 02:50:59 +000026import codecs
Vinay Sajipcf9e2f22012-10-09 09:06:03 +010027import configparser
Vinay Sajip19ec67a2010-09-17 18:57:36 +000028import datetime
Christian Heimes180510d2008-03-03 19:15:45 +000029import pickle
30import io
31import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000032import json
Christian Heimes180510d2008-03-03 19:15:45 +000033import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000034import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010035import random
Christian Heimes180510d2008-03-03 19:15:45 +000036import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000037import select
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Antoine Pitrou712cb732013-12-21 15:51:54 +010042from test.script_helper import assert_python_ok
Eric V. Smith851cad72012-03-11 22:46:04 -070043from test.support import (captured_stdout, run_with_locale, run_unittest,
44 patch, requires_zlib, TestHandler, Matcher)
Christian Heimes180510d2008-03-03 19:15:45 +000045import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010046import time
Christian Heimes180510d2008-03-03 19:15:45 +000047import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000048import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000049import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000050try:
51 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010053 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010054 import asynchat
55 import asyncore
56 import errno
57 from http.server import HTTPServer, BaseHTTPRequestHandler
58 import smtpd
59 from urllib.parse import urlparse, parse_qs
60 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip5421f352013-09-27 18:18:28 +010061 ThreadingTCPServer, StreamRequestHandler,
62 ThreadingUnixStreamServer,
63 ThreadingUnixDatagramServer)
Victor Stinner45df8202010-04-28 22:31:17 +000064except ImportError:
65 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010066try:
67 import win32evtlog
68except ImportError:
69 win32evtlog = None
70try:
71 import win32evtlogutil
72except ImportError:
73 win32evtlogutil = None
74 win32evtlog = None
Eric V. Smith851cad72012-03-11 22:46:04 -070075try:
76 import zlib
77except ImportError:
78 pass
Christian Heimes18c66892008-02-17 13:31:39 +000079
Christian Heimes180510d2008-03-03 19:15:45 +000080class BaseTest(unittest.TestCase):
81
82 """Base class for logging tests."""
83
84 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030085 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000086 message_num = 0
87
88 def setUp(self):
89 """Setup the default logging stream to an internal StringIO instance,
90 so that we can examine log output as we want."""
91 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000092 logging._acquireLock()
93 try:
Christian Heimes180510d2008-03-03 19:15:45 +000094 self.saved_handlers = logging._handlers.copy()
95 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000096 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070097 self.saved_name_to_level = logging._nameToLevel.copy()
98 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000099 self.logger_states = logger_states = {}
100 for name in saved_loggers:
101 logger_states[name] = getattr(saved_loggers[name],
102 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +0000103 finally:
104 logging._releaseLock()
105
Florent Xicluna5252f9f2011-11-07 19:43:05 +0100106 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +0000107 self.logger1 = logging.getLogger("\xab\xd7\xbb")
108 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +0000109
Christian Heimes180510d2008-03-03 19:15:45 +0000110 self.root_logger = logging.getLogger("")
111 self.original_logging_level = self.root_logger.getEffectiveLevel()
112
113 self.stream = io.StringIO()
114 self.root_logger.setLevel(logging.DEBUG)
115 self.root_hdlr = logging.StreamHandler(self.stream)
116 self.root_formatter = logging.Formatter(self.log_format)
117 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000118 if self.logger1.hasHandlers():
119 hlist = self.logger1.handlers + self.root_logger.handlers
120 raise AssertionError('Unexpected handlers: %s' % hlist)
121 if self.logger2.hasHandlers():
122 hlist = self.logger2.handlers + self.root_logger.handlers
123 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000124 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000125 self.assertTrue(self.logger1.hasHandlers())
126 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000127
128 def tearDown(self):
129 """Remove our logging stream, and restore the original logging
130 level."""
131 self.stream.close()
132 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000133 while self.root_logger.handlers:
134 h = self.root_logger.handlers[0]
135 self.root_logger.removeHandler(h)
136 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000137 self.root_logger.setLevel(self.original_logging_level)
138 logging._acquireLock()
139 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700140 logging._levelToName.clear()
141 logging._levelToName.update(self.saved_level_to_name)
142 logging._nameToLevel.clear()
143 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000144 logging._handlers.clear()
145 logging._handlers.update(self.saved_handlers)
146 logging._handlerList[:] = self.saved_handler_list
147 loggerDict = logging.getLogger().manager.loggerDict
148 loggerDict.clear()
149 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000150 logger_states = self.logger_states
151 for name in self.logger_states:
152 if logger_states[name] is not None:
153 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000154 finally:
155 logging._releaseLock()
156
Vinay Sajip4ded5512012-10-02 15:56:16 +0100157 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000158 """Match the collected log lines against the regular expression
159 self.expected_log_pat, and compare the extracted group values to
160 the expected_values list of tuples."""
161 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100162 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300163 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100164 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000165 for actual, expected in zip(actual_lines, expected_values):
166 match = pat.search(actual)
167 if not match:
168 self.fail("Log line does not match expected pattern:\n" +
169 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000170 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000171 s = stream.read()
172 if s:
173 self.fail("Remaining output at end of log stream:\n" + s)
174
175 def next_message(self):
176 """Generate a message consisting solely of an auto-incrementing
177 integer."""
178 self.message_num += 1
179 return "%d" % self.message_num
180
181
182class BuiltinLevelsTest(BaseTest):
183 """Test builtin levels and their inheritance."""
184
185 def test_flat(self):
186 #Logging levels in a flat logger namespace.
187 m = self.next_message
188
189 ERR = logging.getLogger("ERR")
190 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000191 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000192 INF.setLevel(logging.INFO)
193 DEB = logging.getLogger("DEB")
194 DEB.setLevel(logging.DEBUG)
195
196 # These should log.
197 ERR.log(logging.CRITICAL, m())
198 ERR.error(m())
199
200 INF.log(logging.CRITICAL, m())
201 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 INF.info(m())
204
205 DEB.log(logging.CRITICAL, m())
206 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 DEB.warning(m())
208 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000209 DEB.debug(m())
210
211 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100212 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000213 ERR.info(m())
214 ERR.debug(m())
215
216 INF.debug(m())
217
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000218 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000219 ('ERR', 'CRITICAL', '1'),
220 ('ERR', 'ERROR', '2'),
221 ('INF', 'CRITICAL', '3'),
222 ('INF', 'ERROR', '4'),
223 ('INF', 'WARNING', '5'),
224 ('INF', 'INFO', '6'),
225 ('DEB', 'CRITICAL', '7'),
226 ('DEB', 'ERROR', '8'),
227 ('DEB', 'WARNING', '9'),
228 ('DEB', 'INFO', '10'),
229 ('DEB', 'DEBUG', '11'),
230 ])
231
232 def test_nested_explicit(self):
233 # Logging levels in a nested namespace, all explicitly set.
234 m = self.next_message
235
236 INF = logging.getLogger("INF")
237 INF.setLevel(logging.INFO)
238 INF_ERR = logging.getLogger("INF.ERR")
239 INF_ERR.setLevel(logging.ERROR)
240
241 # These should log.
242 INF_ERR.log(logging.CRITICAL, m())
243 INF_ERR.error(m())
244
245 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100246 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000247 INF_ERR.info(m())
248 INF_ERR.debug(m())
249
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000250 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000251 ('INF.ERR', 'CRITICAL', '1'),
252 ('INF.ERR', 'ERROR', '2'),
253 ])
254
255 def test_nested_inherited(self):
256 #Logging levels in a nested namespace, inherited from parent loggers.
257 m = self.next_message
258
259 INF = logging.getLogger("INF")
260 INF.setLevel(logging.INFO)
261 INF_ERR = logging.getLogger("INF.ERR")
262 INF_ERR.setLevel(logging.ERROR)
263 INF_UNDEF = logging.getLogger("INF.UNDEF")
264 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
265 UNDEF = logging.getLogger("UNDEF")
266
267 # These should log.
268 INF_UNDEF.log(logging.CRITICAL, m())
269 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100270 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000271 INF_UNDEF.info(m())
272 INF_ERR_UNDEF.log(logging.CRITICAL, m())
273 INF_ERR_UNDEF.error(m())
274
275 # These should not log.
276 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100277 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000278 INF_ERR_UNDEF.info(m())
279 INF_ERR_UNDEF.debug(m())
280
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000281 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000282 ('INF.UNDEF', 'CRITICAL', '1'),
283 ('INF.UNDEF', 'ERROR', '2'),
284 ('INF.UNDEF', 'WARNING', '3'),
285 ('INF.UNDEF', 'INFO', '4'),
286 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
287 ('INF.ERR.UNDEF', 'ERROR', '6'),
288 ])
289
290 def test_nested_with_virtual_parent(self):
291 # Logging levels when some parent does not exist yet.
292 m = self.next_message
293
294 INF = logging.getLogger("INF")
295 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
296 CHILD = logging.getLogger("INF.BADPARENT")
297 INF.setLevel(logging.INFO)
298
299 # These should log.
300 GRANDCHILD.log(logging.FATAL, m())
301 GRANDCHILD.info(m())
302 CHILD.log(logging.FATAL, m())
303 CHILD.info(m())
304
305 # These should not log.
306 GRANDCHILD.debug(m())
307 CHILD.debug(m())
308
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000309 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000310 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
311 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
312 ('INF.BADPARENT', 'CRITICAL', '3'),
313 ('INF.BADPARENT', 'INFO', '4'),
314 ])
315
316
317class BasicFilterTest(BaseTest):
318
319 """Test the bundled Filter class."""
320
321 def test_filter(self):
322 # Only messages satisfying the specified criteria pass through the
323 # filter.
324 filter_ = logging.Filter("spam.eggs")
325 handler = self.root_logger.handlers[0]
326 try:
327 handler.addFilter(filter_)
328 spam = logging.getLogger("spam")
329 spam_eggs = logging.getLogger("spam.eggs")
330 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
331 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
332
333 spam.info(self.next_message())
334 spam_eggs.info(self.next_message()) # Good.
335 spam_eggs_fish.info(self.next_message()) # Good.
336 spam_bakedbeans.info(self.next_message())
337
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000338 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000339 ('spam.eggs', 'INFO', '2'),
340 ('spam.eggs.fish', 'INFO', '3'),
341 ])
342 finally:
343 handler.removeFilter(filter_)
344
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000345 def test_callable_filter(self):
346 # Only messages satisfying the specified criteria pass through the
347 # filter.
348
349 def filterfunc(record):
350 parts = record.name.split('.')
351 prefix = '.'.join(parts[:2])
352 return prefix == 'spam.eggs'
353
354 handler = self.root_logger.handlers[0]
355 try:
356 handler.addFilter(filterfunc)
357 spam = logging.getLogger("spam")
358 spam_eggs = logging.getLogger("spam.eggs")
359 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
360 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
361
362 spam.info(self.next_message())
363 spam_eggs.info(self.next_message()) # Good.
364 spam_eggs_fish.info(self.next_message()) # Good.
365 spam_bakedbeans.info(self.next_message())
366
367 self.assert_log_lines([
368 ('spam.eggs', 'INFO', '2'),
369 ('spam.eggs.fish', 'INFO', '3'),
370 ])
371 finally:
372 handler.removeFilter(filterfunc)
373
Vinay Sajip985ef872011-04-26 19:34:04 +0100374 def test_empty_filter(self):
375 f = logging.Filter()
376 r = logging.makeLogRecord({'name': 'spam.eggs'})
377 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000378
379#
380# First, we define our levels. There can be as many as you want - the only
381# limitations are that they should be integers, the lowest should be > 0 and
382# larger values mean less information being logged. If you need specific
383# level values which do not fit into these limitations, you can use a
384# mapping dictionary to convert between your application levels and the
385# logging system.
386#
387SILENT = 120
388TACITURN = 119
389TERSE = 118
390EFFUSIVE = 117
391SOCIABLE = 116
392VERBOSE = 115
393TALKATIVE = 114
394GARRULOUS = 113
395CHATTERBOX = 112
396BORING = 111
397
398LEVEL_RANGE = range(BORING, SILENT + 1)
399
400#
401# Next, we define names for our levels. You don't need to do this - in which
402# case the system will use "Level n" to denote the text for the level.
403#
404my_logging_levels = {
405 SILENT : 'Silent',
406 TACITURN : 'Taciturn',
407 TERSE : 'Terse',
408 EFFUSIVE : 'Effusive',
409 SOCIABLE : 'Sociable',
410 VERBOSE : 'Verbose',
411 TALKATIVE : 'Talkative',
412 GARRULOUS : 'Garrulous',
413 CHATTERBOX : 'Chatterbox',
414 BORING : 'Boring',
415}
416
417class GarrulousFilter(logging.Filter):
418
419 """A filter which blocks garrulous messages."""
420
421 def filter(self, record):
422 return record.levelno != GARRULOUS
423
424class VerySpecificFilter(logging.Filter):
425
426 """A filter which blocks sociable and taciturn messages."""
427
428 def filter(self, record):
429 return record.levelno not in [SOCIABLE, TACITURN]
430
431
432class CustomLevelsAndFiltersTest(BaseTest):
433
434 """Test various filtering possibilities with custom logging levels."""
435
436 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300437 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000438
439 def setUp(self):
440 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000441 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000442 logging.addLevelName(k, v)
443
444 def log_at_all_levels(self, logger):
445 for lvl in LEVEL_RANGE:
446 logger.log(lvl, self.next_message())
447
448 def test_logger_filter(self):
449 # Filter at logger level.
450 self.root_logger.setLevel(VERBOSE)
451 # Levels >= 'Verbose' are good.
452 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000453 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000454 ('Verbose', '5'),
455 ('Sociable', '6'),
456 ('Effusive', '7'),
457 ('Terse', '8'),
458 ('Taciturn', '9'),
459 ('Silent', '10'),
460 ])
461
462 def test_handler_filter(self):
463 # Filter at handler level.
464 self.root_logger.handlers[0].setLevel(SOCIABLE)
465 try:
466 # Levels >= 'Sociable' are good.
467 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000468 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000469 ('Sociable', '6'),
470 ('Effusive', '7'),
471 ('Terse', '8'),
472 ('Taciturn', '9'),
473 ('Silent', '10'),
474 ])
475 finally:
476 self.root_logger.handlers[0].setLevel(logging.NOTSET)
477
478 def test_specific_filters(self):
479 # Set a specific filter object on the handler, and then add another
480 # filter object on the logger itself.
481 handler = self.root_logger.handlers[0]
482 specific_filter = None
483 garr = GarrulousFilter()
484 handler.addFilter(garr)
485 try:
486 self.log_at_all_levels(self.root_logger)
487 first_lines = [
488 # Notice how 'Garrulous' is missing
489 ('Boring', '1'),
490 ('Chatterbox', '2'),
491 ('Talkative', '4'),
492 ('Verbose', '5'),
493 ('Sociable', '6'),
494 ('Effusive', '7'),
495 ('Terse', '8'),
496 ('Taciturn', '9'),
497 ('Silent', '10'),
498 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000499 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000500
501 specific_filter = VerySpecificFilter()
502 self.root_logger.addFilter(specific_filter)
503 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000504 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000505 # Not only 'Garrulous' is still missing, but also 'Sociable'
506 # and 'Taciturn'
507 ('Boring', '11'),
508 ('Chatterbox', '12'),
509 ('Talkative', '14'),
510 ('Verbose', '15'),
511 ('Effusive', '17'),
512 ('Terse', '18'),
513 ('Silent', '20'),
514 ])
515 finally:
516 if specific_filter:
517 self.root_logger.removeFilter(specific_filter)
518 handler.removeFilter(garr)
519
520
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100521class HandlerTest(BaseTest):
522 def test_name(self):
523 h = logging.Handler()
524 h.name = 'generic'
525 self.assertEqual(h.name, 'generic')
526 h.name = 'anothergeneric'
527 self.assertEqual(h.name, 'anothergeneric')
528 self.assertRaises(NotImplementedError, h.emit, None)
529
Vinay Sajip5a35b062011-04-27 11:31:14 +0100530 def test_builtin_handlers(self):
531 # We can't actually *use* too many handlers in the tests,
532 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200533 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100534 for existing in (True, False):
535 fd, fn = tempfile.mkstemp()
536 os.close(fd)
537 if not existing:
538 os.unlink(fn)
539 h = logging.handlers.WatchedFileHandler(fn, delay=True)
540 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100541 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100542 self.assertEqual(dev, -1)
543 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100544 r = logging.makeLogRecord({'msg': 'Test'})
545 h.handle(r)
546 # Now remove the file.
547 os.unlink(fn)
548 self.assertFalse(os.path.exists(fn))
549 # The next call should recreate the file.
550 h.handle(r)
551 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100552 else:
553 self.assertEqual(h.dev, -1)
554 self.assertEqual(h.ino, -1)
555 h.close()
556 if existing:
557 os.unlink(fn)
558 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100559 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100560 else:
561 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100562 try:
563 h = logging.handlers.SysLogHandler(sockname)
564 self.assertEqual(h.facility, h.LOG_USER)
565 self.assertTrue(h.unixsocket)
566 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200567 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100568 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100569 for method in ('GET', 'POST', 'PUT'):
570 if method == 'PUT':
571 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
572 'localhost', '/log', method)
573 else:
574 h = logging.handlers.HTTPHandler('localhost', '/log', method)
575 h.close()
576 h = logging.handlers.BufferingHandler(0)
577 r = logging.makeLogRecord({})
578 self.assertTrue(h.shouldFlush(r))
579 h.close()
580 h = logging.handlers.BufferingHandler(1)
581 self.assertFalse(h.shouldFlush(r))
582 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100583
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100584 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100585 @unittest.skipUnless(threading, 'Threading required for this test.')
586 def test_race(self):
587 # Issue #14632 refers.
588 def remove_loop(fname, tries):
589 for _ in range(tries):
590 try:
591 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000592 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100593 except OSError:
594 pass
595 time.sleep(0.004 * random.randint(0, 4))
596
Vinay Sajipc94871a2012-04-25 10:51:35 +0100597 del_count = 500
598 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100599
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000600 self.handle_time = None
601 self.deletion_time = None
602
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100604 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
605 os.close(fd)
606 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
607 remover.daemon = True
608 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100609 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100610 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
611 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100612 try:
613 for _ in range(log_count):
614 time.sleep(0.005)
615 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000616 try:
617 self.handle_time = time.time()
618 h.handle(r)
619 except Exception:
620 print('Deleted at %s, '
621 'opened at %s' % (self.deletion_time,
622 self.handle_time))
623 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100624 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100625 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100626 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100627 if os.path.exists(fn):
628 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100629
630
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100631class BadStream(object):
632 def write(self, data):
633 raise RuntimeError('deliberate mistake')
634
635class TestStreamHandler(logging.StreamHandler):
636 def handleError(self, record):
637 self.error_record = record
638
639class StreamHandlerTest(BaseTest):
640 def test_error_handling(self):
641 h = TestStreamHandler(BadStream())
642 r = logging.makeLogRecord({})
643 old_raise = logging.raiseExceptions
Vinay Sajip985ef872011-04-26 19:34:04 +0100644 old_stderr = sys.stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100645 try:
646 h.handle(r)
647 self.assertIs(h.error_record, r)
Vinay Sajip985ef872011-04-26 19:34:04 +0100648 h = logging.StreamHandler(BadStream())
649 sys.stderr = sio = io.StringIO()
650 h.handle(r)
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100651 self.assertIn('\nRuntimeError: deliberate mistake\n',
652 sio.getvalue())
Vinay Sajip985ef872011-04-26 19:34:04 +0100653 logging.raiseExceptions = False
654 sys.stderr = sio = io.StringIO()
655 h.handle(r)
656 self.assertEqual('', sio.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100657 finally:
658 logging.raiseExceptions = old_raise
Vinay Sajip985ef872011-04-26 19:34:04 +0100659 sys.stderr = old_stderr
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100660
Vinay Sajip7367d082011-05-02 13:17:27 +0100661# -- The following section could be moved into a server_helper.py module
662# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100663
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100665 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100666 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100667 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100668
Vinay Sajipce7c9782011-05-17 07:15:53 +0100669 :param addr: A (host, port) tuple which the server listens on.
670 You can specify a port value of zero: the server's
671 *port* attribute will hold the actual port number
672 used, which can be used in client connections.
673 :param handler: A callable which will be called to process
674 incoming messages. The handler will be passed
675 the client address tuple, who the message is from,
676 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100677 :param poll_interval: The interval, in seconds, used in the underlying
678 :func:`select` or :func:`poll` call by
679 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100680 :param sockmap: A dictionary which will be used to hold
681 :class:`asyncore.dispatcher` instances used by
682 :func:`asyncore.loop`. This avoids changing the
683 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100684 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100685
686 def __init__(self, addr, handler, poll_interval, sockmap):
Vinay Sajip30298b42013-06-07 15:21:41 +0100687 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap)
688 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 self._handler = handler
690 self._thread = None
691 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 def process_message(self, peer, mailfrom, rcpttos, data):
694 """
695 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100696
Vinay Sajipce7c9782011-05-17 07:15:53 +0100697 Typically, this will be a test case method.
698 :param peer: The client (host, port) tuple.
699 :param mailfrom: The address of the sender.
700 :param rcpttos: The addresses of the recipients.
701 :param data: The message.
702 """
703 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100704
Vinay Sajipce7c9782011-05-17 07:15:53 +0100705 def start(self):
706 """
707 Start the server running on a separate daemon thread.
708 """
709 self._thread = t = threading.Thread(target=self.serve_forever,
710 args=(self.poll_interval,))
711 t.setDaemon(True)
712 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100713
Vinay Sajipce7c9782011-05-17 07:15:53 +0100714 def serve_forever(self, poll_interval):
715 """
716 Run the :mod:`asyncore` loop until normal termination
717 conditions arise.
718 :param poll_interval: The interval, in seconds, used in the underlying
719 :func:`select` or :func:`poll` call by
720 :func:`asyncore.loop`.
721 """
722 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100723 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200724 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100725 # On FreeBSD 8, closing the server repeatably
726 # raises this error. We swallow it if the
727 # server has been closed.
728 if self.connected or self.accepting:
729 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100730
Vinay Sajipce7c9782011-05-17 07:15:53 +0100731 def stop(self, timeout=None):
732 """
733 Stop the thread by closing the server instance.
734 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100735
Vinay Sajipce7c9782011-05-17 07:15:53 +0100736 :param timeout: How long to wait for the server thread
737 to terminate.
738 """
739 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100740 self._thread.join(timeout)
741 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100742
Vinay Sajipce7c9782011-05-17 07:15:53 +0100743 class ControlMixin(object):
744 """
745 This mixin is used to start a server on a separate thread, and
746 shut it down programmatically. Request handling is simplified - instead
747 of needing to derive a suitable RequestHandler subclass, you just
748 provide a callable which will be passed each received request to be
749 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100750
Vinay Sajipce7c9782011-05-17 07:15:53 +0100751 :param handler: A handler callable which will be called with a
752 single parameter - the request - in order to
753 process the request. This handler is called on the
754 server thread, effectively meaning that requests are
755 processed serially. While not quite Web scale ;-),
756 this should be fine for testing applications.
757 :param poll_interval: The polling interval in seconds.
758 """
759 def __init__(self, handler, poll_interval):
760 self._thread = None
761 self.poll_interval = poll_interval
762 self._handler = handler
763 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100764
Vinay Sajipce7c9782011-05-17 07:15:53 +0100765 def start(self):
766 """
767 Create a daemon thread to run the server, and start it.
768 """
769 self._thread = t = threading.Thread(target=self.serve_forever,
770 args=(self.poll_interval,))
771 t.setDaemon(True)
772 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100773
Vinay Sajipce7c9782011-05-17 07:15:53 +0100774 def serve_forever(self, poll_interval):
775 """
776 Run the server. Set the ready flag before entering the
777 service loop.
778 """
779 self.ready.set()
780 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 def stop(self, timeout=None):
783 """
784 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100785
Vinay Sajipce7c9782011-05-17 07:15:53 +0100786 :param timeout: How long to wait for the server thread
787 to terminate.
788 """
789 self.shutdown()
790 if self._thread is not None:
791 self._thread.join(timeout)
792 self._thread = None
793 self.server_close()
794 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 class TestHTTPServer(ControlMixin, HTTPServer):
797 """
798 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Vinay Sajipce7c9782011-05-17 07:15:53 +0100800 :param addr: A tuple with the IP address and port to listen on.
801 :param handler: A handler callable which will be called with a
802 single parameter - the request - in order to
803 process the request.
804 :param poll_interval: The polling interval in seconds.
805 :param log: Pass ``True`` to enable log messages.
806 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100807 def __init__(self, addr, handler, poll_interval=0.5,
808 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100809 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
810 def __getattr__(self, name, default=None):
811 if name.startswith('do_'):
812 return self.process_request
813 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100814
Vinay Sajipce7c9782011-05-17 07:15:53 +0100815 def process_request(self):
816 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100817
Vinay Sajipce7c9782011-05-17 07:15:53 +0100818 def log_message(self, format, *args):
819 if log:
820 super(DelegatingHTTPRequestHandler,
821 self).log_message(format, *args)
822 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
823 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100824 self.sslctx = sslctx
825
826 def get_request(self):
827 try:
828 sock, addr = self.socket.accept()
829 if self.sslctx:
830 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200831 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100832 # socket errors are silenced by the caller, print them here
833 sys.stderr.write("Got an error:\n%s\n" % e)
834 raise
835 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 class TestTCPServer(ControlMixin, ThreadingTCPServer):
838 """
839 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100840
Vinay Sajipce7c9782011-05-17 07:15:53 +0100841 :param addr: A tuple with the IP address and port to listen on.
842 :param handler: A handler callable which will be called with a single
843 parameter - the request - in order to process the request.
844 :param poll_interval: The polling interval in seconds.
845 :bind_and_activate: If True (the default), binds the server and starts it
846 listening. If False, you need to call
847 :meth:`server_bind` and :meth:`server_activate` at
848 some later time before calling :meth:`start`, so that
849 the server will set up the socket and listen on it.
850 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Vinay Sajipce7c9782011-05-17 07:15:53 +0100852 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100853
Vinay Sajipce7c9782011-05-17 07:15:53 +0100854 def __init__(self, addr, handler, poll_interval=0.5,
855 bind_and_activate=True):
856 class DelegatingTCPRequestHandler(StreamRequestHandler):
857
858 def handle(self):
859 self.server._handler(self)
860 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
861 bind_and_activate)
862 ControlMixin.__init__(self, handler, poll_interval)
863
864 def server_bind(self):
865 super(TestTCPServer, self).server_bind()
866 self.port = self.socket.getsockname()[1]
867
Vinay Sajip5421f352013-09-27 18:18:28 +0100868 class TestUnixStreamServer(TestTCPServer):
869 address_family = socket.AF_UNIX
870
Vinay Sajipce7c9782011-05-17 07:15:53 +0100871 class TestUDPServer(ControlMixin, ThreadingUDPServer):
872 """
873 A UDP server which is controllable using :class:`ControlMixin`.
874
875 :param addr: A tuple with the IP address and port to listen on.
876 :param handler: A handler callable which will be called with a
877 single parameter - the request - in order to
878 process the request.
879 :param poll_interval: The polling interval for shutdown requests,
880 in seconds.
881 :bind_and_activate: If True (the default), binds the server and
882 starts it listening. If False, you need to
883 call :meth:`server_bind` and
884 :meth:`server_activate` at some later time
885 before calling :meth:`start`, so that the server will
886 set up the socket and listen on it.
887 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100888 def __init__(self, addr, handler, poll_interval=0.5,
889 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100890 class DelegatingUDPRequestHandler(DatagramRequestHandler):
891
892 def handle(self):
893 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100894
895 def finish(self):
896 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100897 if data:
898 try:
899 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200900 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100901 if not self.server._closed:
902 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100903
Vinay Sajip3ef12292011-05-23 23:00:42 +0100904 ThreadingUDPServer.__init__(self, addr,
905 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906 bind_and_activate)
907 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100908 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100909
910 def server_bind(self):
911 super(TestUDPServer, self).server_bind()
912 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100913
Vinay Sajipba980db2011-05-23 21:37:54 +0100914 def server_close(self):
915 super(TestUDPServer, self).server_close()
916 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100917
Vinay Sajip5421f352013-09-27 18:18:28 +0100918 class TestUnixDatagramServer(TestUDPServer):
919 address_family = socket.AF_UNIX
920
Vinay Sajip7367d082011-05-02 13:17:27 +0100921# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100922
Vinay Sajipce7c9782011-05-17 07:15:53 +0100923@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100924class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000925 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100926 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100927 sockmap = {}
928 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
929 sockmap)
930 server.start()
931 addr = ('localhost', server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000932 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
933 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100934 self.assertEqual(h.toaddrs, ['you'])
935 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100936 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100937 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100938 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000939 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100940 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000941 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100942 self.assertEqual(len(self.messages), 1)
943 peer, mailfrom, rcpttos, data = self.messages[0]
944 self.assertEqual(mailfrom, 'me')
945 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100946 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100947 self.assertTrue(data.endswith('\n\nHello'))
948 h.close()
949
950 def process_message(self, *args):
951 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100952 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100953
Christian Heimes180510d2008-03-03 19:15:45 +0000954class MemoryHandlerTest(BaseTest):
955
956 """Tests for the MemoryHandler."""
957
958 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300959 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000960
961 def setUp(self):
962 BaseTest.setUp(self)
963 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
964 self.root_hdlr)
965 self.mem_logger = logging.getLogger('mem')
966 self.mem_logger.propagate = 0
967 self.mem_logger.addHandler(self.mem_hdlr)
968
969 def tearDown(self):
970 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000971 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000972
973 def test_flush(self):
974 # The memory handler flushes to its target handler based on specific
975 # criteria (message count and message level).
976 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000977 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000978 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000979 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000980 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100981 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000982 lines = [
983 ('DEBUG', '1'),
984 ('INFO', '2'),
985 ('WARNING', '3'),
986 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000987 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000988 for n in (4, 14):
989 for i in range(9):
990 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000991 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000992 # This will flush because it's the 10th message since the last
993 # flush.
994 self.mem_logger.debug(self.next_message())
995 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000996 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000997
998 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000999 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001000
1001
1002class ExceptionFormatter(logging.Formatter):
1003 """A special exception formatter."""
1004 def formatException(self, ei):
1005 return "Got a [%s]" % ei[0].__name__
1006
1007
1008class ConfigFileTest(BaseTest):
1009
1010 """Reading logging config from a .ini-style config file."""
1011
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001012 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001013
1014 # config0 is a standard configuration.
1015 config0 = """
1016 [loggers]
1017 keys=root
1018
1019 [handlers]
1020 keys=hand1
1021
1022 [formatters]
1023 keys=form1
1024
1025 [logger_root]
1026 level=WARNING
1027 handlers=hand1
1028
1029 [handler_hand1]
1030 class=StreamHandler
1031 level=NOTSET
1032 formatter=form1
1033 args=(sys.stdout,)
1034
1035 [formatter_form1]
1036 format=%(levelname)s ++ %(message)s
1037 datefmt=
1038 """
1039
1040 # config1 adds a little to the standard configuration.
1041 config1 = """
1042 [loggers]
1043 keys=root,parser
1044
1045 [handlers]
1046 keys=hand1
1047
1048 [formatters]
1049 keys=form1
1050
1051 [logger_root]
1052 level=WARNING
1053 handlers=
1054
1055 [logger_parser]
1056 level=DEBUG
1057 handlers=hand1
1058 propagate=1
1059 qualname=compiler.parser
1060
1061 [handler_hand1]
1062 class=StreamHandler
1063 level=NOTSET
1064 formatter=form1
1065 args=(sys.stdout,)
1066
1067 [formatter_form1]
1068 format=%(levelname)s ++ %(message)s
1069 datefmt=
1070 """
1071
Vinay Sajip3f84b072011-03-07 17:49:33 +00001072 # config1a moves the handler to the root.
1073 config1a = """
1074 [loggers]
1075 keys=root,parser
1076
1077 [handlers]
1078 keys=hand1
1079
1080 [formatters]
1081 keys=form1
1082
1083 [logger_root]
1084 level=WARNING
1085 handlers=hand1
1086
1087 [logger_parser]
1088 level=DEBUG
1089 handlers=
1090 propagate=1
1091 qualname=compiler.parser
1092
1093 [handler_hand1]
1094 class=StreamHandler
1095 level=NOTSET
1096 formatter=form1
1097 args=(sys.stdout,)
1098
1099 [formatter_form1]
1100 format=%(levelname)s ++ %(message)s
1101 datefmt=
1102 """
1103
Christian Heimes180510d2008-03-03 19:15:45 +00001104 # config2 has a subtle configuration error that should be reported
1105 config2 = config1.replace("sys.stdout", "sys.stbout")
1106
1107 # config3 has a less subtle configuration error
1108 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1109
1110 # config4 specifies a custom formatter class to be loaded
1111 config4 = """
1112 [loggers]
1113 keys=root
1114
1115 [handlers]
1116 keys=hand1
1117
1118 [formatters]
1119 keys=form1
1120
1121 [logger_root]
1122 level=NOTSET
1123 handlers=hand1
1124
1125 [handler_hand1]
1126 class=StreamHandler
1127 level=NOTSET
1128 formatter=form1
1129 args=(sys.stdout,)
1130
1131 [formatter_form1]
1132 class=""" + __name__ + """.ExceptionFormatter
1133 format=%(levelname)s:%(name)s:%(message)s
1134 datefmt=
1135 """
1136
Georg Brandl3dbca812008-07-23 16:10:53 +00001137 # config5 specifies a custom handler class to be loaded
1138 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1139
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001140 # config6 uses ', ' delimiters in the handlers and formatters sections
1141 config6 = """
1142 [loggers]
1143 keys=root,parser
1144
1145 [handlers]
1146 keys=hand1, hand2
1147
1148 [formatters]
1149 keys=form1, form2
1150
1151 [logger_root]
1152 level=WARNING
1153 handlers=
1154
1155 [logger_parser]
1156 level=DEBUG
1157 handlers=hand1
1158 propagate=1
1159 qualname=compiler.parser
1160
1161 [handler_hand1]
1162 class=StreamHandler
1163 level=NOTSET
1164 formatter=form1
1165 args=(sys.stdout,)
1166
1167 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001168 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001169 level=NOTSET
1170 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001171 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001172
1173 [formatter_form1]
1174 format=%(levelname)s ++ %(message)s
1175 datefmt=
1176
1177 [formatter_form2]
1178 format=%(message)s
1179 datefmt=
1180 """
1181
Vinay Sajip3f84b072011-03-07 17:49:33 +00001182 # config7 adds a compiler logger.
1183 config7 = """
1184 [loggers]
1185 keys=root,parser,compiler
1186
1187 [handlers]
1188 keys=hand1
1189
1190 [formatters]
1191 keys=form1
1192
1193 [logger_root]
1194 level=WARNING
1195 handlers=hand1
1196
1197 [logger_compiler]
1198 level=DEBUG
1199 handlers=
1200 propagate=1
1201 qualname=compiler
1202
1203 [logger_parser]
1204 level=DEBUG
1205 handlers=
1206 propagate=1
1207 qualname=compiler.parser
1208
1209 [handler_hand1]
1210 class=StreamHandler
1211 level=NOTSET
1212 formatter=form1
1213 args=(sys.stdout,)
1214
1215 [formatter_form1]
1216 format=%(levelname)s ++ %(message)s
1217 datefmt=
1218 """
1219
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001220 disable_test = """
1221 [loggers]
1222 keys=root
1223
1224 [handlers]
1225 keys=screen
1226
1227 [formatters]
1228 keys=
1229
1230 [logger_root]
1231 level=DEBUG
1232 handlers=screen
1233
1234 [handler_screen]
1235 level=DEBUG
1236 class=StreamHandler
1237 args=(sys.stdout,)
1238 formatter=
1239 """
1240
1241 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001242 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001243 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001244
1245 def test_config0_ok(self):
1246 # A simple config file which overrides the default settings.
1247 with captured_stdout() as output:
1248 self.apply_config(self.config0)
1249 logger = logging.getLogger()
1250 # Won't output anything
1251 logger.info(self.next_message())
1252 # Outputs a message
1253 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001254 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001255 ('ERROR', '2'),
1256 ], stream=output)
1257 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001258 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001259
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001260 def test_config0_using_cp_ok(self):
1261 # A simple config file which overrides the default settings.
1262 with captured_stdout() as output:
1263 file = io.StringIO(textwrap.dedent(self.config0))
1264 cp = configparser.ConfigParser()
1265 cp.read_file(file)
1266 logging.config.fileConfig(cp)
1267 logger = logging.getLogger()
1268 # Won't output anything
1269 logger.info(self.next_message())
1270 # Outputs a message
1271 logger.error(self.next_message())
1272 self.assert_log_lines([
1273 ('ERROR', '2'),
1274 ], stream=output)
1275 # Original logger output is empty.
1276 self.assert_log_lines([])
1277
Georg Brandl3dbca812008-07-23 16:10:53 +00001278 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001279 # A config file defining a sub-parser as well.
1280 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001281 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001282 logger = logging.getLogger("compiler.parser")
1283 # Both will output a message
1284 logger.info(self.next_message())
1285 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001286 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001287 ('INFO', '1'),
1288 ('ERROR', '2'),
1289 ], stream=output)
1290 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001291 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001292
1293 def test_config2_failure(self):
1294 # A simple config file which overrides the default settings.
1295 self.assertRaises(Exception, self.apply_config, self.config2)
1296
1297 def test_config3_failure(self):
1298 # A simple config file which overrides the default settings.
1299 self.assertRaises(Exception, self.apply_config, self.config3)
1300
1301 def test_config4_ok(self):
1302 # A config file specifying a custom formatter class.
1303 with captured_stdout() as output:
1304 self.apply_config(self.config4)
1305 logger = logging.getLogger()
1306 try:
1307 raise RuntimeError()
1308 except RuntimeError:
1309 logging.exception("just testing")
1310 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001311 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001312 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1313 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001314 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001315
Georg Brandl3dbca812008-07-23 16:10:53 +00001316 def test_config5_ok(self):
1317 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001318
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001319 def test_config6_ok(self):
1320 self.test_config1_ok(config=self.config6)
1321
Vinay Sajip3f84b072011-03-07 17:49:33 +00001322 def test_config7_ok(self):
1323 with captured_stdout() as output:
1324 self.apply_config(self.config1a)
1325 logger = logging.getLogger("compiler.parser")
1326 # See issue #11424. compiler-hyphenated sorts
1327 # between compiler and compiler.xyz and this
1328 # was preventing compiler.xyz from being included
1329 # in the child loggers of compiler because of an
1330 # overzealous loop termination condition.
1331 hyphenated = logging.getLogger('compiler-hyphenated')
1332 # All will output a message
1333 logger.info(self.next_message())
1334 logger.error(self.next_message())
1335 hyphenated.critical(self.next_message())
1336 self.assert_log_lines([
1337 ('INFO', '1'),
1338 ('ERROR', '2'),
1339 ('CRITICAL', '3'),
1340 ], stream=output)
1341 # Original logger output is empty.
1342 self.assert_log_lines([])
1343 with captured_stdout() as output:
1344 self.apply_config(self.config7)
1345 logger = logging.getLogger("compiler.parser")
1346 self.assertFalse(logger.disabled)
1347 # Both will output a message
1348 logger.info(self.next_message())
1349 logger.error(self.next_message())
1350 logger = logging.getLogger("compiler.lexer")
1351 # Both will output a message
1352 logger.info(self.next_message())
1353 logger.error(self.next_message())
1354 # Will not appear
1355 hyphenated.critical(self.next_message())
1356 self.assert_log_lines([
1357 ('INFO', '4'),
1358 ('ERROR', '5'),
1359 ('INFO', '6'),
1360 ('ERROR', '7'),
1361 ], stream=output)
1362 # Original logger output is empty.
1363 self.assert_log_lines([])
1364
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001365 def test_logger_disabling(self):
1366 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001367 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001368 self.assertFalse(logger.disabled)
1369 self.apply_config(self.disable_test)
1370 self.assertTrue(logger.disabled)
1371 self.apply_config(self.disable_test, disable_existing_loggers=False)
1372 self.assertFalse(logger.disabled)
1373
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001374
Victor Stinner45df8202010-04-28 22:31:17 +00001375@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001376class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001377
Christian Heimes180510d2008-03-03 19:15:45 +00001378 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001379
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001380 if threading:
1381 server_class = TestTCPServer
1382 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001383
Christian Heimes180510d2008-03-03 19:15:45 +00001384 def setUp(self):
1385 """Set up a TCP server to receive log messages, and a SocketHandler
1386 pointing to that server's address and port."""
1387 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001388 self.server = server = self.server_class(self.address,
1389 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001390 server.start()
1391 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001392 hcls = logging.handlers.SocketHandler
1393 if isinstance(server.server_address, tuple):
1394 self.sock_hdlr = hcls('localhost', server.port)
1395 else:
1396 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001397 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001398 self.root_logger.removeHandler(self.root_logger.handlers[0])
1399 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001400 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001401
Christian Heimes180510d2008-03-03 19:15:45 +00001402 def tearDown(self):
1403 """Shutdown the TCP server."""
1404 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001405 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001406 self.root_logger.removeHandler(self.sock_hdlr)
1407 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001408 finally:
1409 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001410
Vinay Sajip7367d082011-05-02 13:17:27 +01001411 def handle_socket(self, request):
1412 conn = request.connection
1413 while True:
1414 chunk = conn.recv(4)
1415 if len(chunk) < 4:
1416 break
1417 slen = struct.unpack(">L", chunk)[0]
1418 chunk = conn.recv(slen)
1419 while len(chunk) < slen:
1420 chunk = chunk + conn.recv(slen - len(chunk))
1421 obj = pickle.loads(chunk)
1422 record = logging.makeLogRecord(obj)
1423 self.log_output += record.msg + '\n'
1424 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001425
Christian Heimes180510d2008-03-03 19:15:45 +00001426 def test_output(self):
1427 # The log message sent to the SocketHandler is properly received.
1428 logger = logging.getLogger("tcp")
1429 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001430 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001431 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001432 self.handled.acquire()
1433 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001434
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001435 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001436 # Avoid timing-related failures due to SocketHandler's own hard-wired
1437 # one-second timeout on socket.create_connection() (issue #16264).
1438 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001439 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001440 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001441 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001442 try:
1443 raise RuntimeError('Deliberate mistake')
1444 except RuntimeError:
1445 self.root_logger.exception('Never sent')
1446 self.root_logger.error('Never sent, either')
1447 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001448 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001449 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1450 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001451
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001452def _get_temp_domain_socket():
1453 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1454 os.close(fd)
1455 # just need a name - file can't be present, or we'll get an
1456 # 'address already in use' error.
1457 os.remove(fn)
1458 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001459
1460@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001461class UnixSocketHandlerTest(SocketHandlerTest):
1462
1463 """Test for SocketHandler with unix sockets."""
1464
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001465 if threading:
1466 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001467
1468 def setUp(self):
1469 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001470 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001471 SocketHandlerTest.setUp(self)
1472
1473 def tearDown(self):
1474 SocketHandlerTest.tearDown(self)
1475 os.remove(self.address)
1476
1477@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001478class DatagramHandlerTest(BaseTest):
1479
1480 """Test for DatagramHandler."""
1481
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001482 if threading:
1483 server_class = TestUDPServer
1484 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001485
Vinay Sajip7367d082011-05-02 13:17:27 +01001486 def setUp(self):
1487 """Set up a UDP server to receive log messages, and a DatagramHandler
1488 pointing to that server's address and port."""
1489 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001490 self.server = server = self.server_class(self.address,
1491 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001492 server.start()
1493 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001494 hcls = logging.handlers.DatagramHandler
1495 if isinstance(server.server_address, tuple):
1496 self.sock_hdlr = hcls('localhost', server.port)
1497 else:
1498 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 self.log_output = ''
1500 self.root_logger.removeHandler(self.root_logger.handlers[0])
1501 self.root_logger.addHandler(self.sock_hdlr)
1502 self.handled = threading.Event()
1503
1504 def tearDown(self):
1505 """Shutdown the UDP server."""
1506 try:
1507 self.server.stop(2.0)
1508 self.root_logger.removeHandler(self.sock_hdlr)
1509 self.sock_hdlr.close()
1510 finally:
1511 BaseTest.tearDown(self)
1512
1513 def handle_datagram(self, request):
1514 slen = struct.pack('>L', 0) # length of prefix
1515 packet = request.packet[len(slen):]
1516 obj = pickle.loads(packet)
1517 record = logging.makeLogRecord(obj)
1518 self.log_output += record.msg + '\n'
1519 self.handled.set()
1520
1521 def test_output(self):
1522 # The log message sent to the DatagramHandler is properly received.
1523 logger = logging.getLogger("udp")
1524 logger.error("spam")
1525 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001526 self.handled.clear()
1527 logger.error("eggs")
1528 self.handled.wait()
1529 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001530
1531
1532@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001533class UnixDatagramHandlerTest(DatagramHandlerTest):
1534
1535 """Test for DatagramHandler using Unix sockets."""
1536
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001537 if threading:
1538 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001539
1540 def setUp(self):
1541 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001542 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001543 DatagramHandlerTest.setUp(self)
1544
1545 def tearDown(self):
1546 DatagramHandlerTest.tearDown(self)
1547 os.remove(self.address)
1548
1549@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001550class SysLogHandlerTest(BaseTest):
1551
1552 """Test for SysLogHandler using UDP."""
1553
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001554 if threading:
1555 server_class = TestUDPServer
1556 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001557
Vinay Sajip7367d082011-05-02 13:17:27 +01001558 def setUp(self):
1559 """Set up a UDP server to receive log messages, and a SysLogHandler
1560 pointing to that server's address and port."""
1561 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001562 self.server = server = self.server_class(self.address,
1563 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001564 server.start()
1565 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001566 hcls = logging.handlers.SysLogHandler
1567 if isinstance(server.server_address, tuple):
1568 self.sl_hdlr = hcls(('localhost', server.port))
1569 else:
1570 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001571 self.log_output = ''
1572 self.root_logger.removeHandler(self.root_logger.handlers[0])
1573 self.root_logger.addHandler(self.sl_hdlr)
1574 self.handled = threading.Event()
1575
1576 def tearDown(self):
1577 """Shutdown the UDP server."""
1578 try:
1579 self.server.stop(2.0)
1580 self.root_logger.removeHandler(self.sl_hdlr)
1581 self.sl_hdlr.close()
1582 finally:
1583 BaseTest.tearDown(self)
1584
1585 def handle_datagram(self, request):
1586 self.log_output = request.packet
1587 self.handled.set()
1588
1589 def test_output(self):
1590 # The log message sent to the SysLogHandler is properly received.
1591 logger = logging.getLogger("slh")
1592 logger.error("sp\xe4m")
1593 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001594 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001595 self.handled.clear()
1596 self.sl_hdlr.append_nul = False
1597 logger.error("sp\xe4m")
1598 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001599 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001600 self.handled.clear()
1601 self.sl_hdlr.ident = "h\xe4m-"
1602 logger.error("sp\xe4m")
1603 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001604 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001605
1606
1607@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001608class UnixSysLogHandlerTest(SysLogHandlerTest):
1609
1610 """Test for SysLogHandler with Unix sockets."""
1611
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001612 if threading:
1613 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001614
1615 def setUp(self):
1616 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001617 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001618 SysLogHandlerTest.setUp(self)
1619
1620 def tearDown(self):
1621 SysLogHandlerTest.tearDown(self)
1622 os.remove(self.address)
1623
Vinay Sajip5421f352013-09-27 18:18:28 +01001624@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001625class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001626 """Test for HTTPHandler."""
1627
Vinay Sajip9ba87612011-05-21 11:32:15 +01001628 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1629MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1630zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1631aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1632AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16330tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16345LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1635piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16362z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1637i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1638PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1639E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1640rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1641/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1642-----END RSA PRIVATE KEY-----
1643-----BEGIN CERTIFICATE-----
1644MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1645BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1646EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1647xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1648l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1649vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1650BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1651S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1652BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16534f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16541c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1655IRbTpvlHWPjsSvHz0ZOH
1656-----END CERTIFICATE-----"""
1657
Vinay Sajip7367d082011-05-02 13:17:27 +01001658 def setUp(self):
1659 """Set up an HTTP server to receive log messages, and a HTTPHandler
1660 pointing to that server's address and port."""
1661 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001662 self.handled = threading.Event()
1663
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001665 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001666 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001667 if self.command == 'POST':
1668 try:
1669 rlen = int(request.headers['Content-Length'])
1670 self.post_data = request.rfile.read(rlen)
1671 except:
1672 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001673 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001674 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001675 self.handled.set()
1676
1677 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001678 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001680 root_logger = self.root_logger
1681 root_logger.removeHandler(self.root_logger.handlers[0])
1682 for secure in (False, True):
1683 addr = ('localhost', 0)
1684 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001685 try:
1686 import ssl
1687 fd, fn = tempfile.mkstemp()
1688 os.close(fd)
1689 with open(fn, 'w') as f:
1690 f.write(self.PEMFILE)
1691 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1692 sslctx.load_cert_chain(fn)
1693 os.unlink(fn)
1694 except ImportError:
1695 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001696 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001697 sslctx = None
1698 self.server = server = TestHTTPServer(addr, self.handle_request,
1699 0.01, sslctx=sslctx)
1700 server.start()
1701 server.ready.wait()
1702 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001703 secure_client = secure and sslctx
1704 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1705 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001706 self.log_data = None
1707 root_logger.addHandler(self.h_hdlr)
1708
1709 for method in ('GET', 'POST'):
1710 self.h_hdlr.method = method
1711 self.handled.clear()
1712 msg = "sp\xe4m"
1713 logger.error(msg)
1714 self.handled.wait()
1715 self.assertEqual(self.log_data.path, '/frob')
1716 self.assertEqual(self.command, method)
1717 if method == 'GET':
1718 d = parse_qs(self.log_data.query)
1719 else:
1720 d = parse_qs(self.post_data.decode('utf-8'))
1721 self.assertEqual(d['name'], ['http'])
1722 self.assertEqual(d['funcName'], ['test_output'])
1723 self.assertEqual(d['msg'], [msg])
1724
1725 self.server.stop(2.0)
1726 self.root_logger.removeHandler(self.h_hdlr)
1727 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001728
Christian Heimes180510d2008-03-03 19:15:45 +00001729class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001732
Christian Heimes180510d2008-03-03 19:15:45 +00001733 def setUp(self):
1734 """Create a dict to remember potentially destroyed objects."""
1735 BaseTest.setUp(self)
1736 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001737
Christian Heimes180510d2008-03-03 19:15:45 +00001738 def _watch_for_survival(self, *args):
1739 """Watch the given objects for survival, by creating weakrefs to
1740 them."""
1741 for obj in args:
1742 key = id(obj), repr(obj)
1743 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001744
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001745 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001746 """Assert that all objects watched for survival have survived."""
1747 # Trigger cycle breaking.
1748 gc.collect()
1749 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001750 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001751 if ref() is None:
1752 dead.append(repr_)
1753 if dead:
1754 self.fail("%d objects should have survived "
1755 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001756
Christian Heimes180510d2008-03-03 19:15:45 +00001757 def test_persistent_loggers(self):
1758 # Logger objects are persistent and retain their configuration, even
1759 # if visible references are destroyed.
1760 self.root_logger.setLevel(logging.INFO)
1761 foo = logging.getLogger("foo")
1762 self._watch_for_survival(foo)
1763 foo.setLevel(logging.DEBUG)
1764 self.root_logger.debug(self.next_message())
1765 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001766 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001767 ('foo', 'DEBUG', '2'),
1768 ])
1769 del foo
1770 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001771 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001772 # foo has retained its settings.
1773 bar = logging.getLogger("foo")
1774 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001775 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001776 ('foo', 'DEBUG', '2'),
1777 ('foo', 'DEBUG', '3'),
1778 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001779
Benjamin Petersonf91df042009-02-13 02:50:59 +00001780
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001781class EncodingTest(BaseTest):
1782 def test_encoding_plain_file(self):
1783 # In Python 2.x, a plain file object is treated as having no encoding.
1784 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001785 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1786 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001787 # the non-ascii data we write to the log.
1788 data = "foo\x80"
1789 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001790 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001791 log.addHandler(handler)
1792 try:
1793 # write non-ascii data to the log.
1794 log.warning(data)
1795 finally:
1796 log.removeHandler(handler)
1797 handler.close()
1798 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001799 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001800 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001801 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001802 finally:
1803 f.close()
1804 finally:
1805 if os.path.isfile(fn):
1806 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001807
Benjamin Petersonf91df042009-02-13 02:50:59 +00001808 def test_encoding_cyrillic_unicode(self):
1809 log = logging.getLogger("test")
1810 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1811 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1812 #Ensure it's written in a Cyrillic encoding
1813 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001814 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001815 stream = io.BytesIO()
1816 writer = writer_class(stream, 'strict')
1817 handler = logging.StreamHandler(writer)
1818 log.addHandler(handler)
1819 try:
1820 log.warning(message)
1821 finally:
1822 log.removeHandler(handler)
1823 handler.close()
1824 # check we wrote exactly those bytes, ignoring trailing \n etc
1825 s = stream.getvalue()
1826 #Compare against what the data should be when encoded in CP-1251
1827 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1828
1829
Georg Brandlf9734072008-12-07 15:30:06 +00001830class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001831
Georg Brandlf9734072008-12-07 15:30:06 +00001832 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001833 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001834 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001835 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001836 warnings.filterwarnings("always", category=UserWarning)
1837 stream = io.StringIO()
1838 h = logging.StreamHandler(stream)
1839 logger = logging.getLogger("py.warnings")
1840 logger.addHandler(h)
1841 warnings.warn("I'm warning you...")
1842 logger.removeHandler(h)
1843 s = stream.getvalue()
1844 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001845 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001846
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001847 #See if an explicit file uses the original implementation
1848 a_file = io.StringIO()
1849 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1850 a_file, "Dummy line")
1851 s = a_file.getvalue()
1852 a_file.close()
1853 self.assertEqual(s,
1854 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1855
1856 def test_warnings_no_handlers(self):
1857 with warnings.catch_warnings():
1858 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001859 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001860
1861 # confirm our assumption: no loggers are set
1862 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001863 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001864
1865 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001866 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001867 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001868
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001869
1870def formatFunc(format, datefmt=None):
1871 return logging.Formatter(format, datefmt)
1872
1873def handlerFunc():
1874 return logging.StreamHandler()
1875
1876class CustomHandler(logging.StreamHandler):
1877 pass
1878
1879class ConfigDictTest(BaseTest):
1880
1881 """Reading logging config from a dictionary."""
1882
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001883 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001884
1885 # config0 is a standard configuration.
1886 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001887 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001888 'formatters': {
1889 'form1' : {
1890 'format' : '%(levelname)s ++ %(message)s',
1891 },
1892 },
1893 'handlers' : {
1894 'hand1' : {
1895 'class' : 'logging.StreamHandler',
1896 'formatter' : 'form1',
1897 'level' : 'NOTSET',
1898 'stream' : 'ext://sys.stdout',
1899 },
1900 },
1901 'root' : {
1902 'level' : 'WARNING',
1903 'handlers' : ['hand1'],
1904 },
1905 }
1906
1907 # config1 adds a little to the standard configuration.
1908 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001909 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001910 'formatters': {
1911 'form1' : {
1912 'format' : '%(levelname)s ++ %(message)s',
1913 },
1914 },
1915 'handlers' : {
1916 'hand1' : {
1917 'class' : 'logging.StreamHandler',
1918 'formatter' : 'form1',
1919 'level' : 'NOTSET',
1920 'stream' : 'ext://sys.stdout',
1921 },
1922 },
1923 'loggers' : {
1924 'compiler.parser' : {
1925 'level' : 'DEBUG',
1926 'handlers' : ['hand1'],
1927 },
1928 },
1929 'root' : {
1930 'level' : 'WARNING',
1931 },
1932 }
1933
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001934 # config1a moves the handler to the root. Used with config8a
1935 config1a = {
1936 'version': 1,
1937 'formatters': {
1938 'form1' : {
1939 'format' : '%(levelname)s ++ %(message)s',
1940 },
1941 },
1942 'handlers' : {
1943 'hand1' : {
1944 'class' : 'logging.StreamHandler',
1945 'formatter' : 'form1',
1946 'level' : 'NOTSET',
1947 'stream' : 'ext://sys.stdout',
1948 },
1949 },
1950 'loggers' : {
1951 'compiler.parser' : {
1952 'level' : 'DEBUG',
1953 },
1954 },
1955 'root' : {
1956 'level' : 'WARNING',
1957 'handlers' : ['hand1'],
1958 },
1959 }
1960
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001961 # config2 has a subtle configuration error that should be reported
1962 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001963 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001964 'formatters': {
1965 'form1' : {
1966 'format' : '%(levelname)s ++ %(message)s',
1967 },
1968 },
1969 'handlers' : {
1970 'hand1' : {
1971 'class' : 'logging.StreamHandler',
1972 'formatter' : 'form1',
1973 'level' : 'NOTSET',
1974 'stream' : 'ext://sys.stdbout',
1975 },
1976 },
1977 'loggers' : {
1978 'compiler.parser' : {
1979 'level' : 'DEBUG',
1980 'handlers' : ['hand1'],
1981 },
1982 },
1983 'root' : {
1984 'level' : 'WARNING',
1985 },
1986 }
1987
1988 #As config1 but with a misspelt level on a handler
1989 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001990 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001991 'formatters': {
1992 'form1' : {
1993 'format' : '%(levelname)s ++ %(message)s',
1994 },
1995 },
1996 'handlers' : {
1997 'hand1' : {
1998 'class' : 'logging.StreamHandler',
1999 'formatter' : 'form1',
2000 'level' : 'NTOSET',
2001 'stream' : 'ext://sys.stdout',
2002 },
2003 },
2004 'loggers' : {
2005 'compiler.parser' : {
2006 'level' : 'DEBUG',
2007 'handlers' : ['hand1'],
2008 },
2009 },
2010 'root' : {
2011 'level' : 'WARNING',
2012 },
2013 }
2014
2015
2016 #As config1 but with a misspelt level on a logger
2017 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002018 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002019 'formatters': {
2020 'form1' : {
2021 'format' : '%(levelname)s ++ %(message)s',
2022 },
2023 },
2024 'handlers' : {
2025 'hand1' : {
2026 'class' : 'logging.StreamHandler',
2027 'formatter' : 'form1',
2028 'level' : 'NOTSET',
2029 'stream' : 'ext://sys.stdout',
2030 },
2031 },
2032 'loggers' : {
2033 'compiler.parser' : {
2034 'level' : 'DEBUG',
2035 'handlers' : ['hand1'],
2036 },
2037 },
2038 'root' : {
2039 'level' : 'WRANING',
2040 },
2041 }
2042
2043 # config3 has a less subtle configuration error
2044 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002045 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002046 'formatters': {
2047 'form1' : {
2048 'format' : '%(levelname)s ++ %(message)s',
2049 },
2050 },
2051 'handlers' : {
2052 'hand1' : {
2053 'class' : 'logging.StreamHandler',
2054 'formatter' : 'misspelled_name',
2055 'level' : 'NOTSET',
2056 'stream' : 'ext://sys.stdout',
2057 },
2058 },
2059 'loggers' : {
2060 'compiler.parser' : {
2061 'level' : 'DEBUG',
2062 'handlers' : ['hand1'],
2063 },
2064 },
2065 'root' : {
2066 'level' : 'WARNING',
2067 },
2068 }
2069
2070 # config4 specifies a custom formatter class to be loaded
2071 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002072 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002073 'formatters': {
2074 'form1' : {
2075 '()' : __name__ + '.ExceptionFormatter',
2076 'format' : '%(levelname)s:%(name)s:%(message)s',
2077 },
2078 },
2079 'handlers' : {
2080 'hand1' : {
2081 'class' : 'logging.StreamHandler',
2082 'formatter' : 'form1',
2083 'level' : 'NOTSET',
2084 'stream' : 'ext://sys.stdout',
2085 },
2086 },
2087 'root' : {
2088 'level' : 'NOTSET',
2089 'handlers' : ['hand1'],
2090 },
2091 }
2092
2093 # As config4 but using an actual callable rather than a string
2094 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002095 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002096 'formatters': {
2097 'form1' : {
2098 '()' : ExceptionFormatter,
2099 'format' : '%(levelname)s:%(name)s:%(message)s',
2100 },
2101 'form2' : {
2102 '()' : __name__ + '.formatFunc',
2103 'format' : '%(levelname)s:%(name)s:%(message)s',
2104 },
2105 'form3' : {
2106 '()' : formatFunc,
2107 'format' : '%(levelname)s:%(name)s:%(message)s',
2108 },
2109 },
2110 'handlers' : {
2111 'hand1' : {
2112 'class' : 'logging.StreamHandler',
2113 'formatter' : 'form1',
2114 'level' : 'NOTSET',
2115 'stream' : 'ext://sys.stdout',
2116 },
2117 'hand2' : {
2118 '()' : handlerFunc,
2119 },
2120 },
2121 'root' : {
2122 'level' : 'NOTSET',
2123 'handlers' : ['hand1'],
2124 },
2125 }
2126
2127 # config5 specifies a custom handler class to be loaded
2128 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002129 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002130 'formatters': {
2131 'form1' : {
2132 'format' : '%(levelname)s ++ %(message)s',
2133 },
2134 },
2135 'handlers' : {
2136 'hand1' : {
2137 'class' : __name__ + '.CustomHandler',
2138 'formatter' : 'form1',
2139 'level' : 'NOTSET',
2140 'stream' : 'ext://sys.stdout',
2141 },
2142 },
2143 'loggers' : {
2144 'compiler.parser' : {
2145 'level' : 'DEBUG',
2146 'handlers' : ['hand1'],
2147 },
2148 },
2149 'root' : {
2150 'level' : 'WARNING',
2151 },
2152 }
2153
2154 # config6 specifies a custom handler class to be loaded
2155 # but has bad arguments
2156 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002157 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002158 'formatters': {
2159 'form1' : {
2160 'format' : '%(levelname)s ++ %(message)s',
2161 },
2162 },
2163 'handlers' : {
2164 'hand1' : {
2165 'class' : __name__ + '.CustomHandler',
2166 'formatter' : 'form1',
2167 'level' : 'NOTSET',
2168 'stream' : 'ext://sys.stdout',
2169 '9' : 'invalid parameter name',
2170 },
2171 },
2172 'loggers' : {
2173 'compiler.parser' : {
2174 'level' : 'DEBUG',
2175 'handlers' : ['hand1'],
2176 },
2177 },
2178 'root' : {
2179 'level' : 'WARNING',
2180 },
2181 }
2182
2183 #config 7 does not define compiler.parser but defines compiler.lexer
2184 #so compiler.parser should be disabled after applying it
2185 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002186 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002187 'formatters': {
2188 'form1' : {
2189 'format' : '%(levelname)s ++ %(message)s',
2190 },
2191 },
2192 'handlers' : {
2193 'hand1' : {
2194 'class' : 'logging.StreamHandler',
2195 'formatter' : 'form1',
2196 'level' : 'NOTSET',
2197 'stream' : 'ext://sys.stdout',
2198 },
2199 },
2200 'loggers' : {
2201 'compiler.lexer' : {
2202 'level' : 'DEBUG',
2203 'handlers' : ['hand1'],
2204 },
2205 },
2206 'root' : {
2207 'level' : 'WARNING',
2208 },
2209 }
2210
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002211 # config8 defines both compiler and compiler.lexer
2212 # so compiler.parser should not be disabled (since
2213 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002214 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002215 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002216 'disable_existing_loggers' : False,
2217 'formatters': {
2218 'form1' : {
2219 'format' : '%(levelname)s ++ %(message)s',
2220 },
2221 },
2222 'handlers' : {
2223 'hand1' : {
2224 'class' : 'logging.StreamHandler',
2225 'formatter' : 'form1',
2226 'level' : 'NOTSET',
2227 'stream' : 'ext://sys.stdout',
2228 },
2229 },
2230 'loggers' : {
2231 'compiler' : {
2232 'level' : 'DEBUG',
2233 'handlers' : ['hand1'],
2234 },
2235 'compiler.lexer' : {
2236 },
2237 },
2238 'root' : {
2239 'level' : 'WARNING',
2240 },
2241 }
2242
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002243 # config8a disables existing loggers
2244 config8a = {
2245 'version': 1,
2246 'disable_existing_loggers' : True,
2247 'formatters': {
2248 'form1' : {
2249 'format' : '%(levelname)s ++ %(message)s',
2250 },
2251 },
2252 'handlers' : {
2253 'hand1' : {
2254 'class' : 'logging.StreamHandler',
2255 'formatter' : 'form1',
2256 'level' : 'NOTSET',
2257 'stream' : 'ext://sys.stdout',
2258 },
2259 },
2260 'loggers' : {
2261 'compiler' : {
2262 'level' : 'DEBUG',
2263 'handlers' : ['hand1'],
2264 },
2265 'compiler.lexer' : {
2266 },
2267 },
2268 'root' : {
2269 'level' : 'WARNING',
2270 },
2271 }
2272
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002273 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002274 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 'formatters': {
2276 'form1' : {
2277 'format' : '%(levelname)s ++ %(message)s',
2278 },
2279 },
2280 'handlers' : {
2281 'hand1' : {
2282 'class' : 'logging.StreamHandler',
2283 'formatter' : 'form1',
2284 'level' : 'WARNING',
2285 'stream' : 'ext://sys.stdout',
2286 },
2287 },
2288 'loggers' : {
2289 'compiler.parser' : {
2290 'level' : 'WARNING',
2291 'handlers' : ['hand1'],
2292 },
2293 },
2294 'root' : {
2295 'level' : 'NOTSET',
2296 },
2297 }
2298
2299 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002300 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002301 'incremental' : True,
2302 'handlers' : {
2303 'hand1' : {
2304 'level' : 'WARNING',
2305 },
2306 },
2307 'loggers' : {
2308 'compiler.parser' : {
2309 'level' : 'INFO',
2310 },
2311 },
2312 }
2313
2314 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002315 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002316 'incremental' : True,
2317 'handlers' : {
2318 'hand1' : {
2319 'level' : 'INFO',
2320 },
2321 },
2322 'loggers' : {
2323 'compiler.parser' : {
2324 'level' : 'INFO',
2325 },
2326 },
2327 }
2328
2329 #As config1 but with a filter added
2330 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002331 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002332 'formatters': {
2333 'form1' : {
2334 'format' : '%(levelname)s ++ %(message)s',
2335 },
2336 },
2337 'filters' : {
2338 'filt1' : {
2339 'name' : 'compiler.parser',
2340 },
2341 },
2342 'handlers' : {
2343 'hand1' : {
2344 'class' : 'logging.StreamHandler',
2345 'formatter' : 'form1',
2346 'level' : 'NOTSET',
2347 'stream' : 'ext://sys.stdout',
2348 'filters' : ['filt1'],
2349 },
2350 },
2351 'loggers' : {
2352 'compiler.parser' : {
2353 'level' : 'DEBUG',
2354 'filters' : ['filt1'],
2355 },
2356 },
2357 'root' : {
2358 'level' : 'WARNING',
2359 'handlers' : ['hand1'],
2360 },
2361 }
2362
2363 #As config1 but using cfg:// references
2364 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002365 'version': 1,
2366 'true_formatters': {
2367 'form1' : {
2368 'format' : '%(levelname)s ++ %(message)s',
2369 },
2370 },
2371 'handler_configs': {
2372 'hand1' : {
2373 'class' : 'logging.StreamHandler',
2374 'formatter' : 'form1',
2375 'level' : 'NOTSET',
2376 'stream' : 'ext://sys.stdout',
2377 },
2378 },
2379 'formatters' : 'cfg://true_formatters',
2380 'handlers' : {
2381 'hand1' : 'cfg://handler_configs[hand1]',
2382 },
2383 'loggers' : {
2384 'compiler.parser' : {
2385 'level' : 'DEBUG',
2386 'handlers' : ['hand1'],
2387 },
2388 },
2389 'root' : {
2390 'level' : 'WARNING',
2391 },
2392 }
2393
2394 #As config11 but missing the version key
2395 config12 = {
2396 'true_formatters': {
2397 'form1' : {
2398 'format' : '%(levelname)s ++ %(message)s',
2399 },
2400 },
2401 'handler_configs': {
2402 'hand1' : {
2403 'class' : 'logging.StreamHandler',
2404 'formatter' : 'form1',
2405 'level' : 'NOTSET',
2406 'stream' : 'ext://sys.stdout',
2407 },
2408 },
2409 'formatters' : 'cfg://true_formatters',
2410 'handlers' : {
2411 'hand1' : 'cfg://handler_configs[hand1]',
2412 },
2413 'loggers' : {
2414 'compiler.parser' : {
2415 'level' : 'DEBUG',
2416 'handlers' : ['hand1'],
2417 },
2418 },
2419 'root' : {
2420 'level' : 'WARNING',
2421 },
2422 }
2423
2424 #As config11 but using an unsupported version
2425 config13 = {
2426 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002427 'true_formatters': {
2428 'form1' : {
2429 'format' : '%(levelname)s ++ %(message)s',
2430 },
2431 },
2432 'handler_configs': {
2433 'hand1' : {
2434 'class' : 'logging.StreamHandler',
2435 'formatter' : 'form1',
2436 'level' : 'NOTSET',
2437 'stream' : 'ext://sys.stdout',
2438 },
2439 },
2440 'formatters' : 'cfg://true_formatters',
2441 'handlers' : {
2442 'hand1' : 'cfg://handler_configs[hand1]',
2443 },
2444 'loggers' : {
2445 'compiler.parser' : {
2446 'level' : 'DEBUG',
2447 'handlers' : ['hand1'],
2448 },
2449 },
2450 'root' : {
2451 'level' : 'WARNING',
2452 },
2453 }
2454
Vinay Sajip8d270232012-11-15 14:20:18 +00002455 # As config0, but with properties
2456 config14 = {
2457 'version': 1,
2458 'formatters': {
2459 'form1' : {
2460 'format' : '%(levelname)s ++ %(message)s',
2461 },
2462 },
2463 'handlers' : {
2464 'hand1' : {
2465 'class' : 'logging.StreamHandler',
2466 'formatter' : 'form1',
2467 'level' : 'NOTSET',
2468 'stream' : 'ext://sys.stdout',
2469 '.': {
2470 'foo': 'bar',
2471 'terminator': '!\n',
2472 }
2473 },
2474 },
2475 'root' : {
2476 'level' : 'WARNING',
2477 'handlers' : ['hand1'],
2478 },
2479 }
2480
Vinay Sajip3f885b52013-03-22 15:19:54 +00002481 out_of_order = {
2482 "version": 1,
2483 "formatters": {
2484 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002485 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2486 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002487 }
2488 },
2489 "handlers": {
2490 "fileGlobal": {
2491 "class": "logging.StreamHandler",
2492 "level": "DEBUG",
2493 "formatter": "mySimpleFormatter"
2494 },
2495 "bufferGlobal": {
2496 "class": "logging.handlers.MemoryHandler",
2497 "capacity": 5,
2498 "formatter": "mySimpleFormatter",
2499 "target": "fileGlobal",
2500 "level": "DEBUG"
2501 }
2502 },
2503 "loggers": {
2504 "mymodule": {
2505 "level": "DEBUG",
2506 "handlers": ["bufferGlobal"],
2507 "propagate": "true"
2508 }
2509 }
2510 }
2511
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002512 def apply_config(self, conf):
2513 logging.config.dictConfig(conf)
2514
2515 def test_config0_ok(self):
2516 # A simple config which overrides the default settings.
2517 with captured_stdout() as output:
2518 self.apply_config(self.config0)
2519 logger = logging.getLogger()
2520 # Won't output anything
2521 logger.info(self.next_message())
2522 # Outputs a message
2523 logger.error(self.next_message())
2524 self.assert_log_lines([
2525 ('ERROR', '2'),
2526 ], stream=output)
2527 # Original logger output is empty.
2528 self.assert_log_lines([])
2529
2530 def test_config1_ok(self, config=config1):
2531 # A config defining a sub-parser as well.
2532 with captured_stdout() as output:
2533 self.apply_config(config)
2534 logger = logging.getLogger("compiler.parser")
2535 # Both will output a message
2536 logger.info(self.next_message())
2537 logger.error(self.next_message())
2538 self.assert_log_lines([
2539 ('INFO', '1'),
2540 ('ERROR', '2'),
2541 ], stream=output)
2542 # Original logger output is empty.
2543 self.assert_log_lines([])
2544
2545 def test_config2_failure(self):
2546 # A simple config which overrides the default settings.
2547 self.assertRaises(Exception, self.apply_config, self.config2)
2548
2549 def test_config2a_failure(self):
2550 # A simple config which overrides the default settings.
2551 self.assertRaises(Exception, self.apply_config, self.config2a)
2552
2553 def test_config2b_failure(self):
2554 # A simple config which overrides the default settings.
2555 self.assertRaises(Exception, self.apply_config, self.config2b)
2556
2557 def test_config3_failure(self):
2558 # A simple config which overrides the default settings.
2559 self.assertRaises(Exception, self.apply_config, self.config3)
2560
2561 def test_config4_ok(self):
2562 # A config specifying a custom formatter class.
2563 with captured_stdout() as output:
2564 self.apply_config(self.config4)
2565 #logger = logging.getLogger()
2566 try:
2567 raise RuntimeError()
2568 except RuntimeError:
2569 logging.exception("just testing")
2570 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002571 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002572 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2573 # Original logger output is empty
2574 self.assert_log_lines([])
2575
2576 def test_config4a_ok(self):
2577 # A config specifying a custom formatter class.
2578 with captured_stdout() as output:
2579 self.apply_config(self.config4a)
2580 #logger = logging.getLogger()
2581 try:
2582 raise RuntimeError()
2583 except RuntimeError:
2584 logging.exception("just testing")
2585 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002586 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002587 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2588 # Original logger output is empty
2589 self.assert_log_lines([])
2590
2591 def test_config5_ok(self):
2592 self.test_config1_ok(config=self.config5)
2593
2594 def test_config6_failure(self):
2595 self.assertRaises(Exception, self.apply_config, self.config6)
2596
2597 def test_config7_ok(self):
2598 with captured_stdout() as output:
2599 self.apply_config(self.config1)
2600 logger = logging.getLogger("compiler.parser")
2601 # Both will output a message
2602 logger.info(self.next_message())
2603 logger.error(self.next_message())
2604 self.assert_log_lines([
2605 ('INFO', '1'),
2606 ('ERROR', '2'),
2607 ], stream=output)
2608 # Original logger output is empty.
2609 self.assert_log_lines([])
2610 with captured_stdout() as output:
2611 self.apply_config(self.config7)
2612 logger = logging.getLogger("compiler.parser")
2613 self.assertTrue(logger.disabled)
2614 logger = logging.getLogger("compiler.lexer")
2615 # Both will output a message
2616 logger.info(self.next_message())
2617 logger.error(self.next_message())
2618 self.assert_log_lines([
2619 ('INFO', '3'),
2620 ('ERROR', '4'),
2621 ], stream=output)
2622 # Original logger output is empty.
2623 self.assert_log_lines([])
2624
2625 #Same as test_config_7_ok but don't disable old loggers.
2626 def test_config_8_ok(self):
2627 with captured_stdout() as output:
2628 self.apply_config(self.config1)
2629 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002630 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002631 logger.info(self.next_message())
2632 logger.error(self.next_message())
2633 self.assert_log_lines([
2634 ('INFO', '1'),
2635 ('ERROR', '2'),
2636 ], stream=output)
2637 # Original logger output is empty.
2638 self.assert_log_lines([])
2639 with captured_stdout() as output:
2640 self.apply_config(self.config8)
2641 logger = logging.getLogger("compiler.parser")
2642 self.assertFalse(logger.disabled)
2643 # Both will output a message
2644 logger.info(self.next_message())
2645 logger.error(self.next_message())
2646 logger = logging.getLogger("compiler.lexer")
2647 # Both will output a message
2648 logger.info(self.next_message())
2649 logger.error(self.next_message())
2650 self.assert_log_lines([
2651 ('INFO', '3'),
2652 ('ERROR', '4'),
2653 ('INFO', '5'),
2654 ('ERROR', '6'),
2655 ], stream=output)
2656 # Original logger output is empty.
2657 self.assert_log_lines([])
2658
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002659 def test_config_8a_ok(self):
2660 with captured_stdout() as output:
2661 self.apply_config(self.config1a)
2662 logger = logging.getLogger("compiler.parser")
2663 # See issue #11424. compiler-hyphenated sorts
2664 # between compiler and compiler.xyz and this
2665 # was preventing compiler.xyz from being included
2666 # in the child loggers of compiler because of an
2667 # overzealous loop termination condition.
2668 hyphenated = logging.getLogger('compiler-hyphenated')
2669 # All will output a message
2670 logger.info(self.next_message())
2671 logger.error(self.next_message())
2672 hyphenated.critical(self.next_message())
2673 self.assert_log_lines([
2674 ('INFO', '1'),
2675 ('ERROR', '2'),
2676 ('CRITICAL', '3'),
2677 ], stream=output)
2678 # Original logger output is empty.
2679 self.assert_log_lines([])
2680 with captured_stdout() as output:
2681 self.apply_config(self.config8a)
2682 logger = logging.getLogger("compiler.parser")
2683 self.assertFalse(logger.disabled)
2684 # Both will output a message
2685 logger.info(self.next_message())
2686 logger.error(self.next_message())
2687 logger = logging.getLogger("compiler.lexer")
2688 # Both will output a message
2689 logger.info(self.next_message())
2690 logger.error(self.next_message())
2691 # Will not appear
2692 hyphenated.critical(self.next_message())
2693 self.assert_log_lines([
2694 ('INFO', '4'),
2695 ('ERROR', '5'),
2696 ('INFO', '6'),
2697 ('ERROR', '7'),
2698 ], stream=output)
2699 # Original logger output is empty.
2700 self.assert_log_lines([])
2701
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002702 def test_config_9_ok(self):
2703 with captured_stdout() as output:
2704 self.apply_config(self.config9)
2705 logger = logging.getLogger("compiler.parser")
2706 #Nothing will be output since both handler and logger are set to WARNING
2707 logger.info(self.next_message())
2708 self.assert_log_lines([], stream=output)
2709 self.apply_config(self.config9a)
2710 #Nothing will be output since both handler is still set to WARNING
2711 logger.info(self.next_message())
2712 self.assert_log_lines([], stream=output)
2713 self.apply_config(self.config9b)
2714 #Message should now be output
2715 logger.info(self.next_message())
2716 self.assert_log_lines([
2717 ('INFO', '3'),
2718 ], stream=output)
2719
2720 def test_config_10_ok(self):
2721 with captured_stdout() as output:
2722 self.apply_config(self.config10)
2723 logger = logging.getLogger("compiler.parser")
2724 logger.warning(self.next_message())
2725 logger = logging.getLogger('compiler')
2726 #Not output, because filtered
2727 logger.warning(self.next_message())
2728 logger = logging.getLogger('compiler.lexer')
2729 #Not output, because filtered
2730 logger.warning(self.next_message())
2731 logger = logging.getLogger("compiler.parser.codegen")
2732 #Output, as not filtered
2733 logger.error(self.next_message())
2734 self.assert_log_lines([
2735 ('WARNING', '1'),
2736 ('ERROR', '4'),
2737 ], stream=output)
2738
2739 def test_config11_ok(self):
2740 self.test_config1_ok(self.config11)
2741
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002742 def test_config12_failure(self):
2743 self.assertRaises(Exception, self.apply_config, self.config12)
2744
2745 def test_config13_failure(self):
2746 self.assertRaises(Exception, self.apply_config, self.config13)
2747
Vinay Sajip8d270232012-11-15 14:20:18 +00002748 def test_config14_ok(self):
2749 with captured_stdout() as output:
2750 self.apply_config(self.config14)
2751 h = logging._handlers['hand1']
2752 self.assertEqual(h.foo, 'bar')
2753 self.assertEqual(h.terminator, '!\n')
2754 logging.warning('Exclamation')
2755 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2756
Victor Stinner45df8202010-04-28 22:31:17 +00002757 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002758 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002759 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002760 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002761 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002762 t.start()
2763 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002764 # Now get the port allocated
2765 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002766 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002767 try:
2768 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2769 sock.settimeout(2.0)
2770 sock.connect(('localhost', port))
2771
2772 slen = struct.pack('>L', len(text))
2773 s = slen + text
2774 sentsofar = 0
2775 left = len(s)
2776 while left > 0:
2777 sent = sock.send(s[sentsofar:])
2778 sentsofar += sent
2779 left -= sent
2780 sock.close()
2781 finally:
2782 t.ready.wait(2.0)
2783 logging.config.stopListening()
2784 t.join(2.0)
2785
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002786 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002787 def test_listen_config_10_ok(self):
2788 with captured_stdout() as output:
2789 self.setup_via_listener(json.dumps(self.config10))
2790 logger = logging.getLogger("compiler.parser")
2791 logger.warning(self.next_message())
2792 logger = logging.getLogger('compiler')
2793 #Not output, because filtered
2794 logger.warning(self.next_message())
2795 logger = logging.getLogger('compiler.lexer')
2796 #Not output, because filtered
2797 logger.warning(self.next_message())
2798 logger = logging.getLogger("compiler.parser.codegen")
2799 #Output, as not filtered
2800 logger.error(self.next_message())
2801 self.assert_log_lines([
2802 ('WARNING', '1'),
2803 ('ERROR', '4'),
2804 ], stream=output)
2805
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002806 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002807 def test_listen_config_1_ok(self):
2808 with captured_stdout() as output:
2809 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2810 logger = logging.getLogger("compiler.parser")
2811 # Both will output a message
2812 logger.info(self.next_message())
2813 logger.error(self.next_message())
2814 self.assert_log_lines([
2815 ('INFO', '1'),
2816 ('ERROR', '2'),
2817 ], stream=output)
2818 # Original logger output is empty.
2819 self.assert_log_lines([])
2820
Vinay Sajip4ded5512012-10-02 15:56:16 +01002821 @unittest.skipUnless(threading, 'Threading required for this test.')
2822 def test_listen_verify(self):
2823
2824 def verify_fail(stuff):
2825 return None
2826
2827 def verify_reverse(stuff):
2828 return stuff[::-1]
2829
2830 logger = logging.getLogger("compiler.parser")
2831 to_send = textwrap.dedent(ConfigFileTest.config1)
2832 # First, specify a verification function that will fail.
2833 # We expect to see no output, since our configuration
2834 # never took effect.
2835 with captured_stdout() as output:
2836 self.setup_via_listener(to_send, verify_fail)
2837 # Both will output a message
2838 logger.info(self.next_message())
2839 logger.error(self.next_message())
2840 self.assert_log_lines([], stream=output)
2841 # Original logger output has the stuff we logged.
2842 self.assert_log_lines([
2843 ('INFO', '1'),
2844 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002845 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002846
2847 # Now, perform no verification. Our configuration
2848 # should take effect.
2849
2850 with captured_stdout() as output:
2851 self.setup_via_listener(to_send) # no verify callable specified
2852 logger = logging.getLogger("compiler.parser")
2853 # Both will output a message
2854 logger.info(self.next_message())
2855 logger.error(self.next_message())
2856 self.assert_log_lines([
2857 ('INFO', '3'),
2858 ('ERROR', '4'),
2859 ], stream=output)
2860 # Original logger output still has the stuff we logged before.
2861 self.assert_log_lines([
2862 ('INFO', '1'),
2863 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002864 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002865
2866 # Now, perform verification which transforms the bytes.
2867
2868 with captured_stdout() as output:
2869 self.setup_via_listener(to_send[::-1], verify_reverse)
2870 logger = logging.getLogger("compiler.parser")
2871 # Both will output a message
2872 logger.info(self.next_message())
2873 logger.error(self.next_message())
2874 self.assert_log_lines([
2875 ('INFO', '5'),
2876 ('ERROR', '6'),
2877 ], stream=output)
2878 # Original logger output still has the stuff we logged before.
2879 self.assert_log_lines([
2880 ('INFO', '1'),
2881 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002882 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002883
Vinay Sajip3f885b52013-03-22 15:19:54 +00002884 def test_out_of_order(self):
2885 self.apply_config(self.out_of_order)
2886 handler = logging.getLogger('mymodule').handlers[0]
2887 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002888 self.assertIsInstance(handler.formatter._style,
2889 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890
Vinay Sajip373baef2011-04-26 20:05:24 +01002891 def test_baseconfig(self):
2892 d = {
2893 'atuple': (1, 2, 3),
2894 'alist': ['a', 'b', 'c'],
2895 'adict': {'d': 'e', 'f': 3 },
2896 'nest1': ('g', ('h', 'i'), 'j'),
2897 'nest2': ['k', ['l', 'm'], 'n'],
2898 'nest3': ['o', 'cfg://alist', 'p'],
2899 }
2900 bc = logging.config.BaseConfigurator(d)
2901 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2902 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2903 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2904 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2905 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2906 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2907 v = bc.convert('cfg://nest3')
2908 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2909 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2910 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2911 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002912
2913class ManagerTest(BaseTest):
2914 def test_manager_loggerclass(self):
2915 logged = []
2916
2917 class MyLogger(logging.Logger):
2918 def _log(self, level, msg, args, exc_info=None, extra=None):
2919 logged.append(msg)
2920
2921 man = logging.Manager(None)
2922 self.assertRaises(TypeError, man.setLoggerClass, int)
2923 man.setLoggerClass(MyLogger)
2924 logger = man.getLogger('test')
2925 logger.warning('should appear in logged')
2926 logging.warning('should not appear in logged')
2927
2928 self.assertEqual(logged, ['should appear in logged'])
2929
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002930 def test_set_log_record_factory(self):
2931 man = logging.Manager(None)
2932 expected = object()
2933 man.setLogRecordFactory(expected)
2934 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002935
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002936class ChildLoggerTest(BaseTest):
2937 def test_child_loggers(self):
2938 r = logging.getLogger()
2939 l1 = logging.getLogger('abc')
2940 l2 = logging.getLogger('def.ghi')
2941 c1 = r.getChild('xyz')
2942 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002943 self.assertIs(c1, logging.getLogger('xyz'))
2944 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002945 c1 = l1.getChild('def')
2946 c2 = c1.getChild('ghi')
2947 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002948 self.assertIs(c1, logging.getLogger('abc.def'))
2949 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2950 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002951
2952
Vinay Sajip6fac8172010-10-19 20:44:14 +00002953class DerivedLogRecord(logging.LogRecord):
2954 pass
2955
Vinay Sajip61561522010-12-03 11:50:38 +00002956class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002957
2958 def setUp(self):
2959 class CheckingFilter(logging.Filter):
2960 def __init__(self, cls):
2961 self.cls = cls
2962
2963 def filter(self, record):
2964 t = type(record)
2965 if t is not self.cls:
2966 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2967 self.cls)
2968 raise TypeError(msg)
2969 return True
2970
2971 BaseTest.setUp(self)
2972 self.filter = CheckingFilter(DerivedLogRecord)
2973 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002974 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002975
2976 def tearDown(self):
2977 self.root_logger.removeFilter(self.filter)
2978 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002979 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002980
2981 def test_logrecord_class(self):
2982 self.assertRaises(TypeError, self.root_logger.warning,
2983 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002984 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002985 self.root_logger.error(self.next_message())
2986 self.assert_log_lines([
2987 ('root', 'ERROR', '2'),
2988 ])
2989
2990
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002991class QueueHandlerTest(BaseTest):
2992 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002993 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002994
2995 def setUp(self):
2996 BaseTest.setUp(self)
2997 self.queue = queue.Queue(-1)
2998 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
2999 self.que_logger = logging.getLogger('que')
3000 self.que_logger.propagate = False
3001 self.que_logger.setLevel(logging.WARNING)
3002 self.que_logger.addHandler(self.que_hdlr)
3003
3004 def tearDown(self):
3005 self.que_hdlr.close()
3006 BaseTest.tearDown(self)
3007
3008 def test_queue_handler(self):
3009 self.que_logger.debug(self.next_message())
3010 self.assertRaises(queue.Empty, self.queue.get_nowait)
3011 self.que_logger.info(self.next_message())
3012 self.assertRaises(queue.Empty, self.queue.get_nowait)
3013 msg = self.next_message()
3014 self.que_logger.warning(msg)
3015 data = self.queue.get_nowait()
3016 self.assertTrue(isinstance(data, logging.LogRecord))
3017 self.assertEqual(data.name, self.que_logger.name)
3018 self.assertEqual((data.msg, data.args), (msg, None))
3019
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003020 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3021 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003022 def test_queue_listener(self):
3023 handler = TestHandler(Matcher())
3024 listener = logging.handlers.QueueListener(self.queue, handler)
3025 listener.start()
3026 try:
3027 self.que_logger.warning(self.next_message())
3028 self.que_logger.error(self.next_message())
3029 self.que_logger.critical(self.next_message())
3030 finally:
3031 listener.stop()
3032 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3033 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3034 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3035
Vinay Sajip37eb3382011-04-26 20:26:41 +01003036ZERO = datetime.timedelta(0)
3037
3038class UTC(datetime.tzinfo):
3039 def utcoffset(self, dt):
3040 return ZERO
3041
3042 dst = utcoffset
3043
3044 def tzname(self, dt):
3045 return 'UTC'
3046
3047utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003048
Vinay Sajipa39c5712010-10-25 13:57:39 +00003049class FormatterTest(unittest.TestCase):
3050 def setUp(self):
3051 self.common = {
3052 'name': 'formatter.test',
3053 'level': logging.DEBUG,
3054 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3055 'lineno': 42,
3056 'exc_info': None,
3057 'func': None,
3058 'msg': 'Message with %d %s',
3059 'args': (2, 'placeholders'),
3060 }
3061 self.variants = {
3062 }
3063
3064 def get_record(self, name=None):
3065 result = dict(self.common)
3066 if name is not None:
3067 result.update(self.variants[name])
3068 return logging.makeLogRecord(result)
3069
3070 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003071 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003072 r = self.get_record()
3073 f = logging.Formatter('${%(message)s}')
3074 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3075 f = logging.Formatter('%(random)s')
3076 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003077 self.assertFalse(f.usesTime())
3078 f = logging.Formatter('%(asctime)s')
3079 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003080 f = logging.Formatter('%(asctime)-15s')
3081 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003082 f = logging.Formatter('asctime')
3083 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003084
3085 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003086 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003087 r = self.get_record()
3088 f = logging.Formatter('$%{message}%$', style='{')
3089 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3090 f = logging.Formatter('{random}', style='{')
3091 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003092 self.assertFalse(f.usesTime())
3093 f = logging.Formatter('{asctime}', style='{')
3094 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003095 f = logging.Formatter('{asctime!s:15}', style='{')
3096 self.assertTrue(f.usesTime())
3097 f = logging.Formatter('{asctime:15}', style='{')
3098 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003099 f = logging.Formatter('asctime', style='{')
3100 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003101
3102 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003103 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003104 r = self.get_record()
3105 f = logging.Formatter('$message', style='$')
3106 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3107 f = logging.Formatter('$$%${message}%$$', style='$')
3108 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3109 f = logging.Formatter('${random}', style='$')
3110 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003111 self.assertFalse(f.usesTime())
3112 f = logging.Formatter('${asctime}', style='$')
3113 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003114 f = logging.Formatter('${asctime', style='$')
3115 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003116 f = logging.Formatter('$asctime', style='$')
3117 self.assertTrue(f.usesTime())
3118 f = logging.Formatter('asctime', style='$')
3119 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003120
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003121 def test_invalid_style(self):
3122 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3123
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003124 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003125 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003126 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3127 # We use None to indicate we want the local timezone
3128 # We're essentially converting a UTC time to local time
3129 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003130 r.msecs = 123
3131 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003132 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003133 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3134 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003135 f.format(r)
3136 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3137
3138class TestBufferingFormatter(logging.BufferingFormatter):
3139 def formatHeader(self, records):
3140 return '[(%d)' % len(records)
3141
3142 def formatFooter(self, records):
3143 return '(%d)]' % len(records)
3144
3145class BufferingFormatterTest(unittest.TestCase):
3146 def setUp(self):
3147 self.records = [
3148 logging.makeLogRecord({'msg': 'one'}),
3149 logging.makeLogRecord({'msg': 'two'}),
3150 ]
3151
3152 def test_default(self):
3153 f = logging.BufferingFormatter()
3154 self.assertEqual('', f.format([]))
3155 self.assertEqual('onetwo', f.format(self.records))
3156
3157 def test_custom(self):
3158 f = TestBufferingFormatter()
3159 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3160 lf = logging.Formatter('<%(message)s>')
3161 f = TestBufferingFormatter(lf)
3162 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003163
3164class ExceptionTest(BaseTest):
3165 def test_formatting(self):
3166 r = self.root_logger
3167 h = RecordingHandler()
3168 r.addHandler(h)
3169 try:
3170 raise RuntimeError('deliberate mistake')
3171 except:
3172 logging.exception('failed', stack_info=True)
3173 r.removeHandler(h)
3174 h.close()
3175 r = h.records[0]
3176 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3177 'call last):\n'))
3178 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3179 'deliberate mistake'))
3180 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3181 'call last):\n'))
3182 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3183 'stack_info=True)'))
3184
3185
Vinay Sajip5a27d402010-12-10 11:42:57 +00003186class LastResortTest(BaseTest):
3187 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003188 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003189 root = self.root_logger
3190 root.removeHandler(self.root_hdlr)
3191 old_stderr = sys.stderr
3192 old_lastresort = logging.lastResort
3193 old_raise_exceptions = logging.raiseExceptions
3194 try:
3195 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003196 root.debug('This should not appear')
3197 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003198 root.warning('This is your final chance!')
3199 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3200 #No handlers and no last resort, so 'No handlers' message
3201 logging.lastResort = None
3202 sys.stderr = sio = io.StringIO()
3203 root.warning('This is your final chance!')
3204 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3205 # 'No handlers' message only printed once
3206 sys.stderr = sio = io.StringIO()
3207 root.warning('This is your final chance!')
3208 self.assertEqual(sio.getvalue(), '')
3209 root.manager.emittedNoHandlerWarning = False
3210 #If raiseExceptions is False, no message is printed
3211 logging.raiseExceptions = False
3212 sys.stderr = sio = io.StringIO()
3213 root.warning('This is your final chance!')
3214 self.assertEqual(sio.getvalue(), '')
3215 finally:
3216 sys.stderr = old_stderr
3217 root.addHandler(self.root_hdlr)
3218 logging.lastResort = old_lastresort
3219 logging.raiseExceptions = old_raise_exceptions
3220
3221
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003222class FakeHandler:
3223
3224 def __init__(self, identifier, called):
3225 for method in ('acquire', 'flush', 'close', 'release'):
3226 setattr(self, method, self.record_call(identifier, method, called))
3227
3228 def record_call(self, identifier, method_name, called):
3229 def inner():
3230 called.append('{} - {}'.format(identifier, method_name))
3231 return inner
3232
3233
3234class RecordingHandler(logging.NullHandler):
3235
3236 def __init__(self, *args, **kwargs):
3237 super(RecordingHandler, self).__init__(*args, **kwargs)
3238 self.records = []
3239
3240 def handle(self, record):
3241 """Keep track of all the emitted records."""
3242 self.records.append(record)
3243
3244
3245class ShutdownTest(BaseTest):
3246
Vinay Sajip5e66b162011-04-20 15:41:14 +01003247 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003248
3249 def setUp(self):
3250 super(ShutdownTest, self).setUp()
3251 self.called = []
3252
3253 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003254 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003255
3256 def raise_error(self, error):
3257 def inner():
3258 raise error()
3259 return inner
3260
3261 def test_no_failure(self):
3262 # create some fake handlers
3263 handler0 = FakeHandler(0, self.called)
3264 handler1 = FakeHandler(1, self.called)
3265 handler2 = FakeHandler(2, self.called)
3266
3267 # create live weakref to those handlers
3268 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3269
3270 logging.shutdown(handlerList=list(handlers))
3271
3272 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3273 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3274 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3275 self.assertEqual(expected, self.called)
3276
3277 def _test_with_failure_in_method(self, method, error):
3278 handler = FakeHandler(0, self.called)
3279 setattr(handler, method, self.raise_error(error))
3280 handlers = [logging.weakref.ref(handler)]
3281
3282 logging.shutdown(handlerList=list(handlers))
3283
3284 self.assertEqual('0 - release', self.called[-1])
3285
3286 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003287 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003288
3289 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003290 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003291
3292 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003293 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003294
3295 def test_with_valueerror_in_acquire(self):
3296 self._test_with_failure_in_method('acquire', ValueError)
3297
3298 def test_with_valueerror_in_flush(self):
3299 self._test_with_failure_in_method('flush', ValueError)
3300
3301 def test_with_valueerror_in_close(self):
3302 self._test_with_failure_in_method('close', ValueError)
3303
3304 def test_with_other_error_in_acquire_without_raise(self):
3305 logging.raiseExceptions = False
3306 self._test_with_failure_in_method('acquire', IndexError)
3307
3308 def test_with_other_error_in_flush_without_raise(self):
3309 logging.raiseExceptions = False
3310 self._test_with_failure_in_method('flush', IndexError)
3311
3312 def test_with_other_error_in_close_without_raise(self):
3313 logging.raiseExceptions = False
3314 self._test_with_failure_in_method('close', IndexError)
3315
3316 def test_with_other_error_in_acquire_with_raise(self):
3317 logging.raiseExceptions = True
3318 self.assertRaises(IndexError, self._test_with_failure_in_method,
3319 'acquire', IndexError)
3320
3321 def test_with_other_error_in_flush_with_raise(self):
3322 logging.raiseExceptions = True
3323 self.assertRaises(IndexError, self._test_with_failure_in_method,
3324 'flush', IndexError)
3325
3326 def test_with_other_error_in_close_with_raise(self):
3327 logging.raiseExceptions = True
3328 self.assertRaises(IndexError, self._test_with_failure_in_method,
3329 'close', IndexError)
3330
3331
3332class ModuleLevelMiscTest(BaseTest):
3333
Vinay Sajip5e66b162011-04-20 15:41:14 +01003334 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003335
3336 def test_disable(self):
3337 old_disable = logging.root.manager.disable
3338 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003339 self.assertEqual(old_disable, 0)
3340 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003341
3342 logging.disable(83)
3343 self.assertEqual(logging.root.manager.disable, 83)
3344
3345 def _test_log(self, method, level=None):
3346 called = []
3347 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003348 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003349
3350 recording = RecordingHandler()
3351 logging.root.addHandler(recording)
3352
3353 log_method = getattr(logging, method)
3354 if level is not None:
3355 log_method(level, "test me: %r", recording)
3356 else:
3357 log_method("test me: %r", recording)
3358
3359 self.assertEqual(len(recording.records), 1)
3360 record = recording.records[0]
3361 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3362
3363 expected_level = level if level is not None else getattr(logging, method.upper())
3364 self.assertEqual(record.levelno, expected_level)
3365
3366 # basicConfig was not called!
3367 self.assertEqual(called, [])
3368
3369 def test_log(self):
3370 self._test_log('log', logging.ERROR)
3371
3372 def test_debug(self):
3373 self._test_log('debug')
3374
3375 def test_info(self):
3376 self._test_log('info')
3377
3378 def test_warning(self):
3379 self._test_log('warning')
3380
3381 def test_error(self):
3382 self._test_log('error')
3383
3384 def test_critical(self):
3385 self._test_log('critical')
3386
3387 def test_set_logger_class(self):
3388 self.assertRaises(TypeError, logging.setLoggerClass, object)
3389
3390 class MyLogger(logging.Logger):
3391 pass
3392
3393 logging.setLoggerClass(MyLogger)
3394 self.assertEqual(logging.getLoggerClass(), MyLogger)
3395
3396 logging.setLoggerClass(logging.Logger)
3397 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3398
Antoine Pitrou712cb732013-12-21 15:51:54 +01003399 def test_logging_at_shutdown(self):
3400 # Issue #20037
3401 code = """if 1:
3402 import logging
3403
3404 class A:
3405 def __del__(self):
3406 try:
3407 raise ValueError("some error")
3408 except Exception:
3409 logging.exception("exception in __del__")
3410
3411 a = A()"""
3412 rc, out, err = assert_python_ok("-c", code)
3413 err = err.decode()
3414 self.assertIn("exception in __del__", err)
3415 self.assertIn("ValueError: some error", err)
3416
3417
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003418class LogRecordTest(BaseTest):
3419 def test_str_rep(self):
3420 r = logging.makeLogRecord({})
3421 s = str(r)
3422 self.assertTrue(s.startswith('<LogRecord: '))
3423 self.assertTrue(s.endswith('>'))
3424
3425 def test_dict_arg(self):
3426 h = RecordingHandler()
3427 r = logging.getLogger()
3428 r.addHandler(h)
3429 d = {'less' : 'more' }
3430 logging.warning('less is %(less)s', d)
3431 self.assertIs(h.records[0].args, d)
3432 self.assertEqual(h.records[0].message, 'less is more')
3433 r.removeHandler(h)
3434 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003435
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003436 def test_multiprocessing(self):
3437 r = logging.makeLogRecord({})
3438 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003439 try:
3440 import multiprocessing as mp
3441 r = logging.makeLogRecord({})
3442 self.assertEqual(r.processName, mp.current_process().name)
3443 except ImportError:
3444 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003445
3446 def test_optional(self):
3447 r = logging.makeLogRecord({})
3448 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003449 if threading:
3450 NOT_NONE(r.thread)
3451 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003452 NOT_NONE(r.process)
3453 NOT_NONE(r.processName)
3454 log_threads = logging.logThreads
3455 log_processes = logging.logProcesses
3456 log_multiprocessing = logging.logMultiprocessing
3457 try:
3458 logging.logThreads = False
3459 logging.logProcesses = False
3460 logging.logMultiprocessing = False
3461 r = logging.makeLogRecord({})
3462 NONE = self.assertIsNone
3463 NONE(r.thread)
3464 NONE(r.threadName)
3465 NONE(r.process)
3466 NONE(r.processName)
3467 finally:
3468 logging.logThreads = log_threads
3469 logging.logProcesses = log_processes
3470 logging.logMultiprocessing = log_multiprocessing
3471
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003472class BasicConfigTest(unittest.TestCase):
3473
Vinay Sajip95bf5042011-04-20 11:50:56 +01003474 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003475
3476 def setUp(self):
3477 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003478 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003479 self.saved_handlers = logging._handlers.copy()
3480 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003481 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003482 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003483 logging.root.handlers = []
3484
3485 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003486 for h in logging.root.handlers[:]:
3487 logging.root.removeHandler(h)
3488 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003489 super(BasicConfigTest, self).tearDown()
3490
Vinay Sajip3def7e02011-04-20 10:58:06 +01003491 def cleanup(self):
3492 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003493 logging._handlers.clear()
3494 logging._handlers.update(self.saved_handlers)
3495 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003496 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003497
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003498 def test_no_kwargs(self):
3499 logging.basicConfig()
3500
3501 # handler defaults to a StreamHandler to sys.stderr
3502 self.assertEqual(len(logging.root.handlers), 1)
3503 handler = logging.root.handlers[0]
3504 self.assertIsInstance(handler, logging.StreamHandler)
3505 self.assertEqual(handler.stream, sys.stderr)
3506
3507 formatter = handler.formatter
3508 # format defaults to logging.BASIC_FORMAT
3509 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3510 # datefmt defaults to None
3511 self.assertIsNone(formatter.datefmt)
3512 # style defaults to %
3513 self.assertIsInstance(formatter._style, logging.PercentStyle)
3514
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003515 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003516 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003517
Vinay Sajip1fd12022014-01-13 21:59:56 +00003518 def test_strformatstyle(self):
3519 with captured_stdout() as output:
3520 logging.basicConfig(stream=sys.stdout, style="{")
3521 logging.error("Log an error")
3522 sys.stdout.seek(0)
3523 self.assertEqual(output.getvalue().strip(),
3524 "ERROR:root:Log an error")
3525
3526 def test_stringtemplatestyle(self):
3527 with captured_stdout() as output:
3528 logging.basicConfig(stream=sys.stdout, style="$")
3529 logging.error("Log an error")
3530 sys.stdout.seek(0)
3531 self.assertEqual(output.getvalue().strip(),
3532 "ERROR:root:Log an error")
3533
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003534 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003535
3536 def cleanup(h1, h2, fn):
3537 h1.close()
3538 h2.close()
3539 os.remove(fn)
3540
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003541 logging.basicConfig(filename='test.log')
3542
3543 self.assertEqual(len(logging.root.handlers), 1)
3544 handler = logging.root.handlers[0]
3545 self.assertIsInstance(handler, logging.FileHandler)
3546
3547 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003548 self.assertEqual(handler.stream.mode, expected.stream.mode)
3549 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003550 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003551
3552 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003553
3554 def cleanup(h1, h2, fn):
3555 h1.close()
3556 h2.close()
3557 os.remove(fn)
3558
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003559 logging.basicConfig(filename='test.log', filemode='wb')
3560
3561 handler = logging.root.handlers[0]
3562 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003563 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003564 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003565
3566 def test_stream(self):
3567 stream = io.StringIO()
3568 self.addCleanup(stream.close)
3569 logging.basicConfig(stream=stream)
3570
3571 self.assertEqual(len(logging.root.handlers), 1)
3572 handler = logging.root.handlers[0]
3573 self.assertIsInstance(handler, logging.StreamHandler)
3574 self.assertEqual(handler.stream, stream)
3575
3576 def test_format(self):
3577 logging.basicConfig(format='foo')
3578
3579 formatter = logging.root.handlers[0].formatter
3580 self.assertEqual(formatter._style._fmt, 'foo')
3581
3582 def test_datefmt(self):
3583 logging.basicConfig(datefmt='bar')
3584
3585 formatter = logging.root.handlers[0].formatter
3586 self.assertEqual(formatter.datefmt, 'bar')
3587
3588 def test_style(self):
3589 logging.basicConfig(style='$')
3590
3591 formatter = logging.root.handlers[0].formatter
3592 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3593
3594 def test_level(self):
3595 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003596 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003597
3598 logging.basicConfig(level=57)
3599 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003600 # Test that second call has no effect
3601 logging.basicConfig(level=58)
3602 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003603
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003604 def test_incompatible(self):
3605 assertRaises = self.assertRaises
3606 handlers = [logging.StreamHandler()]
3607 stream = sys.stderr
3608 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3609 stream=stream)
3610 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3611 handlers=handlers)
3612 assertRaises(ValueError, logging.basicConfig, stream=stream,
3613 handlers=handlers)
3614
3615 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003616 handlers = [
3617 logging.StreamHandler(),
3618 logging.StreamHandler(sys.stdout),
3619 logging.StreamHandler(),
3620 ]
3621 f = logging.Formatter()
3622 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003623 logging.basicConfig(handlers=handlers)
3624 self.assertIs(handlers[0], logging.root.handlers[0])
3625 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003626 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003627 self.assertIsNotNone(handlers[0].formatter)
3628 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003629 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003630 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3631
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003632 def _test_log(self, method, level=None):
3633 # logging.root has no handlers so basicConfig should be called
3634 called = []
3635
3636 old_basic_config = logging.basicConfig
3637 def my_basic_config(*a, **kw):
3638 old_basic_config()
3639 old_level = logging.root.level
3640 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003641 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003642 called.append((a, kw))
3643
3644 patch(self, logging, 'basicConfig', my_basic_config)
3645
3646 log_method = getattr(logging, method)
3647 if level is not None:
3648 log_method(level, "test me")
3649 else:
3650 log_method("test me")
3651
3652 # basicConfig was called with no arguments
3653 self.assertEqual(called, [((), {})])
3654
3655 def test_log(self):
3656 self._test_log('log', logging.WARNING)
3657
3658 def test_debug(self):
3659 self._test_log('debug')
3660
3661 def test_info(self):
3662 self._test_log('info')
3663
3664 def test_warning(self):
3665 self._test_log('warning')
3666
3667 def test_error(self):
3668 self._test_log('error')
3669
3670 def test_critical(self):
3671 self._test_log('critical')
3672
3673
3674class LoggerAdapterTest(unittest.TestCase):
3675
3676 def setUp(self):
3677 super(LoggerAdapterTest, self).setUp()
3678 old_handler_list = logging._handlerList[:]
3679
3680 self.recording = RecordingHandler()
3681 self.logger = logging.root
3682 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003683 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003684 self.addCleanup(self.recording.close)
3685
3686 def cleanup():
3687 logging._handlerList[:] = old_handler_list
3688
3689 self.addCleanup(cleanup)
3690 self.addCleanup(logging.shutdown)
3691 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3692
3693 def test_exception(self):
3694 msg = 'testing exception: %r'
3695 exc = None
3696 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003697 1 / 0
3698 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003699 exc = e
3700 self.adapter.exception(msg, self.recording)
3701
3702 self.assertEqual(len(self.recording.records), 1)
3703 record = self.recording.records[0]
3704 self.assertEqual(record.levelno, logging.ERROR)
3705 self.assertEqual(record.msg, msg)
3706 self.assertEqual(record.args, (self.recording,))
3707 self.assertEqual(record.exc_info,
3708 (exc.__class__, exc, exc.__traceback__))
3709
3710 def test_critical(self):
3711 msg = 'critical test! %r'
3712 self.adapter.critical(msg, self.recording)
3713
3714 self.assertEqual(len(self.recording.records), 1)
3715 record = self.recording.records[0]
3716 self.assertEqual(record.levelno, logging.CRITICAL)
3717 self.assertEqual(record.msg, msg)
3718 self.assertEqual(record.args, (self.recording,))
3719
3720 def test_is_enabled_for(self):
3721 old_disable = self.adapter.logger.manager.disable
3722 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003723 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3724 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003725 self.assertFalse(self.adapter.isEnabledFor(32))
3726
3727 def test_has_handlers(self):
3728 self.assertTrue(self.adapter.hasHandlers())
3729
3730 for handler in self.logger.handlers:
3731 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003732
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003733 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003734 self.assertFalse(self.adapter.hasHandlers())
3735
3736
3737class LoggerTest(BaseTest):
3738
3739 def setUp(self):
3740 super(LoggerTest, self).setUp()
3741 self.recording = RecordingHandler()
3742 self.logger = logging.Logger(name='blah')
3743 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003744 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003745 self.addCleanup(self.recording.close)
3746 self.addCleanup(logging.shutdown)
3747
3748 def test_set_invalid_level(self):
3749 self.assertRaises(TypeError, self.logger.setLevel, object())
3750
3751 def test_exception(self):
3752 msg = 'testing exception: %r'
3753 exc = None
3754 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003755 1 / 0
3756 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003757 exc = e
3758 self.logger.exception(msg, self.recording)
3759
3760 self.assertEqual(len(self.recording.records), 1)
3761 record = self.recording.records[0]
3762 self.assertEqual(record.levelno, logging.ERROR)
3763 self.assertEqual(record.msg, msg)
3764 self.assertEqual(record.args, (self.recording,))
3765 self.assertEqual(record.exc_info,
3766 (exc.__class__, exc, exc.__traceback__))
3767
3768 def test_log_invalid_level_with_raise(self):
3769 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003770 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003771
3772 logging.raiseExceptions = True
3773 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3774
3775 def test_log_invalid_level_no_raise(self):
3776 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003777 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003778
3779 logging.raiseExceptions = False
3780 self.logger.log('10', 'test message') # no exception happens
3781
3782 def test_find_caller_with_stack_info(self):
3783 called = []
3784 patch(self, logging.traceback, 'print_stack',
3785 lambda f, file: called.append(file.getvalue()))
3786
3787 self.logger.findCaller(stack_info=True)
3788
3789 self.assertEqual(len(called), 1)
3790 self.assertEqual('Stack (most recent call last):\n', called[0])
3791
3792 def test_make_record_with_extra_overwrite(self):
3793 name = 'my record'
3794 level = 13
3795 fn = lno = msg = args = exc_info = func = sinfo = None
3796 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3797 exc_info, func, sinfo)
3798
3799 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3800 extra = {key: 'some value'}
3801 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3802 fn, lno, msg, args, exc_info,
3803 extra=extra, sinfo=sinfo)
3804
3805 def test_make_record_with_extra_no_overwrite(self):
3806 name = 'my record'
3807 level = 13
3808 fn = lno = msg = args = exc_info = func = sinfo = None
3809 extra = {'valid_key': 'some value'}
3810 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3811 exc_info, extra=extra, sinfo=sinfo)
3812 self.assertIn('valid_key', result.__dict__)
3813
3814 def test_has_handlers(self):
3815 self.assertTrue(self.logger.hasHandlers())
3816
3817 for handler in self.logger.handlers:
3818 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003819 self.assertFalse(self.logger.hasHandlers())
3820
3821 def test_has_handlers_no_propagate(self):
3822 child_logger = logging.getLogger('blah.child')
3823 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003824 self.assertFalse(child_logger.hasHandlers())
3825
3826 def test_is_enabled_for(self):
3827 old_disable = self.logger.manager.disable
3828 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003829 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003830 self.assertFalse(self.logger.isEnabledFor(22))
3831
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003832 def test_root_logger_aliases(self):
3833 root = logging.getLogger()
3834 self.assertIs(root, logging.root)
3835 self.assertIs(root, logging.getLogger(None))
3836 self.assertIs(root, logging.getLogger(''))
3837 self.assertIs(root, logging.getLogger('foo').root)
3838 self.assertIs(root, logging.getLogger('foo.bar').root)
3839 self.assertIs(root, logging.getLogger('foo').parent)
3840
3841 self.assertIsNot(root, logging.getLogger('\0'))
3842 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3843
3844 def test_invalid_names(self):
3845 self.assertRaises(TypeError, logging.getLogger, any)
3846 self.assertRaises(TypeError, logging.getLogger, b'foo')
3847
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003848
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003849class BaseFileTest(BaseTest):
3850 "Base class for handler tests that write log files"
3851
3852 def setUp(self):
3853 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003854 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3855 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003856 self.rmfiles = []
3857
3858 def tearDown(self):
3859 for fn in self.rmfiles:
3860 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003861 if os.path.exists(self.fn):
3862 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003863 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003864
3865 def assertLogFile(self, filename):
3866 "Assert a log file is there and register it for deletion"
3867 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003868 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003869 self.rmfiles.append(filename)
3870
3871
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003872class FileHandlerTest(BaseFileTest):
3873 def test_delay(self):
3874 os.unlink(self.fn)
3875 fh = logging.FileHandler(self.fn, delay=True)
3876 self.assertIsNone(fh.stream)
3877 self.assertFalse(os.path.exists(self.fn))
3878 fh.handle(logging.makeLogRecord({}))
3879 self.assertIsNotNone(fh.stream)
3880 self.assertTrue(os.path.exists(self.fn))
3881 fh.close()
3882
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003883class RotatingFileHandlerTest(BaseFileTest):
3884 def next_rec(self):
3885 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3886 self.next_message(), None, None, None)
3887
3888 def test_should_not_rollover(self):
3889 # If maxbytes is zero rollover never occurs
3890 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3891 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003892 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003893
3894 def test_should_rollover(self):
3895 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3896 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003897 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003898
3899 def test_file_created(self):
3900 # checks that the file is created and assumes it was created
3901 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003902 rh = logging.handlers.RotatingFileHandler(self.fn)
3903 rh.emit(self.next_rec())
3904 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003905 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003906
3907 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003908 def namer(name):
3909 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003910 rh = logging.handlers.RotatingFileHandler(
3911 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003912 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003913 rh.emit(self.next_rec())
3914 self.assertLogFile(self.fn)
3915 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003916 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003917 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003918 self.assertLogFile(namer(self.fn + ".2"))
3919 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3920 rh.close()
3921
Eric V. Smith851cad72012-03-11 22:46:04 -07003922 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003923 def test_rotator(self):
3924 def namer(name):
3925 return name + ".gz"
3926
3927 def rotator(source, dest):
3928 with open(source, "rb") as sf:
3929 data = sf.read()
3930 compressed = zlib.compress(data, 9)
3931 with open(dest, "wb") as df:
3932 df.write(compressed)
3933 os.remove(source)
3934
3935 rh = logging.handlers.RotatingFileHandler(
3936 self.fn, backupCount=2, maxBytes=1)
3937 rh.rotator = rotator
3938 rh.namer = namer
3939 m1 = self.next_rec()
3940 rh.emit(m1)
3941 self.assertLogFile(self.fn)
3942 m2 = self.next_rec()
3943 rh.emit(m2)
3944 fn = namer(self.fn + ".1")
3945 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003946 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003947 with open(fn, "rb") as f:
3948 compressed = f.read()
3949 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003950 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003951 rh.emit(self.next_rec())
3952 fn = namer(self.fn + ".2")
3953 self.assertLogFile(fn)
3954 with open(fn, "rb") as f:
3955 compressed = f.read()
3956 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003957 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003958 rh.emit(self.next_rec())
3959 fn = namer(self.fn + ".2")
3960 with open(fn, "rb") as f:
3961 compressed = f.read()
3962 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003963 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003964 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003965 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003966
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003967class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003968 # other test methods added below
3969 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003970 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3971 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003972 fmt = logging.Formatter('%(asctime)s %(message)s')
3973 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003974 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003975 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003976 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003977 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003978 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003979 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003980 fh.close()
3981 # At this point, we should have a recent rotated file which we
3982 # can test for the existence of. However, in practice, on some
3983 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003984 # in time to go to look for the log file. So, we go back a fair
3985 # bit, and stop as soon as we see a rotated file. In theory this
3986 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003987 found = False
3988 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003989 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003990 for secs in range(GO_BACK):
3991 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003992 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3993 found = os.path.exists(fn)
3994 if found:
3995 self.rmfiles.append(fn)
3996 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003997 msg = 'No rotated files found, went back %d seconds' % GO_BACK
3998 if not found:
3999 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004000 dn, fn = os.path.split(self.fn)
4001 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004002 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4003 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004004 for f in files:
4005 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004006 path = os.path.join(dn, f)
4007 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004008 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004009 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004010
Vinay Sajip0372e102011-05-05 12:59:14 +01004011 def test_invalid(self):
4012 assertRaises = self.assertRaises
4013 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004014 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004015 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004016 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004017 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004018 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004019
Vinay Sajipa7130792013-04-12 17:04:23 +01004020 def test_compute_rollover_daily_attime(self):
4021 currentTime = 0
4022 atTime = datetime.time(12, 0, 0)
4023 rh = logging.handlers.TimedRotatingFileHandler(
4024 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4025 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004026 try:
4027 actual = rh.computeRollover(currentTime)
4028 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004029
Vinay Sajipd86ac962013-04-14 12:20:46 +01004030 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4031 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4032 finally:
4033 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004034
Vinay Sajip10e8c492013-05-18 10:19:54 -07004035 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004036 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004037 currentTime = int(time.time())
4038 today = currentTime - currentTime % 86400
4039
Vinay Sajipa7130792013-04-12 17:04:23 +01004040 atTime = datetime.time(12, 0, 0)
4041
Vinay Sajip10e8c492013-05-18 10:19:54 -07004042 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004043 for day in range(7):
4044 rh = logging.handlers.TimedRotatingFileHandler(
4045 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4046 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004047 try:
4048 if wday > day:
4049 # The rollover day has already passed this week, so we
4050 # go over into next week
4051 expected = (7 - wday + day)
4052 else:
4053 expected = (day - wday)
4054 # At this point expected is in days from now, convert to seconds
4055 expected *= 24 * 60 * 60
4056 # Add in the rollover time
4057 expected += 12 * 60 * 60
4058 # Add in adjustment for today
4059 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004060 actual = rh.computeRollover(today)
4061 if actual != expected:
4062 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004063 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004064 self.assertEqual(actual, expected)
4065 if day == wday:
4066 # goes into following week
4067 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004068 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004069 if actual != expected:
4070 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004071 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004072 self.assertEqual(actual, expected)
4073 finally:
4074 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004075
4076
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004077def secs(**kw):
4078 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4079
4080for when, exp in (('S', 1),
4081 ('M', 60),
4082 ('H', 60 * 60),
4083 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004084 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004085 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004086 ('W0', secs(days=4, hours=24)),
4087 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004088 def test_compute_rollover(self, when=when, exp=exp):
4089 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004090 self.fn, when=when, interval=1, backupCount=0, utc=True)
4091 currentTime = 0.0
4092 actual = rh.computeRollover(currentTime)
4093 if exp != actual:
4094 # Failures occur on some systems for MIDNIGHT and W0.
4095 # Print detailed calculation for MIDNIGHT so we can try to see
4096 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004097 if when == 'MIDNIGHT':
4098 try:
4099 if rh.utc:
4100 t = time.gmtime(currentTime)
4101 else:
4102 t = time.localtime(currentTime)
4103 currentHour = t[3]
4104 currentMinute = t[4]
4105 currentSecond = t[5]
4106 # r is the number of seconds left between now and midnight
4107 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4108 currentMinute) * 60 +
4109 currentSecond)
4110 result = currentTime + r
4111 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4112 print('currentHour: %s' % currentHour, file=sys.stderr)
4113 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4114 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4115 print('r: %s' % r, file=sys.stderr)
4116 print('result: %s' % result, file=sys.stderr)
4117 except Exception:
4118 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4119 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004120 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004121 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4122
Vinay Sajip60ccd822011-05-09 17:32:09 +01004123
4124@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4125class NTEventLogHandlerTest(BaseTest):
4126 def test_basic(self):
4127 logtype = 'Application'
4128 elh = win32evtlog.OpenEventLog(None, logtype)
4129 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4130 h = logging.handlers.NTEventLogHandler('test_logging')
4131 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4132 h.handle(r)
4133 h.close()
4134 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004135 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004136 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4137 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4138 found = False
4139 GO_BACK = 100
4140 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4141 for e in events:
4142 if e.SourceName != 'test_logging':
4143 continue
4144 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4145 if msg != 'Test Log Message\r\n':
4146 continue
4147 found = True
4148 break
4149 msg = 'Record not found in event log, went back %d records' % GO_BACK
4150 self.assertTrue(found, msg=msg)
4151
Christian Heimes180510d2008-03-03 19:15:45 +00004152# Set the locale to the platform-dependent default. I have no idea
4153# why the test does this, but in any case we save the current locale
4154# first and restore it at the end.
4155@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004156def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004157 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004158 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004159 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4160 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4161 ManagerTest, FormatterTest, BufferingFormatterTest,
4162 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4163 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4164 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4165 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004166 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004167 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004168 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4169 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004170 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004171
Christian Heimes180510d2008-03-03 19:15:45 +00004172if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004173 test_main()