blob: 6f6dd18d800d3fb5f167caee3292878c029bd843 [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
868 class TestUDPServer(ControlMixin, ThreadingUDPServer):
869 """
870 A UDP server which is controllable using :class:`ControlMixin`.
871
872 :param addr: A tuple with the IP address and port to listen on.
873 :param handler: A handler callable which will be called with a
874 single parameter - the request - in order to
875 process the request.
876 :param poll_interval: The polling interval for shutdown requests,
877 in seconds.
878 :bind_and_activate: If True (the default), binds the server and
879 starts it listening. If False, you need to
880 call :meth:`server_bind` and
881 :meth:`server_activate` at some later time
882 before calling :meth:`start`, so that the server will
883 set up the socket and listen on it.
884 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100885 def __init__(self, addr, handler, poll_interval=0.5,
886 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100887 class DelegatingUDPRequestHandler(DatagramRequestHandler):
888
889 def handle(self):
890 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100891
892 def finish(self):
893 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if data:
895 try:
896 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200897 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100898 if not self.server._closed:
899 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100900
Vinay Sajip3ef12292011-05-23 23:00:42 +0100901 ThreadingUDPServer.__init__(self, addr,
902 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100903 bind_and_activate)
904 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100905 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100906
907 def server_bind(self):
908 super(TestUDPServer, self).server_bind()
909 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Vinay Sajipba980db2011-05-23 21:37:54 +0100911 def server_close(self):
912 super(TestUDPServer, self).server_close()
913 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100914
Victor Stinnerec5a8602014-06-02 14:41:51 +0200915 if hasattr(socket, "AF_UNIX"):
916 class TestUnixStreamServer(TestTCPServer):
917 address_family = socket.AF_UNIX
918
919 class TestUnixDatagramServer(TestUDPServer):
920 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100921
Vinay Sajip7367d082011-05-02 13:17:27 +0100922# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100923
Vinay Sajipce7c9782011-05-17 07:15:53 +0100924@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100925class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000926 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100927 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100928 sockmap = {}
929 server = TestSMTPServer(('localhost', 0), self.process_message, 0.001,
930 sockmap)
931 server.start()
932 addr = ('localhost', server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000933 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
934 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 self.assertEqual(h.toaddrs, ['you'])
936 self.messages = []
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 r = logging.makeLogRecord({'msg': 'Hello'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100938 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000940 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100941 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000942 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100943 self.assertEqual(len(self.messages), 1)
944 peer, mailfrom, rcpttos, data = self.messages[0]
945 self.assertEqual(mailfrom, 'me')
946 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100947 self.assertIn('\nSubject: Log\n', data)
Vinay Sajipa463d252011-04-30 21:52:48 +0100948 self.assertTrue(data.endswith('\n\nHello'))
949 h.close()
950
951 def process_message(self, *args):
952 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100953 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100954
Christian Heimes180510d2008-03-03 19:15:45 +0000955class MemoryHandlerTest(BaseTest):
956
957 """Tests for the MemoryHandler."""
958
959 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300960 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000961
962 def setUp(self):
963 BaseTest.setUp(self)
964 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
965 self.root_hdlr)
966 self.mem_logger = logging.getLogger('mem')
967 self.mem_logger.propagate = 0
968 self.mem_logger.addHandler(self.mem_hdlr)
969
970 def tearDown(self):
971 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000972 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000973
974 def test_flush(self):
975 # The memory handler flushes to its target handler based on specific
976 # criteria (message count and message level).
977 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000978 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000979 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000980 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000981 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100982 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000983 lines = [
984 ('DEBUG', '1'),
985 ('INFO', '2'),
986 ('WARNING', '3'),
987 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 for n in (4, 14):
990 for i in range(9):
991 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000992 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000993 # This will flush because it's the 10th message since the last
994 # flush.
995 self.mem_logger.debug(self.next_message())
996 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000997 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000998
999 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001000 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001001
1002
1003class ExceptionFormatter(logging.Formatter):
1004 """A special exception formatter."""
1005 def formatException(self, ei):
1006 return "Got a [%s]" % ei[0].__name__
1007
1008
1009class ConfigFileTest(BaseTest):
1010
1011 """Reading logging config from a .ini-style config file."""
1012
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001013 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001014
1015 # config0 is a standard configuration.
1016 config0 = """
1017 [loggers]
1018 keys=root
1019
1020 [handlers]
1021 keys=hand1
1022
1023 [formatters]
1024 keys=form1
1025
1026 [logger_root]
1027 level=WARNING
1028 handlers=hand1
1029
1030 [handler_hand1]
1031 class=StreamHandler
1032 level=NOTSET
1033 formatter=form1
1034 args=(sys.stdout,)
1035
1036 [formatter_form1]
1037 format=%(levelname)s ++ %(message)s
1038 datefmt=
1039 """
1040
1041 # config1 adds a little to the standard configuration.
1042 config1 = """
1043 [loggers]
1044 keys=root,parser
1045
1046 [handlers]
1047 keys=hand1
1048
1049 [formatters]
1050 keys=form1
1051
1052 [logger_root]
1053 level=WARNING
1054 handlers=
1055
1056 [logger_parser]
1057 level=DEBUG
1058 handlers=hand1
1059 propagate=1
1060 qualname=compiler.parser
1061
1062 [handler_hand1]
1063 class=StreamHandler
1064 level=NOTSET
1065 formatter=form1
1066 args=(sys.stdout,)
1067
1068 [formatter_form1]
1069 format=%(levelname)s ++ %(message)s
1070 datefmt=
1071 """
1072
Vinay Sajip3f84b072011-03-07 17:49:33 +00001073 # config1a moves the handler to the root.
1074 config1a = """
1075 [loggers]
1076 keys=root,parser
1077
1078 [handlers]
1079 keys=hand1
1080
1081 [formatters]
1082 keys=form1
1083
1084 [logger_root]
1085 level=WARNING
1086 handlers=hand1
1087
1088 [logger_parser]
1089 level=DEBUG
1090 handlers=
1091 propagate=1
1092 qualname=compiler.parser
1093
1094 [handler_hand1]
1095 class=StreamHandler
1096 level=NOTSET
1097 formatter=form1
1098 args=(sys.stdout,)
1099
1100 [formatter_form1]
1101 format=%(levelname)s ++ %(message)s
1102 datefmt=
1103 """
1104
Christian Heimes180510d2008-03-03 19:15:45 +00001105 # config2 has a subtle configuration error that should be reported
1106 config2 = config1.replace("sys.stdout", "sys.stbout")
1107
1108 # config3 has a less subtle configuration error
1109 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1110
1111 # config4 specifies a custom formatter class to be loaded
1112 config4 = """
1113 [loggers]
1114 keys=root
1115
1116 [handlers]
1117 keys=hand1
1118
1119 [formatters]
1120 keys=form1
1121
1122 [logger_root]
1123 level=NOTSET
1124 handlers=hand1
1125
1126 [handler_hand1]
1127 class=StreamHandler
1128 level=NOTSET
1129 formatter=form1
1130 args=(sys.stdout,)
1131
1132 [formatter_form1]
1133 class=""" + __name__ + """.ExceptionFormatter
1134 format=%(levelname)s:%(name)s:%(message)s
1135 datefmt=
1136 """
1137
Georg Brandl3dbca812008-07-23 16:10:53 +00001138 # config5 specifies a custom handler class to be loaded
1139 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1140
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001141 # config6 uses ', ' delimiters in the handlers and formatters sections
1142 config6 = """
1143 [loggers]
1144 keys=root,parser
1145
1146 [handlers]
1147 keys=hand1, hand2
1148
1149 [formatters]
1150 keys=form1, form2
1151
1152 [logger_root]
1153 level=WARNING
1154 handlers=
1155
1156 [logger_parser]
1157 level=DEBUG
1158 handlers=hand1
1159 propagate=1
1160 qualname=compiler.parser
1161
1162 [handler_hand1]
1163 class=StreamHandler
1164 level=NOTSET
1165 formatter=form1
1166 args=(sys.stdout,)
1167
1168 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001169 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001170 level=NOTSET
1171 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001172 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001173
1174 [formatter_form1]
1175 format=%(levelname)s ++ %(message)s
1176 datefmt=
1177
1178 [formatter_form2]
1179 format=%(message)s
1180 datefmt=
1181 """
1182
Vinay Sajip3f84b072011-03-07 17:49:33 +00001183 # config7 adds a compiler logger.
1184 config7 = """
1185 [loggers]
1186 keys=root,parser,compiler
1187
1188 [handlers]
1189 keys=hand1
1190
1191 [formatters]
1192 keys=form1
1193
1194 [logger_root]
1195 level=WARNING
1196 handlers=hand1
1197
1198 [logger_compiler]
1199 level=DEBUG
1200 handlers=
1201 propagate=1
1202 qualname=compiler
1203
1204 [logger_parser]
1205 level=DEBUG
1206 handlers=
1207 propagate=1
1208 qualname=compiler.parser
1209
1210 [handler_hand1]
1211 class=StreamHandler
1212 level=NOTSET
1213 formatter=form1
1214 args=(sys.stdout,)
1215
1216 [formatter_form1]
1217 format=%(levelname)s ++ %(message)s
1218 datefmt=
1219 """
1220
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001221 disable_test = """
1222 [loggers]
1223 keys=root
1224
1225 [handlers]
1226 keys=screen
1227
1228 [formatters]
1229 keys=
1230
1231 [logger_root]
1232 level=DEBUG
1233 handlers=screen
1234
1235 [handler_screen]
1236 level=DEBUG
1237 class=StreamHandler
1238 args=(sys.stdout,)
1239 formatter=
1240 """
1241
1242 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001243 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001244 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001245
1246 def test_config0_ok(self):
1247 # A simple config file which overrides the default settings.
1248 with captured_stdout() as output:
1249 self.apply_config(self.config0)
1250 logger = logging.getLogger()
1251 # Won't output anything
1252 logger.info(self.next_message())
1253 # Outputs a message
1254 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001255 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001256 ('ERROR', '2'),
1257 ], stream=output)
1258 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001259 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001260
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001261 def test_config0_using_cp_ok(self):
1262 # A simple config file which overrides the default settings.
1263 with captured_stdout() as output:
1264 file = io.StringIO(textwrap.dedent(self.config0))
1265 cp = configparser.ConfigParser()
1266 cp.read_file(file)
1267 logging.config.fileConfig(cp)
1268 logger = logging.getLogger()
1269 # Won't output anything
1270 logger.info(self.next_message())
1271 # Outputs a message
1272 logger.error(self.next_message())
1273 self.assert_log_lines([
1274 ('ERROR', '2'),
1275 ], stream=output)
1276 # Original logger output is empty.
1277 self.assert_log_lines([])
1278
Georg Brandl3dbca812008-07-23 16:10:53 +00001279 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001280 # A config file defining a sub-parser as well.
1281 with captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001282 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001283 logger = logging.getLogger("compiler.parser")
1284 # Both will output a message
1285 logger.info(self.next_message())
1286 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001287 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001288 ('INFO', '1'),
1289 ('ERROR', '2'),
1290 ], stream=output)
1291 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001292 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001293
1294 def test_config2_failure(self):
1295 # A simple config file which overrides the default settings.
1296 self.assertRaises(Exception, self.apply_config, self.config2)
1297
1298 def test_config3_failure(self):
1299 # A simple config file which overrides the default settings.
1300 self.assertRaises(Exception, self.apply_config, self.config3)
1301
1302 def test_config4_ok(self):
1303 # A config file specifying a custom formatter class.
1304 with captured_stdout() as output:
1305 self.apply_config(self.config4)
1306 logger = logging.getLogger()
1307 try:
1308 raise RuntimeError()
1309 except RuntimeError:
1310 logging.exception("just testing")
1311 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001312 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001313 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1314 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001315 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001316
Georg Brandl3dbca812008-07-23 16:10:53 +00001317 def test_config5_ok(self):
1318 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001319
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001320 def test_config6_ok(self):
1321 self.test_config1_ok(config=self.config6)
1322
Vinay Sajip3f84b072011-03-07 17:49:33 +00001323 def test_config7_ok(self):
1324 with captured_stdout() as output:
1325 self.apply_config(self.config1a)
1326 logger = logging.getLogger("compiler.parser")
1327 # See issue #11424. compiler-hyphenated sorts
1328 # between compiler and compiler.xyz and this
1329 # was preventing compiler.xyz from being included
1330 # in the child loggers of compiler because of an
1331 # overzealous loop termination condition.
1332 hyphenated = logging.getLogger('compiler-hyphenated')
1333 # All will output a message
1334 logger.info(self.next_message())
1335 logger.error(self.next_message())
1336 hyphenated.critical(self.next_message())
1337 self.assert_log_lines([
1338 ('INFO', '1'),
1339 ('ERROR', '2'),
1340 ('CRITICAL', '3'),
1341 ], stream=output)
1342 # Original logger output is empty.
1343 self.assert_log_lines([])
1344 with captured_stdout() as output:
1345 self.apply_config(self.config7)
1346 logger = logging.getLogger("compiler.parser")
1347 self.assertFalse(logger.disabled)
1348 # Both will output a message
1349 logger.info(self.next_message())
1350 logger.error(self.next_message())
1351 logger = logging.getLogger("compiler.lexer")
1352 # Both will output a message
1353 logger.info(self.next_message())
1354 logger.error(self.next_message())
1355 # Will not appear
1356 hyphenated.critical(self.next_message())
1357 self.assert_log_lines([
1358 ('INFO', '4'),
1359 ('ERROR', '5'),
1360 ('INFO', '6'),
1361 ('ERROR', '7'),
1362 ], stream=output)
1363 # Original logger output is empty.
1364 self.assert_log_lines([])
1365
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001366 def test_logger_disabling(self):
1367 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001368 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001369 self.assertFalse(logger.disabled)
1370 self.apply_config(self.disable_test)
1371 self.assertTrue(logger.disabled)
1372 self.apply_config(self.disable_test, disable_existing_loggers=False)
1373 self.assertFalse(logger.disabled)
1374
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001375
Victor Stinner45df8202010-04-28 22:31:17 +00001376@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001377class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001378
Christian Heimes180510d2008-03-03 19:15:45 +00001379 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001380
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001381 if threading:
1382 server_class = TestTCPServer
1383 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001384
Christian Heimes180510d2008-03-03 19:15:45 +00001385 def setUp(self):
1386 """Set up a TCP server to receive log messages, and a SocketHandler
1387 pointing to that server's address and port."""
1388 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001389 self.server = server = self.server_class(self.address,
1390 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001391 server.start()
1392 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001393 hcls = logging.handlers.SocketHandler
1394 if isinstance(server.server_address, tuple):
1395 self.sock_hdlr = hcls('localhost', server.port)
1396 else:
1397 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001398 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001399 self.root_logger.removeHandler(self.root_logger.handlers[0])
1400 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001401 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001402
Christian Heimes180510d2008-03-03 19:15:45 +00001403 def tearDown(self):
1404 """Shutdown the TCP server."""
1405 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001406 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001407 self.root_logger.removeHandler(self.sock_hdlr)
1408 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001409 finally:
1410 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001411
Vinay Sajip7367d082011-05-02 13:17:27 +01001412 def handle_socket(self, request):
1413 conn = request.connection
1414 while True:
1415 chunk = conn.recv(4)
1416 if len(chunk) < 4:
1417 break
1418 slen = struct.unpack(">L", chunk)[0]
1419 chunk = conn.recv(slen)
1420 while len(chunk) < slen:
1421 chunk = chunk + conn.recv(slen - len(chunk))
1422 obj = pickle.loads(chunk)
1423 record = logging.makeLogRecord(obj)
1424 self.log_output += record.msg + '\n'
1425 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001426
Christian Heimes180510d2008-03-03 19:15:45 +00001427 def test_output(self):
1428 # The log message sent to the SocketHandler is properly received.
1429 logger = logging.getLogger("tcp")
1430 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001431 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001432 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001433 self.handled.acquire()
1434 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001435
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001436 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001437 # Avoid timing-related failures due to SocketHandler's own hard-wired
1438 # one-second timeout on socket.create_connection() (issue #16264).
1439 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001440 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001441 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001442 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001443 try:
1444 raise RuntimeError('Deliberate mistake')
1445 except RuntimeError:
1446 self.root_logger.exception('Never sent')
1447 self.root_logger.error('Never sent, either')
1448 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001449 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001450 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1451 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001452
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001453def _get_temp_domain_socket():
1454 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1455 os.close(fd)
1456 # just need a name - file can't be present, or we'll get an
1457 # 'address already in use' error.
1458 os.remove(fn)
1459 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001460
Victor Stinnerec5a8602014-06-02 14:41:51 +02001461@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001462@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001463class UnixSocketHandlerTest(SocketHandlerTest):
1464
1465 """Test for SocketHandler with unix sockets."""
1466
Victor Stinnerec5a8602014-06-02 14:41:51 +02001467 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001468 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001469
1470 def setUp(self):
1471 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001472 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001473 SocketHandlerTest.setUp(self)
1474
1475 def tearDown(self):
1476 SocketHandlerTest.tearDown(self)
1477 os.remove(self.address)
1478
1479@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001480class DatagramHandlerTest(BaseTest):
1481
1482 """Test for DatagramHandler."""
1483
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001484 if threading:
1485 server_class = TestUDPServer
1486 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001487
Vinay Sajip7367d082011-05-02 13:17:27 +01001488 def setUp(self):
1489 """Set up a UDP server to receive log messages, and a DatagramHandler
1490 pointing to that server's address and port."""
1491 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001492 self.server = server = self.server_class(self.address,
1493 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001494 server.start()
1495 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001496 hcls = logging.handlers.DatagramHandler
1497 if isinstance(server.server_address, tuple):
1498 self.sock_hdlr = hcls('localhost', server.port)
1499 else:
1500 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001501 self.log_output = ''
1502 self.root_logger.removeHandler(self.root_logger.handlers[0])
1503 self.root_logger.addHandler(self.sock_hdlr)
1504 self.handled = threading.Event()
1505
1506 def tearDown(self):
1507 """Shutdown the UDP server."""
1508 try:
1509 self.server.stop(2.0)
1510 self.root_logger.removeHandler(self.sock_hdlr)
1511 self.sock_hdlr.close()
1512 finally:
1513 BaseTest.tearDown(self)
1514
1515 def handle_datagram(self, request):
1516 slen = struct.pack('>L', 0) # length of prefix
1517 packet = request.packet[len(slen):]
1518 obj = pickle.loads(packet)
1519 record = logging.makeLogRecord(obj)
1520 self.log_output += record.msg + '\n'
1521 self.handled.set()
1522
1523 def test_output(self):
1524 # The log message sent to the DatagramHandler is properly received.
1525 logger = logging.getLogger("udp")
1526 logger.error("spam")
1527 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001528 self.handled.clear()
1529 logger.error("eggs")
1530 self.handled.wait()
1531 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001532
Victor Stinnerec5a8602014-06-02 14:41:51 +02001533@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001534@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001535class UnixDatagramHandlerTest(DatagramHandlerTest):
1536
1537 """Test for DatagramHandler using Unix sockets."""
1538
Victor Stinnerec5a8602014-06-02 14:41:51 +02001539 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001540 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001541
1542 def setUp(self):
1543 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001544 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001545 DatagramHandlerTest.setUp(self)
1546
1547 def tearDown(self):
1548 DatagramHandlerTest.tearDown(self)
1549 os.remove(self.address)
1550
1551@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001552class SysLogHandlerTest(BaseTest):
1553
1554 """Test for SysLogHandler using UDP."""
1555
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001556 if threading:
1557 server_class = TestUDPServer
1558 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001559
Vinay Sajip7367d082011-05-02 13:17:27 +01001560 def setUp(self):
1561 """Set up a UDP server to receive log messages, and a SysLogHandler
1562 pointing to that server's address and port."""
1563 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001564 self.server = server = self.server_class(self.address,
1565 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001566 server.start()
1567 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001568 hcls = logging.handlers.SysLogHandler
1569 if isinstance(server.server_address, tuple):
1570 self.sl_hdlr = hcls(('localhost', server.port))
1571 else:
1572 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001573 self.log_output = ''
1574 self.root_logger.removeHandler(self.root_logger.handlers[0])
1575 self.root_logger.addHandler(self.sl_hdlr)
1576 self.handled = threading.Event()
1577
1578 def tearDown(self):
1579 """Shutdown the UDP server."""
1580 try:
1581 self.server.stop(2.0)
1582 self.root_logger.removeHandler(self.sl_hdlr)
1583 self.sl_hdlr.close()
1584 finally:
1585 BaseTest.tearDown(self)
1586
1587 def handle_datagram(self, request):
1588 self.log_output = request.packet
1589 self.handled.set()
1590
1591 def test_output(self):
1592 # The log message sent to the SysLogHandler is properly received.
1593 logger = logging.getLogger("slh")
1594 logger.error("sp\xe4m")
1595 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001596 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001597 self.handled.clear()
1598 self.sl_hdlr.append_nul = False
1599 logger.error("sp\xe4m")
1600 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001601 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001602 self.handled.clear()
1603 self.sl_hdlr.ident = "h\xe4m-"
1604 logger.error("sp\xe4m")
1605 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001606 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001607
Victor Stinnerec5a8602014-06-02 14:41:51 +02001608@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001609@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001610class UnixSysLogHandlerTest(SysLogHandlerTest):
1611
1612 """Test for SysLogHandler with Unix sockets."""
1613
Victor Stinnerec5a8602014-06-02 14:41:51 +02001614 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001615 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001616
1617 def setUp(self):
1618 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001619 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001620 SysLogHandlerTest.setUp(self)
1621
1622 def tearDown(self):
1623 SysLogHandlerTest.tearDown(self)
1624 os.remove(self.address)
1625
Vinay Sajip5421f352013-09-27 18:18:28 +01001626@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001627class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001628 """Test for HTTPHandler."""
1629
Vinay Sajip9ba87612011-05-21 11:32:15 +01001630 PEMFILE = """-----BEGIN RSA PRIVATE KEY-----
1631MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG
1632zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5
1633aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB
1634AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7
16350tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB
16365LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs
1637piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy
16382z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y
1639i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN
1640PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb
1641E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa
1642rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8
1643/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV
1644-----END RSA PRIVATE KEY-----
1645-----BEGIN CERTIFICATE-----
1646MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
1647BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx
1648EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
1649xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9
1650l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt
1651vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O
1652BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo
1653S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM
1654BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq
16554f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+
16561c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt
1657IRbTpvlHWPjsSvHz0ZOH
1658-----END CERTIFICATE-----"""
1659
Vinay Sajip7367d082011-05-02 13:17:27 +01001660 def setUp(self):
1661 """Set up an HTTP server to receive log messages, and a HTTPHandler
1662 pointing to that server's address and port."""
1663 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 self.handled = threading.Event()
1665
Vinay Sajip7367d082011-05-02 13:17:27 +01001666 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001667 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001668 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001669 if self.command == 'POST':
1670 try:
1671 rlen = int(request.headers['Content-Length'])
1672 self.post_data = request.rfile.read(rlen)
1673 except:
1674 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001675 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001676 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001677 self.handled.set()
1678
1679 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001680 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001681 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001682 root_logger = self.root_logger
1683 root_logger.removeHandler(self.root_logger.handlers[0])
1684 for secure in (False, True):
1685 addr = ('localhost', 0)
1686 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001687 try:
1688 import ssl
1689 fd, fn = tempfile.mkstemp()
1690 os.close(fd)
1691 with open(fn, 'w') as f:
1692 f.write(self.PEMFILE)
1693 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1694 sslctx.load_cert_chain(fn)
1695 os.unlink(fn)
1696 except ImportError:
1697 sslctx = None
Vinay Sajip0372e102011-05-05 12:59:14 +01001698 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001699 sslctx = None
1700 self.server = server = TestHTTPServer(addr, self.handle_request,
1701 0.01, sslctx=sslctx)
1702 server.start()
1703 server.ready.wait()
1704 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001705 secure_client = secure and sslctx
1706 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
1707 secure=secure_client)
Vinay Sajip9ba87612011-05-21 11:32:15 +01001708 self.log_data = None
1709 root_logger.addHandler(self.h_hdlr)
1710
1711 for method in ('GET', 'POST'):
1712 self.h_hdlr.method = method
1713 self.handled.clear()
1714 msg = "sp\xe4m"
1715 logger.error(msg)
1716 self.handled.wait()
1717 self.assertEqual(self.log_data.path, '/frob')
1718 self.assertEqual(self.command, method)
1719 if method == 'GET':
1720 d = parse_qs(self.log_data.query)
1721 else:
1722 d = parse_qs(self.post_data.decode('utf-8'))
1723 self.assertEqual(d['name'], ['http'])
1724 self.assertEqual(d['funcName'], ['test_output'])
1725 self.assertEqual(d['msg'], [msg])
1726
1727 self.server.stop(2.0)
1728 self.root_logger.removeHandler(self.h_hdlr)
1729 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001730
Christian Heimes180510d2008-03-03 19:15:45 +00001731class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001732
Christian Heimes180510d2008-03-03 19:15:45 +00001733 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001734
Christian Heimes180510d2008-03-03 19:15:45 +00001735 def setUp(self):
1736 """Create a dict to remember potentially destroyed objects."""
1737 BaseTest.setUp(self)
1738 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001739
Christian Heimes180510d2008-03-03 19:15:45 +00001740 def _watch_for_survival(self, *args):
1741 """Watch the given objects for survival, by creating weakrefs to
1742 them."""
1743 for obj in args:
1744 key = id(obj), repr(obj)
1745 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001746
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001747 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001748 """Assert that all objects watched for survival have survived."""
1749 # Trigger cycle breaking.
1750 gc.collect()
1751 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001752 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001753 if ref() is None:
1754 dead.append(repr_)
1755 if dead:
1756 self.fail("%d objects should have survived "
1757 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001758
Christian Heimes180510d2008-03-03 19:15:45 +00001759 def test_persistent_loggers(self):
1760 # Logger objects are persistent and retain their configuration, even
1761 # if visible references are destroyed.
1762 self.root_logger.setLevel(logging.INFO)
1763 foo = logging.getLogger("foo")
1764 self._watch_for_survival(foo)
1765 foo.setLevel(logging.DEBUG)
1766 self.root_logger.debug(self.next_message())
1767 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001768 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001769 ('foo', 'DEBUG', '2'),
1770 ])
1771 del foo
1772 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001773 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001774 # foo has retained its settings.
1775 bar = logging.getLogger("foo")
1776 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001777 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001778 ('foo', 'DEBUG', '2'),
1779 ('foo', 'DEBUG', '3'),
1780 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001781
Benjamin Petersonf91df042009-02-13 02:50:59 +00001782
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001783class EncodingTest(BaseTest):
1784 def test_encoding_plain_file(self):
1785 # In Python 2.x, a plain file object is treated as having no encoding.
1786 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001787 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1788 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001789 # the non-ascii data we write to the log.
1790 data = "foo\x80"
1791 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001792 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001793 log.addHandler(handler)
1794 try:
1795 # write non-ascii data to the log.
1796 log.warning(data)
1797 finally:
1798 log.removeHandler(handler)
1799 handler.close()
1800 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001801 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001802 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001803 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001804 finally:
1805 f.close()
1806 finally:
1807 if os.path.isfile(fn):
1808 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001809
Benjamin Petersonf91df042009-02-13 02:50:59 +00001810 def test_encoding_cyrillic_unicode(self):
1811 log = logging.getLogger("test")
1812 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1813 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1814 #Ensure it's written in a Cyrillic encoding
1815 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001816 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001817 stream = io.BytesIO()
1818 writer = writer_class(stream, 'strict')
1819 handler = logging.StreamHandler(writer)
1820 log.addHandler(handler)
1821 try:
1822 log.warning(message)
1823 finally:
1824 log.removeHandler(handler)
1825 handler.close()
1826 # check we wrote exactly those bytes, ignoring trailing \n etc
1827 s = stream.getvalue()
1828 #Compare against what the data should be when encoded in CP-1251
1829 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1830
1831
Georg Brandlf9734072008-12-07 15:30:06 +00001832class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001833
Georg Brandlf9734072008-12-07 15:30:06 +00001834 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001835 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001836 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001837 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001838 warnings.filterwarnings("always", category=UserWarning)
1839 stream = io.StringIO()
1840 h = logging.StreamHandler(stream)
1841 logger = logging.getLogger("py.warnings")
1842 logger.addHandler(h)
1843 warnings.warn("I'm warning you...")
1844 logger.removeHandler(h)
1845 s = stream.getvalue()
1846 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001847 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001848
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001849 #See if an explicit file uses the original implementation
1850 a_file = io.StringIO()
1851 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1852 a_file, "Dummy line")
1853 s = a_file.getvalue()
1854 a_file.close()
1855 self.assertEqual(s,
1856 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1857
1858 def test_warnings_no_handlers(self):
1859 with warnings.catch_warnings():
1860 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001861 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001862
1863 # confirm our assumption: no loggers are set
1864 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001865 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001866
1867 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001868 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001869 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001870
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001871
1872def formatFunc(format, datefmt=None):
1873 return logging.Formatter(format, datefmt)
1874
1875def handlerFunc():
1876 return logging.StreamHandler()
1877
1878class CustomHandler(logging.StreamHandler):
1879 pass
1880
1881class ConfigDictTest(BaseTest):
1882
1883 """Reading logging config from a dictionary."""
1884
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001885 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001886
1887 # config0 is a standard configuration.
1888 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001889 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001890 'formatters': {
1891 'form1' : {
1892 'format' : '%(levelname)s ++ %(message)s',
1893 },
1894 },
1895 'handlers' : {
1896 'hand1' : {
1897 'class' : 'logging.StreamHandler',
1898 'formatter' : 'form1',
1899 'level' : 'NOTSET',
1900 'stream' : 'ext://sys.stdout',
1901 },
1902 },
1903 'root' : {
1904 'level' : 'WARNING',
1905 'handlers' : ['hand1'],
1906 },
1907 }
1908
1909 # config1 adds a little to the standard configuration.
1910 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001911 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001912 'formatters': {
1913 'form1' : {
1914 'format' : '%(levelname)s ++ %(message)s',
1915 },
1916 },
1917 'handlers' : {
1918 'hand1' : {
1919 'class' : 'logging.StreamHandler',
1920 'formatter' : 'form1',
1921 'level' : 'NOTSET',
1922 'stream' : 'ext://sys.stdout',
1923 },
1924 },
1925 'loggers' : {
1926 'compiler.parser' : {
1927 'level' : 'DEBUG',
1928 'handlers' : ['hand1'],
1929 },
1930 },
1931 'root' : {
1932 'level' : 'WARNING',
1933 },
1934 }
1935
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001936 # config1a moves the handler to the root. Used with config8a
1937 config1a = {
1938 'version': 1,
1939 'formatters': {
1940 'form1' : {
1941 'format' : '%(levelname)s ++ %(message)s',
1942 },
1943 },
1944 'handlers' : {
1945 'hand1' : {
1946 'class' : 'logging.StreamHandler',
1947 'formatter' : 'form1',
1948 'level' : 'NOTSET',
1949 'stream' : 'ext://sys.stdout',
1950 },
1951 },
1952 'loggers' : {
1953 'compiler.parser' : {
1954 'level' : 'DEBUG',
1955 },
1956 },
1957 'root' : {
1958 'level' : 'WARNING',
1959 'handlers' : ['hand1'],
1960 },
1961 }
1962
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001963 # config2 has a subtle configuration error that should be reported
1964 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001965 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001966 'formatters': {
1967 'form1' : {
1968 'format' : '%(levelname)s ++ %(message)s',
1969 },
1970 },
1971 'handlers' : {
1972 'hand1' : {
1973 'class' : 'logging.StreamHandler',
1974 'formatter' : 'form1',
1975 'level' : 'NOTSET',
1976 'stream' : 'ext://sys.stdbout',
1977 },
1978 },
1979 'loggers' : {
1980 'compiler.parser' : {
1981 'level' : 'DEBUG',
1982 'handlers' : ['hand1'],
1983 },
1984 },
1985 'root' : {
1986 'level' : 'WARNING',
1987 },
1988 }
1989
1990 #As config1 but with a misspelt level on a handler
1991 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001992 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001993 'formatters': {
1994 'form1' : {
1995 'format' : '%(levelname)s ++ %(message)s',
1996 },
1997 },
1998 'handlers' : {
1999 'hand1' : {
2000 'class' : 'logging.StreamHandler',
2001 'formatter' : 'form1',
2002 'level' : 'NTOSET',
2003 'stream' : 'ext://sys.stdout',
2004 },
2005 },
2006 'loggers' : {
2007 'compiler.parser' : {
2008 'level' : 'DEBUG',
2009 'handlers' : ['hand1'],
2010 },
2011 },
2012 'root' : {
2013 'level' : 'WARNING',
2014 },
2015 }
2016
2017
2018 #As config1 but with a misspelt level on a logger
2019 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002020 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002021 'formatters': {
2022 'form1' : {
2023 'format' : '%(levelname)s ++ %(message)s',
2024 },
2025 },
2026 'handlers' : {
2027 'hand1' : {
2028 'class' : 'logging.StreamHandler',
2029 'formatter' : 'form1',
2030 'level' : 'NOTSET',
2031 'stream' : 'ext://sys.stdout',
2032 },
2033 },
2034 'loggers' : {
2035 'compiler.parser' : {
2036 'level' : 'DEBUG',
2037 'handlers' : ['hand1'],
2038 },
2039 },
2040 'root' : {
2041 'level' : 'WRANING',
2042 },
2043 }
2044
2045 # config3 has a less subtle configuration error
2046 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002047 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002048 'formatters': {
2049 'form1' : {
2050 'format' : '%(levelname)s ++ %(message)s',
2051 },
2052 },
2053 'handlers' : {
2054 'hand1' : {
2055 'class' : 'logging.StreamHandler',
2056 'formatter' : 'misspelled_name',
2057 'level' : 'NOTSET',
2058 'stream' : 'ext://sys.stdout',
2059 },
2060 },
2061 'loggers' : {
2062 'compiler.parser' : {
2063 'level' : 'DEBUG',
2064 'handlers' : ['hand1'],
2065 },
2066 },
2067 'root' : {
2068 'level' : 'WARNING',
2069 },
2070 }
2071
2072 # config4 specifies a custom formatter class to be loaded
2073 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002074 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002075 'formatters': {
2076 'form1' : {
2077 '()' : __name__ + '.ExceptionFormatter',
2078 'format' : '%(levelname)s:%(name)s:%(message)s',
2079 },
2080 },
2081 'handlers' : {
2082 'hand1' : {
2083 'class' : 'logging.StreamHandler',
2084 'formatter' : 'form1',
2085 'level' : 'NOTSET',
2086 'stream' : 'ext://sys.stdout',
2087 },
2088 },
2089 'root' : {
2090 'level' : 'NOTSET',
2091 'handlers' : ['hand1'],
2092 },
2093 }
2094
2095 # As config4 but using an actual callable rather than a string
2096 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002097 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002098 'formatters': {
2099 'form1' : {
2100 '()' : ExceptionFormatter,
2101 'format' : '%(levelname)s:%(name)s:%(message)s',
2102 },
2103 'form2' : {
2104 '()' : __name__ + '.formatFunc',
2105 'format' : '%(levelname)s:%(name)s:%(message)s',
2106 },
2107 'form3' : {
2108 '()' : formatFunc,
2109 'format' : '%(levelname)s:%(name)s:%(message)s',
2110 },
2111 },
2112 'handlers' : {
2113 'hand1' : {
2114 'class' : 'logging.StreamHandler',
2115 'formatter' : 'form1',
2116 'level' : 'NOTSET',
2117 'stream' : 'ext://sys.stdout',
2118 },
2119 'hand2' : {
2120 '()' : handlerFunc,
2121 },
2122 },
2123 'root' : {
2124 'level' : 'NOTSET',
2125 'handlers' : ['hand1'],
2126 },
2127 }
2128
2129 # config5 specifies a custom handler class to be loaded
2130 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002131 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002132 'formatters': {
2133 'form1' : {
2134 'format' : '%(levelname)s ++ %(message)s',
2135 },
2136 },
2137 'handlers' : {
2138 'hand1' : {
2139 'class' : __name__ + '.CustomHandler',
2140 'formatter' : 'form1',
2141 'level' : 'NOTSET',
2142 'stream' : 'ext://sys.stdout',
2143 },
2144 },
2145 'loggers' : {
2146 'compiler.parser' : {
2147 'level' : 'DEBUG',
2148 'handlers' : ['hand1'],
2149 },
2150 },
2151 'root' : {
2152 'level' : 'WARNING',
2153 },
2154 }
2155
2156 # config6 specifies a custom handler class to be loaded
2157 # but has bad arguments
2158 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002159 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002160 'formatters': {
2161 'form1' : {
2162 'format' : '%(levelname)s ++ %(message)s',
2163 },
2164 },
2165 'handlers' : {
2166 'hand1' : {
2167 'class' : __name__ + '.CustomHandler',
2168 'formatter' : 'form1',
2169 'level' : 'NOTSET',
2170 'stream' : 'ext://sys.stdout',
2171 '9' : 'invalid parameter name',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.parser' : {
2176 'level' : 'DEBUG',
2177 'handlers' : ['hand1'],
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WARNING',
2182 },
2183 }
2184
2185 #config 7 does not define compiler.parser but defines compiler.lexer
2186 #so compiler.parser should be disabled after applying it
2187 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002188 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002189 'formatters': {
2190 'form1' : {
2191 'format' : '%(levelname)s ++ %(message)s',
2192 },
2193 },
2194 'handlers' : {
2195 'hand1' : {
2196 'class' : 'logging.StreamHandler',
2197 'formatter' : 'form1',
2198 'level' : 'NOTSET',
2199 'stream' : 'ext://sys.stdout',
2200 },
2201 },
2202 'loggers' : {
2203 'compiler.lexer' : {
2204 'level' : 'DEBUG',
2205 'handlers' : ['hand1'],
2206 },
2207 },
2208 'root' : {
2209 'level' : 'WARNING',
2210 },
2211 }
2212
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002213 # config8 defines both compiler and compiler.lexer
2214 # so compiler.parser should not be disabled (since
2215 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002216 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002217 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002218 'disable_existing_loggers' : False,
2219 'formatters': {
2220 'form1' : {
2221 'format' : '%(levelname)s ++ %(message)s',
2222 },
2223 },
2224 'handlers' : {
2225 'hand1' : {
2226 'class' : 'logging.StreamHandler',
2227 'formatter' : 'form1',
2228 'level' : 'NOTSET',
2229 'stream' : 'ext://sys.stdout',
2230 },
2231 },
2232 'loggers' : {
2233 'compiler' : {
2234 'level' : 'DEBUG',
2235 'handlers' : ['hand1'],
2236 },
2237 'compiler.lexer' : {
2238 },
2239 },
2240 'root' : {
2241 'level' : 'WARNING',
2242 },
2243 }
2244
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002245 # config8a disables existing loggers
2246 config8a = {
2247 'version': 1,
2248 'disable_existing_loggers' : True,
2249 'formatters': {
2250 'form1' : {
2251 'format' : '%(levelname)s ++ %(message)s',
2252 },
2253 },
2254 'handlers' : {
2255 'hand1' : {
2256 'class' : 'logging.StreamHandler',
2257 'formatter' : 'form1',
2258 'level' : 'NOTSET',
2259 'stream' : 'ext://sys.stdout',
2260 },
2261 },
2262 'loggers' : {
2263 'compiler' : {
2264 'level' : 'DEBUG',
2265 'handlers' : ['hand1'],
2266 },
2267 'compiler.lexer' : {
2268 },
2269 },
2270 'root' : {
2271 'level' : 'WARNING',
2272 },
2273 }
2274
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002275 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002276 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002277 'formatters': {
2278 'form1' : {
2279 'format' : '%(levelname)s ++ %(message)s',
2280 },
2281 },
2282 'handlers' : {
2283 'hand1' : {
2284 'class' : 'logging.StreamHandler',
2285 'formatter' : 'form1',
2286 'level' : 'WARNING',
2287 'stream' : 'ext://sys.stdout',
2288 },
2289 },
2290 'loggers' : {
2291 'compiler.parser' : {
2292 'level' : 'WARNING',
2293 'handlers' : ['hand1'],
2294 },
2295 },
2296 'root' : {
2297 'level' : 'NOTSET',
2298 },
2299 }
2300
2301 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002302 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002303 'incremental' : True,
2304 'handlers' : {
2305 'hand1' : {
2306 'level' : 'WARNING',
2307 },
2308 },
2309 'loggers' : {
2310 'compiler.parser' : {
2311 'level' : 'INFO',
2312 },
2313 },
2314 }
2315
2316 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002317 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002318 'incremental' : True,
2319 'handlers' : {
2320 'hand1' : {
2321 'level' : 'INFO',
2322 },
2323 },
2324 'loggers' : {
2325 'compiler.parser' : {
2326 'level' : 'INFO',
2327 },
2328 },
2329 }
2330
2331 #As config1 but with a filter added
2332 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002333 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002334 'formatters': {
2335 'form1' : {
2336 'format' : '%(levelname)s ++ %(message)s',
2337 },
2338 },
2339 'filters' : {
2340 'filt1' : {
2341 'name' : 'compiler.parser',
2342 },
2343 },
2344 'handlers' : {
2345 'hand1' : {
2346 'class' : 'logging.StreamHandler',
2347 'formatter' : 'form1',
2348 'level' : 'NOTSET',
2349 'stream' : 'ext://sys.stdout',
2350 'filters' : ['filt1'],
2351 },
2352 },
2353 'loggers' : {
2354 'compiler.parser' : {
2355 'level' : 'DEBUG',
2356 'filters' : ['filt1'],
2357 },
2358 },
2359 'root' : {
2360 'level' : 'WARNING',
2361 'handlers' : ['hand1'],
2362 },
2363 }
2364
2365 #As config1 but using cfg:// references
2366 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002367 'version': 1,
2368 'true_formatters': {
2369 'form1' : {
2370 'format' : '%(levelname)s ++ %(message)s',
2371 },
2372 },
2373 'handler_configs': {
2374 'hand1' : {
2375 'class' : 'logging.StreamHandler',
2376 'formatter' : 'form1',
2377 'level' : 'NOTSET',
2378 'stream' : 'ext://sys.stdout',
2379 },
2380 },
2381 'formatters' : 'cfg://true_formatters',
2382 'handlers' : {
2383 'hand1' : 'cfg://handler_configs[hand1]',
2384 },
2385 'loggers' : {
2386 'compiler.parser' : {
2387 'level' : 'DEBUG',
2388 'handlers' : ['hand1'],
2389 },
2390 },
2391 'root' : {
2392 'level' : 'WARNING',
2393 },
2394 }
2395
2396 #As config11 but missing the version key
2397 config12 = {
2398 'true_formatters': {
2399 'form1' : {
2400 'format' : '%(levelname)s ++ %(message)s',
2401 },
2402 },
2403 'handler_configs': {
2404 'hand1' : {
2405 'class' : 'logging.StreamHandler',
2406 'formatter' : 'form1',
2407 'level' : 'NOTSET',
2408 'stream' : 'ext://sys.stdout',
2409 },
2410 },
2411 'formatters' : 'cfg://true_formatters',
2412 'handlers' : {
2413 'hand1' : 'cfg://handler_configs[hand1]',
2414 },
2415 'loggers' : {
2416 'compiler.parser' : {
2417 'level' : 'DEBUG',
2418 'handlers' : ['hand1'],
2419 },
2420 },
2421 'root' : {
2422 'level' : 'WARNING',
2423 },
2424 }
2425
2426 #As config11 but using an unsupported version
2427 config13 = {
2428 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002429 'true_formatters': {
2430 'form1' : {
2431 'format' : '%(levelname)s ++ %(message)s',
2432 },
2433 },
2434 'handler_configs': {
2435 'hand1' : {
2436 'class' : 'logging.StreamHandler',
2437 'formatter' : 'form1',
2438 'level' : 'NOTSET',
2439 'stream' : 'ext://sys.stdout',
2440 },
2441 },
2442 'formatters' : 'cfg://true_formatters',
2443 'handlers' : {
2444 'hand1' : 'cfg://handler_configs[hand1]',
2445 },
2446 'loggers' : {
2447 'compiler.parser' : {
2448 'level' : 'DEBUG',
2449 'handlers' : ['hand1'],
2450 },
2451 },
2452 'root' : {
2453 'level' : 'WARNING',
2454 },
2455 }
2456
Vinay Sajip8d270232012-11-15 14:20:18 +00002457 # As config0, but with properties
2458 config14 = {
2459 'version': 1,
2460 'formatters': {
2461 'form1' : {
2462 'format' : '%(levelname)s ++ %(message)s',
2463 },
2464 },
2465 'handlers' : {
2466 'hand1' : {
2467 'class' : 'logging.StreamHandler',
2468 'formatter' : 'form1',
2469 'level' : 'NOTSET',
2470 'stream' : 'ext://sys.stdout',
2471 '.': {
2472 'foo': 'bar',
2473 'terminator': '!\n',
2474 }
2475 },
2476 },
2477 'root' : {
2478 'level' : 'WARNING',
2479 'handlers' : ['hand1'],
2480 },
2481 }
2482
Vinay Sajip3f885b52013-03-22 15:19:54 +00002483 out_of_order = {
2484 "version": 1,
2485 "formatters": {
2486 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002487 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2488 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002489 }
2490 },
2491 "handlers": {
2492 "fileGlobal": {
2493 "class": "logging.StreamHandler",
2494 "level": "DEBUG",
2495 "formatter": "mySimpleFormatter"
2496 },
2497 "bufferGlobal": {
2498 "class": "logging.handlers.MemoryHandler",
2499 "capacity": 5,
2500 "formatter": "mySimpleFormatter",
2501 "target": "fileGlobal",
2502 "level": "DEBUG"
2503 }
2504 },
2505 "loggers": {
2506 "mymodule": {
2507 "level": "DEBUG",
2508 "handlers": ["bufferGlobal"],
2509 "propagate": "true"
2510 }
2511 }
2512 }
2513
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002514 def apply_config(self, conf):
2515 logging.config.dictConfig(conf)
2516
2517 def test_config0_ok(self):
2518 # A simple config which overrides the default settings.
2519 with captured_stdout() as output:
2520 self.apply_config(self.config0)
2521 logger = logging.getLogger()
2522 # Won't output anything
2523 logger.info(self.next_message())
2524 # Outputs a message
2525 logger.error(self.next_message())
2526 self.assert_log_lines([
2527 ('ERROR', '2'),
2528 ], stream=output)
2529 # Original logger output is empty.
2530 self.assert_log_lines([])
2531
2532 def test_config1_ok(self, config=config1):
2533 # A config defining a sub-parser as well.
2534 with captured_stdout() as output:
2535 self.apply_config(config)
2536 logger = logging.getLogger("compiler.parser")
2537 # Both will output a message
2538 logger.info(self.next_message())
2539 logger.error(self.next_message())
2540 self.assert_log_lines([
2541 ('INFO', '1'),
2542 ('ERROR', '2'),
2543 ], stream=output)
2544 # Original logger output is empty.
2545 self.assert_log_lines([])
2546
2547 def test_config2_failure(self):
2548 # A simple config which overrides the default settings.
2549 self.assertRaises(Exception, self.apply_config, self.config2)
2550
2551 def test_config2a_failure(self):
2552 # A simple config which overrides the default settings.
2553 self.assertRaises(Exception, self.apply_config, self.config2a)
2554
2555 def test_config2b_failure(self):
2556 # A simple config which overrides the default settings.
2557 self.assertRaises(Exception, self.apply_config, self.config2b)
2558
2559 def test_config3_failure(self):
2560 # A simple config which overrides the default settings.
2561 self.assertRaises(Exception, self.apply_config, self.config3)
2562
2563 def test_config4_ok(self):
2564 # A config specifying a custom formatter class.
2565 with captured_stdout() as output:
2566 self.apply_config(self.config4)
2567 #logger = logging.getLogger()
2568 try:
2569 raise RuntimeError()
2570 except RuntimeError:
2571 logging.exception("just testing")
2572 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002573 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002574 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2575 # Original logger output is empty
2576 self.assert_log_lines([])
2577
2578 def test_config4a_ok(self):
2579 # A config specifying a custom formatter class.
2580 with captured_stdout() as output:
2581 self.apply_config(self.config4a)
2582 #logger = logging.getLogger()
2583 try:
2584 raise RuntimeError()
2585 except RuntimeError:
2586 logging.exception("just testing")
2587 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002588 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002589 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2590 # Original logger output is empty
2591 self.assert_log_lines([])
2592
2593 def test_config5_ok(self):
2594 self.test_config1_ok(config=self.config5)
2595
2596 def test_config6_failure(self):
2597 self.assertRaises(Exception, self.apply_config, self.config6)
2598
2599 def test_config7_ok(self):
2600 with captured_stdout() as output:
2601 self.apply_config(self.config1)
2602 logger = logging.getLogger("compiler.parser")
2603 # Both will output a message
2604 logger.info(self.next_message())
2605 logger.error(self.next_message())
2606 self.assert_log_lines([
2607 ('INFO', '1'),
2608 ('ERROR', '2'),
2609 ], stream=output)
2610 # Original logger output is empty.
2611 self.assert_log_lines([])
2612 with captured_stdout() as output:
2613 self.apply_config(self.config7)
2614 logger = logging.getLogger("compiler.parser")
2615 self.assertTrue(logger.disabled)
2616 logger = logging.getLogger("compiler.lexer")
2617 # Both will output a message
2618 logger.info(self.next_message())
2619 logger.error(self.next_message())
2620 self.assert_log_lines([
2621 ('INFO', '3'),
2622 ('ERROR', '4'),
2623 ], stream=output)
2624 # Original logger output is empty.
2625 self.assert_log_lines([])
2626
2627 #Same as test_config_7_ok but don't disable old loggers.
2628 def test_config_8_ok(self):
2629 with captured_stdout() as output:
2630 self.apply_config(self.config1)
2631 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002632 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002633 logger.info(self.next_message())
2634 logger.error(self.next_message())
2635 self.assert_log_lines([
2636 ('INFO', '1'),
2637 ('ERROR', '2'),
2638 ], stream=output)
2639 # Original logger output is empty.
2640 self.assert_log_lines([])
2641 with captured_stdout() as output:
2642 self.apply_config(self.config8)
2643 logger = logging.getLogger("compiler.parser")
2644 self.assertFalse(logger.disabled)
2645 # Both will output a message
2646 logger.info(self.next_message())
2647 logger.error(self.next_message())
2648 logger = logging.getLogger("compiler.lexer")
2649 # Both will output a message
2650 logger.info(self.next_message())
2651 logger.error(self.next_message())
2652 self.assert_log_lines([
2653 ('INFO', '3'),
2654 ('ERROR', '4'),
2655 ('INFO', '5'),
2656 ('ERROR', '6'),
2657 ], stream=output)
2658 # Original logger output is empty.
2659 self.assert_log_lines([])
2660
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002661 def test_config_8a_ok(self):
2662 with captured_stdout() as output:
2663 self.apply_config(self.config1a)
2664 logger = logging.getLogger("compiler.parser")
2665 # See issue #11424. compiler-hyphenated sorts
2666 # between compiler and compiler.xyz and this
2667 # was preventing compiler.xyz from being included
2668 # in the child loggers of compiler because of an
2669 # overzealous loop termination condition.
2670 hyphenated = logging.getLogger('compiler-hyphenated')
2671 # All will output a message
2672 logger.info(self.next_message())
2673 logger.error(self.next_message())
2674 hyphenated.critical(self.next_message())
2675 self.assert_log_lines([
2676 ('INFO', '1'),
2677 ('ERROR', '2'),
2678 ('CRITICAL', '3'),
2679 ], stream=output)
2680 # Original logger output is empty.
2681 self.assert_log_lines([])
2682 with captured_stdout() as output:
2683 self.apply_config(self.config8a)
2684 logger = logging.getLogger("compiler.parser")
2685 self.assertFalse(logger.disabled)
2686 # Both will output a message
2687 logger.info(self.next_message())
2688 logger.error(self.next_message())
2689 logger = logging.getLogger("compiler.lexer")
2690 # Both will output a message
2691 logger.info(self.next_message())
2692 logger.error(self.next_message())
2693 # Will not appear
2694 hyphenated.critical(self.next_message())
2695 self.assert_log_lines([
2696 ('INFO', '4'),
2697 ('ERROR', '5'),
2698 ('INFO', '6'),
2699 ('ERROR', '7'),
2700 ], stream=output)
2701 # Original logger output is empty.
2702 self.assert_log_lines([])
2703
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002704 def test_config_9_ok(self):
2705 with captured_stdout() as output:
2706 self.apply_config(self.config9)
2707 logger = logging.getLogger("compiler.parser")
2708 #Nothing will be output since both handler and logger are set to WARNING
2709 logger.info(self.next_message())
2710 self.assert_log_lines([], stream=output)
2711 self.apply_config(self.config9a)
2712 #Nothing will be output since both handler is still set to WARNING
2713 logger.info(self.next_message())
2714 self.assert_log_lines([], stream=output)
2715 self.apply_config(self.config9b)
2716 #Message should now be output
2717 logger.info(self.next_message())
2718 self.assert_log_lines([
2719 ('INFO', '3'),
2720 ], stream=output)
2721
2722 def test_config_10_ok(self):
2723 with captured_stdout() as output:
2724 self.apply_config(self.config10)
2725 logger = logging.getLogger("compiler.parser")
2726 logger.warning(self.next_message())
2727 logger = logging.getLogger('compiler')
2728 #Not output, because filtered
2729 logger.warning(self.next_message())
2730 logger = logging.getLogger('compiler.lexer')
2731 #Not output, because filtered
2732 logger.warning(self.next_message())
2733 logger = logging.getLogger("compiler.parser.codegen")
2734 #Output, as not filtered
2735 logger.error(self.next_message())
2736 self.assert_log_lines([
2737 ('WARNING', '1'),
2738 ('ERROR', '4'),
2739 ], stream=output)
2740
2741 def test_config11_ok(self):
2742 self.test_config1_ok(self.config11)
2743
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002744 def test_config12_failure(self):
2745 self.assertRaises(Exception, self.apply_config, self.config12)
2746
2747 def test_config13_failure(self):
2748 self.assertRaises(Exception, self.apply_config, self.config13)
2749
Vinay Sajip8d270232012-11-15 14:20:18 +00002750 def test_config14_ok(self):
2751 with captured_stdout() as output:
2752 self.apply_config(self.config14)
2753 h = logging._handlers['hand1']
2754 self.assertEqual(h.foo, 'bar')
2755 self.assertEqual(h.terminator, '!\n')
2756 logging.warning('Exclamation')
2757 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2758
Victor Stinner45df8202010-04-28 22:31:17 +00002759 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002760 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002761 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002762 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002763 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002764 t.start()
2765 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002766 # Now get the port allocated
2767 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002769 try:
2770 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2771 sock.settimeout(2.0)
2772 sock.connect(('localhost', port))
2773
2774 slen = struct.pack('>L', len(text))
2775 s = slen + text
2776 sentsofar = 0
2777 left = len(s)
2778 while left > 0:
2779 sent = sock.send(s[sentsofar:])
2780 sentsofar += sent
2781 left -= sent
2782 sock.close()
2783 finally:
2784 t.ready.wait(2.0)
2785 logging.config.stopListening()
2786 t.join(2.0)
2787
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002788 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002789 def test_listen_config_10_ok(self):
2790 with captured_stdout() as output:
2791 self.setup_via_listener(json.dumps(self.config10))
2792 logger = logging.getLogger("compiler.parser")
2793 logger.warning(self.next_message())
2794 logger = logging.getLogger('compiler')
2795 #Not output, because filtered
2796 logger.warning(self.next_message())
2797 logger = logging.getLogger('compiler.lexer')
2798 #Not output, because filtered
2799 logger.warning(self.next_message())
2800 logger = logging.getLogger("compiler.parser.codegen")
2801 #Output, as not filtered
2802 logger.error(self.next_message())
2803 self.assert_log_lines([
2804 ('WARNING', '1'),
2805 ('ERROR', '4'),
2806 ], stream=output)
2807
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002808 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002809 def test_listen_config_1_ok(self):
2810 with captured_stdout() as output:
2811 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2812 logger = logging.getLogger("compiler.parser")
2813 # Both will output a message
2814 logger.info(self.next_message())
2815 logger.error(self.next_message())
2816 self.assert_log_lines([
2817 ('INFO', '1'),
2818 ('ERROR', '2'),
2819 ], stream=output)
2820 # Original logger output is empty.
2821 self.assert_log_lines([])
2822
Vinay Sajip4ded5512012-10-02 15:56:16 +01002823 @unittest.skipUnless(threading, 'Threading required for this test.')
2824 def test_listen_verify(self):
2825
2826 def verify_fail(stuff):
2827 return None
2828
2829 def verify_reverse(stuff):
2830 return stuff[::-1]
2831
2832 logger = logging.getLogger("compiler.parser")
2833 to_send = textwrap.dedent(ConfigFileTest.config1)
2834 # First, specify a verification function that will fail.
2835 # We expect to see no output, since our configuration
2836 # never took effect.
2837 with captured_stdout() as output:
2838 self.setup_via_listener(to_send, verify_fail)
2839 # Both will output a message
2840 logger.info(self.next_message())
2841 logger.error(self.next_message())
2842 self.assert_log_lines([], stream=output)
2843 # Original logger output has the stuff we logged.
2844 self.assert_log_lines([
2845 ('INFO', '1'),
2846 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002847 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002848
2849 # Now, perform no verification. Our configuration
2850 # should take effect.
2851
2852 with captured_stdout() as output:
2853 self.setup_via_listener(to_send) # no verify callable specified
2854 logger = logging.getLogger("compiler.parser")
2855 # Both will output a message
2856 logger.info(self.next_message())
2857 logger.error(self.next_message())
2858 self.assert_log_lines([
2859 ('INFO', '3'),
2860 ('ERROR', '4'),
2861 ], stream=output)
2862 # Original logger output still has the stuff we logged before.
2863 self.assert_log_lines([
2864 ('INFO', '1'),
2865 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002866 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002867
2868 # Now, perform verification which transforms the bytes.
2869
2870 with captured_stdout() as output:
2871 self.setup_via_listener(to_send[::-1], verify_reverse)
2872 logger = logging.getLogger("compiler.parser")
2873 # Both will output a message
2874 logger.info(self.next_message())
2875 logger.error(self.next_message())
2876 self.assert_log_lines([
2877 ('INFO', '5'),
2878 ('ERROR', '6'),
2879 ], stream=output)
2880 # Original logger output still has the stuff we logged before.
2881 self.assert_log_lines([
2882 ('INFO', '1'),
2883 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002884 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002885
Vinay Sajip3f885b52013-03-22 15:19:54 +00002886 def test_out_of_order(self):
2887 self.apply_config(self.out_of_order)
2888 handler = logging.getLogger('mymodule').handlers[0]
2889 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002890 self.assertIsInstance(handler.formatter._style,
2891 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002892
Vinay Sajip373baef2011-04-26 20:05:24 +01002893 def test_baseconfig(self):
2894 d = {
2895 'atuple': (1, 2, 3),
2896 'alist': ['a', 'b', 'c'],
2897 'adict': {'d': 'e', 'f': 3 },
2898 'nest1': ('g', ('h', 'i'), 'j'),
2899 'nest2': ['k', ['l', 'm'], 'n'],
2900 'nest3': ['o', 'cfg://alist', 'p'],
2901 }
2902 bc = logging.config.BaseConfigurator(d)
2903 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2904 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2905 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2906 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2907 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2908 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2909 v = bc.convert('cfg://nest3')
2910 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2911 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2912 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2913 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002914
2915class ManagerTest(BaseTest):
2916 def test_manager_loggerclass(self):
2917 logged = []
2918
2919 class MyLogger(logging.Logger):
2920 def _log(self, level, msg, args, exc_info=None, extra=None):
2921 logged.append(msg)
2922
2923 man = logging.Manager(None)
2924 self.assertRaises(TypeError, man.setLoggerClass, int)
2925 man.setLoggerClass(MyLogger)
2926 logger = man.getLogger('test')
2927 logger.warning('should appear in logged')
2928 logging.warning('should not appear in logged')
2929
2930 self.assertEqual(logged, ['should appear in logged'])
2931
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002932 def test_set_log_record_factory(self):
2933 man = logging.Manager(None)
2934 expected = object()
2935 man.setLogRecordFactory(expected)
2936 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002937
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002938class ChildLoggerTest(BaseTest):
2939 def test_child_loggers(self):
2940 r = logging.getLogger()
2941 l1 = logging.getLogger('abc')
2942 l2 = logging.getLogger('def.ghi')
2943 c1 = r.getChild('xyz')
2944 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002945 self.assertIs(c1, logging.getLogger('xyz'))
2946 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002947 c1 = l1.getChild('def')
2948 c2 = c1.getChild('ghi')
2949 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002950 self.assertIs(c1, logging.getLogger('abc.def'))
2951 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2952 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002953
2954
Vinay Sajip6fac8172010-10-19 20:44:14 +00002955class DerivedLogRecord(logging.LogRecord):
2956 pass
2957
Vinay Sajip61561522010-12-03 11:50:38 +00002958class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002959
2960 def setUp(self):
2961 class CheckingFilter(logging.Filter):
2962 def __init__(self, cls):
2963 self.cls = cls
2964
2965 def filter(self, record):
2966 t = type(record)
2967 if t is not self.cls:
2968 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2969 self.cls)
2970 raise TypeError(msg)
2971 return True
2972
2973 BaseTest.setUp(self)
2974 self.filter = CheckingFilter(DerivedLogRecord)
2975 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002976 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002977
2978 def tearDown(self):
2979 self.root_logger.removeFilter(self.filter)
2980 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002981 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002982
2983 def test_logrecord_class(self):
2984 self.assertRaises(TypeError, self.root_logger.warning,
2985 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002986 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002987 self.root_logger.error(self.next_message())
2988 self.assert_log_lines([
2989 ('root', 'ERROR', '2'),
2990 ])
2991
2992
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002993class QueueHandlerTest(BaseTest):
2994 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002995 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002996
2997 def setUp(self):
2998 BaseTest.setUp(self)
2999 self.queue = queue.Queue(-1)
3000 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3001 self.que_logger = logging.getLogger('que')
3002 self.que_logger.propagate = False
3003 self.que_logger.setLevel(logging.WARNING)
3004 self.que_logger.addHandler(self.que_hdlr)
3005
3006 def tearDown(self):
3007 self.que_hdlr.close()
3008 BaseTest.tearDown(self)
3009
3010 def test_queue_handler(self):
3011 self.que_logger.debug(self.next_message())
3012 self.assertRaises(queue.Empty, self.queue.get_nowait)
3013 self.que_logger.info(self.next_message())
3014 self.assertRaises(queue.Empty, self.queue.get_nowait)
3015 msg = self.next_message()
3016 self.que_logger.warning(msg)
3017 data = self.queue.get_nowait()
3018 self.assertTrue(isinstance(data, logging.LogRecord))
3019 self.assertEqual(data.name, self.que_logger.name)
3020 self.assertEqual((data.msg, data.args), (msg, None))
3021
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003022 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3023 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003024 def test_queue_listener(self):
3025 handler = TestHandler(Matcher())
3026 listener = logging.handlers.QueueListener(self.queue, handler)
3027 listener.start()
3028 try:
3029 self.que_logger.warning(self.next_message())
3030 self.que_logger.error(self.next_message())
3031 self.que_logger.critical(self.next_message())
3032 finally:
3033 listener.stop()
3034 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3035 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3036 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
3037
Vinay Sajip37eb3382011-04-26 20:26:41 +01003038ZERO = datetime.timedelta(0)
3039
3040class UTC(datetime.tzinfo):
3041 def utcoffset(self, dt):
3042 return ZERO
3043
3044 dst = utcoffset
3045
3046 def tzname(self, dt):
3047 return 'UTC'
3048
3049utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003050
Vinay Sajipa39c5712010-10-25 13:57:39 +00003051class FormatterTest(unittest.TestCase):
3052 def setUp(self):
3053 self.common = {
3054 'name': 'formatter.test',
3055 'level': logging.DEBUG,
3056 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3057 'lineno': 42,
3058 'exc_info': None,
3059 'func': None,
3060 'msg': 'Message with %d %s',
3061 'args': (2, 'placeholders'),
3062 }
3063 self.variants = {
3064 }
3065
3066 def get_record(self, name=None):
3067 result = dict(self.common)
3068 if name is not None:
3069 result.update(self.variants[name])
3070 return logging.makeLogRecord(result)
3071
3072 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003073 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003074 r = self.get_record()
3075 f = logging.Formatter('${%(message)s}')
3076 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3077 f = logging.Formatter('%(random)s')
3078 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003079 self.assertFalse(f.usesTime())
3080 f = logging.Formatter('%(asctime)s')
3081 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003082 f = logging.Formatter('%(asctime)-15s')
3083 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003084 f = logging.Formatter('asctime')
3085 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003086
3087 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003088 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003089 r = self.get_record()
3090 f = logging.Formatter('$%{message}%$', style='{')
3091 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3092 f = logging.Formatter('{random}', style='{')
3093 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003094 self.assertFalse(f.usesTime())
3095 f = logging.Formatter('{asctime}', style='{')
3096 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003097 f = logging.Formatter('{asctime!s:15}', style='{')
3098 self.assertTrue(f.usesTime())
3099 f = logging.Formatter('{asctime:15}', style='{')
3100 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003101 f = logging.Formatter('asctime', style='{')
3102 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003103
3104 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003105 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003106 r = self.get_record()
3107 f = logging.Formatter('$message', style='$')
3108 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3109 f = logging.Formatter('$$%${message}%$$', style='$')
3110 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3111 f = logging.Formatter('${random}', style='$')
3112 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003113 self.assertFalse(f.usesTime())
3114 f = logging.Formatter('${asctime}', style='$')
3115 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003116 f = logging.Formatter('${asctime', style='$')
3117 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003118 f = logging.Formatter('$asctime', style='$')
3119 self.assertTrue(f.usesTime())
3120 f = logging.Formatter('asctime', style='$')
3121 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003122
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003123 def test_invalid_style(self):
3124 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3125
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003126 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003127 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003128 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3129 # We use None to indicate we want the local timezone
3130 # We're essentially converting a UTC time to local time
3131 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003132 r.msecs = 123
3133 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003134 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003135 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3136 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003137 f.format(r)
3138 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3139
3140class TestBufferingFormatter(logging.BufferingFormatter):
3141 def formatHeader(self, records):
3142 return '[(%d)' % len(records)
3143
3144 def formatFooter(self, records):
3145 return '(%d)]' % len(records)
3146
3147class BufferingFormatterTest(unittest.TestCase):
3148 def setUp(self):
3149 self.records = [
3150 logging.makeLogRecord({'msg': 'one'}),
3151 logging.makeLogRecord({'msg': 'two'}),
3152 ]
3153
3154 def test_default(self):
3155 f = logging.BufferingFormatter()
3156 self.assertEqual('', f.format([]))
3157 self.assertEqual('onetwo', f.format(self.records))
3158
3159 def test_custom(self):
3160 f = TestBufferingFormatter()
3161 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3162 lf = logging.Formatter('<%(message)s>')
3163 f = TestBufferingFormatter(lf)
3164 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003165
3166class ExceptionTest(BaseTest):
3167 def test_formatting(self):
3168 r = self.root_logger
3169 h = RecordingHandler()
3170 r.addHandler(h)
3171 try:
3172 raise RuntimeError('deliberate mistake')
3173 except:
3174 logging.exception('failed', stack_info=True)
3175 r.removeHandler(h)
3176 h.close()
3177 r = h.records[0]
3178 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3179 'call last):\n'))
3180 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3181 'deliberate mistake'))
3182 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3183 'call last):\n'))
3184 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3185 'stack_info=True)'))
3186
3187
Vinay Sajip5a27d402010-12-10 11:42:57 +00003188class LastResortTest(BaseTest):
3189 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003190 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003191 root = self.root_logger
3192 root.removeHandler(self.root_hdlr)
3193 old_stderr = sys.stderr
3194 old_lastresort = logging.lastResort
3195 old_raise_exceptions = logging.raiseExceptions
3196 try:
3197 sys.stderr = sio = io.StringIO()
Vinay Sajip8188f582011-07-25 19:58:13 +01003198 root.debug('This should not appear')
3199 self.assertEqual(sio.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003200 root.warning('This is your final chance!')
3201 self.assertEqual(sio.getvalue(), 'This is your final chance!\n')
3202 #No handlers and no last resort, so 'No handlers' message
3203 logging.lastResort = None
3204 sys.stderr = sio = io.StringIO()
3205 root.warning('This is your final chance!')
3206 self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n')
3207 # 'No handlers' message only printed once
3208 sys.stderr = sio = io.StringIO()
3209 root.warning('This is your final chance!')
3210 self.assertEqual(sio.getvalue(), '')
3211 root.manager.emittedNoHandlerWarning = False
3212 #If raiseExceptions is False, no message is printed
3213 logging.raiseExceptions = False
3214 sys.stderr = sio = io.StringIO()
3215 root.warning('This is your final chance!')
3216 self.assertEqual(sio.getvalue(), '')
3217 finally:
3218 sys.stderr = old_stderr
3219 root.addHandler(self.root_hdlr)
3220 logging.lastResort = old_lastresort
3221 logging.raiseExceptions = old_raise_exceptions
3222
3223
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003224class FakeHandler:
3225
3226 def __init__(self, identifier, called):
3227 for method in ('acquire', 'flush', 'close', 'release'):
3228 setattr(self, method, self.record_call(identifier, method, called))
3229
3230 def record_call(self, identifier, method_name, called):
3231 def inner():
3232 called.append('{} - {}'.format(identifier, method_name))
3233 return inner
3234
3235
3236class RecordingHandler(logging.NullHandler):
3237
3238 def __init__(self, *args, **kwargs):
3239 super(RecordingHandler, self).__init__(*args, **kwargs)
3240 self.records = []
3241
3242 def handle(self, record):
3243 """Keep track of all the emitted records."""
3244 self.records.append(record)
3245
3246
3247class ShutdownTest(BaseTest):
3248
Vinay Sajip5e66b162011-04-20 15:41:14 +01003249 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003250
3251 def setUp(self):
3252 super(ShutdownTest, self).setUp()
3253 self.called = []
3254
3255 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003256 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003257
3258 def raise_error(self, error):
3259 def inner():
3260 raise error()
3261 return inner
3262
3263 def test_no_failure(self):
3264 # create some fake handlers
3265 handler0 = FakeHandler(0, self.called)
3266 handler1 = FakeHandler(1, self.called)
3267 handler2 = FakeHandler(2, self.called)
3268
3269 # create live weakref to those handlers
3270 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3271
3272 logging.shutdown(handlerList=list(handlers))
3273
3274 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3275 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3276 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3277 self.assertEqual(expected, self.called)
3278
3279 def _test_with_failure_in_method(self, method, error):
3280 handler = FakeHandler(0, self.called)
3281 setattr(handler, method, self.raise_error(error))
3282 handlers = [logging.weakref.ref(handler)]
3283
3284 logging.shutdown(handlerList=list(handlers))
3285
3286 self.assertEqual('0 - release', self.called[-1])
3287
3288 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003289 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003290
3291 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003292 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003293
3294 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003295 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003296
3297 def test_with_valueerror_in_acquire(self):
3298 self._test_with_failure_in_method('acquire', ValueError)
3299
3300 def test_with_valueerror_in_flush(self):
3301 self._test_with_failure_in_method('flush', ValueError)
3302
3303 def test_with_valueerror_in_close(self):
3304 self._test_with_failure_in_method('close', ValueError)
3305
3306 def test_with_other_error_in_acquire_without_raise(self):
3307 logging.raiseExceptions = False
3308 self._test_with_failure_in_method('acquire', IndexError)
3309
3310 def test_with_other_error_in_flush_without_raise(self):
3311 logging.raiseExceptions = False
3312 self._test_with_failure_in_method('flush', IndexError)
3313
3314 def test_with_other_error_in_close_without_raise(self):
3315 logging.raiseExceptions = False
3316 self._test_with_failure_in_method('close', IndexError)
3317
3318 def test_with_other_error_in_acquire_with_raise(self):
3319 logging.raiseExceptions = True
3320 self.assertRaises(IndexError, self._test_with_failure_in_method,
3321 'acquire', IndexError)
3322
3323 def test_with_other_error_in_flush_with_raise(self):
3324 logging.raiseExceptions = True
3325 self.assertRaises(IndexError, self._test_with_failure_in_method,
3326 'flush', IndexError)
3327
3328 def test_with_other_error_in_close_with_raise(self):
3329 logging.raiseExceptions = True
3330 self.assertRaises(IndexError, self._test_with_failure_in_method,
3331 'close', IndexError)
3332
3333
3334class ModuleLevelMiscTest(BaseTest):
3335
Vinay Sajip5e66b162011-04-20 15:41:14 +01003336 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003337
3338 def test_disable(self):
3339 old_disable = logging.root.manager.disable
3340 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003341 self.assertEqual(old_disable, 0)
3342 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003343
3344 logging.disable(83)
3345 self.assertEqual(logging.root.manager.disable, 83)
3346
3347 def _test_log(self, method, level=None):
3348 called = []
3349 patch(self, logging, 'basicConfig',
Vinay Sajip00bdbe12011-04-22 00:17:46 +01003350 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003351
3352 recording = RecordingHandler()
3353 logging.root.addHandler(recording)
3354
3355 log_method = getattr(logging, method)
3356 if level is not None:
3357 log_method(level, "test me: %r", recording)
3358 else:
3359 log_method("test me: %r", recording)
3360
3361 self.assertEqual(len(recording.records), 1)
3362 record = recording.records[0]
3363 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3364
3365 expected_level = level if level is not None else getattr(logging, method.upper())
3366 self.assertEqual(record.levelno, expected_level)
3367
3368 # basicConfig was not called!
3369 self.assertEqual(called, [])
3370
3371 def test_log(self):
3372 self._test_log('log', logging.ERROR)
3373
3374 def test_debug(self):
3375 self._test_log('debug')
3376
3377 def test_info(self):
3378 self._test_log('info')
3379
3380 def test_warning(self):
3381 self._test_log('warning')
3382
3383 def test_error(self):
3384 self._test_log('error')
3385
3386 def test_critical(self):
3387 self._test_log('critical')
3388
3389 def test_set_logger_class(self):
3390 self.assertRaises(TypeError, logging.setLoggerClass, object)
3391
3392 class MyLogger(logging.Logger):
3393 pass
3394
3395 logging.setLoggerClass(MyLogger)
3396 self.assertEqual(logging.getLoggerClass(), MyLogger)
3397
3398 logging.setLoggerClass(logging.Logger)
3399 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3400
Antoine Pitrou712cb732013-12-21 15:51:54 +01003401 def test_logging_at_shutdown(self):
3402 # Issue #20037
3403 code = """if 1:
3404 import logging
3405
3406 class A:
3407 def __del__(self):
3408 try:
3409 raise ValueError("some error")
3410 except Exception:
3411 logging.exception("exception in __del__")
3412
3413 a = A()"""
3414 rc, out, err = assert_python_ok("-c", code)
3415 err = err.decode()
3416 self.assertIn("exception in __del__", err)
3417 self.assertIn("ValueError: some error", err)
3418
3419
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003420class LogRecordTest(BaseTest):
3421 def test_str_rep(self):
3422 r = logging.makeLogRecord({})
3423 s = str(r)
3424 self.assertTrue(s.startswith('<LogRecord: '))
3425 self.assertTrue(s.endswith('>'))
3426
3427 def test_dict_arg(self):
3428 h = RecordingHandler()
3429 r = logging.getLogger()
3430 r.addHandler(h)
3431 d = {'less' : 'more' }
3432 logging.warning('less is %(less)s', d)
3433 self.assertIs(h.records[0].args, d)
3434 self.assertEqual(h.records[0].message, 'less is more')
3435 r.removeHandler(h)
3436 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003437
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003438 def test_multiprocessing(self):
3439 r = logging.makeLogRecord({})
3440 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003441 try:
3442 import multiprocessing as mp
3443 r = logging.makeLogRecord({})
3444 self.assertEqual(r.processName, mp.current_process().name)
3445 except ImportError:
3446 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003447
3448 def test_optional(self):
3449 r = logging.makeLogRecord({})
3450 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003451 if threading:
3452 NOT_NONE(r.thread)
3453 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003454 NOT_NONE(r.process)
3455 NOT_NONE(r.processName)
3456 log_threads = logging.logThreads
3457 log_processes = logging.logProcesses
3458 log_multiprocessing = logging.logMultiprocessing
3459 try:
3460 logging.logThreads = False
3461 logging.logProcesses = False
3462 logging.logMultiprocessing = False
3463 r = logging.makeLogRecord({})
3464 NONE = self.assertIsNone
3465 NONE(r.thread)
3466 NONE(r.threadName)
3467 NONE(r.process)
3468 NONE(r.processName)
3469 finally:
3470 logging.logThreads = log_threads
3471 logging.logProcesses = log_processes
3472 logging.logMultiprocessing = log_multiprocessing
3473
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003474class BasicConfigTest(unittest.TestCase):
3475
Vinay Sajip95bf5042011-04-20 11:50:56 +01003476 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003477
3478 def setUp(self):
3479 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003480 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003481 self.saved_handlers = logging._handlers.copy()
3482 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003483 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003484 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003485 logging.root.handlers = []
3486
3487 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003488 for h in logging.root.handlers[:]:
3489 logging.root.removeHandler(h)
3490 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003491 super(BasicConfigTest, self).tearDown()
3492
Vinay Sajip3def7e02011-04-20 10:58:06 +01003493 def cleanup(self):
3494 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003495 logging._handlers.clear()
3496 logging._handlers.update(self.saved_handlers)
3497 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003498 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003499
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003500 def test_no_kwargs(self):
3501 logging.basicConfig()
3502
3503 # handler defaults to a StreamHandler to sys.stderr
3504 self.assertEqual(len(logging.root.handlers), 1)
3505 handler = logging.root.handlers[0]
3506 self.assertIsInstance(handler, logging.StreamHandler)
3507 self.assertEqual(handler.stream, sys.stderr)
3508
3509 formatter = handler.formatter
3510 # format defaults to logging.BASIC_FORMAT
3511 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3512 # datefmt defaults to None
3513 self.assertIsNone(formatter.datefmt)
3514 # style defaults to %
3515 self.assertIsInstance(formatter._style, logging.PercentStyle)
3516
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003517 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003518 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003519
Vinay Sajip1fd12022014-01-13 21:59:56 +00003520 def test_strformatstyle(self):
3521 with captured_stdout() as output:
3522 logging.basicConfig(stream=sys.stdout, style="{")
3523 logging.error("Log an error")
3524 sys.stdout.seek(0)
3525 self.assertEqual(output.getvalue().strip(),
3526 "ERROR:root:Log an error")
3527
3528 def test_stringtemplatestyle(self):
3529 with captured_stdout() as output:
3530 logging.basicConfig(stream=sys.stdout, style="$")
3531 logging.error("Log an error")
3532 sys.stdout.seek(0)
3533 self.assertEqual(output.getvalue().strip(),
3534 "ERROR:root:Log an error")
3535
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003536 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003537
3538 def cleanup(h1, h2, fn):
3539 h1.close()
3540 h2.close()
3541 os.remove(fn)
3542
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003543 logging.basicConfig(filename='test.log')
3544
3545 self.assertEqual(len(logging.root.handlers), 1)
3546 handler = logging.root.handlers[0]
3547 self.assertIsInstance(handler, logging.FileHandler)
3548
3549 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003550 self.assertEqual(handler.stream.mode, expected.stream.mode)
3551 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003552 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003553
3554 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003555
3556 def cleanup(h1, h2, fn):
3557 h1.close()
3558 h2.close()
3559 os.remove(fn)
3560
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561 logging.basicConfig(filename='test.log', filemode='wb')
3562
3563 handler = logging.root.handlers[0]
3564 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003565 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003566 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003567
3568 def test_stream(self):
3569 stream = io.StringIO()
3570 self.addCleanup(stream.close)
3571 logging.basicConfig(stream=stream)
3572
3573 self.assertEqual(len(logging.root.handlers), 1)
3574 handler = logging.root.handlers[0]
3575 self.assertIsInstance(handler, logging.StreamHandler)
3576 self.assertEqual(handler.stream, stream)
3577
3578 def test_format(self):
3579 logging.basicConfig(format='foo')
3580
3581 formatter = logging.root.handlers[0].formatter
3582 self.assertEqual(formatter._style._fmt, 'foo')
3583
3584 def test_datefmt(self):
3585 logging.basicConfig(datefmt='bar')
3586
3587 formatter = logging.root.handlers[0].formatter
3588 self.assertEqual(formatter.datefmt, 'bar')
3589
3590 def test_style(self):
3591 logging.basicConfig(style='$')
3592
3593 formatter = logging.root.handlers[0].formatter
3594 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3595
3596 def test_level(self):
3597 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003598 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003599
3600 logging.basicConfig(level=57)
3601 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003602 # Test that second call has no effect
3603 logging.basicConfig(level=58)
3604 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003605
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003606 def test_incompatible(self):
3607 assertRaises = self.assertRaises
3608 handlers = [logging.StreamHandler()]
3609 stream = sys.stderr
3610 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3611 stream=stream)
3612 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3613 handlers=handlers)
3614 assertRaises(ValueError, logging.basicConfig, stream=stream,
3615 handlers=handlers)
3616
3617 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003618 handlers = [
3619 logging.StreamHandler(),
3620 logging.StreamHandler(sys.stdout),
3621 logging.StreamHandler(),
3622 ]
3623 f = logging.Formatter()
3624 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003625 logging.basicConfig(handlers=handlers)
3626 self.assertIs(handlers[0], logging.root.handlers[0])
3627 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003628 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003629 self.assertIsNotNone(handlers[0].formatter)
3630 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003631 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003632 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3633
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003634 def _test_log(self, method, level=None):
3635 # logging.root has no handlers so basicConfig should be called
3636 called = []
3637
3638 old_basic_config = logging.basicConfig
3639 def my_basic_config(*a, **kw):
3640 old_basic_config()
3641 old_level = logging.root.level
3642 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003643 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003644 called.append((a, kw))
3645
3646 patch(self, logging, 'basicConfig', my_basic_config)
3647
3648 log_method = getattr(logging, method)
3649 if level is not None:
3650 log_method(level, "test me")
3651 else:
3652 log_method("test me")
3653
3654 # basicConfig was called with no arguments
3655 self.assertEqual(called, [((), {})])
3656
3657 def test_log(self):
3658 self._test_log('log', logging.WARNING)
3659
3660 def test_debug(self):
3661 self._test_log('debug')
3662
3663 def test_info(self):
3664 self._test_log('info')
3665
3666 def test_warning(self):
3667 self._test_log('warning')
3668
3669 def test_error(self):
3670 self._test_log('error')
3671
3672 def test_critical(self):
3673 self._test_log('critical')
3674
3675
3676class LoggerAdapterTest(unittest.TestCase):
3677
3678 def setUp(self):
3679 super(LoggerAdapterTest, self).setUp()
3680 old_handler_list = logging._handlerList[:]
3681
3682 self.recording = RecordingHandler()
3683 self.logger = logging.root
3684 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003685 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003686 self.addCleanup(self.recording.close)
3687
3688 def cleanup():
3689 logging._handlerList[:] = old_handler_list
3690
3691 self.addCleanup(cleanup)
3692 self.addCleanup(logging.shutdown)
3693 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3694
3695 def test_exception(self):
3696 msg = 'testing exception: %r'
3697 exc = None
3698 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003699 1 / 0
3700 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003701 exc = e
3702 self.adapter.exception(msg, self.recording)
3703
3704 self.assertEqual(len(self.recording.records), 1)
3705 record = self.recording.records[0]
3706 self.assertEqual(record.levelno, logging.ERROR)
3707 self.assertEqual(record.msg, msg)
3708 self.assertEqual(record.args, (self.recording,))
3709 self.assertEqual(record.exc_info,
3710 (exc.__class__, exc, exc.__traceback__))
3711
3712 def test_critical(self):
3713 msg = 'critical test! %r'
3714 self.adapter.critical(msg, self.recording)
3715
3716 self.assertEqual(len(self.recording.records), 1)
3717 record = self.recording.records[0]
3718 self.assertEqual(record.levelno, logging.CRITICAL)
3719 self.assertEqual(record.msg, msg)
3720 self.assertEqual(record.args, (self.recording,))
3721
3722 def test_is_enabled_for(self):
3723 old_disable = self.adapter.logger.manager.disable
3724 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003725 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3726 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003727 self.assertFalse(self.adapter.isEnabledFor(32))
3728
3729 def test_has_handlers(self):
3730 self.assertTrue(self.adapter.hasHandlers())
3731
3732 for handler in self.logger.handlers:
3733 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003734
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003735 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003736 self.assertFalse(self.adapter.hasHandlers())
3737
3738
3739class LoggerTest(BaseTest):
3740
3741 def setUp(self):
3742 super(LoggerTest, self).setUp()
3743 self.recording = RecordingHandler()
3744 self.logger = logging.Logger(name='blah')
3745 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003746 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003747 self.addCleanup(self.recording.close)
3748 self.addCleanup(logging.shutdown)
3749
3750 def test_set_invalid_level(self):
3751 self.assertRaises(TypeError, self.logger.setLevel, object())
3752
3753 def test_exception(self):
3754 msg = 'testing exception: %r'
3755 exc = None
3756 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003757 1 / 0
3758 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003759 exc = e
3760 self.logger.exception(msg, self.recording)
3761
3762 self.assertEqual(len(self.recording.records), 1)
3763 record = self.recording.records[0]
3764 self.assertEqual(record.levelno, logging.ERROR)
3765 self.assertEqual(record.msg, msg)
3766 self.assertEqual(record.args, (self.recording,))
3767 self.assertEqual(record.exc_info,
3768 (exc.__class__, exc, exc.__traceback__))
3769
3770 def test_log_invalid_level_with_raise(self):
3771 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003772 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003773
3774 logging.raiseExceptions = True
3775 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
3776
3777 def test_log_invalid_level_no_raise(self):
3778 old_raise = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003779 self.addCleanup(setattr, logging, 'raiseExecptions', old_raise)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003780
3781 logging.raiseExceptions = False
3782 self.logger.log('10', 'test message') # no exception happens
3783
3784 def test_find_caller_with_stack_info(self):
3785 called = []
3786 patch(self, logging.traceback, 'print_stack',
3787 lambda f, file: called.append(file.getvalue()))
3788
3789 self.logger.findCaller(stack_info=True)
3790
3791 self.assertEqual(len(called), 1)
3792 self.assertEqual('Stack (most recent call last):\n', called[0])
3793
3794 def test_make_record_with_extra_overwrite(self):
3795 name = 'my record'
3796 level = 13
3797 fn = lno = msg = args = exc_info = func = sinfo = None
3798 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3799 exc_info, func, sinfo)
3800
3801 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3802 extra = {key: 'some value'}
3803 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3804 fn, lno, msg, args, exc_info,
3805 extra=extra, sinfo=sinfo)
3806
3807 def test_make_record_with_extra_no_overwrite(self):
3808 name = 'my record'
3809 level = 13
3810 fn = lno = msg = args = exc_info = func = sinfo = None
3811 extra = {'valid_key': 'some value'}
3812 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3813 exc_info, extra=extra, sinfo=sinfo)
3814 self.assertIn('valid_key', result.__dict__)
3815
3816 def test_has_handlers(self):
3817 self.assertTrue(self.logger.hasHandlers())
3818
3819 for handler in self.logger.handlers:
3820 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003821 self.assertFalse(self.logger.hasHandlers())
3822
3823 def test_has_handlers_no_propagate(self):
3824 child_logger = logging.getLogger('blah.child')
3825 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003826 self.assertFalse(child_logger.hasHandlers())
3827
3828 def test_is_enabled_for(self):
3829 old_disable = self.logger.manager.disable
3830 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003831 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003832 self.assertFalse(self.logger.isEnabledFor(22))
3833
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003834 def test_root_logger_aliases(self):
3835 root = logging.getLogger()
3836 self.assertIs(root, logging.root)
3837 self.assertIs(root, logging.getLogger(None))
3838 self.assertIs(root, logging.getLogger(''))
3839 self.assertIs(root, logging.getLogger('foo').root)
3840 self.assertIs(root, logging.getLogger('foo.bar').root)
3841 self.assertIs(root, logging.getLogger('foo').parent)
3842
3843 self.assertIsNot(root, logging.getLogger('\0'))
3844 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3845
3846 def test_invalid_names(self):
3847 self.assertRaises(TypeError, logging.getLogger, any)
3848 self.assertRaises(TypeError, logging.getLogger, b'foo')
3849
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003850
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003851class BaseFileTest(BaseTest):
3852 "Base class for handler tests that write log files"
3853
3854 def setUp(self):
3855 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003856 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3857 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003858 self.rmfiles = []
3859
3860 def tearDown(self):
3861 for fn in self.rmfiles:
3862 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003863 if os.path.exists(self.fn):
3864 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003865 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003866
3867 def assertLogFile(self, filename):
3868 "Assert a log file is there and register it for deletion"
3869 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003870 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003871 self.rmfiles.append(filename)
3872
3873
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003874class FileHandlerTest(BaseFileTest):
3875 def test_delay(self):
3876 os.unlink(self.fn)
3877 fh = logging.FileHandler(self.fn, delay=True)
3878 self.assertIsNone(fh.stream)
3879 self.assertFalse(os.path.exists(self.fn))
3880 fh.handle(logging.makeLogRecord({}))
3881 self.assertIsNotNone(fh.stream)
3882 self.assertTrue(os.path.exists(self.fn))
3883 fh.close()
3884
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003885class RotatingFileHandlerTest(BaseFileTest):
3886 def next_rec(self):
3887 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3888 self.next_message(), None, None, None)
3889
3890 def test_should_not_rollover(self):
3891 # If maxbytes is zero rollover never occurs
3892 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3893 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003894 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003895
3896 def test_should_rollover(self):
3897 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3898 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003899 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003900
3901 def test_file_created(self):
3902 # checks that the file is created and assumes it was created
3903 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003904 rh = logging.handlers.RotatingFileHandler(self.fn)
3905 rh.emit(self.next_rec())
3906 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003907 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003908
3909 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003910 def namer(name):
3911 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003912 rh = logging.handlers.RotatingFileHandler(
3913 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003914 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003915 rh.emit(self.next_rec())
3916 self.assertLogFile(self.fn)
3917 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003918 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003919 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003920 self.assertLogFile(namer(self.fn + ".2"))
3921 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3922 rh.close()
3923
Eric V. Smith851cad72012-03-11 22:46:04 -07003924 @requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003925 def test_rotator(self):
3926 def namer(name):
3927 return name + ".gz"
3928
3929 def rotator(source, dest):
3930 with open(source, "rb") as sf:
3931 data = sf.read()
3932 compressed = zlib.compress(data, 9)
3933 with open(dest, "wb") as df:
3934 df.write(compressed)
3935 os.remove(source)
3936
3937 rh = logging.handlers.RotatingFileHandler(
3938 self.fn, backupCount=2, maxBytes=1)
3939 rh.rotator = rotator
3940 rh.namer = namer
3941 m1 = self.next_rec()
3942 rh.emit(m1)
3943 self.assertLogFile(self.fn)
3944 m2 = self.next_rec()
3945 rh.emit(m2)
3946 fn = namer(self.fn + ".1")
3947 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003948 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003949 with open(fn, "rb") as f:
3950 compressed = f.read()
3951 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003952 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003953 rh.emit(self.next_rec())
3954 fn = namer(self.fn + ".2")
3955 self.assertLogFile(fn)
3956 with open(fn, "rb") as f:
3957 compressed = f.read()
3958 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003959 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003960 rh.emit(self.next_rec())
3961 fn = namer(self.fn + ".2")
3962 with open(fn, "rb") as f:
3963 compressed = f.read()
3964 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003965 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003966 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00003967 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003968
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003969class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01003970 # other test methods added below
3971 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01003972 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
3973 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00003974 fmt = logging.Formatter('%(asctime)s %(message)s')
3975 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003976 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003977 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01003978 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00003979 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00003980 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00003981 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01003982 fh.close()
3983 # At this point, we should have a recent rotated file which we
3984 # can test for the existence of. However, in practice, on some
3985 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01003986 # in time to go to look for the log file. So, we go back a fair
3987 # bit, and stop as soon as we see a rotated file. In theory this
3988 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01003989 found = False
3990 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01003991 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01003992 for secs in range(GO_BACK):
3993 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01003994 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
3995 found = os.path.exists(fn)
3996 if found:
3997 self.rmfiles.append(fn)
3998 break
Vinay Sajip672c5812011-05-13 07:09:40 +01003999 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4000 if not found:
4001 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004002 dn, fn = os.path.split(self.fn)
4003 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004004 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4005 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004006 for f in files:
4007 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004008 path = os.path.join(dn, f)
4009 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004010 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004011 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004012
Vinay Sajip0372e102011-05-05 12:59:14 +01004013 def test_invalid(self):
4014 assertRaises = self.assertRaises
4015 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004016 self.fn, 'X', 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, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004019 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004020 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004021
Vinay Sajipa7130792013-04-12 17:04:23 +01004022 def test_compute_rollover_daily_attime(self):
4023 currentTime = 0
4024 atTime = datetime.time(12, 0, 0)
4025 rh = logging.handlers.TimedRotatingFileHandler(
4026 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4027 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004028 try:
4029 actual = rh.computeRollover(currentTime)
4030 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004031
Vinay Sajipd86ac962013-04-14 12:20:46 +01004032 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4033 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4034 finally:
4035 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004036
Vinay Sajip10e8c492013-05-18 10:19:54 -07004037 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004038 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004039 currentTime = int(time.time())
4040 today = currentTime - currentTime % 86400
4041
Vinay Sajipa7130792013-04-12 17:04:23 +01004042 atTime = datetime.time(12, 0, 0)
4043
Vinay Sajip10e8c492013-05-18 10:19:54 -07004044 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004045 for day in range(7):
4046 rh = logging.handlers.TimedRotatingFileHandler(
4047 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4048 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004049 try:
4050 if wday > day:
4051 # The rollover day has already passed this week, so we
4052 # go over into next week
4053 expected = (7 - wday + day)
4054 else:
4055 expected = (day - wday)
4056 # At this point expected is in days from now, convert to seconds
4057 expected *= 24 * 60 * 60
4058 # Add in the rollover time
4059 expected += 12 * 60 * 60
4060 # Add in adjustment for today
4061 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004062 actual = rh.computeRollover(today)
4063 if actual != expected:
4064 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004065 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004066 self.assertEqual(actual, expected)
4067 if day == wday:
4068 # goes into following week
4069 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004070 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004071 if actual != expected:
4072 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004073 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004074 self.assertEqual(actual, expected)
4075 finally:
4076 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004077
4078
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004079def secs(**kw):
4080 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4081
4082for when, exp in (('S', 1),
4083 ('M', 60),
4084 ('H', 60 * 60),
4085 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004086 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004087 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004088 ('W0', secs(days=4, hours=24)),
4089 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004090 def test_compute_rollover(self, when=when, exp=exp):
4091 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004092 self.fn, when=when, interval=1, backupCount=0, utc=True)
4093 currentTime = 0.0
4094 actual = rh.computeRollover(currentTime)
4095 if exp != actual:
4096 # Failures occur on some systems for MIDNIGHT and W0.
4097 # Print detailed calculation for MIDNIGHT so we can try to see
4098 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004099 if when == 'MIDNIGHT':
4100 try:
4101 if rh.utc:
4102 t = time.gmtime(currentTime)
4103 else:
4104 t = time.localtime(currentTime)
4105 currentHour = t[3]
4106 currentMinute = t[4]
4107 currentSecond = t[5]
4108 # r is the number of seconds left between now and midnight
4109 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4110 currentMinute) * 60 +
4111 currentSecond)
4112 result = currentTime + r
4113 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4114 print('currentHour: %s' % currentHour, file=sys.stderr)
4115 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4116 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4117 print('r: %s' % r, file=sys.stderr)
4118 print('result: %s' % result, file=sys.stderr)
4119 except Exception:
4120 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4121 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004122 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004123 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4124
Vinay Sajip60ccd822011-05-09 17:32:09 +01004125
4126@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.')
4127class NTEventLogHandlerTest(BaseTest):
4128 def test_basic(self):
4129 logtype = 'Application'
4130 elh = win32evtlog.OpenEventLog(None, logtype)
4131 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
4132 h = logging.handlers.NTEventLogHandler('test_logging')
4133 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4134 h.handle(r)
4135 h.close()
4136 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004137 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004138 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4139 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4140 found = False
4141 GO_BACK = 100
4142 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4143 for e in events:
4144 if e.SourceName != 'test_logging':
4145 continue
4146 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4147 if msg != 'Test Log Message\r\n':
4148 continue
4149 found = True
4150 break
4151 msg = 'Record not found in event log, went back %d records' % GO_BACK
4152 self.assertTrue(found, msg=msg)
4153
Christian Heimes180510d2008-03-03 19:15:45 +00004154# Set the locale to the platform-dependent default. I have no idea
4155# why the test does this, but in any case we save the current locale
4156# first and restore it at the end.
4157@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004158def test_main():
Christian Heimes180510d2008-03-03 19:15:45 +00004159 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004160 CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest,
Vinay Sajip7367d082011-05-02 13:17:27 +01004161 ConfigFileTest, SocketHandlerTest, DatagramHandlerTest,
4162 MemoryTest, EncodingTest, WarningsTest, ConfigDictTest,
4163 ManagerTest, FormatterTest, BufferingFormatterTest,
4164 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4165 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest,
4166 BasicConfigTest, LoggerAdapterTest, LoggerTest,
4167 SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004168 LastResortTest, LogRecordTest, ExceptionTest,
Vinay Sajip60ccd822011-05-09 17:32:09 +01004169 SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
Vinay Sajip5421f352013-09-27 18:18:28 +01004170 TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
4171 UnixDatagramHandlerTest, UnixSysLogHandlerTest
Vinay Sajipbc85d842010-09-17 23:35:29 +00004172 )
Jeremy Hylton096d9862003-07-18 03:19:20 +00004173
Christian Heimes180510d2008-03-03 19:15:45 +00004174if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004175 test_main()