blob: 9e9a439eab52287c2293f6f28aee4648a8951176 [file] [log] [blame]
Vinay Sajip1feedb42014-05-31 08:19:12 +01001# Copyright 2001-2014 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 Sajip1feedb42014-05-31 08:19:12 +010019Copyright (C) 2001-2014 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
Christian Heimes180510d2008-03-03 19:15:45 +000037import socket
Christian Heimes180510d2008-03-03 19:15:45 +000038import struct
39import sys
40import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030041from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010042from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000043import textwrap
Vinay Sajip37eb3382011-04-26 20:26:41 +010044import time
Christian Heimes180510d2008-03-03 19:15:45 +000045import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000046import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000047import weakref
Victor Stinner45df8202010-04-28 22:31:17 +000048try:
49 import threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010050 # The following imports are needed only for tests which
Florent Xicluna5252f9f2011-11-07 19:43:05 +010051 # require threading
Vinay Sajipce7c9782011-05-17 07:15:53 +010052 import asyncore
Vinay Sajipce7c9782011-05-17 07:15:53 +010053 from http.server import HTTPServer, BaseHTTPRequestHandler
54 import smtpd
55 from urllib.parse import urlparse, parse_qs
56 from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
Vinay Sajip1feedb42014-05-31 08:19:12 +010057 ThreadingTCPServer, StreamRequestHandler)
Victor Stinner45df8202010-04-28 22:31:17 +000058except ImportError:
59 threading = None
Vinay Sajip60ccd822011-05-09 17:32:09 +010060try:
Vinay Sajip223349c2015-10-01 20:37:54 +010061 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010062except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010063 win32evtlog = win32evtlogutil = pywintypes = None
64
Eric V. Smith851cad72012-03-11 22:46:04 -070065try:
66 import zlib
67except ImportError:
68 pass
Christian Heimes18c66892008-02-17 13:31:39 +000069
Christian Heimes180510d2008-03-03 19:15:45 +000070class BaseTest(unittest.TestCase):
71
72 """Base class for logging tests."""
73
74 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030075 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000076 message_num = 0
77
78 def setUp(self):
79 """Setup the default logging stream to an internal StringIO instance,
80 so that we can examine log output as we want."""
81 logger_dict = logging.getLogger().manager.loggerDict
Christian Heimes18c66892008-02-17 13:31:39 +000082 logging._acquireLock()
83 try:
Christian Heimes180510d2008-03-03 19:15:45 +000084 self.saved_handlers = logging._handlers.copy()
85 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000086 self.saved_loggers = saved_loggers = logger_dict.copy()
Vinay Sajip3b84eae2013-05-25 03:20:34 -070087 self.saved_name_to_level = logging._nameToLevel.copy()
88 self.saved_level_to_name = logging._levelToName.copy()
Vinay Sajip7b60f4e2010-12-27 14:31:52 +000089 self.logger_states = logger_states = {}
90 for name in saved_loggers:
91 logger_states[name] = getattr(saved_loggers[name],
92 'disabled', None)
Christian Heimes18c66892008-02-17 13:31:39 +000093 finally:
94 logging._releaseLock()
95
Florent Xicluna5252f9f2011-11-07 19:43:05 +010096 # Set two unused loggers
Vinay Sajipb4a08092010-09-20 09:55:00 +000097 self.logger1 = logging.getLogger("\xab\xd7\xbb")
98 self.logger2 = logging.getLogger("\u013f\u00d6\u0047")
Benjamin Peterson22005fc2010-04-11 16:25:06 +000099
Christian Heimes180510d2008-03-03 19:15:45 +0000100 self.root_logger = logging.getLogger("")
101 self.original_logging_level = self.root_logger.getEffectiveLevel()
102
103 self.stream = io.StringIO()
104 self.root_logger.setLevel(logging.DEBUG)
105 self.root_hdlr = logging.StreamHandler(self.stream)
106 self.root_formatter = logging.Formatter(self.log_format)
107 self.root_hdlr.setFormatter(self.root_formatter)
Vinay Sajip7b0e86e2010-12-30 23:26:50 +0000108 if self.logger1.hasHandlers():
109 hlist = self.logger1.handlers + self.root_logger.handlers
110 raise AssertionError('Unexpected handlers: %s' % hlist)
111 if self.logger2.hasHandlers():
112 hlist = self.logger2.handlers + self.root_logger.handlers
113 raise AssertionError('Unexpected handlers: %s' % hlist)
Christian Heimes180510d2008-03-03 19:15:45 +0000114 self.root_logger.addHandler(self.root_hdlr)
Vinay Sajipb4a08092010-09-20 09:55:00 +0000115 self.assertTrue(self.logger1.hasHandlers())
116 self.assertTrue(self.logger2.hasHandlers())
Christian Heimes180510d2008-03-03 19:15:45 +0000117
118 def tearDown(self):
119 """Remove our logging stream, and restore the original logging
120 level."""
121 self.stream.close()
122 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +0000123 while self.root_logger.handlers:
124 h = self.root_logger.handlers[0]
125 self.root_logger.removeHandler(h)
126 h.close()
Christian Heimes180510d2008-03-03 19:15:45 +0000127 self.root_logger.setLevel(self.original_logging_level)
128 logging._acquireLock()
129 try:
Vinay Sajip3b84eae2013-05-25 03:20:34 -0700130 logging._levelToName.clear()
131 logging._levelToName.update(self.saved_level_to_name)
132 logging._nameToLevel.clear()
133 logging._nameToLevel.update(self.saved_name_to_level)
Christian Heimes180510d2008-03-03 19:15:45 +0000134 logging._handlers.clear()
135 logging._handlers.update(self.saved_handlers)
136 logging._handlerList[:] = self.saved_handler_list
137 loggerDict = logging.getLogger().manager.loggerDict
138 loggerDict.clear()
139 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000140 logger_states = self.logger_states
141 for name in self.logger_states:
142 if logger_states[name] is not None:
143 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000144 finally:
145 logging._releaseLock()
146
Vinay Sajip4ded5512012-10-02 15:56:16 +0100147 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000148 """Match the collected log lines against the regular expression
149 self.expected_log_pat, and compare the extracted group values to
150 the expected_values list of tuples."""
151 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100152 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300153 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100154 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000155 for actual, expected in zip(actual_lines, expected_values):
156 match = pat.search(actual)
157 if not match:
158 self.fail("Log line does not match expected pattern:\n" +
159 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000160 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000161 s = stream.read()
162 if s:
163 self.fail("Remaining output at end of log stream:\n" + s)
164
165 def next_message(self):
166 """Generate a message consisting solely of an auto-incrementing
167 integer."""
168 self.message_num += 1
169 return "%d" % self.message_num
170
171
172class BuiltinLevelsTest(BaseTest):
173 """Test builtin levels and their inheritance."""
174
175 def test_flat(self):
176 #Logging levels in a flat logger namespace.
177 m = self.next_message
178
179 ERR = logging.getLogger("ERR")
180 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000181 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000182 INF.setLevel(logging.INFO)
183 DEB = logging.getLogger("DEB")
184 DEB.setLevel(logging.DEBUG)
185
186 # These should log.
187 ERR.log(logging.CRITICAL, m())
188 ERR.error(m())
189
190 INF.log(logging.CRITICAL, m())
191 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100192 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000193 INF.info(m())
194
195 DEB.log(logging.CRITICAL, m())
196 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100197 DEB.warning(m())
198 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000199 DEB.debug(m())
200
201 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000203 ERR.info(m())
204 ERR.debug(m())
205
206 INF.debug(m())
207
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000208 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000209 ('ERR', 'CRITICAL', '1'),
210 ('ERR', 'ERROR', '2'),
211 ('INF', 'CRITICAL', '3'),
212 ('INF', 'ERROR', '4'),
213 ('INF', 'WARNING', '5'),
214 ('INF', 'INFO', '6'),
215 ('DEB', 'CRITICAL', '7'),
216 ('DEB', 'ERROR', '8'),
217 ('DEB', 'WARNING', '9'),
218 ('DEB', 'INFO', '10'),
219 ('DEB', 'DEBUG', '11'),
220 ])
221
222 def test_nested_explicit(self):
223 # Logging levels in a nested namespace, all explicitly set.
224 m = self.next_message
225
226 INF = logging.getLogger("INF")
227 INF.setLevel(logging.INFO)
228 INF_ERR = logging.getLogger("INF.ERR")
229 INF_ERR.setLevel(logging.ERROR)
230
231 # These should log.
232 INF_ERR.log(logging.CRITICAL, m())
233 INF_ERR.error(m())
234
235 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100236 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000237 INF_ERR.info(m())
238 INF_ERR.debug(m())
239
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000240 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000241 ('INF.ERR', 'CRITICAL', '1'),
242 ('INF.ERR', 'ERROR', '2'),
243 ])
244
245 def test_nested_inherited(self):
246 #Logging levels in a nested namespace, inherited from parent loggers.
247 m = self.next_message
248
249 INF = logging.getLogger("INF")
250 INF.setLevel(logging.INFO)
251 INF_ERR = logging.getLogger("INF.ERR")
252 INF_ERR.setLevel(logging.ERROR)
253 INF_UNDEF = logging.getLogger("INF.UNDEF")
254 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
255 UNDEF = logging.getLogger("UNDEF")
256
257 # These should log.
258 INF_UNDEF.log(logging.CRITICAL, m())
259 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100260 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000261 INF_UNDEF.info(m())
262 INF_ERR_UNDEF.log(logging.CRITICAL, m())
263 INF_ERR_UNDEF.error(m())
264
265 # These should not log.
266 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100267 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000268 INF_ERR_UNDEF.info(m())
269 INF_ERR_UNDEF.debug(m())
270
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000271 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000272 ('INF.UNDEF', 'CRITICAL', '1'),
273 ('INF.UNDEF', 'ERROR', '2'),
274 ('INF.UNDEF', 'WARNING', '3'),
275 ('INF.UNDEF', 'INFO', '4'),
276 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
277 ('INF.ERR.UNDEF', 'ERROR', '6'),
278 ])
279
280 def test_nested_with_virtual_parent(self):
281 # Logging levels when some parent does not exist yet.
282 m = self.next_message
283
284 INF = logging.getLogger("INF")
285 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
286 CHILD = logging.getLogger("INF.BADPARENT")
287 INF.setLevel(logging.INFO)
288
289 # These should log.
290 GRANDCHILD.log(logging.FATAL, m())
291 GRANDCHILD.info(m())
292 CHILD.log(logging.FATAL, m())
293 CHILD.info(m())
294
295 # These should not log.
296 GRANDCHILD.debug(m())
297 CHILD.debug(m())
298
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000299 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000300 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
301 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
302 ('INF.BADPARENT', 'CRITICAL', '3'),
303 ('INF.BADPARENT', 'INFO', '4'),
304 ])
305
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100306 def test_regression_22386(self):
307 """See issue #22386 for more information."""
308 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
309 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000310
311class BasicFilterTest(BaseTest):
312
313 """Test the bundled Filter class."""
314
315 def test_filter(self):
316 # Only messages satisfying the specified criteria pass through the
317 # filter.
318 filter_ = logging.Filter("spam.eggs")
319 handler = self.root_logger.handlers[0]
320 try:
321 handler.addFilter(filter_)
322 spam = logging.getLogger("spam")
323 spam_eggs = logging.getLogger("spam.eggs")
324 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
325 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
326
327 spam.info(self.next_message())
328 spam_eggs.info(self.next_message()) # Good.
329 spam_eggs_fish.info(self.next_message()) # Good.
330 spam_bakedbeans.info(self.next_message())
331
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000332 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000333 ('spam.eggs', 'INFO', '2'),
334 ('spam.eggs.fish', 'INFO', '3'),
335 ])
336 finally:
337 handler.removeFilter(filter_)
338
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000339 def test_callable_filter(self):
340 # Only messages satisfying the specified criteria pass through the
341 # filter.
342
343 def filterfunc(record):
344 parts = record.name.split('.')
345 prefix = '.'.join(parts[:2])
346 return prefix == 'spam.eggs'
347
348 handler = self.root_logger.handlers[0]
349 try:
350 handler.addFilter(filterfunc)
351 spam = logging.getLogger("spam")
352 spam_eggs = logging.getLogger("spam.eggs")
353 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
354 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
355
356 spam.info(self.next_message())
357 spam_eggs.info(self.next_message()) # Good.
358 spam_eggs_fish.info(self.next_message()) # Good.
359 spam_bakedbeans.info(self.next_message())
360
361 self.assert_log_lines([
362 ('spam.eggs', 'INFO', '2'),
363 ('spam.eggs.fish', 'INFO', '3'),
364 ])
365 finally:
366 handler.removeFilter(filterfunc)
367
Vinay Sajip985ef872011-04-26 19:34:04 +0100368 def test_empty_filter(self):
369 f = logging.Filter()
370 r = logging.makeLogRecord({'name': 'spam.eggs'})
371 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000372
373#
374# First, we define our levels. There can be as many as you want - the only
375# limitations are that they should be integers, the lowest should be > 0 and
376# larger values mean less information being logged. If you need specific
377# level values which do not fit into these limitations, you can use a
378# mapping dictionary to convert between your application levels and the
379# logging system.
380#
381SILENT = 120
382TACITURN = 119
383TERSE = 118
384EFFUSIVE = 117
385SOCIABLE = 116
386VERBOSE = 115
387TALKATIVE = 114
388GARRULOUS = 113
389CHATTERBOX = 112
390BORING = 111
391
392LEVEL_RANGE = range(BORING, SILENT + 1)
393
394#
395# Next, we define names for our levels. You don't need to do this - in which
396# case the system will use "Level n" to denote the text for the level.
397#
398my_logging_levels = {
399 SILENT : 'Silent',
400 TACITURN : 'Taciturn',
401 TERSE : 'Terse',
402 EFFUSIVE : 'Effusive',
403 SOCIABLE : 'Sociable',
404 VERBOSE : 'Verbose',
405 TALKATIVE : 'Talkative',
406 GARRULOUS : 'Garrulous',
407 CHATTERBOX : 'Chatterbox',
408 BORING : 'Boring',
409}
410
411class GarrulousFilter(logging.Filter):
412
413 """A filter which blocks garrulous messages."""
414
415 def filter(self, record):
416 return record.levelno != GARRULOUS
417
418class VerySpecificFilter(logging.Filter):
419
420 """A filter which blocks sociable and taciturn messages."""
421
422 def filter(self, record):
423 return record.levelno not in [SOCIABLE, TACITURN]
424
425
426class CustomLevelsAndFiltersTest(BaseTest):
427
428 """Test various filtering possibilities with custom logging levels."""
429
430 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300431 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000432
433 def setUp(self):
434 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000435 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000436 logging.addLevelName(k, v)
437
438 def log_at_all_levels(self, logger):
439 for lvl in LEVEL_RANGE:
440 logger.log(lvl, self.next_message())
441
442 def test_logger_filter(self):
443 # Filter at logger level.
444 self.root_logger.setLevel(VERBOSE)
445 # Levels >= 'Verbose' are good.
446 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000447 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000448 ('Verbose', '5'),
449 ('Sociable', '6'),
450 ('Effusive', '7'),
451 ('Terse', '8'),
452 ('Taciturn', '9'),
453 ('Silent', '10'),
454 ])
455
456 def test_handler_filter(self):
457 # Filter at handler level.
458 self.root_logger.handlers[0].setLevel(SOCIABLE)
459 try:
460 # Levels >= 'Sociable' are good.
461 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000462 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000463 ('Sociable', '6'),
464 ('Effusive', '7'),
465 ('Terse', '8'),
466 ('Taciturn', '9'),
467 ('Silent', '10'),
468 ])
469 finally:
470 self.root_logger.handlers[0].setLevel(logging.NOTSET)
471
472 def test_specific_filters(self):
473 # Set a specific filter object on the handler, and then add another
474 # filter object on the logger itself.
475 handler = self.root_logger.handlers[0]
476 specific_filter = None
477 garr = GarrulousFilter()
478 handler.addFilter(garr)
479 try:
480 self.log_at_all_levels(self.root_logger)
481 first_lines = [
482 # Notice how 'Garrulous' is missing
483 ('Boring', '1'),
484 ('Chatterbox', '2'),
485 ('Talkative', '4'),
486 ('Verbose', '5'),
487 ('Sociable', '6'),
488 ('Effusive', '7'),
489 ('Terse', '8'),
490 ('Taciturn', '9'),
491 ('Silent', '10'),
492 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000493 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000494
495 specific_filter = VerySpecificFilter()
496 self.root_logger.addFilter(specific_filter)
497 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000498 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000499 # Not only 'Garrulous' is still missing, but also 'Sociable'
500 # and 'Taciturn'
501 ('Boring', '11'),
502 ('Chatterbox', '12'),
503 ('Talkative', '14'),
504 ('Verbose', '15'),
505 ('Effusive', '17'),
506 ('Terse', '18'),
507 ('Silent', '20'),
508 ])
509 finally:
510 if specific_filter:
511 self.root_logger.removeFilter(specific_filter)
512 handler.removeFilter(garr)
513
514
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100515class HandlerTest(BaseTest):
516 def test_name(self):
517 h = logging.Handler()
518 h.name = 'generic'
519 self.assertEqual(h.name, 'generic')
520 h.name = 'anothergeneric'
521 self.assertEqual(h.name, 'anothergeneric')
522 self.assertRaises(NotImplementedError, h.emit, None)
523
Vinay Sajip5a35b062011-04-27 11:31:14 +0100524 def test_builtin_handlers(self):
525 # We can't actually *use* too many handlers in the tests,
526 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200527 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100528 for existing in (True, False):
529 fd, fn = tempfile.mkstemp()
530 os.close(fd)
531 if not existing:
532 os.unlink(fn)
533 h = logging.handlers.WatchedFileHandler(fn, delay=True)
534 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100535 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100536 self.assertEqual(dev, -1)
537 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100538 r = logging.makeLogRecord({'msg': 'Test'})
539 h.handle(r)
540 # Now remove the file.
541 os.unlink(fn)
542 self.assertFalse(os.path.exists(fn))
543 # The next call should recreate the file.
544 h.handle(r)
545 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100546 else:
547 self.assertEqual(h.dev, -1)
548 self.assertEqual(h.ino, -1)
549 h.close()
550 if existing:
551 os.unlink(fn)
552 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100553 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100554 else:
555 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100556 try:
557 h = logging.handlers.SysLogHandler(sockname)
558 self.assertEqual(h.facility, h.LOG_USER)
559 self.assertTrue(h.unixsocket)
560 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200561 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100562 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100563 for method in ('GET', 'POST', 'PUT'):
564 if method == 'PUT':
565 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
566 'localhost', '/log', method)
567 else:
568 h = logging.handlers.HTTPHandler('localhost', '/log', method)
569 h.close()
570 h = logging.handlers.BufferingHandler(0)
571 r = logging.makeLogRecord({})
572 self.assertTrue(h.shouldFlush(r))
573 h.close()
574 h = logging.handlers.BufferingHandler(1)
575 self.assertFalse(h.shouldFlush(r))
576 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100577
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100578 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100579 @unittest.skipUnless(threading, 'Threading required for this test.')
580 def test_race(self):
581 # Issue #14632 refers.
582 def remove_loop(fname, tries):
583 for _ in range(tries):
584 try:
585 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000586 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100587 except OSError:
588 pass
589 time.sleep(0.004 * random.randint(0, 4))
590
Vinay Sajipc94871a2012-04-25 10:51:35 +0100591 del_count = 500
592 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100593
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000594 self.handle_time = None
595 self.deletion_time = None
596
Vinay Sajipa5798de2012-04-24 23:33:33 +0100597 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100598 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
599 os.close(fd)
600 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
601 remover.daemon = True
602 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100603 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100604 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
605 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100606 try:
607 for _ in range(log_count):
608 time.sleep(0.005)
609 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000610 try:
611 self.handle_time = time.time()
612 h.handle(r)
613 except Exception:
614 print('Deleted at %s, '
615 'opened at %s' % (self.deletion_time,
616 self.handle_time))
617 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100618 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100619 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100620 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100621 if os.path.exists(fn):
622 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100623
624
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100625class BadStream(object):
626 def write(self, data):
627 raise RuntimeError('deliberate mistake')
628
629class TestStreamHandler(logging.StreamHandler):
630 def handleError(self, record):
631 self.error_record = record
632
633class StreamHandlerTest(BaseTest):
634 def test_error_handling(self):
635 h = TestStreamHandler(BadStream())
636 r = logging.makeLogRecord({})
637 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100638
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100639 try:
640 h.handle(r)
641 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100642
Vinay Sajip985ef872011-04-26 19:34:04 +0100643 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100644 with support.captured_stderr() as stderr:
645 h.handle(r)
646 msg = '\nRuntimeError: deliberate mistake\n'
647 self.assertIn(msg, stderr.getvalue())
648
Vinay Sajip985ef872011-04-26 19:34:04 +0100649 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100650 with support.captured_stderr() as stderr:
651 h.handle(r)
652 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100653 finally:
654 logging.raiseExceptions = old_raise
655
Vinay Sajip7367d082011-05-02 13:17:27 +0100656# -- The following section could be moved into a server_helper.py module
657# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100658
Vinay Sajipce7c9782011-05-17 07:15:53 +0100659if threading:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100660 class TestSMTPServer(smtpd.SMTPServer):
Vinay Sajip314b92b2011-05-02 14:31:16 +0100661 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100662 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100663
Vinay Sajipce7c9782011-05-17 07:15:53 +0100664 :param addr: A (host, port) tuple which the server listens on.
665 You can specify a port value of zero: the server's
666 *port* attribute will hold the actual port number
667 used, which can be used in client connections.
668 :param handler: A callable which will be called to process
669 incoming messages. The handler will be passed
670 the client address tuple, who the message is from,
671 a list of recipients and the message data.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100672 :param poll_interval: The interval, in seconds, used in the underlying
673 :func:`select` or :func:`poll` call by
674 :func:`asyncore.loop`.
Vinay Sajipce7c9782011-05-17 07:15:53 +0100675 :param sockmap: A dictionary which will be used to hold
676 :class:`asyncore.dispatcher` instances used by
677 :func:`asyncore.loop`. This avoids changing the
678 :mod:`asyncore` module's global state.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100679 """
Vinay Sajipce7c9782011-05-17 07:15:53 +0100680
681 def __init__(self, addr, handler, poll_interval, sockmap):
R David Murray1144da52014-06-11 12:27:40 -0400682 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
683 decode_data=True)
Vinay Sajip30298b42013-06-07 15:21:41 +0100684 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100685 self._handler = handler
686 self._thread = None
687 self.poll_interval = poll_interval
Vinay Sajipa463d252011-04-30 21:52:48 +0100688
Vinay Sajipce7c9782011-05-17 07:15:53 +0100689 def process_message(self, peer, mailfrom, rcpttos, data):
690 """
691 Delegates to the handler passed in to the server's constructor.
Vinay Sajipa463d252011-04-30 21:52:48 +0100692
Vinay Sajipce7c9782011-05-17 07:15:53 +0100693 Typically, this will be a test case method.
694 :param peer: The client (host, port) tuple.
695 :param mailfrom: The address of the sender.
696 :param rcpttos: The addresses of the recipients.
697 :param data: The message.
698 """
699 self._handler(peer, mailfrom, rcpttos, data)
Vinay Sajip7367d082011-05-02 13:17:27 +0100700
Vinay Sajipce7c9782011-05-17 07:15:53 +0100701 def start(self):
702 """
703 Start the server running on a separate daemon thread.
704 """
705 self._thread = t = threading.Thread(target=self.serve_forever,
706 args=(self.poll_interval,))
707 t.setDaemon(True)
708 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100709
Vinay Sajipce7c9782011-05-17 07:15:53 +0100710 def serve_forever(self, poll_interval):
711 """
712 Run the :mod:`asyncore` loop until normal termination
713 conditions arise.
714 :param poll_interval: The interval, in seconds, used in the underlying
715 :func:`select` or :func:`poll` call by
716 :func:`asyncore.loop`.
717 """
718 try:
Vinay Sajip30298b42013-06-07 15:21:41 +0100719 asyncore.loop(poll_interval, map=self._map)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200720 except OSError:
Vinay Sajipce7c9782011-05-17 07:15:53 +0100721 # On FreeBSD 8, closing the server repeatably
722 # raises this error. We swallow it if the
723 # server has been closed.
724 if self.connected or self.accepting:
725 raise
Vinay Sajip7367d082011-05-02 13:17:27 +0100726
Vinay Sajipce7c9782011-05-17 07:15:53 +0100727 def stop(self, timeout=None):
728 """
729 Stop the thread by closing the server instance.
730 Wait for the server thread to terminate.
Vinay Sajip7367d082011-05-02 13:17:27 +0100731
Vinay Sajipce7c9782011-05-17 07:15:53 +0100732 :param timeout: How long to wait for the server thread
733 to terminate.
734 """
735 self.close()
Vinay Sajip7367d082011-05-02 13:17:27 +0100736 self._thread.join(timeout)
737 self._thread = None
Vinay Sajip7367d082011-05-02 13:17:27 +0100738
Vinay Sajipce7c9782011-05-17 07:15:53 +0100739 class ControlMixin(object):
740 """
741 This mixin is used to start a server on a separate thread, and
742 shut it down programmatically. Request handling is simplified - instead
743 of needing to derive a suitable RequestHandler subclass, you just
744 provide a callable which will be passed each received request to be
745 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100746
Vinay Sajipce7c9782011-05-17 07:15:53 +0100747 :param handler: A handler callable which will be called with a
748 single parameter - the request - in order to
749 process the request. This handler is called on the
750 server thread, effectively meaning that requests are
751 processed serially. While not quite Web scale ;-),
752 this should be fine for testing applications.
753 :param poll_interval: The polling interval in seconds.
754 """
755 def __init__(self, handler, poll_interval):
756 self._thread = None
757 self.poll_interval = poll_interval
758 self._handler = handler
759 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100760
Vinay Sajipce7c9782011-05-17 07:15:53 +0100761 def start(self):
762 """
763 Create a daemon thread to run the server, and start it.
764 """
765 self._thread = t = threading.Thread(target=self.serve_forever,
766 args=(self.poll_interval,))
767 t.setDaemon(True)
768 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100769
Vinay Sajipce7c9782011-05-17 07:15:53 +0100770 def serve_forever(self, poll_interval):
771 """
772 Run the server. Set the ready flag before entering the
773 service loop.
774 """
775 self.ready.set()
776 super(ControlMixin, self).serve_forever(poll_interval)
Vinay Sajip7367d082011-05-02 13:17:27 +0100777
Vinay Sajipce7c9782011-05-17 07:15:53 +0100778 def stop(self, timeout=None):
779 """
780 Tell the server thread to stop, and wait for it to do so.
Vinay Sajip7367d082011-05-02 13:17:27 +0100781
Vinay Sajipce7c9782011-05-17 07:15:53 +0100782 :param timeout: How long to wait for the server thread
783 to terminate.
784 """
785 self.shutdown()
786 if self._thread is not None:
787 self._thread.join(timeout)
788 self._thread = None
789 self.server_close()
790 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100791
Vinay Sajipce7c9782011-05-17 07:15:53 +0100792 class TestHTTPServer(ControlMixin, HTTPServer):
793 """
794 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100795
Vinay Sajipce7c9782011-05-17 07:15:53 +0100796 :param addr: A tuple with the IP address and port to listen on.
797 :param handler: A handler callable which will be called with a
798 single parameter - the request - in order to
799 process the request.
800 :param poll_interval: The polling interval in seconds.
801 :param log: Pass ``True`` to enable log messages.
802 """
Vinay Sajip32565b62011-05-21 00:34:51 +0100803 def __init__(self, addr, handler, poll_interval=0.5,
804 log=False, sslctx=None):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100805 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
806 def __getattr__(self, name, default=None):
807 if name.startswith('do_'):
808 return self.process_request
809 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100810
Vinay Sajipce7c9782011-05-17 07:15:53 +0100811 def process_request(self):
812 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Vinay Sajipce7c9782011-05-17 07:15:53 +0100814 def log_message(self, format, *args):
815 if log:
816 super(DelegatingHTTPRequestHandler,
817 self).log_message(format, *args)
818 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
819 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100820 self.sslctx = sslctx
821
822 def get_request(self):
823 try:
824 sock, addr = self.socket.accept()
825 if self.sslctx:
826 sock = self.sslctx.wrap_socket(sock, server_side=True)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200827 except OSError as e:
Vinay Sajip32565b62011-05-21 00:34:51 +0100828 # socket errors are silenced by the caller, print them here
829 sys.stderr.write("Got an error:\n%s\n" % e)
830 raise
831 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100832
Vinay Sajipce7c9782011-05-17 07:15:53 +0100833 class TestTCPServer(ControlMixin, ThreadingTCPServer):
834 """
835 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100836
Vinay Sajipce7c9782011-05-17 07:15:53 +0100837 :param addr: A tuple with the IP address and port to listen on.
838 :param handler: A handler callable which will be called with a single
839 parameter - the request - in order to process the request.
840 :param poll_interval: The polling interval in seconds.
841 :bind_and_activate: If True (the default), binds the server and starts it
842 listening. If False, you need to call
843 :meth:`server_bind` and :meth:`server_activate` at
844 some later time before calling :meth:`start`, so that
845 the server will set up the socket and listen on it.
846 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100847
Vinay Sajipce7c9782011-05-17 07:15:53 +0100848 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100849
Vinay Sajipce7c9782011-05-17 07:15:53 +0100850 def __init__(self, addr, handler, poll_interval=0.5,
851 bind_and_activate=True):
852 class DelegatingTCPRequestHandler(StreamRequestHandler):
853
854 def handle(self):
855 self.server._handler(self)
856 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
857 bind_and_activate)
858 ControlMixin.__init__(self, handler, poll_interval)
859
860 def server_bind(self):
861 super(TestTCPServer, self).server_bind()
862 self.port = self.socket.getsockname()[1]
863
864 class TestUDPServer(ControlMixin, ThreadingUDPServer):
865 """
866 A UDP server which is controllable using :class:`ControlMixin`.
867
868 :param addr: A tuple with the IP address and port to listen on.
869 :param handler: A handler callable which will be called with a
870 single parameter - the request - in order to
871 process the request.
872 :param poll_interval: The polling interval for shutdown requests,
873 in seconds.
874 :bind_and_activate: If True (the default), binds the server and
875 starts it listening. If False, you need to
876 call :meth:`server_bind` and
877 :meth:`server_activate` at some later time
878 before calling :meth:`start`, so that the server will
879 set up the socket and listen on it.
880 """
Vinay Sajip3ef12292011-05-23 23:00:42 +0100881 def __init__(self, addr, handler, poll_interval=0.5,
882 bind_and_activate=True):
Vinay Sajipce7c9782011-05-17 07:15:53 +0100883 class DelegatingUDPRequestHandler(DatagramRequestHandler):
884
885 def handle(self):
886 self.server._handler(self)
Vinay Sajipba980db2011-05-23 21:37:54 +0100887
888 def finish(self):
889 data = self.wfile.getvalue()
Vinay Sajip3ef12292011-05-23 23:00:42 +0100890 if data:
891 try:
892 super(DelegatingUDPRequestHandler, self).finish()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200893 except OSError:
Vinay Sajip3ef12292011-05-23 23:00:42 +0100894 if not self.server._closed:
895 raise
Vinay Sajipba980db2011-05-23 21:37:54 +0100896
Vinay Sajip3ef12292011-05-23 23:00:42 +0100897 ThreadingUDPServer.__init__(self, addr,
898 DelegatingUDPRequestHandler,
Vinay Sajipce7c9782011-05-17 07:15:53 +0100899 bind_and_activate)
900 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajipba980db2011-05-23 21:37:54 +0100901 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100902
903 def server_bind(self):
904 super(TestUDPServer, self).server_bind()
905 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100906
Vinay Sajipba980db2011-05-23 21:37:54 +0100907 def server_close(self):
908 super(TestUDPServer, self).server_close()
909 self._closed = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100910
Victor Stinnerec5a8602014-06-02 14:41:51 +0200911 if hasattr(socket, "AF_UNIX"):
912 class TestUnixStreamServer(TestTCPServer):
913 address_family = socket.AF_UNIX
914
915 class TestUnixDatagramServer(TestUDPServer):
916 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100917
Vinay Sajip7367d082011-05-02 13:17:27 +0100918# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100919
Vinay Sajipce7c9782011-05-17 07:15:53 +0100920@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipa463d252011-04-30 21:52:48 +0100921class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000922 TIMEOUT = 8.0
Vinay Sajipa463d252011-04-30 21:52:48 +0100923 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100924 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800925 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100926 sockmap)
927 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800928 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000929 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
930 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100931 self.assertEqual(h.toaddrs, ['you'])
932 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100933 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100934 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100935 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000936 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100937 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000938 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100939 self.assertEqual(len(self.messages), 1)
940 peer, mailfrom, rcpttos, data = self.messages[0]
941 self.assertEqual(mailfrom, 'me')
942 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100943 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100944 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100945 h.close()
946
947 def process_message(self, *args):
948 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +0100949 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +0100950
Christian Heimes180510d2008-03-03 19:15:45 +0000951class MemoryHandlerTest(BaseTest):
952
953 """Tests for the MemoryHandler."""
954
955 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300956 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000957
958 def setUp(self):
959 BaseTest.setUp(self)
960 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipcccf6062016-07-22 16:27:31 +0100961 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +0000962 self.mem_logger = logging.getLogger('mem')
963 self.mem_logger.propagate = 0
964 self.mem_logger.addHandler(self.mem_hdlr)
965
966 def tearDown(self):
967 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000968 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +0000969
970 def test_flush(self):
971 # The memory handler flushes to its target handler based on specific
972 # criteria (message count and message level).
973 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000974 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000975 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000976 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +0000977 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100978 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +0000979 lines = [
980 ('DEBUG', '1'),
981 ('INFO', '2'),
982 ('WARNING', '3'),
983 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000984 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000985 for n in (4, 14):
986 for i in range(9):
987 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000988 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000989 # This will flush because it's the 10th message since the last
990 # flush.
991 self.mem_logger.debug(self.next_message())
992 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000993 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000994
995 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000996 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000997
Vinay Sajipcccf6062016-07-22 16:27:31 +0100998 def test_flush_on_close(self):
999 """
1000 Test that the flush-on-close configuration works as expected.
1001 """
1002 self.mem_logger.debug(self.next_message())
1003 self.assert_log_lines([])
1004 self.mem_logger.info(self.next_message())
1005 self.assert_log_lines([])
1006 self.mem_logger.removeHandler(self.mem_hdlr)
1007 # Default behaviour is to flush on close. Check that it happens.
1008 self.mem_hdlr.close()
1009 lines = [
1010 ('DEBUG', '1'),
1011 ('INFO', '2'),
1012 ]
1013 self.assert_log_lines(lines)
1014 # Now configure for flushing not to be done on close.
1015 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1016 self.root_hdlr,
1017 False)
1018 self.mem_logger.addHandler(self.mem_hdlr)
1019 self.mem_logger.debug(self.next_message())
1020 self.assert_log_lines(lines) # no change
1021 self.mem_logger.info(self.next_message())
1022 self.assert_log_lines(lines) # no change
1023 self.mem_logger.removeHandler(self.mem_hdlr)
1024 self.mem_hdlr.close()
1025 # assert that no new lines have been added
1026 self.assert_log_lines(lines) # no change
1027
Christian Heimes180510d2008-03-03 19:15:45 +00001028
1029class ExceptionFormatter(logging.Formatter):
1030 """A special exception formatter."""
1031 def formatException(self, ei):
1032 return "Got a [%s]" % ei[0].__name__
1033
1034
1035class ConfigFileTest(BaseTest):
1036
1037 """Reading logging config from a .ini-style config file."""
1038
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001039 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001040
1041 # config0 is a standard configuration.
1042 config0 = """
1043 [loggers]
1044 keys=root
1045
1046 [handlers]
1047 keys=hand1
1048
1049 [formatters]
1050 keys=form1
1051
1052 [logger_root]
1053 level=WARNING
1054 handlers=hand1
1055
1056 [handler_hand1]
1057 class=StreamHandler
1058 level=NOTSET
1059 formatter=form1
1060 args=(sys.stdout,)
1061
1062 [formatter_form1]
1063 format=%(levelname)s ++ %(message)s
1064 datefmt=
1065 """
1066
1067 # config1 adds a little to the standard configuration.
1068 config1 = """
1069 [loggers]
1070 keys=root,parser
1071
1072 [handlers]
1073 keys=hand1
1074
1075 [formatters]
1076 keys=form1
1077
1078 [logger_root]
1079 level=WARNING
1080 handlers=
1081
1082 [logger_parser]
1083 level=DEBUG
1084 handlers=hand1
1085 propagate=1
1086 qualname=compiler.parser
1087
1088 [handler_hand1]
1089 class=StreamHandler
1090 level=NOTSET
1091 formatter=form1
1092 args=(sys.stdout,)
1093
1094 [formatter_form1]
1095 format=%(levelname)s ++ %(message)s
1096 datefmt=
1097 """
1098
Vinay Sajip3f84b072011-03-07 17:49:33 +00001099 # config1a moves the handler to the root.
1100 config1a = """
1101 [loggers]
1102 keys=root,parser
1103
1104 [handlers]
1105 keys=hand1
1106
1107 [formatters]
1108 keys=form1
1109
1110 [logger_root]
1111 level=WARNING
1112 handlers=hand1
1113
1114 [logger_parser]
1115 level=DEBUG
1116 handlers=
1117 propagate=1
1118 qualname=compiler.parser
1119
1120 [handler_hand1]
1121 class=StreamHandler
1122 level=NOTSET
1123 formatter=form1
1124 args=(sys.stdout,)
1125
1126 [formatter_form1]
1127 format=%(levelname)s ++ %(message)s
1128 datefmt=
1129 """
1130
Christian Heimes180510d2008-03-03 19:15:45 +00001131 # config2 has a subtle configuration error that should be reported
1132 config2 = config1.replace("sys.stdout", "sys.stbout")
1133
1134 # config3 has a less subtle configuration error
1135 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1136
1137 # config4 specifies a custom formatter class to be loaded
1138 config4 = """
1139 [loggers]
1140 keys=root
1141
1142 [handlers]
1143 keys=hand1
1144
1145 [formatters]
1146 keys=form1
1147
1148 [logger_root]
1149 level=NOTSET
1150 handlers=hand1
1151
1152 [handler_hand1]
1153 class=StreamHandler
1154 level=NOTSET
1155 formatter=form1
1156 args=(sys.stdout,)
1157
1158 [formatter_form1]
1159 class=""" + __name__ + """.ExceptionFormatter
1160 format=%(levelname)s:%(name)s:%(message)s
1161 datefmt=
1162 """
1163
Georg Brandl3dbca812008-07-23 16:10:53 +00001164 # config5 specifies a custom handler class to be loaded
1165 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1166
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001167 # config6 uses ', ' delimiters in the handlers and formatters sections
1168 config6 = """
1169 [loggers]
1170 keys=root,parser
1171
1172 [handlers]
1173 keys=hand1, hand2
1174
1175 [formatters]
1176 keys=form1, form2
1177
1178 [logger_root]
1179 level=WARNING
1180 handlers=
1181
1182 [logger_parser]
1183 level=DEBUG
1184 handlers=hand1
1185 propagate=1
1186 qualname=compiler.parser
1187
1188 [handler_hand1]
1189 class=StreamHandler
1190 level=NOTSET
1191 formatter=form1
1192 args=(sys.stdout,)
1193
1194 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001195 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001196 level=NOTSET
1197 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001198 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001199
1200 [formatter_form1]
1201 format=%(levelname)s ++ %(message)s
1202 datefmt=
1203
1204 [formatter_form2]
1205 format=%(message)s
1206 datefmt=
1207 """
1208
Vinay Sajip3f84b072011-03-07 17:49:33 +00001209 # config7 adds a compiler logger.
1210 config7 = """
1211 [loggers]
1212 keys=root,parser,compiler
1213
1214 [handlers]
1215 keys=hand1
1216
1217 [formatters]
1218 keys=form1
1219
1220 [logger_root]
1221 level=WARNING
1222 handlers=hand1
1223
1224 [logger_compiler]
1225 level=DEBUG
1226 handlers=
1227 propagate=1
1228 qualname=compiler
1229
1230 [logger_parser]
1231 level=DEBUG
1232 handlers=
1233 propagate=1
1234 qualname=compiler.parser
1235
1236 [handler_hand1]
1237 class=StreamHandler
1238 level=NOTSET
1239 formatter=form1
1240 args=(sys.stdout,)
1241
1242 [formatter_form1]
1243 format=%(levelname)s ++ %(message)s
1244 datefmt=
1245 """
1246
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001247 disable_test = """
1248 [loggers]
1249 keys=root
1250
1251 [handlers]
1252 keys=screen
1253
1254 [formatters]
1255 keys=
1256
1257 [logger_root]
1258 level=DEBUG
1259 handlers=screen
1260
1261 [handler_screen]
1262 level=DEBUG
1263 class=StreamHandler
1264 args=(sys.stdout,)
1265 formatter=
1266 """
1267
1268 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001269 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001270 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001271
1272 def test_config0_ok(self):
1273 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001274 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001275 self.apply_config(self.config0)
1276 logger = logging.getLogger()
1277 # Won't output anything
1278 logger.info(self.next_message())
1279 # Outputs a message
1280 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001281 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001282 ('ERROR', '2'),
1283 ], stream=output)
1284 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001285 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001286
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001287 def test_config0_using_cp_ok(self):
1288 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001289 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001290 file = io.StringIO(textwrap.dedent(self.config0))
1291 cp = configparser.ConfigParser()
1292 cp.read_file(file)
1293 logging.config.fileConfig(cp)
1294 logger = logging.getLogger()
1295 # Won't output anything
1296 logger.info(self.next_message())
1297 # Outputs a message
1298 logger.error(self.next_message())
1299 self.assert_log_lines([
1300 ('ERROR', '2'),
1301 ], stream=output)
1302 # Original logger output is empty.
1303 self.assert_log_lines([])
1304
Georg Brandl3dbca812008-07-23 16:10:53 +00001305 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001306 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001307 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001308 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001309 logger = logging.getLogger("compiler.parser")
1310 # Both will output a message
1311 logger.info(self.next_message())
1312 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001313 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001314 ('INFO', '1'),
1315 ('ERROR', '2'),
1316 ], stream=output)
1317 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001318 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001319
1320 def test_config2_failure(self):
1321 # A simple config file which overrides the default settings.
1322 self.assertRaises(Exception, self.apply_config, self.config2)
1323
1324 def test_config3_failure(self):
1325 # A simple config file which overrides the default settings.
1326 self.assertRaises(Exception, self.apply_config, self.config3)
1327
1328 def test_config4_ok(self):
1329 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001330 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001331 self.apply_config(self.config4)
1332 logger = logging.getLogger()
1333 try:
1334 raise RuntimeError()
1335 except RuntimeError:
1336 logging.exception("just testing")
1337 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001338 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001339 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1340 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001341 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001342
Georg Brandl3dbca812008-07-23 16:10:53 +00001343 def test_config5_ok(self):
1344 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001345
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001346 def test_config6_ok(self):
1347 self.test_config1_ok(config=self.config6)
1348
Vinay Sajip3f84b072011-03-07 17:49:33 +00001349 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001350 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001351 self.apply_config(self.config1a)
1352 logger = logging.getLogger("compiler.parser")
1353 # See issue #11424. compiler-hyphenated sorts
1354 # between compiler and compiler.xyz and this
1355 # was preventing compiler.xyz from being included
1356 # in the child loggers of compiler because of an
1357 # overzealous loop termination condition.
1358 hyphenated = logging.getLogger('compiler-hyphenated')
1359 # All will output a message
1360 logger.info(self.next_message())
1361 logger.error(self.next_message())
1362 hyphenated.critical(self.next_message())
1363 self.assert_log_lines([
1364 ('INFO', '1'),
1365 ('ERROR', '2'),
1366 ('CRITICAL', '3'),
1367 ], stream=output)
1368 # Original logger output is empty.
1369 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001370 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001371 self.apply_config(self.config7)
1372 logger = logging.getLogger("compiler.parser")
1373 self.assertFalse(logger.disabled)
1374 # Both will output a message
1375 logger.info(self.next_message())
1376 logger.error(self.next_message())
1377 logger = logging.getLogger("compiler.lexer")
1378 # Both will output a message
1379 logger.info(self.next_message())
1380 logger.error(self.next_message())
1381 # Will not appear
1382 hyphenated.critical(self.next_message())
1383 self.assert_log_lines([
1384 ('INFO', '4'),
1385 ('ERROR', '5'),
1386 ('INFO', '6'),
1387 ('ERROR', '7'),
1388 ], stream=output)
1389 # Original logger output is empty.
1390 self.assert_log_lines([])
1391
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001392 def test_logger_disabling(self):
1393 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001394 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001395 self.assertFalse(logger.disabled)
1396 self.apply_config(self.disable_test)
1397 self.assertTrue(logger.disabled)
1398 self.apply_config(self.disable_test, disable_existing_loggers=False)
1399 self.assertFalse(logger.disabled)
1400
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001401
Victor Stinner45df8202010-04-28 22:31:17 +00001402@unittest.skipUnless(threading, 'Threading required for this test.')
Christian Heimes180510d2008-03-03 19:15:45 +00001403class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001404
Christian Heimes180510d2008-03-03 19:15:45 +00001405 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001406
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001407 if threading:
1408 server_class = TestTCPServer
1409 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001410
Christian Heimes180510d2008-03-03 19:15:45 +00001411 def setUp(self):
1412 """Set up a TCP server to receive log messages, and a SocketHandler
1413 pointing to that server's address and port."""
1414 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001415 self.server = server = self.server_class(self.address,
1416 self.handle_socket, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001417 server.start()
1418 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001419 hcls = logging.handlers.SocketHandler
1420 if isinstance(server.server_address, tuple):
1421 self.sock_hdlr = hcls('localhost', server.port)
1422 else:
1423 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001424 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001425 self.root_logger.removeHandler(self.root_logger.handlers[0])
1426 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001427 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001428
Christian Heimes180510d2008-03-03 19:15:45 +00001429 def tearDown(self):
1430 """Shutdown the TCP server."""
1431 try:
Vinay Sajip7367d082011-05-02 13:17:27 +01001432 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001433 self.root_logger.removeHandler(self.sock_hdlr)
1434 self.sock_hdlr.close()
Christian Heimes180510d2008-03-03 19:15:45 +00001435 finally:
1436 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001437
Vinay Sajip7367d082011-05-02 13:17:27 +01001438 def handle_socket(self, request):
1439 conn = request.connection
1440 while True:
1441 chunk = conn.recv(4)
1442 if len(chunk) < 4:
1443 break
1444 slen = struct.unpack(">L", chunk)[0]
1445 chunk = conn.recv(slen)
1446 while len(chunk) < slen:
1447 chunk = chunk + conn.recv(slen - len(chunk))
1448 obj = pickle.loads(chunk)
1449 record = logging.makeLogRecord(obj)
1450 self.log_output += record.msg + '\n'
1451 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001452
Christian Heimes180510d2008-03-03 19:15:45 +00001453 def test_output(self):
1454 # The log message sent to the SocketHandler is properly received.
1455 logger = logging.getLogger("tcp")
1456 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001457 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001458 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001459 self.handled.acquire()
1460 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001461
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001462 def test_noserver(self):
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001463 # Avoid timing-related failures due to SocketHandler's own hard-wired
1464 # one-second timeout on socket.create_connection() (issue #16264).
1465 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001466 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001467 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001468 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001469 try:
1470 raise RuntimeError('Deliberate mistake')
1471 except RuntimeError:
1472 self.root_logger.exception('Never sent')
1473 self.root_logger.error('Never sent, either')
1474 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001475 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001476 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1477 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001478
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001479def _get_temp_domain_socket():
1480 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1481 os.close(fd)
1482 # just need a name - file can't be present, or we'll get an
1483 # 'address already in use' error.
1484 os.remove(fn)
1485 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001486
Victor Stinnerec5a8602014-06-02 14:41:51 +02001487@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001488@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001489class UnixSocketHandlerTest(SocketHandlerTest):
1490
1491 """Test for SocketHandler with unix sockets."""
1492
Victor Stinnerec5a8602014-06-02 14:41:51 +02001493 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001494 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001495
1496 def setUp(self):
1497 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001498 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001499 SocketHandlerTest.setUp(self)
1500
1501 def tearDown(self):
1502 SocketHandlerTest.tearDown(self)
1503 os.remove(self.address)
1504
1505@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001506class DatagramHandlerTest(BaseTest):
1507
1508 """Test for DatagramHandler."""
1509
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001510 if threading:
1511 server_class = TestUDPServer
1512 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001513
Vinay Sajip7367d082011-05-02 13:17:27 +01001514 def setUp(self):
1515 """Set up a UDP server to receive log messages, and a DatagramHandler
1516 pointing to that server's address and port."""
1517 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001518 self.server = server = self.server_class(self.address,
1519 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001520 server.start()
1521 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001522 hcls = logging.handlers.DatagramHandler
1523 if isinstance(server.server_address, tuple):
1524 self.sock_hdlr = hcls('localhost', server.port)
1525 else:
1526 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001527 self.log_output = ''
1528 self.root_logger.removeHandler(self.root_logger.handlers[0])
1529 self.root_logger.addHandler(self.sock_hdlr)
1530 self.handled = threading.Event()
1531
1532 def tearDown(self):
1533 """Shutdown the UDP server."""
1534 try:
1535 self.server.stop(2.0)
1536 self.root_logger.removeHandler(self.sock_hdlr)
1537 self.sock_hdlr.close()
1538 finally:
1539 BaseTest.tearDown(self)
1540
1541 def handle_datagram(self, request):
1542 slen = struct.pack('>L', 0) # length of prefix
1543 packet = request.packet[len(slen):]
1544 obj = pickle.loads(packet)
1545 record = logging.makeLogRecord(obj)
1546 self.log_output += record.msg + '\n'
1547 self.handled.set()
1548
1549 def test_output(self):
1550 # The log message sent to the DatagramHandler is properly received.
1551 logger = logging.getLogger("udp")
1552 logger.error("spam")
1553 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001554 self.handled.clear()
1555 logger.error("eggs")
1556 self.handled.wait()
1557 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001558
Victor Stinnerec5a8602014-06-02 14:41:51 +02001559@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001560@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001561class UnixDatagramHandlerTest(DatagramHandlerTest):
1562
1563 """Test for DatagramHandler using Unix sockets."""
1564
Victor Stinnerec5a8602014-06-02 14:41:51 +02001565 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001566 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001567
1568 def setUp(self):
1569 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001570 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001571 DatagramHandlerTest.setUp(self)
1572
1573 def tearDown(self):
1574 DatagramHandlerTest.tearDown(self)
1575 os.remove(self.address)
1576
1577@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001578class SysLogHandlerTest(BaseTest):
1579
1580 """Test for SysLogHandler using UDP."""
1581
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001582 if threading:
1583 server_class = TestUDPServer
1584 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001585
Vinay Sajip7367d082011-05-02 13:17:27 +01001586 def setUp(self):
1587 """Set up a UDP server to receive log messages, and a SysLogHandler
1588 pointing to that server's address and port."""
1589 BaseTest.setUp(self)
Vinay Sajip5421f352013-09-27 18:18:28 +01001590 self.server = server = self.server_class(self.address,
1591 self.handle_datagram, 0.01)
Vinay Sajip7367d082011-05-02 13:17:27 +01001592 server.start()
1593 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001594 hcls = logging.handlers.SysLogHandler
1595 if isinstance(server.server_address, tuple):
1596 self.sl_hdlr = hcls(('localhost', server.port))
1597 else:
1598 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001599 self.log_output = ''
1600 self.root_logger.removeHandler(self.root_logger.handlers[0])
1601 self.root_logger.addHandler(self.sl_hdlr)
1602 self.handled = threading.Event()
1603
1604 def tearDown(self):
1605 """Shutdown the UDP server."""
1606 try:
1607 self.server.stop(2.0)
1608 self.root_logger.removeHandler(self.sl_hdlr)
1609 self.sl_hdlr.close()
1610 finally:
1611 BaseTest.tearDown(self)
1612
1613 def handle_datagram(self, request):
1614 self.log_output = request.packet
1615 self.handled.set()
1616
1617 def test_output(self):
1618 # The log message sent to the SysLogHandler is properly received.
1619 logger = logging.getLogger("slh")
1620 logger.error("sp\xe4m")
1621 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001622 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001623 self.handled.clear()
1624 self.sl_hdlr.append_nul = False
1625 logger.error("sp\xe4m")
1626 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001627 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001628 self.handled.clear()
1629 self.sl_hdlr.ident = "h\xe4m-"
1630 logger.error("sp\xe4m")
1631 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001632 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001633
Victor Stinnerec5a8602014-06-02 14:41:51 +02001634@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip7367d082011-05-02 13:17:27 +01001635@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip5421f352013-09-27 18:18:28 +01001636class UnixSysLogHandlerTest(SysLogHandlerTest):
1637
1638 """Test for SysLogHandler with Unix sockets."""
1639
Victor Stinnerec5a8602014-06-02 14:41:51 +02001640 if threading and hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001641 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001642
1643 def setUp(self):
1644 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001645 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001646 SysLogHandlerTest.setUp(self)
1647
1648 def tearDown(self):
1649 SysLogHandlerTest.tearDown(self)
1650 os.remove(self.address)
1651
Vinay Sajip5421f352013-09-27 18:18:28 +01001652@unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajip7367d082011-05-02 13:17:27 +01001653class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001654 """Test for HTTPHandler."""
1655
1656 def setUp(self):
1657 """Set up an HTTP server to receive log messages, and a HTTPHandler
1658 pointing to that server's address and port."""
1659 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001660 self.handled = threading.Event()
1661
Vinay Sajip7367d082011-05-02 13:17:27 +01001662 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001663 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001665 if self.command == 'POST':
1666 try:
1667 rlen = int(request.headers['Content-Length'])
1668 self.post_data = request.rfile.read(rlen)
1669 except:
1670 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001671 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001672 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001673 self.handled.set()
1674
1675 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001676 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001677 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001678 root_logger = self.root_logger
1679 root_logger.removeHandler(self.root_logger.handlers[0])
1680 for secure in (False, True):
1681 addr = ('localhost', 0)
1682 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001683 try:
1684 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001685 except ImportError:
1686 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001687 else:
1688 here = os.path.dirname(__file__)
1689 localhost_cert = os.path.join(here, "keycert.pem")
1690 sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1691 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001692
1693 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001694 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001695 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001696 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001697 self.server = server = TestHTTPServer(addr, self.handle_request,
1698 0.01, sslctx=sslctx)
1699 server.start()
1700 server.ready.wait()
1701 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001702 secure_client = secure and sslctx
1703 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001704 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001705 context=context,
1706 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001707 self.log_data = None
1708 root_logger.addHandler(self.h_hdlr)
1709
1710 for method in ('GET', 'POST'):
1711 self.h_hdlr.method = method
1712 self.handled.clear()
1713 msg = "sp\xe4m"
1714 logger.error(msg)
1715 self.handled.wait()
1716 self.assertEqual(self.log_data.path, '/frob')
1717 self.assertEqual(self.command, method)
1718 if method == 'GET':
1719 d = parse_qs(self.log_data.query)
1720 else:
1721 d = parse_qs(self.post_data.decode('utf-8'))
1722 self.assertEqual(d['name'], ['http'])
1723 self.assertEqual(d['funcName'], ['test_output'])
1724 self.assertEqual(d['msg'], [msg])
1725
1726 self.server.stop(2.0)
1727 self.root_logger.removeHandler(self.h_hdlr)
1728 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001729
Christian Heimes180510d2008-03-03 19:15:45 +00001730class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001731
Christian Heimes180510d2008-03-03 19:15:45 +00001732 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001733
Christian Heimes180510d2008-03-03 19:15:45 +00001734 def setUp(self):
1735 """Create a dict to remember potentially destroyed objects."""
1736 BaseTest.setUp(self)
1737 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001738
Christian Heimes180510d2008-03-03 19:15:45 +00001739 def _watch_for_survival(self, *args):
1740 """Watch the given objects for survival, by creating weakrefs to
1741 them."""
1742 for obj in args:
1743 key = id(obj), repr(obj)
1744 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001745
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001746 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001747 """Assert that all objects watched for survival have survived."""
1748 # Trigger cycle breaking.
1749 gc.collect()
1750 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001751 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001752 if ref() is None:
1753 dead.append(repr_)
1754 if dead:
1755 self.fail("%d objects should have survived "
1756 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001757
Christian Heimes180510d2008-03-03 19:15:45 +00001758 def test_persistent_loggers(self):
1759 # Logger objects are persistent and retain their configuration, even
1760 # if visible references are destroyed.
1761 self.root_logger.setLevel(logging.INFO)
1762 foo = logging.getLogger("foo")
1763 self._watch_for_survival(foo)
1764 foo.setLevel(logging.DEBUG)
1765 self.root_logger.debug(self.next_message())
1766 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001767 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001768 ('foo', 'DEBUG', '2'),
1769 ])
1770 del foo
1771 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001772 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001773 # foo has retained its settings.
1774 bar = logging.getLogger("foo")
1775 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001776 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001777 ('foo', 'DEBUG', '2'),
1778 ('foo', 'DEBUG', '3'),
1779 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001780
Benjamin Petersonf91df042009-02-13 02:50:59 +00001781
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001782class EncodingTest(BaseTest):
1783 def test_encoding_plain_file(self):
1784 # In Python 2.x, a plain file object is treated as having no encoding.
1785 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001786 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1787 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001788 # the non-ascii data we write to the log.
1789 data = "foo\x80"
1790 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001791 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001792 log.addHandler(handler)
1793 try:
1794 # write non-ascii data to the log.
1795 log.warning(data)
1796 finally:
1797 log.removeHandler(handler)
1798 handler.close()
1799 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001800 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001801 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001802 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001803 finally:
1804 f.close()
1805 finally:
1806 if os.path.isfile(fn):
1807 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001808
Benjamin Petersonf91df042009-02-13 02:50:59 +00001809 def test_encoding_cyrillic_unicode(self):
1810 log = logging.getLogger("test")
1811 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1812 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1813 #Ensure it's written in a Cyrillic encoding
1814 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001815 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001816 stream = io.BytesIO()
1817 writer = writer_class(stream, 'strict')
1818 handler = logging.StreamHandler(writer)
1819 log.addHandler(handler)
1820 try:
1821 log.warning(message)
1822 finally:
1823 log.removeHandler(handler)
1824 handler.close()
1825 # check we wrote exactly those bytes, ignoring trailing \n etc
1826 s = stream.getvalue()
1827 #Compare against what the data should be when encoded in CP-1251
1828 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1829
1830
Georg Brandlf9734072008-12-07 15:30:06 +00001831class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001832
Georg Brandlf9734072008-12-07 15:30:06 +00001833 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001834 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001835 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001836 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001837 warnings.filterwarnings("always", category=UserWarning)
1838 stream = io.StringIO()
1839 h = logging.StreamHandler(stream)
1840 logger = logging.getLogger("py.warnings")
1841 logger.addHandler(h)
1842 warnings.warn("I'm warning you...")
1843 logger.removeHandler(h)
1844 s = stream.getvalue()
1845 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001846 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001847
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001848 #See if an explicit file uses the original implementation
1849 a_file = io.StringIO()
1850 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1851 a_file, "Dummy line")
1852 s = a_file.getvalue()
1853 a_file.close()
1854 self.assertEqual(s,
1855 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1856
1857 def test_warnings_no_handlers(self):
1858 with warnings.catch_warnings():
1859 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001860 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001861
1862 # confirm our assumption: no loggers are set
1863 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001864 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001865
1866 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001867 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001868 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001869
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001870
1871def formatFunc(format, datefmt=None):
1872 return logging.Formatter(format, datefmt)
1873
1874def handlerFunc():
1875 return logging.StreamHandler()
1876
1877class CustomHandler(logging.StreamHandler):
1878 pass
1879
1880class ConfigDictTest(BaseTest):
1881
1882 """Reading logging config from a dictionary."""
1883
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001884 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001885
1886 # config0 is a standard configuration.
1887 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001888 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001889 'formatters': {
1890 'form1' : {
1891 'format' : '%(levelname)s ++ %(message)s',
1892 },
1893 },
1894 'handlers' : {
1895 'hand1' : {
1896 'class' : 'logging.StreamHandler',
1897 'formatter' : 'form1',
1898 'level' : 'NOTSET',
1899 'stream' : 'ext://sys.stdout',
1900 },
1901 },
1902 'root' : {
1903 'level' : 'WARNING',
1904 'handlers' : ['hand1'],
1905 },
1906 }
1907
1908 # config1 adds a little to the standard configuration.
1909 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001910 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001911 'formatters': {
1912 'form1' : {
1913 'format' : '%(levelname)s ++ %(message)s',
1914 },
1915 },
1916 'handlers' : {
1917 'hand1' : {
1918 'class' : 'logging.StreamHandler',
1919 'formatter' : 'form1',
1920 'level' : 'NOTSET',
1921 'stream' : 'ext://sys.stdout',
1922 },
1923 },
1924 'loggers' : {
1925 'compiler.parser' : {
1926 'level' : 'DEBUG',
1927 'handlers' : ['hand1'],
1928 },
1929 },
1930 'root' : {
1931 'level' : 'WARNING',
1932 },
1933 }
1934
Vinay Sajip9f9991c2011-03-07 18:02:57 +00001935 # config1a moves the handler to the root. Used with config8a
1936 config1a = {
1937 'version': 1,
1938 'formatters': {
1939 'form1' : {
1940 'format' : '%(levelname)s ++ %(message)s',
1941 },
1942 },
1943 'handlers' : {
1944 'hand1' : {
1945 'class' : 'logging.StreamHandler',
1946 'formatter' : 'form1',
1947 'level' : 'NOTSET',
1948 'stream' : 'ext://sys.stdout',
1949 },
1950 },
1951 'loggers' : {
1952 'compiler.parser' : {
1953 'level' : 'DEBUG',
1954 },
1955 },
1956 'root' : {
1957 'level' : 'WARNING',
1958 'handlers' : ['hand1'],
1959 },
1960 }
1961
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001962 # config2 has a subtle configuration error that should be reported
1963 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001964 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001965 'formatters': {
1966 'form1' : {
1967 'format' : '%(levelname)s ++ %(message)s',
1968 },
1969 },
1970 'handlers' : {
1971 'hand1' : {
1972 'class' : 'logging.StreamHandler',
1973 'formatter' : 'form1',
1974 'level' : 'NOTSET',
1975 'stream' : 'ext://sys.stdbout',
1976 },
1977 },
1978 'loggers' : {
1979 'compiler.parser' : {
1980 'level' : 'DEBUG',
1981 'handlers' : ['hand1'],
1982 },
1983 },
1984 'root' : {
1985 'level' : 'WARNING',
1986 },
1987 }
1988
1989 #As config1 but with a misspelt level on a handler
1990 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001991 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001992 'formatters': {
1993 'form1' : {
1994 'format' : '%(levelname)s ++ %(message)s',
1995 },
1996 },
1997 'handlers' : {
1998 'hand1' : {
1999 'class' : 'logging.StreamHandler',
2000 'formatter' : 'form1',
2001 'level' : 'NTOSET',
2002 'stream' : 'ext://sys.stdout',
2003 },
2004 },
2005 'loggers' : {
2006 'compiler.parser' : {
2007 'level' : 'DEBUG',
2008 'handlers' : ['hand1'],
2009 },
2010 },
2011 'root' : {
2012 'level' : 'WARNING',
2013 },
2014 }
2015
2016
2017 #As config1 but with a misspelt level on a logger
2018 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002019 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002020 'formatters': {
2021 'form1' : {
2022 'format' : '%(levelname)s ++ %(message)s',
2023 },
2024 },
2025 'handlers' : {
2026 'hand1' : {
2027 'class' : 'logging.StreamHandler',
2028 'formatter' : 'form1',
2029 'level' : 'NOTSET',
2030 'stream' : 'ext://sys.stdout',
2031 },
2032 },
2033 'loggers' : {
2034 'compiler.parser' : {
2035 'level' : 'DEBUG',
2036 'handlers' : ['hand1'],
2037 },
2038 },
2039 'root' : {
2040 'level' : 'WRANING',
2041 },
2042 }
2043
2044 # config3 has a less subtle configuration error
2045 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002046 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002047 'formatters': {
2048 'form1' : {
2049 'format' : '%(levelname)s ++ %(message)s',
2050 },
2051 },
2052 'handlers' : {
2053 'hand1' : {
2054 'class' : 'logging.StreamHandler',
2055 'formatter' : 'misspelled_name',
2056 'level' : 'NOTSET',
2057 'stream' : 'ext://sys.stdout',
2058 },
2059 },
2060 'loggers' : {
2061 'compiler.parser' : {
2062 'level' : 'DEBUG',
2063 'handlers' : ['hand1'],
2064 },
2065 },
2066 'root' : {
2067 'level' : 'WARNING',
2068 },
2069 }
2070
2071 # config4 specifies a custom formatter class to be loaded
2072 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002073 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002074 'formatters': {
2075 'form1' : {
2076 '()' : __name__ + '.ExceptionFormatter',
2077 'format' : '%(levelname)s:%(name)s:%(message)s',
2078 },
2079 },
2080 'handlers' : {
2081 'hand1' : {
2082 'class' : 'logging.StreamHandler',
2083 'formatter' : 'form1',
2084 'level' : 'NOTSET',
2085 'stream' : 'ext://sys.stdout',
2086 },
2087 },
2088 'root' : {
2089 'level' : 'NOTSET',
2090 'handlers' : ['hand1'],
2091 },
2092 }
2093
2094 # As config4 but using an actual callable rather than a string
2095 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002097 'formatters': {
2098 'form1' : {
2099 '()' : ExceptionFormatter,
2100 'format' : '%(levelname)s:%(name)s:%(message)s',
2101 },
2102 'form2' : {
2103 '()' : __name__ + '.formatFunc',
2104 'format' : '%(levelname)s:%(name)s:%(message)s',
2105 },
2106 'form3' : {
2107 '()' : formatFunc,
2108 'format' : '%(levelname)s:%(name)s:%(message)s',
2109 },
2110 },
2111 'handlers' : {
2112 'hand1' : {
2113 'class' : 'logging.StreamHandler',
2114 'formatter' : 'form1',
2115 'level' : 'NOTSET',
2116 'stream' : 'ext://sys.stdout',
2117 },
2118 'hand2' : {
2119 '()' : handlerFunc,
2120 },
2121 },
2122 'root' : {
2123 'level' : 'NOTSET',
2124 'handlers' : ['hand1'],
2125 },
2126 }
2127
2128 # config5 specifies a custom handler class to be loaded
2129 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002130 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002131 'formatters': {
2132 'form1' : {
2133 'format' : '%(levelname)s ++ %(message)s',
2134 },
2135 },
2136 'handlers' : {
2137 'hand1' : {
2138 'class' : __name__ + '.CustomHandler',
2139 'formatter' : 'form1',
2140 'level' : 'NOTSET',
2141 'stream' : 'ext://sys.stdout',
2142 },
2143 },
2144 'loggers' : {
2145 'compiler.parser' : {
2146 'level' : 'DEBUG',
2147 'handlers' : ['hand1'],
2148 },
2149 },
2150 'root' : {
2151 'level' : 'WARNING',
2152 },
2153 }
2154
2155 # config6 specifies a custom handler class to be loaded
2156 # but has bad arguments
2157 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002158 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002159 'formatters': {
2160 'form1' : {
2161 'format' : '%(levelname)s ++ %(message)s',
2162 },
2163 },
2164 'handlers' : {
2165 'hand1' : {
2166 'class' : __name__ + '.CustomHandler',
2167 'formatter' : 'form1',
2168 'level' : 'NOTSET',
2169 'stream' : 'ext://sys.stdout',
2170 '9' : 'invalid parameter name',
2171 },
2172 },
2173 'loggers' : {
2174 'compiler.parser' : {
2175 'level' : 'DEBUG',
2176 'handlers' : ['hand1'],
2177 },
2178 },
2179 'root' : {
2180 'level' : 'WARNING',
2181 },
2182 }
2183
2184 #config 7 does not define compiler.parser but defines compiler.lexer
2185 #so compiler.parser should be disabled after applying it
2186 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002187 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002188 'formatters': {
2189 'form1' : {
2190 'format' : '%(levelname)s ++ %(message)s',
2191 },
2192 },
2193 'handlers' : {
2194 'hand1' : {
2195 'class' : 'logging.StreamHandler',
2196 'formatter' : 'form1',
2197 'level' : 'NOTSET',
2198 'stream' : 'ext://sys.stdout',
2199 },
2200 },
2201 'loggers' : {
2202 'compiler.lexer' : {
2203 'level' : 'DEBUG',
2204 'handlers' : ['hand1'],
2205 },
2206 },
2207 'root' : {
2208 'level' : 'WARNING',
2209 },
2210 }
2211
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002212 # config8 defines both compiler and compiler.lexer
2213 # so compiler.parser should not be disabled (since
2214 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002215 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002216 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002217 'disable_existing_loggers' : False,
2218 'formatters': {
2219 'form1' : {
2220 'format' : '%(levelname)s ++ %(message)s',
2221 },
2222 },
2223 'handlers' : {
2224 'hand1' : {
2225 'class' : 'logging.StreamHandler',
2226 'formatter' : 'form1',
2227 'level' : 'NOTSET',
2228 'stream' : 'ext://sys.stdout',
2229 },
2230 },
2231 'loggers' : {
2232 'compiler' : {
2233 'level' : 'DEBUG',
2234 'handlers' : ['hand1'],
2235 },
2236 'compiler.lexer' : {
2237 },
2238 },
2239 'root' : {
2240 'level' : 'WARNING',
2241 },
2242 }
2243
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002244 # config8a disables existing loggers
2245 config8a = {
2246 'version': 1,
2247 'disable_existing_loggers' : True,
2248 'formatters': {
2249 'form1' : {
2250 'format' : '%(levelname)s ++ %(message)s',
2251 },
2252 },
2253 'handlers' : {
2254 'hand1' : {
2255 'class' : 'logging.StreamHandler',
2256 'formatter' : 'form1',
2257 'level' : 'NOTSET',
2258 'stream' : 'ext://sys.stdout',
2259 },
2260 },
2261 'loggers' : {
2262 'compiler' : {
2263 'level' : 'DEBUG',
2264 'handlers' : ['hand1'],
2265 },
2266 'compiler.lexer' : {
2267 },
2268 },
2269 'root' : {
2270 'level' : 'WARNING',
2271 },
2272 }
2273
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002274 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002275 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002276 'formatters': {
2277 'form1' : {
2278 'format' : '%(levelname)s ++ %(message)s',
2279 },
2280 },
2281 'handlers' : {
2282 'hand1' : {
2283 'class' : 'logging.StreamHandler',
2284 'formatter' : 'form1',
2285 'level' : 'WARNING',
2286 'stream' : 'ext://sys.stdout',
2287 },
2288 },
2289 'loggers' : {
2290 'compiler.parser' : {
2291 'level' : 'WARNING',
2292 'handlers' : ['hand1'],
2293 },
2294 },
2295 'root' : {
2296 'level' : 'NOTSET',
2297 },
2298 }
2299
2300 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002301 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002302 'incremental' : True,
2303 'handlers' : {
2304 'hand1' : {
2305 'level' : 'WARNING',
2306 },
2307 },
2308 'loggers' : {
2309 'compiler.parser' : {
2310 'level' : 'INFO',
2311 },
2312 },
2313 }
2314
2315 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002316 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002317 'incremental' : True,
2318 'handlers' : {
2319 'hand1' : {
2320 'level' : 'INFO',
2321 },
2322 },
2323 'loggers' : {
2324 'compiler.parser' : {
2325 'level' : 'INFO',
2326 },
2327 },
2328 }
2329
2330 #As config1 but with a filter added
2331 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002332 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002333 'formatters': {
2334 'form1' : {
2335 'format' : '%(levelname)s ++ %(message)s',
2336 },
2337 },
2338 'filters' : {
2339 'filt1' : {
2340 'name' : 'compiler.parser',
2341 },
2342 },
2343 'handlers' : {
2344 'hand1' : {
2345 'class' : 'logging.StreamHandler',
2346 'formatter' : 'form1',
2347 'level' : 'NOTSET',
2348 'stream' : 'ext://sys.stdout',
2349 'filters' : ['filt1'],
2350 },
2351 },
2352 'loggers' : {
2353 'compiler.parser' : {
2354 'level' : 'DEBUG',
2355 'filters' : ['filt1'],
2356 },
2357 },
2358 'root' : {
2359 'level' : 'WARNING',
2360 'handlers' : ['hand1'],
2361 },
2362 }
2363
2364 #As config1 but using cfg:// references
2365 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002366 'version': 1,
2367 'true_formatters': {
2368 'form1' : {
2369 'format' : '%(levelname)s ++ %(message)s',
2370 },
2371 },
2372 'handler_configs': {
2373 'hand1' : {
2374 'class' : 'logging.StreamHandler',
2375 'formatter' : 'form1',
2376 'level' : 'NOTSET',
2377 'stream' : 'ext://sys.stdout',
2378 },
2379 },
2380 'formatters' : 'cfg://true_formatters',
2381 'handlers' : {
2382 'hand1' : 'cfg://handler_configs[hand1]',
2383 },
2384 'loggers' : {
2385 'compiler.parser' : {
2386 'level' : 'DEBUG',
2387 'handlers' : ['hand1'],
2388 },
2389 },
2390 'root' : {
2391 'level' : 'WARNING',
2392 },
2393 }
2394
2395 #As config11 but missing the version key
2396 config12 = {
2397 'true_formatters': {
2398 'form1' : {
2399 'format' : '%(levelname)s ++ %(message)s',
2400 },
2401 },
2402 'handler_configs': {
2403 'hand1' : {
2404 'class' : 'logging.StreamHandler',
2405 'formatter' : 'form1',
2406 'level' : 'NOTSET',
2407 'stream' : 'ext://sys.stdout',
2408 },
2409 },
2410 'formatters' : 'cfg://true_formatters',
2411 'handlers' : {
2412 'hand1' : 'cfg://handler_configs[hand1]',
2413 },
2414 'loggers' : {
2415 'compiler.parser' : {
2416 'level' : 'DEBUG',
2417 'handlers' : ['hand1'],
2418 },
2419 },
2420 'root' : {
2421 'level' : 'WARNING',
2422 },
2423 }
2424
2425 #As config11 but using an unsupported version
2426 config13 = {
2427 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002428 'true_formatters': {
2429 'form1' : {
2430 'format' : '%(levelname)s ++ %(message)s',
2431 },
2432 },
2433 'handler_configs': {
2434 'hand1' : {
2435 'class' : 'logging.StreamHandler',
2436 'formatter' : 'form1',
2437 'level' : 'NOTSET',
2438 'stream' : 'ext://sys.stdout',
2439 },
2440 },
2441 'formatters' : 'cfg://true_formatters',
2442 'handlers' : {
2443 'hand1' : 'cfg://handler_configs[hand1]',
2444 },
2445 'loggers' : {
2446 'compiler.parser' : {
2447 'level' : 'DEBUG',
2448 'handlers' : ['hand1'],
2449 },
2450 },
2451 'root' : {
2452 'level' : 'WARNING',
2453 },
2454 }
2455
Vinay Sajip8d270232012-11-15 14:20:18 +00002456 # As config0, but with properties
2457 config14 = {
2458 'version': 1,
2459 'formatters': {
2460 'form1' : {
2461 'format' : '%(levelname)s ++ %(message)s',
2462 },
2463 },
2464 'handlers' : {
2465 'hand1' : {
2466 'class' : 'logging.StreamHandler',
2467 'formatter' : 'form1',
2468 'level' : 'NOTSET',
2469 'stream' : 'ext://sys.stdout',
2470 '.': {
2471 'foo': 'bar',
2472 'terminator': '!\n',
2473 }
2474 },
2475 },
2476 'root' : {
2477 'level' : 'WARNING',
2478 'handlers' : ['hand1'],
2479 },
2480 }
2481
Vinay Sajip3f885b52013-03-22 15:19:54 +00002482 out_of_order = {
2483 "version": 1,
2484 "formatters": {
2485 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002486 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2487 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002488 }
2489 },
2490 "handlers": {
2491 "fileGlobal": {
2492 "class": "logging.StreamHandler",
2493 "level": "DEBUG",
2494 "formatter": "mySimpleFormatter"
2495 },
2496 "bufferGlobal": {
2497 "class": "logging.handlers.MemoryHandler",
2498 "capacity": 5,
2499 "formatter": "mySimpleFormatter",
2500 "target": "fileGlobal",
2501 "level": "DEBUG"
2502 }
2503 },
2504 "loggers": {
2505 "mymodule": {
2506 "level": "DEBUG",
2507 "handlers": ["bufferGlobal"],
2508 "propagate": "true"
2509 }
2510 }
2511 }
2512
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002513 def apply_config(self, conf):
2514 logging.config.dictConfig(conf)
2515
2516 def test_config0_ok(self):
2517 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002518 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002519 self.apply_config(self.config0)
2520 logger = logging.getLogger()
2521 # Won't output anything
2522 logger.info(self.next_message())
2523 # Outputs a message
2524 logger.error(self.next_message())
2525 self.assert_log_lines([
2526 ('ERROR', '2'),
2527 ], stream=output)
2528 # Original logger output is empty.
2529 self.assert_log_lines([])
2530
2531 def test_config1_ok(self, config=config1):
2532 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002533 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002534 self.apply_config(config)
2535 logger = logging.getLogger("compiler.parser")
2536 # Both will output a message
2537 logger.info(self.next_message())
2538 logger.error(self.next_message())
2539 self.assert_log_lines([
2540 ('INFO', '1'),
2541 ('ERROR', '2'),
2542 ], stream=output)
2543 # Original logger output is empty.
2544 self.assert_log_lines([])
2545
2546 def test_config2_failure(self):
2547 # A simple config which overrides the default settings.
2548 self.assertRaises(Exception, self.apply_config, self.config2)
2549
2550 def test_config2a_failure(self):
2551 # A simple config which overrides the default settings.
2552 self.assertRaises(Exception, self.apply_config, self.config2a)
2553
2554 def test_config2b_failure(self):
2555 # A simple config which overrides the default settings.
2556 self.assertRaises(Exception, self.apply_config, self.config2b)
2557
2558 def test_config3_failure(self):
2559 # A simple config which overrides the default settings.
2560 self.assertRaises(Exception, self.apply_config, self.config3)
2561
2562 def test_config4_ok(self):
2563 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002564 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002565 self.apply_config(self.config4)
2566 #logger = logging.getLogger()
2567 try:
2568 raise RuntimeError()
2569 except RuntimeError:
2570 logging.exception("just testing")
2571 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002572 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002573 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2574 # Original logger output is empty
2575 self.assert_log_lines([])
2576
2577 def test_config4a_ok(self):
2578 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002579 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002580 self.apply_config(self.config4a)
2581 #logger = logging.getLogger()
2582 try:
2583 raise RuntimeError()
2584 except RuntimeError:
2585 logging.exception("just testing")
2586 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002587 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002588 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2589 # Original logger output is empty
2590 self.assert_log_lines([])
2591
2592 def test_config5_ok(self):
2593 self.test_config1_ok(config=self.config5)
2594
2595 def test_config6_failure(self):
2596 self.assertRaises(Exception, self.apply_config, self.config6)
2597
2598 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002599 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002600 self.apply_config(self.config1)
2601 logger = logging.getLogger("compiler.parser")
2602 # Both will output a message
2603 logger.info(self.next_message())
2604 logger.error(self.next_message())
2605 self.assert_log_lines([
2606 ('INFO', '1'),
2607 ('ERROR', '2'),
2608 ], stream=output)
2609 # Original logger output is empty.
2610 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002611 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002612 self.apply_config(self.config7)
2613 logger = logging.getLogger("compiler.parser")
2614 self.assertTrue(logger.disabled)
2615 logger = logging.getLogger("compiler.lexer")
2616 # Both will output a message
2617 logger.info(self.next_message())
2618 logger.error(self.next_message())
2619 self.assert_log_lines([
2620 ('INFO', '3'),
2621 ('ERROR', '4'),
2622 ], stream=output)
2623 # Original logger output is empty.
2624 self.assert_log_lines([])
2625
2626 #Same as test_config_7_ok but don't disable old loggers.
2627 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002628 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002629 self.apply_config(self.config1)
2630 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002631 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002632 logger.info(self.next_message())
2633 logger.error(self.next_message())
2634 self.assert_log_lines([
2635 ('INFO', '1'),
2636 ('ERROR', '2'),
2637 ], stream=output)
2638 # Original logger output is empty.
2639 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002640 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002641 self.apply_config(self.config8)
2642 logger = logging.getLogger("compiler.parser")
2643 self.assertFalse(logger.disabled)
2644 # Both will output a message
2645 logger.info(self.next_message())
2646 logger.error(self.next_message())
2647 logger = logging.getLogger("compiler.lexer")
2648 # Both will output a message
2649 logger.info(self.next_message())
2650 logger.error(self.next_message())
2651 self.assert_log_lines([
2652 ('INFO', '3'),
2653 ('ERROR', '4'),
2654 ('INFO', '5'),
2655 ('ERROR', '6'),
2656 ], stream=output)
2657 # Original logger output is empty.
2658 self.assert_log_lines([])
2659
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002660 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002661 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002662 self.apply_config(self.config1a)
2663 logger = logging.getLogger("compiler.parser")
2664 # See issue #11424. compiler-hyphenated sorts
2665 # between compiler and compiler.xyz and this
2666 # was preventing compiler.xyz from being included
2667 # in the child loggers of compiler because of an
2668 # overzealous loop termination condition.
2669 hyphenated = logging.getLogger('compiler-hyphenated')
2670 # All will output a message
2671 logger.info(self.next_message())
2672 logger.error(self.next_message())
2673 hyphenated.critical(self.next_message())
2674 self.assert_log_lines([
2675 ('INFO', '1'),
2676 ('ERROR', '2'),
2677 ('CRITICAL', '3'),
2678 ], stream=output)
2679 # Original logger output is empty.
2680 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002681 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002682 self.apply_config(self.config8a)
2683 logger = logging.getLogger("compiler.parser")
2684 self.assertFalse(logger.disabled)
2685 # Both will output a message
2686 logger.info(self.next_message())
2687 logger.error(self.next_message())
2688 logger = logging.getLogger("compiler.lexer")
2689 # Both will output a message
2690 logger.info(self.next_message())
2691 logger.error(self.next_message())
2692 # Will not appear
2693 hyphenated.critical(self.next_message())
2694 self.assert_log_lines([
2695 ('INFO', '4'),
2696 ('ERROR', '5'),
2697 ('INFO', '6'),
2698 ('ERROR', '7'),
2699 ], stream=output)
2700 # Original logger output is empty.
2701 self.assert_log_lines([])
2702
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002703 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002704 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002705 self.apply_config(self.config9)
2706 logger = logging.getLogger("compiler.parser")
2707 #Nothing will be output since both handler and logger are set to WARNING
2708 logger.info(self.next_message())
2709 self.assert_log_lines([], stream=output)
2710 self.apply_config(self.config9a)
2711 #Nothing will be output since both handler is still set to WARNING
2712 logger.info(self.next_message())
2713 self.assert_log_lines([], stream=output)
2714 self.apply_config(self.config9b)
2715 #Message should now be output
2716 logger.info(self.next_message())
2717 self.assert_log_lines([
2718 ('INFO', '3'),
2719 ], stream=output)
2720
2721 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002722 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002723 self.apply_config(self.config10)
2724 logger = logging.getLogger("compiler.parser")
2725 logger.warning(self.next_message())
2726 logger = logging.getLogger('compiler')
2727 #Not output, because filtered
2728 logger.warning(self.next_message())
2729 logger = logging.getLogger('compiler.lexer')
2730 #Not output, because filtered
2731 logger.warning(self.next_message())
2732 logger = logging.getLogger("compiler.parser.codegen")
2733 #Output, as not filtered
2734 logger.error(self.next_message())
2735 self.assert_log_lines([
2736 ('WARNING', '1'),
2737 ('ERROR', '4'),
2738 ], stream=output)
2739
2740 def test_config11_ok(self):
2741 self.test_config1_ok(self.config11)
2742
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002743 def test_config12_failure(self):
2744 self.assertRaises(Exception, self.apply_config, self.config12)
2745
2746 def test_config13_failure(self):
2747 self.assertRaises(Exception, self.apply_config, self.config13)
2748
Vinay Sajip8d270232012-11-15 14:20:18 +00002749 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002750 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002751 self.apply_config(self.config14)
2752 h = logging._handlers['hand1']
2753 self.assertEqual(h.foo, 'bar')
2754 self.assertEqual(h.terminator, '!\n')
2755 logging.warning('Exclamation')
2756 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2757
Victor Stinner45df8202010-04-28 22:31:17 +00002758 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip4ded5512012-10-02 15:56:16 +01002759 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002760 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002761 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002762 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002763 t.start()
2764 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002765 # Now get the port allocated
2766 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002767 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 try:
2769 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2770 sock.settimeout(2.0)
2771 sock.connect(('localhost', port))
2772
2773 slen = struct.pack('>L', len(text))
2774 s = slen + text
2775 sentsofar = 0
2776 left = len(s)
2777 while left > 0:
2778 sent = sock.send(s[sentsofar:])
2779 sentsofar += sent
2780 left -= sent
2781 sock.close()
2782 finally:
2783 t.ready.wait(2.0)
2784 logging.config.stopListening()
2785 t.join(2.0)
2786
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002787 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002788 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002789 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002790 self.setup_via_listener(json.dumps(self.config10))
2791 logger = logging.getLogger("compiler.parser")
2792 logger.warning(self.next_message())
2793 logger = logging.getLogger('compiler')
2794 #Not output, because filtered
2795 logger.warning(self.next_message())
2796 logger = logging.getLogger('compiler.lexer')
2797 #Not output, because filtered
2798 logger.warning(self.next_message())
2799 logger = logging.getLogger("compiler.parser.codegen")
2800 #Output, as not filtered
2801 logger.error(self.next_message())
2802 self.assert_log_lines([
2803 ('WARNING', '1'),
2804 ('ERROR', '4'),
2805 ], stream=output)
2806
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01002807 @unittest.skipUnless(threading, 'Threading required for this test.')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002808 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002809 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002810 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2811 logger = logging.getLogger("compiler.parser")
2812 # Both will output a message
2813 logger.info(self.next_message())
2814 logger.error(self.next_message())
2815 self.assert_log_lines([
2816 ('INFO', '1'),
2817 ('ERROR', '2'),
2818 ], stream=output)
2819 # Original logger output is empty.
2820 self.assert_log_lines([])
2821
Vinay Sajip4ded5512012-10-02 15:56:16 +01002822 @unittest.skipUnless(threading, 'Threading required for this test.')
2823 def test_listen_verify(self):
2824
2825 def verify_fail(stuff):
2826 return None
2827
2828 def verify_reverse(stuff):
2829 return stuff[::-1]
2830
2831 logger = logging.getLogger("compiler.parser")
2832 to_send = textwrap.dedent(ConfigFileTest.config1)
2833 # First, specify a verification function that will fail.
2834 # We expect to see no output, since our configuration
2835 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002836 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002837 self.setup_via_listener(to_send, verify_fail)
2838 # Both will output a message
2839 logger.info(self.next_message())
2840 logger.error(self.next_message())
2841 self.assert_log_lines([], stream=output)
2842 # Original logger output has the stuff we logged.
2843 self.assert_log_lines([
2844 ('INFO', '1'),
2845 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002846 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002847
2848 # Now, perform no verification. Our configuration
2849 # should take effect.
2850
Vinay Sajip1feedb42014-05-31 08:19:12 +01002851 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002852 self.setup_via_listener(to_send) # no verify callable specified
2853 logger = logging.getLogger("compiler.parser")
2854 # Both will output a message
2855 logger.info(self.next_message())
2856 logger.error(self.next_message())
2857 self.assert_log_lines([
2858 ('INFO', '3'),
2859 ('ERROR', '4'),
2860 ], stream=output)
2861 # Original logger output still has the stuff we logged before.
2862 self.assert_log_lines([
2863 ('INFO', '1'),
2864 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002865 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002866
2867 # Now, perform verification which transforms the bytes.
2868
Vinay Sajip1feedb42014-05-31 08:19:12 +01002869 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002870 self.setup_via_listener(to_send[::-1], verify_reverse)
2871 logger = logging.getLogger("compiler.parser")
2872 # Both will output a message
2873 logger.info(self.next_message())
2874 logger.error(self.next_message())
2875 self.assert_log_lines([
2876 ('INFO', '5'),
2877 ('ERROR', '6'),
2878 ], stream=output)
2879 # Original logger output still has the stuff we logged before.
2880 self.assert_log_lines([
2881 ('INFO', '1'),
2882 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002883 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002884
Vinay Sajip3f885b52013-03-22 15:19:54 +00002885 def test_out_of_order(self):
2886 self.apply_config(self.out_of_order)
2887 handler = logging.getLogger('mymodule').handlers[0]
2888 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002889 self.assertIsInstance(handler.formatter._style,
2890 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002891
Vinay Sajip373baef2011-04-26 20:05:24 +01002892 def test_baseconfig(self):
2893 d = {
2894 'atuple': (1, 2, 3),
2895 'alist': ['a', 'b', 'c'],
2896 'adict': {'d': 'e', 'f': 3 },
2897 'nest1': ('g', ('h', 'i'), 'j'),
2898 'nest2': ['k', ['l', 'm'], 'n'],
2899 'nest3': ['o', 'cfg://alist', 'p'],
2900 }
2901 bc = logging.config.BaseConfigurator(d)
2902 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2903 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2904 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2905 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
2906 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
2907 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
2908 v = bc.convert('cfg://nest3')
2909 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
2910 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
2911 self.assertRaises(ValueError, bc.convert, 'cfg://!')
2912 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002913
2914class ManagerTest(BaseTest):
2915 def test_manager_loggerclass(self):
2916 logged = []
2917
2918 class MyLogger(logging.Logger):
2919 def _log(self, level, msg, args, exc_info=None, extra=None):
2920 logged.append(msg)
2921
2922 man = logging.Manager(None)
2923 self.assertRaises(TypeError, man.setLoggerClass, int)
2924 man.setLoggerClass(MyLogger)
2925 logger = man.getLogger('test')
2926 logger.warning('should appear in logged')
2927 logging.warning('should not appear in logged')
2928
2929 self.assertEqual(logged, ['should appear in logged'])
2930
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002931 def test_set_log_record_factory(self):
2932 man = logging.Manager(None)
2933 expected = object()
2934 man.setLogRecordFactory(expected)
2935 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002936
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002937class ChildLoggerTest(BaseTest):
2938 def test_child_loggers(self):
2939 r = logging.getLogger()
2940 l1 = logging.getLogger('abc')
2941 l2 = logging.getLogger('def.ghi')
2942 c1 = r.getChild('xyz')
2943 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002944 self.assertIs(c1, logging.getLogger('xyz'))
2945 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002946 c1 = l1.getChild('def')
2947 c2 = c1.getChild('ghi')
2948 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02002949 self.assertIs(c1, logging.getLogger('abc.def'))
2950 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
2951 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00002952
2953
Vinay Sajip6fac8172010-10-19 20:44:14 +00002954class DerivedLogRecord(logging.LogRecord):
2955 pass
2956
Vinay Sajip61561522010-12-03 11:50:38 +00002957class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00002958
2959 def setUp(self):
2960 class CheckingFilter(logging.Filter):
2961 def __init__(self, cls):
2962 self.cls = cls
2963
2964 def filter(self, record):
2965 t = type(record)
2966 if t is not self.cls:
2967 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
2968 self.cls)
2969 raise TypeError(msg)
2970 return True
2971
2972 BaseTest.setUp(self)
2973 self.filter = CheckingFilter(DerivedLogRecord)
2974 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00002975 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00002976
2977 def tearDown(self):
2978 self.root_logger.removeFilter(self.filter)
2979 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00002980 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002981
2982 def test_logrecord_class(self):
2983 self.assertRaises(TypeError, self.root_logger.warning,
2984 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00002985 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00002986 self.root_logger.error(self.next_message())
2987 self.assert_log_lines([
2988 ('root', 'ERROR', '2'),
2989 ])
2990
2991
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002992class QueueHandlerTest(BaseTest):
2993 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002994 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00002995
2996 def setUp(self):
2997 BaseTest.setUp(self)
2998 self.queue = queue.Queue(-1)
2999 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
3000 self.que_logger = logging.getLogger('que')
3001 self.que_logger.propagate = False
3002 self.que_logger.setLevel(logging.WARNING)
3003 self.que_logger.addHandler(self.que_hdlr)
3004
3005 def tearDown(self):
3006 self.que_hdlr.close()
3007 BaseTest.tearDown(self)
3008
3009 def test_queue_handler(self):
3010 self.que_logger.debug(self.next_message())
3011 self.assertRaises(queue.Empty, self.queue.get_nowait)
3012 self.que_logger.info(self.next_message())
3013 self.assertRaises(queue.Empty, self.queue.get_nowait)
3014 msg = self.next_message()
3015 self.que_logger.warning(msg)
3016 data = self.queue.get_nowait()
3017 self.assertTrue(isinstance(data, logging.LogRecord))
3018 self.assertEqual(data.name, self.que_logger.name)
3019 self.assertEqual((data.msg, data.args), (msg, None))
3020
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003021 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3022 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003023 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003024 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003025 listener = logging.handlers.QueueListener(self.queue, handler)
3026 listener.start()
3027 try:
3028 self.que_logger.warning(self.next_message())
3029 self.que_logger.error(self.next_message())
3030 self.que_logger.critical(self.next_message())
3031 finally:
3032 listener.stop()
3033 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3034 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3035 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003036 handler.close()
3037
3038 # Now test with respect_handler_level set
3039
3040 handler = support.TestHandler(support.Matcher())
3041 handler.setLevel(logging.CRITICAL)
3042 listener = logging.handlers.QueueListener(self.queue, handler,
3043 respect_handler_level=True)
3044 listener.start()
3045 try:
3046 self.que_logger.warning(self.next_message())
3047 self.que_logger.error(self.next_message())
3048 self.que_logger.critical(self.next_message())
3049 finally:
3050 listener.stop()
3051 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3052 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3053 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3054
Vinay Sajipe723e962011-04-15 22:27:17 +01003055
Vinay Sajip37eb3382011-04-26 20:26:41 +01003056ZERO = datetime.timedelta(0)
3057
3058class UTC(datetime.tzinfo):
3059 def utcoffset(self, dt):
3060 return ZERO
3061
3062 dst = utcoffset
3063
3064 def tzname(self, dt):
3065 return 'UTC'
3066
3067utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003068
Vinay Sajipa39c5712010-10-25 13:57:39 +00003069class FormatterTest(unittest.TestCase):
3070 def setUp(self):
3071 self.common = {
3072 'name': 'formatter.test',
3073 'level': logging.DEBUG,
3074 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3075 'lineno': 42,
3076 'exc_info': None,
3077 'func': None,
3078 'msg': 'Message with %d %s',
3079 'args': (2, 'placeholders'),
3080 }
3081 self.variants = {
3082 }
3083
3084 def get_record(self, name=None):
3085 result = dict(self.common)
3086 if name is not None:
3087 result.update(self.variants[name])
3088 return logging.makeLogRecord(result)
3089
3090 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003091 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003092 r = self.get_record()
3093 f = logging.Formatter('${%(message)s}')
3094 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3095 f = logging.Formatter('%(random)s')
3096 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003097 self.assertFalse(f.usesTime())
3098 f = logging.Formatter('%(asctime)s')
3099 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003100 f = logging.Formatter('%(asctime)-15s')
3101 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003102 f = logging.Formatter('asctime')
3103 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003104
3105 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003106 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003107 r = self.get_record()
3108 f = logging.Formatter('$%{message}%$', style='{')
3109 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3110 f = logging.Formatter('{random}', style='{')
3111 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003112 self.assertFalse(f.usesTime())
3113 f = logging.Formatter('{asctime}', style='{')
3114 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003115 f = logging.Formatter('{asctime!s:15}', style='{')
3116 self.assertTrue(f.usesTime())
3117 f = logging.Formatter('{asctime:15}', style='{')
3118 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003119 f = logging.Formatter('asctime', style='{')
3120 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003121
3122 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003123 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003124 r = self.get_record()
3125 f = logging.Formatter('$message', style='$')
3126 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3127 f = logging.Formatter('$$%${message}%$$', style='$')
3128 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3129 f = logging.Formatter('${random}', style='$')
3130 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003131 self.assertFalse(f.usesTime())
3132 f = logging.Formatter('${asctime}', style='$')
3133 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003134 f = logging.Formatter('${asctime', style='$')
3135 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003136 f = logging.Formatter('$asctime', style='$')
3137 self.assertTrue(f.usesTime())
3138 f = logging.Formatter('asctime', style='$')
3139 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003140
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003141 def test_invalid_style(self):
3142 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3143
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003144 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003145 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003146 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3147 # We use None to indicate we want the local timezone
3148 # We're essentially converting a UTC time to local time
3149 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003150 r.msecs = 123
3151 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003152 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003153 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3154 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003155 f.format(r)
3156 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3157
3158class TestBufferingFormatter(logging.BufferingFormatter):
3159 def formatHeader(self, records):
3160 return '[(%d)' % len(records)
3161
3162 def formatFooter(self, records):
3163 return '(%d)]' % len(records)
3164
3165class BufferingFormatterTest(unittest.TestCase):
3166 def setUp(self):
3167 self.records = [
3168 logging.makeLogRecord({'msg': 'one'}),
3169 logging.makeLogRecord({'msg': 'two'}),
3170 ]
3171
3172 def test_default(self):
3173 f = logging.BufferingFormatter()
3174 self.assertEqual('', f.format([]))
3175 self.assertEqual('onetwo', f.format(self.records))
3176
3177 def test_custom(self):
3178 f = TestBufferingFormatter()
3179 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3180 lf = logging.Formatter('<%(message)s>')
3181 f = TestBufferingFormatter(lf)
3182 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003183
3184class ExceptionTest(BaseTest):
3185 def test_formatting(self):
3186 r = self.root_logger
3187 h = RecordingHandler()
3188 r.addHandler(h)
3189 try:
3190 raise RuntimeError('deliberate mistake')
3191 except:
3192 logging.exception('failed', stack_info=True)
3193 r.removeHandler(h)
3194 h.close()
3195 r = h.records[0]
3196 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3197 'call last):\n'))
3198 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3199 'deliberate mistake'))
3200 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3201 'call last):\n'))
3202 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3203 'stack_info=True)'))
3204
3205
Vinay Sajip5a27d402010-12-10 11:42:57 +00003206class LastResortTest(BaseTest):
3207 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003208 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003209 root = self.root_logger
3210 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003211 old_lastresort = logging.lastResort
3212 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003213
Vinay Sajip5a27d402010-12-10 11:42:57 +00003214 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003215 with support.captured_stderr() as stderr:
3216 root.debug('This should not appear')
3217 self.assertEqual(stderr.getvalue(), '')
3218 root.warning('Final chance!')
3219 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3220
3221 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003222 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003223 with support.captured_stderr() as stderr:
3224 root.warning('Final chance!')
3225 msg = 'No handlers could be found for logger "root"\n'
3226 self.assertEqual(stderr.getvalue(), msg)
3227
Vinay Sajip5a27d402010-12-10 11:42:57 +00003228 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003229 with support.captured_stderr() as stderr:
3230 root.warning('Final chance!')
3231 self.assertEqual(stderr.getvalue(), '')
3232
3233 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003234 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003235 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003236 with support.captured_stderr() as stderr:
3237 root.warning('Final chance!')
3238 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003239 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003240 root.addHandler(self.root_hdlr)
3241 logging.lastResort = old_lastresort
3242 logging.raiseExceptions = old_raise_exceptions
3243
3244
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003245class FakeHandler:
3246
3247 def __init__(self, identifier, called):
3248 for method in ('acquire', 'flush', 'close', 'release'):
3249 setattr(self, method, self.record_call(identifier, method, called))
3250
3251 def record_call(self, identifier, method_name, called):
3252 def inner():
3253 called.append('{} - {}'.format(identifier, method_name))
3254 return inner
3255
3256
3257class RecordingHandler(logging.NullHandler):
3258
3259 def __init__(self, *args, **kwargs):
3260 super(RecordingHandler, self).__init__(*args, **kwargs)
3261 self.records = []
3262
3263 def handle(self, record):
3264 """Keep track of all the emitted records."""
3265 self.records.append(record)
3266
3267
3268class ShutdownTest(BaseTest):
3269
Vinay Sajip5e66b162011-04-20 15:41:14 +01003270 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003271
3272 def setUp(self):
3273 super(ShutdownTest, self).setUp()
3274 self.called = []
3275
3276 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003277 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003278
3279 def raise_error(self, error):
3280 def inner():
3281 raise error()
3282 return inner
3283
3284 def test_no_failure(self):
3285 # create some fake handlers
3286 handler0 = FakeHandler(0, self.called)
3287 handler1 = FakeHandler(1, self.called)
3288 handler2 = FakeHandler(2, self.called)
3289
3290 # create live weakref to those handlers
3291 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3292
3293 logging.shutdown(handlerList=list(handlers))
3294
3295 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3296 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3297 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3298 self.assertEqual(expected, self.called)
3299
3300 def _test_with_failure_in_method(self, method, error):
3301 handler = FakeHandler(0, self.called)
3302 setattr(handler, method, self.raise_error(error))
3303 handlers = [logging.weakref.ref(handler)]
3304
3305 logging.shutdown(handlerList=list(handlers))
3306
3307 self.assertEqual('0 - release', self.called[-1])
3308
3309 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003310 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003311
3312 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003313 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003314
3315 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003316 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003317
3318 def test_with_valueerror_in_acquire(self):
3319 self._test_with_failure_in_method('acquire', ValueError)
3320
3321 def test_with_valueerror_in_flush(self):
3322 self._test_with_failure_in_method('flush', ValueError)
3323
3324 def test_with_valueerror_in_close(self):
3325 self._test_with_failure_in_method('close', ValueError)
3326
3327 def test_with_other_error_in_acquire_without_raise(self):
3328 logging.raiseExceptions = False
3329 self._test_with_failure_in_method('acquire', IndexError)
3330
3331 def test_with_other_error_in_flush_without_raise(self):
3332 logging.raiseExceptions = False
3333 self._test_with_failure_in_method('flush', IndexError)
3334
3335 def test_with_other_error_in_close_without_raise(self):
3336 logging.raiseExceptions = False
3337 self._test_with_failure_in_method('close', IndexError)
3338
3339 def test_with_other_error_in_acquire_with_raise(self):
3340 logging.raiseExceptions = True
3341 self.assertRaises(IndexError, self._test_with_failure_in_method,
3342 'acquire', IndexError)
3343
3344 def test_with_other_error_in_flush_with_raise(self):
3345 logging.raiseExceptions = True
3346 self.assertRaises(IndexError, self._test_with_failure_in_method,
3347 'flush', IndexError)
3348
3349 def test_with_other_error_in_close_with_raise(self):
3350 logging.raiseExceptions = True
3351 self.assertRaises(IndexError, self._test_with_failure_in_method,
3352 'close', IndexError)
3353
3354
3355class ModuleLevelMiscTest(BaseTest):
3356
Vinay Sajip5e66b162011-04-20 15:41:14 +01003357 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003358
3359 def test_disable(self):
3360 old_disable = logging.root.manager.disable
3361 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003362 self.assertEqual(old_disable, 0)
3363 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003364
3365 logging.disable(83)
3366 self.assertEqual(logging.root.manager.disable, 83)
3367
3368 def _test_log(self, method, level=None):
3369 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003370 support.patch(self, logging, 'basicConfig',
3371 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003372
3373 recording = RecordingHandler()
3374 logging.root.addHandler(recording)
3375
3376 log_method = getattr(logging, method)
3377 if level is not None:
3378 log_method(level, "test me: %r", recording)
3379 else:
3380 log_method("test me: %r", recording)
3381
3382 self.assertEqual(len(recording.records), 1)
3383 record = recording.records[0]
3384 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3385
3386 expected_level = level if level is not None else getattr(logging, method.upper())
3387 self.assertEqual(record.levelno, expected_level)
3388
3389 # basicConfig was not called!
3390 self.assertEqual(called, [])
3391
3392 def test_log(self):
3393 self._test_log('log', logging.ERROR)
3394
3395 def test_debug(self):
3396 self._test_log('debug')
3397
3398 def test_info(self):
3399 self._test_log('info')
3400
3401 def test_warning(self):
3402 self._test_log('warning')
3403
3404 def test_error(self):
3405 self._test_log('error')
3406
3407 def test_critical(self):
3408 self._test_log('critical')
3409
3410 def test_set_logger_class(self):
3411 self.assertRaises(TypeError, logging.setLoggerClass, object)
3412
3413 class MyLogger(logging.Logger):
3414 pass
3415
3416 logging.setLoggerClass(MyLogger)
3417 self.assertEqual(logging.getLoggerClass(), MyLogger)
3418
3419 logging.setLoggerClass(logging.Logger)
3420 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3421
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003422 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003423 def test_logging_at_shutdown(self):
3424 # Issue #20037
3425 code = """if 1:
3426 import logging
3427
3428 class A:
3429 def __del__(self):
3430 try:
3431 raise ValueError("some error")
3432 except Exception:
3433 logging.exception("exception in __del__")
3434
3435 a = A()"""
3436 rc, out, err = assert_python_ok("-c", code)
3437 err = err.decode()
3438 self.assertIn("exception in __del__", err)
3439 self.assertIn("ValueError: some error", err)
3440
3441
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003442class LogRecordTest(BaseTest):
3443 def test_str_rep(self):
3444 r = logging.makeLogRecord({})
3445 s = str(r)
3446 self.assertTrue(s.startswith('<LogRecord: '))
3447 self.assertTrue(s.endswith('>'))
3448
3449 def test_dict_arg(self):
3450 h = RecordingHandler()
3451 r = logging.getLogger()
3452 r.addHandler(h)
3453 d = {'less' : 'more' }
3454 logging.warning('less is %(less)s', d)
3455 self.assertIs(h.records[0].args, d)
3456 self.assertEqual(h.records[0].message, 'less is more')
3457 r.removeHandler(h)
3458 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003459
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003460 def test_multiprocessing(self):
3461 r = logging.makeLogRecord({})
3462 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003463 try:
3464 import multiprocessing as mp
3465 r = logging.makeLogRecord({})
3466 self.assertEqual(r.processName, mp.current_process().name)
3467 except ImportError:
3468 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003469
3470 def test_optional(self):
3471 r = logging.makeLogRecord({})
3472 NOT_NONE = self.assertIsNotNone
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003473 if threading:
3474 NOT_NONE(r.thread)
3475 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003476 NOT_NONE(r.process)
3477 NOT_NONE(r.processName)
3478 log_threads = logging.logThreads
3479 log_processes = logging.logProcesses
3480 log_multiprocessing = logging.logMultiprocessing
3481 try:
3482 logging.logThreads = False
3483 logging.logProcesses = False
3484 logging.logMultiprocessing = False
3485 r = logging.makeLogRecord({})
3486 NONE = self.assertIsNone
3487 NONE(r.thread)
3488 NONE(r.threadName)
3489 NONE(r.process)
3490 NONE(r.processName)
3491 finally:
3492 logging.logThreads = log_threads
3493 logging.logProcesses = log_processes
3494 logging.logMultiprocessing = log_multiprocessing
3495
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003496class BasicConfigTest(unittest.TestCase):
3497
Vinay Sajip95bf5042011-04-20 11:50:56 +01003498 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003499
3500 def setUp(self):
3501 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003502 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003503 self.saved_handlers = logging._handlers.copy()
3504 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003505 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003506 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003507 logging.root.handlers = []
3508
3509 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003510 for h in logging.root.handlers[:]:
3511 logging.root.removeHandler(h)
3512 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003513 super(BasicConfigTest, self).tearDown()
3514
Vinay Sajip3def7e02011-04-20 10:58:06 +01003515 def cleanup(self):
3516 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003517 logging._handlers.clear()
3518 logging._handlers.update(self.saved_handlers)
3519 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003520 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003521
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003522 def test_no_kwargs(self):
3523 logging.basicConfig()
3524
3525 # handler defaults to a StreamHandler to sys.stderr
3526 self.assertEqual(len(logging.root.handlers), 1)
3527 handler = logging.root.handlers[0]
3528 self.assertIsInstance(handler, logging.StreamHandler)
3529 self.assertEqual(handler.stream, sys.stderr)
3530
3531 formatter = handler.formatter
3532 # format defaults to logging.BASIC_FORMAT
3533 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3534 # datefmt defaults to None
3535 self.assertIsNone(formatter.datefmt)
3536 # style defaults to %
3537 self.assertIsInstance(formatter._style, logging.PercentStyle)
3538
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003539 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003540 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003541
Vinay Sajip1fd12022014-01-13 21:59:56 +00003542 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003543 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003544 logging.basicConfig(stream=sys.stdout, style="{")
3545 logging.error("Log an error")
3546 sys.stdout.seek(0)
3547 self.assertEqual(output.getvalue().strip(),
3548 "ERROR:root:Log an error")
3549
3550 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003551 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003552 logging.basicConfig(stream=sys.stdout, style="$")
3553 logging.error("Log an error")
3554 sys.stdout.seek(0)
3555 self.assertEqual(output.getvalue().strip(),
3556 "ERROR:root:Log an error")
3557
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003558 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003559
3560 def cleanup(h1, h2, fn):
3561 h1.close()
3562 h2.close()
3563 os.remove(fn)
3564
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003565 logging.basicConfig(filename='test.log')
3566
3567 self.assertEqual(len(logging.root.handlers), 1)
3568 handler = logging.root.handlers[0]
3569 self.assertIsInstance(handler, logging.FileHandler)
3570
3571 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003572 self.assertEqual(handler.stream.mode, expected.stream.mode)
3573 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003574 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003575
3576 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003577
3578 def cleanup(h1, h2, fn):
3579 h1.close()
3580 h2.close()
3581 os.remove(fn)
3582
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003583 logging.basicConfig(filename='test.log', filemode='wb')
3584
3585 handler = logging.root.handlers[0]
3586 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003587 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003588 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003589
3590 def test_stream(self):
3591 stream = io.StringIO()
3592 self.addCleanup(stream.close)
3593 logging.basicConfig(stream=stream)
3594
3595 self.assertEqual(len(logging.root.handlers), 1)
3596 handler = logging.root.handlers[0]
3597 self.assertIsInstance(handler, logging.StreamHandler)
3598 self.assertEqual(handler.stream, stream)
3599
3600 def test_format(self):
3601 logging.basicConfig(format='foo')
3602
3603 formatter = logging.root.handlers[0].formatter
3604 self.assertEqual(formatter._style._fmt, 'foo')
3605
3606 def test_datefmt(self):
3607 logging.basicConfig(datefmt='bar')
3608
3609 formatter = logging.root.handlers[0].formatter
3610 self.assertEqual(formatter.datefmt, 'bar')
3611
3612 def test_style(self):
3613 logging.basicConfig(style='$')
3614
3615 formatter = logging.root.handlers[0].formatter
3616 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3617
3618 def test_level(self):
3619 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003620 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003621
3622 logging.basicConfig(level=57)
3623 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003624 # Test that second call has no effect
3625 logging.basicConfig(level=58)
3626 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003627
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003628 def test_incompatible(self):
3629 assertRaises = self.assertRaises
3630 handlers = [logging.StreamHandler()]
3631 stream = sys.stderr
3632 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3633 stream=stream)
3634 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3635 handlers=handlers)
3636 assertRaises(ValueError, logging.basicConfig, stream=stream,
3637 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003638 # Issue 23207: test for invalid kwargs
3639 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3640 # Should pop both filename and filemode even if filename is None
3641 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003642
3643 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003644 handlers = [
3645 logging.StreamHandler(),
3646 logging.StreamHandler(sys.stdout),
3647 logging.StreamHandler(),
3648 ]
3649 f = logging.Formatter()
3650 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003651 logging.basicConfig(handlers=handlers)
3652 self.assertIs(handlers[0], logging.root.handlers[0])
3653 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003654 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003655 self.assertIsNotNone(handlers[0].formatter)
3656 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003657 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003658 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3659
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003660 def _test_log(self, method, level=None):
3661 # logging.root has no handlers so basicConfig should be called
3662 called = []
3663
3664 old_basic_config = logging.basicConfig
3665 def my_basic_config(*a, **kw):
3666 old_basic_config()
3667 old_level = logging.root.level
3668 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003669 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003670 called.append((a, kw))
3671
Vinay Sajip1feedb42014-05-31 08:19:12 +01003672 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003673
3674 log_method = getattr(logging, method)
3675 if level is not None:
3676 log_method(level, "test me")
3677 else:
3678 log_method("test me")
3679
3680 # basicConfig was called with no arguments
3681 self.assertEqual(called, [((), {})])
3682
3683 def test_log(self):
3684 self._test_log('log', logging.WARNING)
3685
3686 def test_debug(self):
3687 self._test_log('debug')
3688
3689 def test_info(self):
3690 self._test_log('info')
3691
3692 def test_warning(self):
3693 self._test_log('warning')
3694
3695 def test_error(self):
3696 self._test_log('error')
3697
3698 def test_critical(self):
3699 self._test_log('critical')
3700
3701
3702class LoggerAdapterTest(unittest.TestCase):
3703
3704 def setUp(self):
3705 super(LoggerAdapterTest, self).setUp()
3706 old_handler_list = logging._handlerList[:]
3707
3708 self.recording = RecordingHandler()
3709 self.logger = logging.root
3710 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003711 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003712 self.addCleanup(self.recording.close)
3713
3714 def cleanup():
3715 logging._handlerList[:] = old_handler_list
3716
3717 self.addCleanup(cleanup)
3718 self.addCleanup(logging.shutdown)
3719 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3720
3721 def test_exception(self):
3722 msg = 'testing exception: %r'
3723 exc = None
3724 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003725 1 / 0
3726 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003727 exc = e
3728 self.adapter.exception(msg, self.recording)
3729
3730 self.assertEqual(len(self.recording.records), 1)
3731 record = self.recording.records[0]
3732 self.assertEqual(record.levelno, logging.ERROR)
3733 self.assertEqual(record.msg, msg)
3734 self.assertEqual(record.args, (self.recording,))
3735 self.assertEqual(record.exc_info,
3736 (exc.__class__, exc, exc.__traceback__))
3737
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003738 def test_exception_excinfo(self):
3739 try:
3740 1 / 0
3741 except ZeroDivisionError as e:
3742 exc = e
3743
3744 self.adapter.exception('exc_info test', exc_info=exc)
3745
3746 self.assertEqual(len(self.recording.records), 1)
3747 record = self.recording.records[0]
3748 self.assertEqual(record.exc_info,
3749 (exc.__class__, exc, exc.__traceback__))
3750
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751 def test_critical(self):
3752 msg = 'critical test! %r'
3753 self.adapter.critical(msg, self.recording)
3754
3755 self.assertEqual(len(self.recording.records), 1)
3756 record = self.recording.records[0]
3757 self.assertEqual(record.levelno, logging.CRITICAL)
3758 self.assertEqual(record.msg, msg)
3759 self.assertEqual(record.args, (self.recording,))
3760
3761 def test_is_enabled_for(self):
3762 old_disable = self.adapter.logger.manager.disable
3763 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003764 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3765 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003766 self.assertFalse(self.adapter.isEnabledFor(32))
3767
3768 def test_has_handlers(self):
3769 self.assertTrue(self.adapter.hasHandlers())
3770
3771 for handler in self.logger.handlers:
3772 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003773
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003774 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003775 self.assertFalse(self.adapter.hasHandlers())
3776
3777
3778class LoggerTest(BaseTest):
3779
3780 def setUp(self):
3781 super(LoggerTest, self).setUp()
3782 self.recording = RecordingHandler()
3783 self.logger = logging.Logger(name='blah')
3784 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003785 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003786 self.addCleanup(self.recording.close)
3787 self.addCleanup(logging.shutdown)
3788
3789 def test_set_invalid_level(self):
3790 self.assertRaises(TypeError, self.logger.setLevel, object())
3791
3792 def test_exception(self):
3793 msg = 'testing exception: %r'
3794 exc = None
3795 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003796 1 / 0
3797 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003798 exc = e
3799 self.logger.exception(msg, self.recording)
3800
3801 self.assertEqual(len(self.recording.records), 1)
3802 record = self.recording.records[0]
3803 self.assertEqual(record.levelno, logging.ERROR)
3804 self.assertEqual(record.msg, msg)
3805 self.assertEqual(record.args, (self.recording,))
3806 self.assertEqual(record.exc_info,
3807 (exc.__class__, exc, exc.__traceback__))
3808
3809 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003810 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003811 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003812
3813 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03003814 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03003815 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003816
3817 def test_find_caller_with_stack_info(self):
3818 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003819 support.patch(self, logging.traceback, 'print_stack',
3820 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003821
3822 self.logger.findCaller(stack_info=True)
3823
3824 self.assertEqual(len(called), 1)
3825 self.assertEqual('Stack (most recent call last):\n', called[0])
3826
3827 def test_make_record_with_extra_overwrite(self):
3828 name = 'my record'
3829 level = 13
3830 fn = lno = msg = args = exc_info = func = sinfo = None
3831 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
3832 exc_info, func, sinfo)
3833
3834 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
3835 extra = {key: 'some value'}
3836 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
3837 fn, lno, msg, args, exc_info,
3838 extra=extra, sinfo=sinfo)
3839
3840 def test_make_record_with_extra_no_overwrite(self):
3841 name = 'my record'
3842 level = 13
3843 fn = lno = msg = args = exc_info = func = sinfo = None
3844 extra = {'valid_key': 'some value'}
3845 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
3846 exc_info, extra=extra, sinfo=sinfo)
3847 self.assertIn('valid_key', result.__dict__)
3848
3849 def test_has_handlers(self):
3850 self.assertTrue(self.logger.hasHandlers())
3851
3852 for handler in self.logger.handlers:
3853 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003854 self.assertFalse(self.logger.hasHandlers())
3855
3856 def test_has_handlers_no_propagate(self):
3857 child_logger = logging.getLogger('blah.child')
3858 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003859 self.assertFalse(child_logger.hasHandlers())
3860
3861 def test_is_enabled_for(self):
3862 old_disable = self.logger.manager.disable
3863 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003864 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003865 self.assertFalse(self.logger.isEnabledFor(22))
3866
Florent Xicluna5252f9f2011-11-07 19:43:05 +01003867 def test_root_logger_aliases(self):
3868 root = logging.getLogger()
3869 self.assertIs(root, logging.root)
3870 self.assertIs(root, logging.getLogger(None))
3871 self.assertIs(root, logging.getLogger(''))
3872 self.assertIs(root, logging.getLogger('foo').root)
3873 self.assertIs(root, logging.getLogger('foo.bar').root)
3874 self.assertIs(root, logging.getLogger('foo').parent)
3875
3876 self.assertIsNot(root, logging.getLogger('\0'))
3877 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
3878
3879 def test_invalid_names(self):
3880 self.assertRaises(TypeError, logging.getLogger, any)
3881 self.assertRaises(TypeError, logging.getLogger, b'foo')
3882
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003883
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003884class BaseFileTest(BaseTest):
3885 "Base class for handler tests that write log files"
3886
3887 def setUp(self):
3888 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003889 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
3890 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003891 self.rmfiles = []
3892
3893 def tearDown(self):
3894 for fn in self.rmfiles:
3895 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00003896 if os.path.exists(self.fn):
3897 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00003898 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003899
3900 def assertLogFile(self, filename):
3901 "Assert a log file is there and register it for deletion"
3902 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01003903 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003904 self.rmfiles.append(filename)
3905
3906
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003907class FileHandlerTest(BaseFileTest):
3908 def test_delay(self):
3909 os.unlink(self.fn)
3910 fh = logging.FileHandler(self.fn, delay=True)
3911 self.assertIsNone(fh.stream)
3912 self.assertFalse(os.path.exists(self.fn))
3913 fh.handle(logging.makeLogRecord({}))
3914 self.assertIsNotNone(fh.stream)
3915 self.assertTrue(os.path.exists(self.fn))
3916 fh.close()
3917
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003918class RotatingFileHandlerTest(BaseFileTest):
3919 def next_rec(self):
3920 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
3921 self.next_message(), None, None, None)
3922
3923 def test_should_not_rollover(self):
3924 # If maxbytes is zero rollover never occurs
3925 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
3926 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00003927 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003928
3929 def test_should_rollover(self):
3930 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
3931 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00003932 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003933
3934 def test_file_created(self):
3935 # checks that the file is created and assumes it was created
3936 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003937 rh = logging.handlers.RotatingFileHandler(self.fn)
3938 rh.emit(self.next_rec())
3939 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00003940 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003941
3942 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00003943 def namer(name):
3944 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003945 rh = logging.handlers.RotatingFileHandler(
3946 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003947 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003948 rh.emit(self.next_rec())
3949 self.assertLogFile(self.fn)
3950 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003951 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00003952 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00003953 self.assertLogFile(namer(self.fn + ".2"))
3954 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
3955 rh.close()
3956
Vinay Sajip1feedb42014-05-31 08:19:12 +01003957 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00003958 def test_rotator(self):
3959 def namer(name):
3960 return name + ".gz"
3961
3962 def rotator(source, dest):
3963 with open(source, "rb") as sf:
3964 data = sf.read()
3965 compressed = zlib.compress(data, 9)
3966 with open(dest, "wb") as df:
3967 df.write(compressed)
3968 os.remove(source)
3969
3970 rh = logging.handlers.RotatingFileHandler(
3971 self.fn, backupCount=2, maxBytes=1)
3972 rh.rotator = rotator
3973 rh.namer = namer
3974 m1 = self.next_rec()
3975 rh.emit(m1)
3976 self.assertLogFile(self.fn)
3977 m2 = self.next_rec()
3978 rh.emit(m2)
3979 fn = namer(self.fn + ".1")
3980 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003981 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00003982 with open(fn, "rb") as f:
3983 compressed = f.read()
3984 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003985 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003986 rh.emit(self.next_rec())
3987 fn = namer(self.fn + ".2")
3988 self.assertLogFile(fn)
3989 with open(fn, "rb") as f:
3990 compressed = f.read()
3991 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003992 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003993 rh.emit(self.next_rec())
3994 fn = namer(self.fn + ".2")
3995 with open(fn, "rb") as f:
3996 compressed = f.read()
3997 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00003998 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00003999 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004000 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004001
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004002class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004003 # other test methods added below
4004 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004005 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4006 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004007 fmt = logging.Formatter('%(asctime)s %(message)s')
4008 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004009 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004010 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004011 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004012 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004013 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004014 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004015 fh.close()
4016 # At this point, we should have a recent rotated file which we
4017 # can test for the existence of. However, in practice, on some
4018 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004019 # in time to go to look for the log file. So, we go back a fair
4020 # bit, and stop as soon as we see a rotated file. In theory this
4021 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004022 found = False
4023 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004024 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004025 for secs in range(GO_BACK):
4026 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004027 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4028 found = os.path.exists(fn)
4029 if found:
4030 self.rmfiles.append(fn)
4031 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004032 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4033 if not found:
4034 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004035 dn, fn = os.path.split(self.fn)
4036 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004037 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4038 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004039 for f in files:
4040 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004041 path = os.path.join(dn, f)
4042 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004043 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004044 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004045
Vinay Sajip0372e102011-05-05 12:59:14 +01004046 def test_invalid(self):
4047 assertRaises = self.assertRaises
4048 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004049 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004050 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004051 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004052 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004053 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004054
Vinay Sajipa7130792013-04-12 17:04:23 +01004055 def test_compute_rollover_daily_attime(self):
4056 currentTime = 0
4057 atTime = datetime.time(12, 0, 0)
4058 rh = logging.handlers.TimedRotatingFileHandler(
4059 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4060 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004061 try:
4062 actual = rh.computeRollover(currentTime)
4063 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004064
Vinay Sajipd86ac962013-04-14 12:20:46 +01004065 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4066 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4067 finally:
4068 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004069
Vinay Sajip10e8c492013-05-18 10:19:54 -07004070 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004071 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004072 currentTime = int(time.time())
4073 today = currentTime - currentTime % 86400
4074
Vinay Sajipa7130792013-04-12 17:04:23 +01004075 atTime = datetime.time(12, 0, 0)
4076
Vinay Sajip10e8c492013-05-18 10:19:54 -07004077 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004078 for day in range(7):
4079 rh = logging.handlers.TimedRotatingFileHandler(
4080 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4081 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004082 try:
4083 if wday > day:
4084 # The rollover day has already passed this week, so we
4085 # go over into next week
4086 expected = (7 - wday + day)
4087 else:
4088 expected = (day - wday)
4089 # At this point expected is in days from now, convert to seconds
4090 expected *= 24 * 60 * 60
4091 # Add in the rollover time
4092 expected += 12 * 60 * 60
4093 # Add in adjustment for today
4094 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004095 actual = rh.computeRollover(today)
4096 if actual != expected:
4097 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004098 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004099 self.assertEqual(actual, expected)
4100 if day == wday:
4101 # goes into following week
4102 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004103 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004104 if actual != expected:
4105 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004106 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004107 self.assertEqual(actual, expected)
4108 finally:
4109 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004110
4111
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004112def secs(**kw):
4113 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4114
4115for when, exp in (('S', 1),
4116 ('M', 60),
4117 ('H', 60 * 60),
4118 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004119 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004120 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004121 ('W0', secs(days=4, hours=24)),
4122 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004123 def test_compute_rollover(self, when=when, exp=exp):
4124 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004125 self.fn, when=when, interval=1, backupCount=0, utc=True)
4126 currentTime = 0.0
4127 actual = rh.computeRollover(currentTime)
4128 if exp != actual:
4129 # Failures occur on some systems for MIDNIGHT and W0.
4130 # Print detailed calculation for MIDNIGHT so we can try to see
4131 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004132 if when == 'MIDNIGHT':
4133 try:
4134 if rh.utc:
4135 t = time.gmtime(currentTime)
4136 else:
4137 t = time.localtime(currentTime)
4138 currentHour = t[3]
4139 currentMinute = t[4]
4140 currentSecond = t[5]
4141 # r is the number of seconds left between now and midnight
4142 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4143 currentMinute) * 60 +
4144 currentSecond)
4145 result = currentTime + r
4146 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4147 print('currentHour: %s' % currentHour, file=sys.stderr)
4148 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4149 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4150 print('r: %s' % r, file=sys.stderr)
4151 print('result: %s' % result, file=sys.stderr)
4152 except Exception:
4153 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4154 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004155 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004156 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4157
Vinay Sajip60ccd822011-05-09 17:32:09 +01004158
Vinay Sajip223349c2015-10-01 20:37:54 +01004159@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004160class NTEventLogHandlerTest(BaseTest):
4161 def test_basic(self):
4162 logtype = 'Application'
4163 elh = win32evtlog.OpenEventLog(None, logtype)
4164 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004165
4166 try:
4167 h = logging.handlers.NTEventLogHandler('test_logging')
4168 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004169 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004170 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004171 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004172
Vinay Sajip60ccd822011-05-09 17:32:09 +01004173 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4174 h.handle(r)
4175 h.close()
4176 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004177 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004178 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4179 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4180 found = False
4181 GO_BACK = 100
4182 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4183 for e in events:
4184 if e.SourceName != 'test_logging':
4185 continue
4186 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4187 if msg != 'Test Log Message\r\n':
4188 continue
4189 found = True
4190 break
4191 msg = 'Record not found in event log, went back %d records' % GO_BACK
4192 self.assertTrue(found, msg=msg)
4193
Martin Panter19e69c52015-11-14 12:46:42 +00004194
4195class MiscTestCase(unittest.TestCase):
4196 def test__all__(self):
4197 blacklist = {'logThreads', 'logMultiprocessing',
4198 'logProcesses', 'currentframe',
4199 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4200 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
4201 'root'}
4202 support.check__all__(self, logging, blacklist=blacklist)
4203
4204
Christian Heimes180510d2008-03-03 19:15:45 +00004205# Set the locale to the platform-dependent default. I have no idea
4206# why the test does this, but in any case we save the current locale
4207# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004208@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004209def test_main():
Vinay Sajip1feedb42014-05-31 08:19:12 +01004210 support.run_unittest(
4211 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4212 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4213 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4214 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4215 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4216 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4217 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4218 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
4219 ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
4220 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Martin Panter19e69c52015-11-14 12:46:42 +00004221 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
4222 MiscTestCase)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004223
Christian Heimes180510d2008-03-03 19:15:45 +00004224if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004225 test_main()