blob: eee2ed0c19ec11dd3fb93aaf854735132c2fb3d4 [file] [log] [blame]
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001# Copyright 2001-2017 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 Sajip1e6499c2017-01-09 16:54:12 +000019Copyright (C) 2001-2017 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
Vinay Sajipdb8f4632016-09-08 01:37:03 +010029import pathlib
Christian Heimes180510d2008-03-03 19:15:45 +000030import pickle
31import io
32import gc
Vinay Sajipdb81c4c2010-02-25 23:13:06 +000033import json
Christian Heimes180510d2008-03-03 19:15:45 +000034import os
Vinay Sajip8552d1f2010-09-14 09:34:09 +000035import queue
Vinay Sajip66b8b082012-04-24 23:25:30 +010036import random
Christian Heimes180510d2008-03-03 19:15:45 +000037import re
Christian Heimes180510d2008-03-03 19:15:45 +000038import socket
Christian Heimes180510d2008-03-03 19:15:45 +000039import struct
40import sys
41import tempfile
Berker Peksagce643912015-05-06 06:33:17 +030042from test.support.script_helper import assert_python_ok
Vinay Sajip1feedb42014-05-31 08:19:12 +010043from test import support
Christian Heimes180510d2008-03-03 19:15:45 +000044import textwrap
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020045import threading
Vinay Sajip37eb3382011-04-26 20:26:41 +010046import time
Christian Heimes180510d2008-03-03 19:15:45 +000047import unittest
Georg Brandlf9734072008-12-07 15:30:06 +000048import warnings
Christian Heimes180510d2008-03-03 19:15:45 +000049import weakref
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020050
51import asyncore
52from http.server import HTTPServer, BaseHTTPRequestHandler
53import smtpd
54from urllib.parse import urlparse, parse_qs
55from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
56 ThreadingTCPServer, StreamRequestHandler)
57
Vinay Sajip60ccd822011-05-09 17:32:09 +010058try:
Vinay Sajip223349c2015-10-01 20:37:54 +010059 import win32evtlog, win32evtlogutil, pywintypes
Vinay Sajip60ccd822011-05-09 17:32:09 +010060except ImportError:
Vinay Sajip223349c2015-10-01 20:37:54 +010061 win32evtlog = win32evtlogutil = pywintypes = None
62
Eric V. Smith851cad72012-03-11 22:46:04 -070063try:
64 import zlib
65except ImportError:
66 pass
Christian Heimes18c66892008-02-17 13:31:39 +000067
Christian Heimes180510d2008-03-03 19:15:45 +000068class BaseTest(unittest.TestCase):
69
70 """Base class for logging tests."""
71
72 log_format = "%(name)s -> %(levelname)s: %(message)s"
Ezio Melotti3ffd29b2012-10-02 19:45:00 +030073 expected_log_pat = r"^([\w.]+) -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +000074 message_num = 0
75
76 def setUp(self):
77 """Setup the default logging stream to an internal StringIO instance,
78 so that we can examine log output as we want."""
Victor Stinner69669602017-08-18 23:47:54 +020079 self._threading_key = support.threading_setup()
80
Christian Heimes180510d2008-03-03 19:15:45 +000081 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
Avram Lubkin78c18a92017-07-30 05:36:33 -0400137 manager = logging.getLogger().manager
138 manager.disable = 0
139 loggerDict = manager.loggerDict
Christian Heimes180510d2008-03-03 19:15:45 +0000140 loggerDict.clear()
141 loggerDict.update(self.saved_loggers)
Vinay Sajip7b60f4e2010-12-27 14:31:52 +0000142 logger_states = self.logger_states
143 for name in self.logger_states:
144 if logger_states[name] is not None:
145 self.saved_loggers[name].disabled = logger_states[name]
Christian Heimes180510d2008-03-03 19:15:45 +0000146 finally:
147 logging._releaseLock()
148
Victor Stinner69669602017-08-18 23:47:54 +0200149 self.doCleanups()
150 support.threading_cleanup(*self._threading_key)
151
Vinay Sajip4ded5512012-10-02 15:56:16 +0100152 def assert_log_lines(self, expected_values, stream=None, pat=None):
Christian Heimes180510d2008-03-03 19:15:45 +0000153 """Match the collected log lines against the regular expression
154 self.expected_log_pat, and compare the extracted group values to
155 the expected_values list of tuples."""
156 stream = stream or self.stream
Vinay Sajip4ded5512012-10-02 15:56:16 +0100157 pat = re.compile(pat or self.expected_log_pat)
Serhiy Storchaka50254c52013-08-29 11:35:43 +0300158 actual_lines = stream.getvalue().splitlines()
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100159 self.assertEqual(len(actual_lines), len(expected_values))
Christian Heimes180510d2008-03-03 19:15:45 +0000160 for actual, expected in zip(actual_lines, expected_values):
161 match = pat.search(actual)
162 if not match:
163 self.fail("Log line does not match expected pattern:\n" +
164 actual)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000165 self.assertEqual(tuple(match.groups()), expected)
Christian Heimes180510d2008-03-03 19:15:45 +0000166 s = stream.read()
167 if s:
168 self.fail("Remaining output at end of log stream:\n" + s)
169
170 def next_message(self):
171 """Generate a message consisting solely of an auto-incrementing
172 integer."""
173 self.message_num += 1
174 return "%d" % self.message_num
175
176
177class BuiltinLevelsTest(BaseTest):
178 """Test builtin levels and their inheritance."""
179
180 def test_flat(self):
Mike53f7a7c2017-12-14 14:04:53 +0300181 # Logging levels in a flat logger namespace.
Christian Heimes180510d2008-03-03 19:15:45 +0000182 m = self.next_message
183
184 ERR = logging.getLogger("ERR")
185 ERR.setLevel(logging.ERROR)
Vinay Sajipc84f0162010-09-21 11:25:39 +0000186 INF = logging.LoggerAdapter(logging.getLogger("INF"), {})
Christian Heimes180510d2008-03-03 19:15:45 +0000187 INF.setLevel(logging.INFO)
188 DEB = logging.getLogger("DEB")
189 DEB.setLevel(logging.DEBUG)
190
191 # These should log.
192 ERR.log(logging.CRITICAL, m())
193 ERR.error(m())
194
195 INF.log(logging.CRITICAL, m())
196 INF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100197 INF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000198 INF.info(m())
199
200 DEB.log(logging.CRITICAL, m())
201 DEB.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100202 DEB.warning(m())
203 DEB.info(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000204 DEB.debug(m())
205
206 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100207 ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000208 ERR.info(m())
209 ERR.debug(m())
210
211 INF.debug(m())
212
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000213 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000214 ('ERR', 'CRITICAL', '1'),
215 ('ERR', 'ERROR', '2'),
216 ('INF', 'CRITICAL', '3'),
217 ('INF', 'ERROR', '4'),
218 ('INF', 'WARNING', '5'),
219 ('INF', 'INFO', '6'),
220 ('DEB', 'CRITICAL', '7'),
221 ('DEB', 'ERROR', '8'),
222 ('DEB', 'WARNING', '9'),
223 ('DEB', 'INFO', '10'),
224 ('DEB', 'DEBUG', '11'),
225 ])
226
227 def test_nested_explicit(self):
228 # Logging levels in a nested namespace, all explicitly set.
229 m = self.next_message
230
231 INF = logging.getLogger("INF")
232 INF.setLevel(logging.INFO)
233 INF_ERR = logging.getLogger("INF.ERR")
234 INF_ERR.setLevel(logging.ERROR)
235
236 # These should log.
237 INF_ERR.log(logging.CRITICAL, m())
238 INF_ERR.error(m())
239
240 # These should not log.
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100241 INF_ERR.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000242 INF_ERR.info(m())
243 INF_ERR.debug(m())
244
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000245 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000246 ('INF.ERR', 'CRITICAL', '1'),
247 ('INF.ERR', 'ERROR', '2'),
248 ])
249
250 def test_nested_inherited(self):
Mike53f7a7c2017-12-14 14:04:53 +0300251 # Logging levels in a nested namespace, inherited from parent loggers.
Christian Heimes180510d2008-03-03 19:15:45 +0000252 m = self.next_message
253
254 INF = logging.getLogger("INF")
255 INF.setLevel(logging.INFO)
256 INF_ERR = logging.getLogger("INF.ERR")
257 INF_ERR.setLevel(logging.ERROR)
258 INF_UNDEF = logging.getLogger("INF.UNDEF")
259 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
260 UNDEF = logging.getLogger("UNDEF")
261
262 # These should log.
263 INF_UNDEF.log(logging.CRITICAL, m())
264 INF_UNDEF.error(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100265 INF_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000266 INF_UNDEF.info(m())
267 INF_ERR_UNDEF.log(logging.CRITICAL, m())
268 INF_ERR_UNDEF.error(m())
269
270 # These should not log.
271 INF_UNDEF.debug(m())
Vinay Sajipb9e46e92011-10-26 13:17:20 +0100272 INF_ERR_UNDEF.warning(m())
Christian Heimes180510d2008-03-03 19:15:45 +0000273 INF_ERR_UNDEF.info(m())
274 INF_ERR_UNDEF.debug(m())
275
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000276 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000277 ('INF.UNDEF', 'CRITICAL', '1'),
278 ('INF.UNDEF', 'ERROR', '2'),
279 ('INF.UNDEF', 'WARNING', '3'),
280 ('INF.UNDEF', 'INFO', '4'),
281 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
282 ('INF.ERR.UNDEF', 'ERROR', '6'),
283 ])
284
285 def test_nested_with_virtual_parent(self):
286 # Logging levels when some parent does not exist yet.
287 m = self.next_message
288
289 INF = logging.getLogger("INF")
290 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
291 CHILD = logging.getLogger("INF.BADPARENT")
292 INF.setLevel(logging.INFO)
293
294 # These should log.
295 GRANDCHILD.log(logging.FATAL, m())
296 GRANDCHILD.info(m())
297 CHILD.log(logging.FATAL, m())
298 CHILD.info(m())
299
300 # These should not log.
301 GRANDCHILD.debug(m())
302 CHILD.debug(m())
303
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000304 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000305 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
306 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
307 ('INF.BADPARENT', 'CRITICAL', '3'),
308 ('INF.BADPARENT', 'INFO', '4'),
309 ])
310
Vinay Sajipd1d4fbf2014-09-11 23:06:09 +0100311 def test_regression_22386(self):
312 """See issue #22386 for more information."""
313 self.assertEqual(logging.getLevelName('INFO'), logging.INFO)
314 self.assertEqual(logging.getLevelName(logging.INFO), 'INFO')
Christian Heimes180510d2008-03-03 19:15:45 +0000315
Vinay Sajip8b866d52017-01-11 06:57:55 +0000316 def test_regression_29220(self):
317 """See issue #29220 for more information."""
318 logging.addLevelName(logging.INFO, '')
319 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
320 self.assertEqual(logging.getLevelName(logging.INFO), '')
321
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100322 def test_issue27935(self):
323 fatal = logging.getLevelName('FATAL')
324 self.assertEqual(fatal, logging.FATAL)
325
Vinay Sajip924aaae2017-01-11 17:35:36 +0000326 def test_regression_29220(self):
327 """See issue #29220 for more information."""
328 logging.addLevelName(logging.INFO, '')
329 self.addCleanup(logging.addLevelName, logging.INFO, 'INFO')
330 self.assertEqual(logging.getLevelName(logging.INFO), '')
331 self.assertEqual(logging.getLevelName(logging.NOTSET), 'NOTSET')
332 self.assertEqual(logging.getLevelName('NOTSET'), logging.NOTSET)
333
Christian Heimes180510d2008-03-03 19:15:45 +0000334class BasicFilterTest(BaseTest):
335
336 """Test the bundled Filter class."""
337
338 def test_filter(self):
339 # Only messages satisfying the specified criteria pass through the
340 # filter.
341 filter_ = logging.Filter("spam.eggs")
342 handler = self.root_logger.handlers[0]
343 try:
344 handler.addFilter(filter_)
345 spam = logging.getLogger("spam")
346 spam_eggs = logging.getLogger("spam.eggs")
347 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
348 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
349
350 spam.info(self.next_message())
351 spam_eggs.info(self.next_message()) # Good.
352 spam_eggs_fish.info(self.next_message()) # Good.
353 spam_bakedbeans.info(self.next_message())
354
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000355 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000356 ('spam.eggs', 'INFO', '2'),
357 ('spam.eggs.fish', 'INFO', '3'),
358 ])
359 finally:
360 handler.removeFilter(filter_)
361
Vinay Sajip6dbed2e2010-10-19 20:53:01 +0000362 def test_callable_filter(self):
363 # Only messages satisfying the specified criteria pass through the
364 # filter.
365
366 def filterfunc(record):
367 parts = record.name.split('.')
368 prefix = '.'.join(parts[:2])
369 return prefix == 'spam.eggs'
370
371 handler = self.root_logger.handlers[0]
372 try:
373 handler.addFilter(filterfunc)
374 spam = logging.getLogger("spam")
375 spam_eggs = logging.getLogger("spam.eggs")
376 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
377 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
378
379 spam.info(self.next_message())
380 spam_eggs.info(self.next_message()) # Good.
381 spam_eggs_fish.info(self.next_message()) # Good.
382 spam_bakedbeans.info(self.next_message())
383
384 self.assert_log_lines([
385 ('spam.eggs', 'INFO', '2'),
386 ('spam.eggs.fish', 'INFO', '3'),
387 ])
388 finally:
389 handler.removeFilter(filterfunc)
390
Vinay Sajip985ef872011-04-26 19:34:04 +0100391 def test_empty_filter(self):
392 f = logging.Filter()
393 r = logging.makeLogRecord({'name': 'spam.eggs'})
394 self.assertTrue(f.filter(r))
Christian Heimes180510d2008-03-03 19:15:45 +0000395
396#
397# First, we define our levels. There can be as many as you want - the only
398# limitations are that they should be integers, the lowest should be > 0 and
399# larger values mean less information being logged. If you need specific
400# level values which do not fit into these limitations, you can use a
401# mapping dictionary to convert between your application levels and the
402# logging system.
403#
404SILENT = 120
405TACITURN = 119
406TERSE = 118
407EFFUSIVE = 117
408SOCIABLE = 116
409VERBOSE = 115
410TALKATIVE = 114
411GARRULOUS = 113
412CHATTERBOX = 112
413BORING = 111
414
415LEVEL_RANGE = range(BORING, SILENT + 1)
416
417#
418# Next, we define names for our levels. You don't need to do this - in which
419# case the system will use "Level n" to denote the text for the level.
420#
421my_logging_levels = {
422 SILENT : 'Silent',
423 TACITURN : 'Taciturn',
424 TERSE : 'Terse',
425 EFFUSIVE : 'Effusive',
426 SOCIABLE : 'Sociable',
427 VERBOSE : 'Verbose',
428 TALKATIVE : 'Talkative',
429 GARRULOUS : 'Garrulous',
430 CHATTERBOX : 'Chatterbox',
431 BORING : 'Boring',
432}
433
434class GarrulousFilter(logging.Filter):
435
436 """A filter which blocks garrulous messages."""
437
438 def filter(self, record):
439 return record.levelno != GARRULOUS
440
441class VerySpecificFilter(logging.Filter):
442
443 """A filter which blocks sociable and taciturn messages."""
444
445 def filter(self, record):
446 return record.levelno not in [SOCIABLE, TACITURN]
447
448
449class CustomLevelsAndFiltersTest(BaseTest):
450
451 """Test various filtering possibilities with custom logging levels."""
452
453 # Skip the logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +0300454 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +0000455
456 def setUp(self):
457 BaseTest.setUp(self)
Benjamin Peterson9451a1c2010-03-13 22:30:34 +0000458 for k, v in my_logging_levels.items():
Christian Heimes180510d2008-03-03 19:15:45 +0000459 logging.addLevelName(k, v)
460
461 def log_at_all_levels(self, logger):
462 for lvl in LEVEL_RANGE:
463 logger.log(lvl, self.next_message())
464
465 def test_logger_filter(self):
466 # Filter at logger level.
467 self.root_logger.setLevel(VERBOSE)
468 # Levels >= 'Verbose' are good.
469 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000470 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000471 ('Verbose', '5'),
472 ('Sociable', '6'),
473 ('Effusive', '7'),
474 ('Terse', '8'),
475 ('Taciturn', '9'),
476 ('Silent', '10'),
477 ])
478
479 def test_handler_filter(self):
480 # Filter at handler level.
481 self.root_logger.handlers[0].setLevel(SOCIABLE)
482 try:
483 # Levels >= 'Sociable' are good.
484 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000485 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +0000486 ('Sociable', '6'),
487 ('Effusive', '7'),
488 ('Terse', '8'),
489 ('Taciturn', '9'),
490 ('Silent', '10'),
491 ])
492 finally:
493 self.root_logger.handlers[0].setLevel(logging.NOTSET)
494
495 def test_specific_filters(self):
496 # Set a specific filter object on the handler, and then add another
497 # filter object on the logger itself.
498 handler = self.root_logger.handlers[0]
499 specific_filter = None
500 garr = GarrulousFilter()
501 handler.addFilter(garr)
502 try:
503 self.log_at_all_levels(self.root_logger)
504 first_lines = [
505 # Notice how 'Garrulous' is missing
506 ('Boring', '1'),
507 ('Chatterbox', '2'),
508 ('Talkative', '4'),
509 ('Verbose', '5'),
510 ('Sociable', '6'),
511 ('Effusive', '7'),
512 ('Terse', '8'),
513 ('Taciturn', '9'),
514 ('Silent', '10'),
515 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000516 self.assert_log_lines(first_lines)
Christian Heimes180510d2008-03-03 19:15:45 +0000517
518 specific_filter = VerySpecificFilter()
519 self.root_logger.addFilter(specific_filter)
520 self.log_at_all_levels(self.root_logger)
Benjamin Peterson77108eb2009-07-01 00:43:10 +0000521 self.assert_log_lines(first_lines + [
Christian Heimes180510d2008-03-03 19:15:45 +0000522 # Not only 'Garrulous' is still missing, but also 'Sociable'
523 # and 'Taciturn'
524 ('Boring', '11'),
525 ('Chatterbox', '12'),
526 ('Talkative', '14'),
527 ('Verbose', '15'),
528 ('Effusive', '17'),
529 ('Terse', '18'),
530 ('Silent', '20'),
531 ])
532 finally:
533 if specific_filter:
534 self.root_logger.removeFilter(specific_filter)
535 handler.removeFilter(garr)
536
537
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100538class HandlerTest(BaseTest):
539 def test_name(self):
540 h = logging.Handler()
541 h.name = 'generic'
542 self.assertEqual(h.name, 'generic')
543 h.name = 'anothergeneric'
544 self.assertEqual(h.name, 'anothergeneric')
545 self.assertRaises(NotImplementedError, h.emit, None)
546
Vinay Sajip5a35b062011-04-27 11:31:14 +0100547 def test_builtin_handlers(self):
548 # We can't actually *use* too many handlers in the tests,
549 # but we can try instantiating them with various options
Victor Stinnere6747472011-08-21 00:39:18 +0200550 if sys.platform in ('linux', 'darwin'):
Vinay Sajip5a35b062011-04-27 11:31:14 +0100551 for existing in (True, False):
552 fd, fn = tempfile.mkstemp()
553 os.close(fd)
554 if not existing:
555 os.unlink(fn)
556 h = logging.handlers.WatchedFileHandler(fn, delay=True)
557 if existing:
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100558 dev, ino = h.dev, h.ino
Vinay Sajipa5798de2012-04-24 23:33:33 +0100559 self.assertEqual(dev, -1)
560 self.assertEqual(ino, -1)
Vinay Sajip7fe1d512011-04-28 12:04:58 +0100561 r = logging.makeLogRecord({'msg': 'Test'})
562 h.handle(r)
563 # Now remove the file.
564 os.unlink(fn)
565 self.assertFalse(os.path.exists(fn))
566 # The next call should recreate the file.
567 h.handle(r)
568 self.assertTrue(os.path.exists(fn))
Vinay Sajip5a35b062011-04-27 11:31:14 +0100569 else:
570 self.assertEqual(h.dev, -1)
571 self.assertEqual(h.ino, -1)
572 h.close()
573 if existing:
574 os.unlink(fn)
575 if sys.platform == 'darwin':
Vinay Sajip6bba65c2011-04-27 14:31:55 +0100576 sockname = '/var/run/syslog'
Vinay Sajip5a35b062011-04-27 11:31:14 +0100577 else:
578 sockname = '/dev/log'
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100579 try:
580 h = logging.handlers.SysLogHandler(sockname)
581 self.assertEqual(h.facility, h.LOG_USER)
582 self.assertTrue(h.unixsocket)
583 h.close()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200584 except OSError: # syslogd might not be available
Vinay Sajipdbeb2742011-04-27 14:18:06 +0100585 pass
Vinay Sajip5a35b062011-04-27 11:31:14 +0100586 for method in ('GET', 'POST', 'PUT'):
587 if method == 'PUT':
588 self.assertRaises(ValueError, logging.handlers.HTTPHandler,
589 'localhost', '/log', method)
590 else:
591 h = logging.handlers.HTTPHandler('localhost', '/log', method)
592 h.close()
593 h = logging.handlers.BufferingHandler(0)
594 r = logging.makeLogRecord({})
595 self.assertTrue(h.shouldFlush(r))
596 h.close()
597 h = logging.handlers.BufferingHandler(1)
598 self.assertFalse(h.shouldFlush(r))
599 h.close()
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100600
Vinay Sajipdb8f4632016-09-08 01:37:03 +0100601 def test_path_objects(self):
602 """
603 Test that Path objects are accepted as filename arguments to handlers.
604
605 See Issue #27493.
606 """
607 fd, fn = tempfile.mkstemp()
608 os.close(fd)
609 os.unlink(fn)
610 pfn = pathlib.Path(fn)
611 cases = (
612 (logging.FileHandler, (pfn, 'w')),
613 (logging.handlers.RotatingFileHandler, (pfn, 'a')),
614 (logging.handlers.TimedRotatingFileHandler, (pfn, 'h')),
615 )
616 if sys.platform in ('linux', 'darwin'):
617 cases += ((logging.handlers.WatchedFileHandler, (pfn, 'w')),)
618 for cls, args in cases:
619 h = cls(*args)
620 self.assertTrue(os.path.exists(fn))
621 h.close()
622 os.unlink(fn)
623
Vinay Sajip5e86eed2012-05-29 22:48:10 +0100624 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajipa5798de2012-04-24 23:33:33 +0100625 def test_race(self):
626 # Issue #14632 refers.
627 def remove_loop(fname, tries):
628 for _ in range(tries):
629 try:
630 os.unlink(fname)
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000631 self.deletion_time = time.time()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100632 except OSError:
633 pass
634 time.sleep(0.004 * random.randint(0, 4))
635
Vinay Sajipc94871a2012-04-25 10:51:35 +0100636 del_count = 500
637 log_count = 500
Vinay Sajipa5798de2012-04-24 23:33:33 +0100638
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000639 self.handle_time = None
640 self.deletion_time = None
641
Vinay Sajipa5798de2012-04-24 23:33:33 +0100642 for delay in (False, True):
Vinay Sajipc94871a2012-04-25 10:51:35 +0100643 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
644 os.close(fd)
645 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
646 remover.daemon = True
647 remover.start()
Vinay Sajipa5798de2012-04-24 23:33:33 +0100648 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100649 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
650 h.setFormatter(f)
Vinay Sajipc94871a2012-04-25 10:51:35 +0100651 try:
652 for _ in range(log_count):
653 time.sleep(0.005)
654 r = logging.makeLogRecord({'msg': 'testing' })
Vinay Sajipdc96ca22013-12-03 12:31:23 +0000655 try:
656 self.handle_time = time.time()
657 h.handle(r)
658 except Exception:
659 print('Deleted at %s, '
660 'opened at %s' % (self.deletion_time,
661 self.handle_time))
662 raise
Vinay Sajipc94871a2012-04-25 10:51:35 +0100663 finally:
Vinay Sajipc94871a2012-04-25 10:51:35 +0100664 remover.join()
Vinay Sajipac20f462012-05-03 12:09:38 +0100665 h.close()
Vinay Sajipc94871a2012-04-25 10:51:35 +0100666 if os.path.exists(fn):
667 os.unlink(fn)
Vinay Sajipa5798de2012-04-24 23:33:33 +0100668
669
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100670class BadStream(object):
671 def write(self, data):
672 raise RuntimeError('deliberate mistake')
673
674class TestStreamHandler(logging.StreamHandler):
675 def handleError(self, record):
676 self.error_record = record
677
678class StreamHandlerTest(BaseTest):
679 def test_error_handling(self):
680 h = TestStreamHandler(BadStream())
681 r = logging.makeLogRecord({})
682 old_raise = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +0100683
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100684 try:
685 h.handle(r)
686 self.assertIs(h.error_record, r)
Vinay Sajip1feedb42014-05-31 08:19:12 +0100687
Vinay Sajip985ef872011-04-26 19:34:04 +0100688 h = logging.StreamHandler(BadStream())
Vinay Sajip1feedb42014-05-31 08:19:12 +0100689 with support.captured_stderr() as stderr:
690 h.handle(r)
691 msg = '\nRuntimeError: deliberate mistake\n'
692 self.assertIn(msg, stderr.getvalue())
693
Vinay Sajip985ef872011-04-26 19:34:04 +0100694 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +0100695 with support.captured_stderr() as stderr:
696 h.handle(r)
697 self.assertEqual('', stderr.getvalue())
Vinay Sajip26fe4b72011-04-26 18:43:05 +0100698 finally:
699 logging.raiseExceptions = old_raise
700
Vinay Sajip2543f502017-07-30 10:41:45 +0100701 def test_stream_setting(self):
702 """
703 Test setting the handler's stream
704 """
705 h = logging.StreamHandler()
706 stream = io.StringIO()
707 old = h.setStream(stream)
708 self.assertIs(old, sys.stderr)
709 actual = h.setStream(old)
710 self.assertIs(actual, stream)
711 # test that setting to existing value returns None
712 actual = h.setStream(old)
713 self.assertIsNone(actual)
714
Vinay Sajip7367d082011-05-02 13:17:27 +0100715# -- The following section could be moved into a server_helper.py module
716# -- if it proves to be of wider utility than just test_logging
Vinay Sajipa463d252011-04-30 21:52:48 +0100717
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200718class TestSMTPServer(smtpd.SMTPServer):
719 """
720 This class implements a test SMTP server.
Vinay Sajipa463d252011-04-30 21:52:48 +0100721
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200722 :param addr: A (host, port) tuple which the server listens on.
723 You can specify a port value of zero: the server's
724 *port* attribute will hold the actual port number
725 used, which can be used in client connections.
726 :param handler: A callable which will be called to process
727 incoming messages. The handler will be passed
728 the client address tuple, who the message is from,
729 a list of recipients and the message data.
730 :param poll_interval: The interval, in seconds, used in the underlying
731 :func:`select` or :func:`poll` call by
732 :func:`asyncore.loop`.
733 :param sockmap: A dictionary which will be used to hold
734 :class:`asyncore.dispatcher` instances used by
735 :func:`asyncore.loop`. This avoids changing the
736 :mod:`asyncore` module's global state.
737 """
738
739 def __init__(self, addr, handler, poll_interval, sockmap):
740 smtpd.SMTPServer.__init__(self, addr, None, map=sockmap,
741 decode_data=True)
742 self.port = self.socket.getsockname()[1]
743 self._handler = handler
744 self._thread = None
745 self.poll_interval = poll_interval
746
747 def process_message(self, peer, mailfrom, rcpttos, data):
748 """
749 Delegates to the handler passed in to the server's constructor.
750
751 Typically, this will be a test case method.
752 :param peer: The client (host, port) tuple.
753 :param mailfrom: The address of the sender.
754 :param rcpttos: The addresses of the recipients.
755 :param data: The message.
756 """
757 self._handler(peer, mailfrom, rcpttos, data)
758
759 def start(self):
760 """
761 Start the server running on a separate daemon thread.
762 """
763 self._thread = t = threading.Thread(target=self.serve_forever,
764 args=(self.poll_interval,))
765 t.setDaemon(True)
766 t.start()
767
768 def serve_forever(self, poll_interval):
769 """
770 Run the :mod:`asyncore` loop until normal termination
771 conditions arise.
Vinay Sajip314b92b2011-05-02 14:31:16 +0100772 :param poll_interval: The interval, in seconds, used in the underlying
773 :func:`select` or :func:`poll` call by
774 :func:`asyncore.loop`.
775 """
Victor Stinner13ff2452018-01-22 18:32:50 +0100776 asyncore.loop(poll_interval, map=self._map)
Vinay Sajipce7c9782011-05-17 07:15:53 +0100777
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200778 def stop(self, timeout=None):
779 """
780 Stop the thread by closing the server instance.
781 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100782
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200783 :param timeout: How long to wait for the server thread
784 to terminate.
785 """
786 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700787 support.join_thread(self._thread, timeout)
788 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200789 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100790
Vinay Sajip7367d082011-05-02 13:17:27 +0100791
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200792class ControlMixin(object):
793 """
794 This mixin is used to start a server on a separate thread, and
795 shut it down programmatically. Request handling is simplified - instead
796 of needing to derive a suitable RequestHandler subclass, you just
797 provide a callable which will be passed each received request to be
798 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100799
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200800 :param handler: A handler callable which will be called with a
801 single parameter - the request - in order to
802 process the request. This handler is called on the
803 server thread, effectively meaning that requests are
804 processed serially. While not quite Web scale ;-),
805 this should be fine for testing applications.
806 :param poll_interval: The polling interval in seconds.
807 """
808 def __init__(self, handler, poll_interval):
809 self._thread = None
810 self.poll_interval = poll_interval
811 self._handler = handler
812 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100813
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200814 def start(self):
815 """
816 Create a daemon thread to run the server, and start it.
817 """
818 self._thread = t = threading.Thread(target=self.serve_forever,
819 args=(self.poll_interval,))
820 t.setDaemon(True)
821 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100822
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200823 def serve_forever(self, poll_interval):
824 """
825 Run the server. Set the ready flag before entering the
826 service loop.
827 """
828 self.ready.set()
829 super(ControlMixin, self).serve_forever(poll_interval)
830
831 def stop(self, timeout=None):
832 """
833 Tell the server thread to stop, and wait for it to do so.
834
835 :param timeout: How long to wait for the server thread
836 to terminate.
837 """
838 self.shutdown()
839 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700840 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100841 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200842 self.server_close()
843 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100844
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200845class TestHTTPServer(ControlMixin, HTTPServer):
846 """
847 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100848
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200849 :param addr: A tuple with the IP address and port to listen on.
850 :param handler: A handler callable which will be called with a
851 single parameter - the request - in order to
852 process the request.
853 :param poll_interval: The polling interval in seconds.
854 :param log: Pass ``True`` to enable log messages.
855 """
856 def __init__(self, addr, handler, poll_interval=0.5,
857 log=False, sslctx=None):
858 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
859 def __getattr__(self, name, default=None):
860 if name.startswith('do_'):
861 return self.process_request
862 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100863
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200864 def process_request(self):
865 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100866
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200867 def log_message(self, format, *args):
868 if log:
869 super(DelegatingHTTPRequestHandler,
870 self).log_message(format, *args)
871 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
872 ControlMixin.__init__(self, handler, poll_interval)
873 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100874
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200875 def get_request(self):
876 try:
877 sock, addr = self.socket.accept()
878 if self.sslctx:
879 sock = self.sslctx.wrap_socket(sock, server_side=True)
880 except OSError as e:
881 # socket errors are silenced by the caller, print them here
882 sys.stderr.write("Got an error:\n%s\n" % e)
883 raise
884 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100885
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200886class TestTCPServer(ControlMixin, ThreadingTCPServer):
887 """
888 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100889
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200890 :param addr: A tuple with the IP address and port to listen on.
891 :param handler: A handler callable which will be called with a single
892 parameter - the request - in order to process the request.
893 :param poll_interval: The polling interval in seconds.
894 :bind_and_activate: If True (the default), binds the server and starts it
895 listening. If False, you need to call
896 :meth:`server_bind` and :meth:`server_activate` at
897 some later time before calling :meth:`start`, so that
898 the server will set up the socket and listen on it.
899 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100900
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200901 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100902
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200903 def __init__(self, addr, handler, poll_interval=0.5,
904 bind_and_activate=True):
905 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100906
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200907 def handle(self):
908 self.server._handler(self)
909 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
910 bind_and_activate)
911 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100912
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200913 def server_bind(self):
914 super(TestTCPServer, self).server_bind()
915 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100916
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200917class TestUDPServer(ControlMixin, ThreadingUDPServer):
918 """
919 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100920
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200921 :param addr: A tuple with the IP address and port to listen on.
922 :param handler: A handler callable which will be called with a
923 single parameter - the request - in order to
924 process the request.
925 :param poll_interval: The polling interval for shutdown requests,
926 in seconds.
927 :bind_and_activate: If True (the default), binds the server and
928 starts it listening. If False, you need to
929 call :meth:`server_bind` and
930 :meth:`server_activate` at some later time
931 before calling :meth:`start`, so that the server will
932 set up the socket and listen on it.
933 """
934 def __init__(self, addr, handler, poll_interval=0.5,
935 bind_and_activate=True):
936 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100937
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200938 def handle(self):
939 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100940
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200941 def finish(self):
942 data = self.wfile.getvalue()
943 if data:
944 try:
945 super(DelegatingUDPRequestHandler, self).finish()
946 except OSError:
947 if not self.server._closed:
948 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100949
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200950 ThreadingUDPServer.__init__(self, addr,
951 DelegatingUDPRequestHandler,
952 bind_and_activate)
953 ControlMixin.__init__(self, handler, poll_interval)
954 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100955
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200956 def server_bind(self):
957 super(TestUDPServer, self).server_bind()
958 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100959
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200960 def server_close(self):
961 super(TestUDPServer, self).server_close()
962 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +0100963
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200964if hasattr(socket, "AF_UNIX"):
965 class TestUnixStreamServer(TestTCPServer):
966 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +0100967
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200968 class TestUnixDatagramServer(TestUDPServer):
969 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100970
Vinay Sajip7367d082011-05-02 13:17:27 +0100971# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100972
973class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000974 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200975
Vinay Sajipa463d252011-04-30 21:52:48 +0100976 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100977 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800978 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100979 sockmap)
980 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800981 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000982 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
983 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100984 self.assertEqual(h.toaddrs, ['you'])
985 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100986 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100987 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100988 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000989 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100990 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000991 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100992 self.assertEqual(len(self.messages), 1)
993 peer, mailfrom, rcpttos, data = self.messages[0]
994 self.assertEqual(mailfrom, 'me')
995 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +0100996 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +0100997 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +0100998 h.close()
999
1000 def process_message(self, *args):
1001 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001002 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001003
Christian Heimes180510d2008-03-03 19:15:45 +00001004class MemoryHandlerTest(BaseTest):
1005
1006 """Tests for the MemoryHandler."""
1007
1008 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001009 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001010
1011 def setUp(self):
1012 BaseTest.setUp(self)
1013 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001014 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001015 self.mem_logger = logging.getLogger('mem')
1016 self.mem_logger.propagate = 0
1017 self.mem_logger.addHandler(self.mem_hdlr)
1018
1019 def tearDown(self):
1020 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001021 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001022
1023 def test_flush(self):
1024 # The memory handler flushes to its target handler based on specific
1025 # criteria (message count and message level).
1026 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001027 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001028 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001029 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001030 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001031 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001032 lines = [
1033 ('DEBUG', '1'),
1034 ('INFO', '2'),
1035 ('WARNING', '3'),
1036 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001037 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001038 for n in (4, 14):
1039 for i in range(9):
1040 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001041 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001042 # This will flush because it's the 10th message since the last
1043 # flush.
1044 self.mem_logger.debug(self.next_message())
1045 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001046 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001047
1048 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001049 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001050
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001051 def test_flush_on_close(self):
1052 """
1053 Test that the flush-on-close configuration works as expected.
1054 """
1055 self.mem_logger.debug(self.next_message())
1056 self.assert_log_lines([])
1057 self.mem_logger.info(self.next_message())
1058 self.assert_log_lines([])
1059 self.mem_logger.removeHandler(self.mem_hdlr)
1060 # Default behaviour is to flush on close. Check that it happens.
1061 self.mem_hdlr.close()
1062 lines = [
1063 ('DEBUG', '1'),
1064 ('INFO', '2'),
1065 ]
1066 self.assert_log_lines(lines)
1067 # Now configure for flushing not to be done on close.
1068 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1069 self.root_hdlr,
1070 False)
1071 self.mem_logger.addHandler(self.mem_hdlr)
1072 self.mem_logger.debug(self.next_message())
1073 self.assert_log_lines(lines) # no change
1074 self.mem_logger.info(self.next_message())
1075 self.assert_log_lines(lines) # no change
1076 self.mem_logger.removeHandler(self.mem_hdlr)
1077 self.mem_hdlr.close()
1078 # assert that no new lines have been added
1079 self.assert_log_lines(lines) # no change
1080
Christian Heimes180510d2008-03-03 19:15:45 +00001081
1082class ExceptionFormatter(logging.Formatter):
1083 """A special exception formatter."""
1084 def formatException(self, ei):
1085 return "Got a [%s]" % ei[0].__name__
1086
1087
1088class ConfigFileTest(BaseTest):
1089
1090 """Reading logging config from a .ini-style config file."""
1091
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001092 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001093
1094 # config0 is a standard configuration.
1095 config0 = """
1096 [loggers]
1097 keys=root
1098
1099 [handlers]
1100 keys=hand1
1101
1102 [formatters]
1103 keys=form1
1104
1105 [logger_root]
1106 level=WARNING
1107 handlers=hand1
1108
1109 [handler_hand1]
1110 class=StreamHandler
1111 level=NOTSET
1112 formatter=form1
1113 args=(sys.stdout,)
1114
1115 [formatter_form1]
1116 format=%(levelname)s ++ %(message)s
1117 datefmt=
1118 """
1119
1120 # config1 adds a little to the standard configuration.
1121 config1 = """
1122 [loggers]
1123 keys=root,parser
1124
1125 [handlers]
1126 keys=hand1
1127
1128 [formatters]
1129 keys=form1
1130
1131 [logger_root]
1132 level=WARNING
1133 handlers=
1134
1135 [logger_parser]
1136 level=DEBUG
1137 handlers=hand1
1138 propagate=1
1139 qualname=compiler.parser
1140
1141 [handler_hand1]
1142 class=StreamHandler
1143 level=NOTSET
1144 formatter=form1
1145 args=(sys.stdout,)
1146
1147 [formatter_form1]
1148 format=%(levelname)s ++ %(message)s
1149 datefmt=
1150 """
1151
Vinay Sajip3f84b072011-03-07 17:49:33 +00001152 # config1a moves the handler to the root.
1153 config1a = """
1154 [loggers]
1155 keys=root,parser
1156
1157 [handlers]
1158 keys=hand1
1159
1160 [formatters]
1161 keys=form1
1162
1163 [logger_root]
1164 level=WARNING
1165 handlers=hand1
1166
1167 [logger_parser]
1168 level=DEBUG
1169 handlers=
1170 propagate=1
1171 qualname=compiler.parser
1172
1173 [handler_hand1]
1174 class=StreamHandler
1175 level=NOTSET
1176 formatter=form1
1177 args=(sys.stdout,)
1178
1179 [formatter_form1]
1180 format=%(levelname)s ++ %(message)s
1181 datefmt=
1182 """
1183
Christian Heimes180510d2008-03-03 19:15:45 +00001184 # config2 has a subtle configuration error that should be reported
1185 config2 = config1.replace("sys.stdout", "sys.stbout")
1186
1187 # config3 has a less subtle configuration error
1188 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1189
1190 # config4 specifies a custom formatter class to be loaded
1191 config4 = """
1192 [loggers]
1193 keys=root
1194
1195 [handlers]
1196 keys=hand1
1197
1198 [formatters]
1199 keys=form1
1200
1201 [logger_root]
1202 level=NOTSET
1203 handlers=hand1
1204
1205 [handler_hand1]
1206 class=StreamHandler
1207 level=NOTSET
1208 formatter=form1
1209 args=(sys.stdout,)
1210
1211 [formatter_form1]
1212 class=""" + __name__ + """.ExceptionFormatter
1213 format=%(levelname)s:%(name)s:%(message)s
1214 datefmt=
1215 """
1216
Georg Brandl3dbca812008-07-23 16:10:53 +00001217 # config5 specifies a custom handler class to be loaded
1218 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1219
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001220 # config6 uses ', ' delimiters in the handlers and formatters sections
1221 config6 = """
1222 [loggers]
1223 keys=root,parser
1224
1225 [handlers]
1226 keys=hand1, hand2
1227
1228 [formatters]
1229 keys=form1, form2
1230
1231 [logger_root]
1232 level=WARNING
1233 handlers=
1234
1235 [logger_parser]
1236 level=DEBUG
1237 handlers=hand1
1238 propagate=1
1239 qualname=compiler.parser
1240
1241 [handler_hand1]
1242 class=StreamHandler
1243 level=NOTSET
1244 formatter=form1
1245 args=(sys.stdout,)
1246
1247 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001248 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001249 level=NOTSET
1250 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001251 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001252
1253 [formatter_form1]
1254 format=%(levelname)s ++ %(message)s
1255 datefmt=
1256
1257 [formatter_form2]
1258 format=%(message)s
1259 datefmt=
1260 """
1261
Preston Landers6ea56d22017-08-02 15:44:28 -05001262 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001263 config7 = """
1264 [loggers]
1265 keys=root,parser,compiler
1266
1267 [handlers]
1268 keys=hand1
1269
1270 [formatters]
1271 keys=form1
1272
1273 [logger_root]
1274 level=WARNING
1275 handlers=hand1
1276
1277 [logger_compiler]
1278 level=DEBUG
1279 handlers=
1280 propagate=1
1281 qualname=compiler
1282
1283 [logger_parser]
1284 level=DEBUG
1285 handlers=
1286 propagate=1
1287 qualname=compiler.parser
1288
1289 [handler_hand1]
1290 class=StreamHandler
1291 level=NOTSET
1292 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001293 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001294
1295 [formatter_form1]
1296 format=%(levelname)s ++ %(message)s
1297 datefmt=
1298 """
1299
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001300 disable_test = """
1301 [loggers]
1302 keys=root
1303
1304 [handlers]
1305 keys=screen
1306
1307 [formatters]
1308 keys=
1309
1310 [logger_root]
1311 level=DEBUG
1312 handlers=screen
1313
1314 [handler_screen]
1315 level=DEBUG
1316 class=StreamHandler
1317 args=(sys.stdout,)
1318 formatter=
1319 """
1320
1321 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001322 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001323 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001324
1325 def test_config0_ok(self):
1326 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001327 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001328 self.apply_config(self.config0)
1329 logger = logging.getLogger()
1330 # Won't output anything
1331 logger.info(self.next_message())
1332 # Outputs a message
1333 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001334 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001335 ('ERROR', '2'),
1336 ], stream=output)
1337 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001338 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001339
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001340 def test_config0_using_cp_ok(self):
1341 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001342 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001343 file = io.StringIO(textwrap.dedent(self.config0))
1344 cp = configparser.ConfigParser()
1345 cp.read_file(file)
1346 logging.config.fileConfig(cp)
1347 logger = logging.getLogger()
1348 # Won't output anything
1349 logger.info(self.next_message())
1350 # Outputs a message
1351 logger.error(self.next_message())
1352 self.assert_log_lines([
1353 ('ERROR', '2'),
1354 ], stream=output)
1355 # Original logger output is empty.
1356 self.assert_log_lines([])
1357
Georg Brandl3dbca812008-07-23 16:10:53 +00001358 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001359 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001360 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001361 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001362 logger = logging.getLogger("compiler.parser")
1363 # Both will output a message
1364 logger.info(self.next_message())
1365 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001366 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001367 ('INFO', '1'),
1368 ('ERROR', '2'),
1369 ], stream=output)
1370 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001371 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001372
1373 def test_config2_failure(self):
1374 # A simple config file which overrides the default settings.
1375 self.assertRaises(Exception, self.apply_config, self.config2)
1376
1377 def test_config3_failure(self):
1378 # A simple config file which overrides the default settings.
1379 self.assertRaises(Exception, self.apply_config, self.config3)
1380
1381 def test_config4_ok(self):
1382 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001383 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001384 self.apply_config(self.config4)
1385 logger = logging.getLogger()
1386 try:
1387 raise RuntimeError()
1388 except RuntimeError:
1389 logging.exception("just testing")
1390 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001391 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001392 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1393 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001394 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001395
Georg Brandl3dbca812008-07-23 16:10:53 +00001396 def test_config5_ok(self):
1397 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001398
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001399 def test_config6_ok(self):
1400 self.test_config1_ok(config=self.config6)
1401
Vinay Sajip3f84b072011-03-07 17:49:33 +00001402 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001403 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001404 self.apply_config(self.config1a)
1405 logger = logging.getLogger("compiler.parser")
1406 # See issue #11424. compiler-hyphenated sorts
1407 # between compiler and compiler.xyz and this
1408 # was preventing compiler.xyz from being included
1409 # in the child loggers of compiler because of an
1410 # overzealous loop termination condition.
1411 hyphenated = logging.getLogger('compiler-hyphenated')
1412 # All will output a message
1413 logger.info(self.next_message())
1414 logger.error(self.next_message())
1415 hyphenated.critical(self.next_message())
1416 self.assert_log_lines([
1417 ('INFO', '1'),
1418 ('ERROR', '2'),
1419 ('CRITICAL', '3'),
1420 ], stream=output)
1421 # Original logger output is empty.
1422 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001423 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001424 self.apply_config(self.config7)
1425 logger = logging.getLogger("compiler.parser")
1426 self.assertFalse(logger.disabled)
1427 # Both will output a message
1428 logger.info(self.next_message())
1429 logger.error(self.next_message())
1430 logger = logging.getLogger("compiler.lexer")
1431 # Both will output a message
1432 logger.info(self.next_message())
1433 logger.error(self.next_message())
1434 # Will not appear
1435 hyphenated.critical(self.next_message())
1436 self.assert_log_lines([
1437 ('INFO', '4'),
1438 ('ERROR', '5'),
1439 ('INFO', '6'),
1440 ('ERROR', '7'),
1441 ], stream=output)
1442 # Original logger output is empty.
1443 self.assert_log_lines([])
1444
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001445 def test_logger_disabling(self):
1446 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001447 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001448 self.assertFalse(logger.disabled)
1449 self.apply_config(self.disable_test)
1450 self.assertTrue(logger.disabled)
1451 self.apply_config(self.disable_test, disable_existing_loggers=False)
1452 self.assertFalse(logger.disabled)
1453
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001454
Christian Heimes180510d2008-03-03 19:15:45 +00001455class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001456
Christian Heimes180510d2008-03-03 19:15:45 +00001457 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001458
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001459 server_class = TestTCPServer
1460 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001461
Christian Heimes180510d2008-03-03 19:15:45 +00001462 def setUp(self):
1463 """Set up a TCP server to receive log messages, and a SocketHandler
1464 pointing to that server's address and port."""
1465 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001466 # Issue #29177: deal with errors that happen during setup
1467 self.server = self.sock_hdlr = self.server_exception = None
1468 try:
1469 self.server = server = self.server_class(self.address,
1470 self.handle_socket, 0.01)
1471 server.start()
1472 # Uncomment next line to test error recovery in setUp()
1473 # raise OSError('dummy error raised')
1474 except OSError as e:
1475 self.server_exception = e
1476 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001477 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001478 hcls = logging.handlers.SocketHandler
1479 if isinstance(server.server_address, tuple):
1480 self.sock_hdlr = hcls('localhost', server.port)
1481 else:
1482 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001483 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001484 self.root_logger.removeHandler(self.root_logger.handlers[0])
1485 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001486 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001487
Christian Heimes180510d2008-03-03 19:15:45 +00001488 def tearDown(self):
1489 """Shutdown the TCP server."""
1490 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001491 if self.sock_hdlr:
1492 self.root_logger.removeHandler(self.sock_hdlr)
1493 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001494 if self.server:
1495 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001496 finally:
1497 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001498
Vinay Sajip7367d082011-05-02 13:17:27 +01001499 def handle_socket(self, request):
1500 conn = request.connection
1501 while True:
1502 chunk = conn.recv(4)
1503 if len(chunk) < 4:
1504 break
1505 slen = struct.unpack(">L", chunk)[0]
1506 chunk = conn.recv(slen)
1507 while len(chunk) < slen:
1508 chunk = chunk + conn.recv(slen - len(chunk))
1509 obj = pickle.loads(chunk)
1510 record = logging.makeLogRecord(obj)
1511 self.log_output += record.msg + '\n'
1512 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001513
Christian Heimes180510d2008-03-03 19:15:45 +00001514 def test_output(self):
1515 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001516 if self.server_exception:
1517 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001518 logger = logging.getLogger("tcp")
1519 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001520 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001521 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001522 self.handled.acquire()
1523 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001524
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001525 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001526 if self.server_exception:
1527 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001528 # Avoid timing-related failures due to SocketHandler's own hard-wired
1529 # one-second timeout on socket.create_connection() (issue #16264).
1530 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001531 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001532 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001533 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001534 try:
1535 raise RuntimeError('Deliberate mistake')
1536 except RuntimeError:
1537 self.root_logger.exception('Never sent')
1538 self.root_logger.error('Never sent, either')
1539 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001540 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001541 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1542 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001543
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001544def _get_temp_domain_socket():
1545 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1546 os.close(fd)
1547 # just need a name - file can't be present, or we'll get an
1548 # 'address already in use' error.
1549 os.remove(fn)
1550 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001551
Victor Stinnerec5a8602014-06-02 14:41:51 +02001552@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001553class UnixSocketHandlerTest(SocketHandlerTest):
1554
1555 """Test for SocketHandler with unix sockets."""
1556
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001557 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001558 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001559
1560 def setUp(self):
1561 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001562 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001563 SocketHandlerTest.setUp(self)
1564
1565 def tearDown(self):
1566 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001567 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001568
Vinay Sajip7367d082011-05-02 13:17:27 +01001569class DatagramHandlerTest(BaseTest):
1570
1571 """Test for DatagramHandler."""
1572
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001573 server_class = TestUDPServer
1574 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001575
Vinay Sajip7367d082011-05-02 13:17:27 +01001576 def setUp(self):
1577 """Set up a UDP server to receive log messages, and a DatagramHandler
1578 pointing to that server's address and port."""
1579 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001580 # Issue #29177: deal with errors that happen during setup
1581 self.server = self.sock_hdlr = self.server_exception = None
1582 try:
1583 self.server = server = self.server_class(self.address,
1584 self.handle_datagram, 0.01)
1585 server.start()
1586 # Uncomment next line to test error recovery in setUp()
1587 # raise OSError('dummy error raised')
1588 except OSError as e:
1589 self.server_exception = e
1590 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001591 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001592 hcls = logging.handlers.DatagramHandler
1593 if isinstance(server.server_address, tuple):
1594 self.sock_hdlr = hcls('localhost', server.port)
1595 else:
1596 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001597 self.log_output = ''
1598 self.root_logger.removeHandler(self.root_logger.handlers[0])
1599 self.root_logger.addHandler(self.sock_hdlr)
1600 self.handled = threading.Event()
1601
1602 def tearDown(self):
1603 """Shutdown the UDP server."""
1604 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001605 if self.server:
1606 self.server.stop(2.0)
1607 if self.sock_hdlr:
1608 self.root_logger.removeHandler(self.sock_hdlr)
1609 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001610 finally:
1611 BaseTest.tearDown(self)
1612
1613 def handle_datagram(self, request):
1614 slen = struct.pack('>L', 0) # length of prefix
1615 packet = request.packet[len(slen):]
1616 obj = pickle.loads(packet)
1617 record = logging.makeLogRecord(obj)
1618 self.log_output += record.msg + '\n'
1619 self.handled.set()
1620
1621 def test_output(self):
1622 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001623 if self.server_exception:
1624 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001625 logger = logging.getLogger("udp")
1626 logger.error("spam")
1627 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001628 self.handled.clear()
1629 logger.error("eggs")
1630 self.handled.wait()
1631 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001632
Victor Stinnerec5a8602014-06-02 14:41:51 +02001633@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001634class UnixDatagramHandlerTest(DatagramHandlerTest):
1635
1636 """Test for DatagramHandler using Unix sockets."""
1637
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001638 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001639 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001640
1641 def setUp(self):
1642 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001643 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001644 DatagramHandlerTest.setUp(self)
1645
1646 def tearDown(self):
1647 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001648 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001649
Vinay Sajip7367d082011-05-02 13:17:27 +01001650class SysLogHandlerTest(BaseTest):
1651
1652 """Test for SysLogHandler using UDP."""
1653
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001654 server_class = TestUDPServer
1655 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001656
Vinay Sajip7367d082011-05-02 13:17:27 +01001657 def setUp(self):
1658 """Set up a UDP server to receive log messages, and a SysLogHandler
1659 pointing to that server's address and port."""
1660 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001661 # Issue #29177: deal with errors that happen during setup
1662 self.server = self.sl_hdlr = self.server_exception = None
1663 try:
1664 self.server = server = self.server_class(self.address,
1665 self.handle_datagram, 0.01)
1666 server.start()
1667 # Uncomment next line to test error recovery in setUp()
1668 # raise OSError('dummy error raised')
1669 except OSError as e:
1670 self.server_exception = e
1671 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001672 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001673 hcls = logging.handlers.SysLogHandler
1674 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001675 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001676 else:
1677 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001678 self.log_output = ''
1679 self.root_logger.removeHandler(self.root_logger.handlers[0])
1680 self.root_logger.addHandler(self.sl_hdlr)
1681 self.handled = threading.Event()
1682
1683 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001684 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001685 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001686 if self.server:
1687 self.server.stop(2.0)
1688 if self.sl_hdlr:
1689 self.root_logger.removeHandler(self.sl_hdlr)
1690 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001691 finally:
1692 BaseTest.tearDown(self)
1693
1694 def handle_datagram(self, request):
1695 self.log_output = request.packet
1696 self.handled.set()
1697
1698 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001699 if self.server_exception:
1700 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001701 # The log message sent to the SysLogHandler is properly received.
1702 logger = logging.getLogger("slh")
1703 logger.error("sp\xe4m")
1704 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001705 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001706 self.handled.clear()
1707 self.sl_hdlr.append_nul = False
1708 logger.error("sp\xe4m")
1709 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001710 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001711 self.handled.clear()
1712 self.sl_hdlr.ident = "h\xe4m-"
1713 logger.error("sp\xe4m")
1714 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001715 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001716
Victor Stinnerec5a8602014-06-02 14:41:51 +02001717@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001718class UnixSysLogHandlerTest(SysLogHandlerTest):
1719
1720 """Test for SysLogHandler with Unix sockets."""
1721
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001722 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001723 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001724
1725 def setUp(self):
1726 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001727 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001728 SysLogHandlerTest.setUp(self)
1729
1730 def tearDown(self):
1731 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001732 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001733
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001734@unittest.skipUnless(support.IPV6_ENABLED,
1735 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001736class IPv6SysLogHandlerTest(SysLogHandlerTest):
1737
1738 """Test for SysLogHandler with IPv6 host."""
1739
1740 server_class = TestUDPServer
1741 address = ('::1', 0)
1742
1743 def setUp(self):
1744 self.server_class.address_family = socket.AF_INET6
1745 super(IPv6SysLogHandlerTest, self).setUp()
1746
1747 def tearDown(self):
1748 self.server_class.address_family = socket.AF_INET
1749 super(IPv6SysLogHandlerTest, self).tearDown()
1750
Vinay Sajip7367d082011-05-02 13:17:27 +01001751class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001752 """Test for HTTPHandler."""
1753
1754 def setUp(self):
1755 """Set up an HTTP server to receive log messages, and a HTTPHandler
1756 pointing to that server's address and port."""
1757 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001758 self.handled = threading.Event()
1759
Vinay Sajip7367d082011-05-02 13:17:27 +01001760 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001761 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001762 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001763 if self.command == 'POST':
1764 try:
1765 rlen = int(request.headers['Content-Length'])
1766 self.post_data = request.rfile.read(rlen)
1767 except:
1768 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001769 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001770 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001771 self.handled.set()
1772
1773 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001774 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001775 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001776 root_logger = self.root_logger
1777 root_logger.removeHandler(self.root_logger.handlers[0])
1778 for secure in (False, True):
1779 addr = ('localhost', 0)
1780 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001781 try:
1782 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001783 except ImportError:
1784 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001785 else:
1786 here = os.path.dirname(__file__)
1787 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001788 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001789 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001790
1791 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001792 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001793 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001794 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001795 self.server = server = TestHTTPServer(addr, self.handle_request,
1796 0.01, sslctx=sslctx)
1797 server.start()
1798 server.ready.wait()
1799 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001800 secure_client = secure and sslctx
1801 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001802 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001803 context=context,
1804 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001805 self.log_data = None
1806 root_logger.addHandler(self.h_hdlr)
1807
1808 for method in ('GET', 'POST'):
1809 self.h_hdlr.method = method
1810 self.handled.clear()
1811 msg = "sp\xe4m"
1812 logger.error(msg)
1813 self.handled.wait()
1814 self.assertEqual(self.log_data.path, '/frob')
1815 self.assertEqual(self.command, method)
1816 if method == 'GET':
1817 d = parse_qs(self.log_data.query)
1818 else:
1819 d = parse_qs(self.post_data.decode('utf-8'))
1820 self.assertEqual(d['name'], ['http'])
1821 self.assertEqual(d['funcName'], ['test_output'])
1822 self.assertEqual(d['msg'], [msg])
1823
1824 self.server.stop(2.0)
1825 self.root_logger.removeHandler(self.h_hdlr)
1826 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001827
Christian Heimes180510d2008-03-03 19:15:45 +00001828class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001829
Christian Heimes180510d2008-03-03 19:15:45 +00001830 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001831
Christian Heimes180510d2008-03-03 19:15:45 +00001832 def setUp(self):
1833 """Create a dict to remember potentially destroyed objects."""
1834 BaseTest.setUp(self)
1835 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001836
Christian Heimes180510d2008-03-03 19:15:45 +00001837 def _watch_for_survival(self, *args):
1838 """Watch the given objects for survival, by creating weakrefs to
1839 them."""
1840 for obj in args:
1841 key = id(obj), repr(obj)
1842 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001843
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001844 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001845 """Assert that all objects watched for survival have survived."""
1846 # Trigger cycle breaking.
1847 gc.collect()
1848 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001849 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001850 if ref() is None:
1851 dead.append(repr_)
1852 if dead:
1853 self.fail("%d objects should have survived "
1854 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001855
Christian Heimes180510d2008-03-03 19:15:45 +00001856 def test_persistent_loggers(self):
1857 # Logger objects are persistent and retain their configuration, even
1858 # if visible references are destroyed.
1859 self.root_logger.setLevel(logging.INFO)
1860 foo = logging.getLogger("foo")
1861 self._watch_for_survival(foo)
1862 foo.setLevel(logging.DEBUG)
1863 self.root_logger.debug(self.next_message())
1864 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001865 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001866 ('foo', 'DEBUG', '2'),
1867 ])
1868 del foo
1869 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001870 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001871 # foo has retained its settings.
1872 bar = logging.getLogger("foo")
1873 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001874 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001875 ('foo', 'DEBUG', '2'),
1876 ('foo', 'DEBUG', '3'),
1877 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001878
Benjamin Petersonf91df042009-02-13 02:50:59 +00001879
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001880class EncodingTest(BaseTest):
1881 def test_encoding_plain_file(self):
1882 # In Python 2.x, a plain file object is treated as having no encoding.
1883 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001884 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1885 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001886 # the non-ascii data we write to the log.
1887 data = "foo\x80"
1888 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001889 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001890 log.addHandler(handler)
1891 try:
1892 # write non-ascii data to the log.
1893 log.warning(data)
1894 finally:
1895 log.removeHandler(handler)
1896 handler.close()
1897 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001898 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001899 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001900 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001901 finally:
1902 f.close()
1903 finally:
1904 if os.path.isfile(fn):
1905 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001906
Benjamin Petersonf91df042009-02-13 02:50:59 +00001907 def test_encoding_cyrillic_unicode(self):
1908 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03001909 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00001910 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03001911 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00001912 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001913 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001914 stream = io.BytesIO()
1915 writer = writer_class(stream, 'strict')
1916 handler = logging.StreamHandler(writer)
1917 log.addHandler(handler)
1918 try:
1919 log.warning(message)
1920 finally:
1921 log.removeHandler(handler)
1922 handler.close()
1923 # check we wrote exactly those bytes, ignoring trailing \n etc
1924 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03001925 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00001926 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1927
1928
Georg Brandlf9734072008-12-07 15:30:06 +00001929class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001930
Georg Brandlf9734072008-12-07 15:30:06 +00001931 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001932 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001933 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001934 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001935 warnings.filterwarnings("always", category=UserWarning)
1936 stream = io.StringIO()
1937 h = logging.StreamHandler(stream)
1938 logger = logging.getLogger("py.warnings")
1939 logger.addHandler(h)
1940 warnings.warn("I'm warning you...")
1941 logger.removeHandler(h)
1942 s = stream.getvalue()
1943 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001944 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001945
Mike53f7a7c2017-12-14 14:04:53 +03001946 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001947 a_file = io.StringIO()
1948 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1949 a_file, "Dummy line")
1950 s = a_file.getvalue()
1951 a_file.close()
1952 self.assertEqual(s,
1953 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1954
1955 def test_warnings_no_handlers(self):
1956 with warnings.catch_warnings():
1957 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001958 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001959
1960 # confirm our assumption: no loggers are set
1961 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001962 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001963
1964 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001965 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001966 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001967
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001968
1969def formatFunc(format, datefmt=None):
1970 return logging.Formatter(format, datefmt)
1971
1972def handlerFunc():
1973 return logging.StreamHandler()
1974
1975class CustomHandler(logging.StreamHandler):
1976 pass
1977
1978class ConfigDictTest(BaseTest):
1979
1980 """Reading logging config from a dictionary."""
1981
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001982 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001983
1984 # config0 is a standard configuration.
1985 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001986 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001987 'formatters': {
1988 'form1' : {
1989 'format' : '%(levelname)s ++ %(message)s',
1990 },
1991 },
1992 'handlers' : {
1993 'hand1' : {
1994 'class' : 'logging.StreamHandler',
1995 'formatter' : 'form1',
1996 'level' : 'NOTSET',
1997 'stream' : 'ext://sys.stdout',
1998 },
1999 },
2000 'root' : {
2001 'level' : 'WARNING',
2002 'handlers' : ['hand1'],
2003 },
2004 }
2005
2006 # config1 adds a little to the standard configuration.
2007 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002008 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002009 'formatters': {
2010 'form1' : {
2011 'format' : '%(levelname)s ++ %(message)s',
2012 },
2013 },
2014 'handlers' : {
2015 'hand1' : {
2016 'class' : 'logging.StreamHandler',
2017 'formatter' : 'form1',
2018 'level' : 'NOTSET',
2019 'stream' : 'ext://sys.stdout',
2020 },
2021 },
2022 'loggers' : {
2023 'compiler.parser' : {
2024 'level' : 'DEBUG',
2025 'handlers' : ['hand1'],
2026 },
2027 },
2028 'root' : {
2029 'level' : 'WARNING',
2030 },
2031 }
2032
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002033 # config1a moves the handler to the root. Used with config8a
2034 config1a = {
2035 'version': 1,
2036 'formatters': {
2037 'form1' : {
2038 'format' : '%(levelname)s ++ %(message)s',
2039 },
2040 },
2041 'handlers' : {
2042 'hand1' : {
2043 'class' : 'logging.StreamHandler',
2044 'formatter' : 'form1',
2045 'level' : 'NOTSET',
2046 'stream' : 'ext://sys.stdout',
2047 },
2048 },
2049 'loggers' : {
2050 'compiler.parser' : {
2051 'level' : 'DEBUG',
2052 },
2053 },
2054 'root' : {
2055 'level' : 'WARNING',
2056 'handlers' : ['hand1'],
2057 },
2058 }
2059
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002060 # config2 has a subtle configuration error that should be reported
2061 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002062 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002063 'formatters': {
2064 'form1' : {
2065 'format' : '%(levelname)s ++ %(message)s',
2066 },
2067 },
2068 'handlers' : {
2069 'hand1' : {
2070 'class' : 'logging.StreamHandler',
2071 'formatter' : 'form1',
2072 'level' : 'NOTSET',
2073 'stream' : 'ext://sys.stdbout',
2074 },
2075 },
2076 'loggers' : {
2077 'compiler.parser' : {
2078 'level' : 'DEBUG',
2079 'handlers' : ['hand1'],
2080 },
2081 },
2082 'root' : {
2083 'level' : 'WARNING',
2084 },
2085 }
2086
Mike53f7a7c2017-12-14 14:04:53 +03002087 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002088 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002089 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002090 'formatters': {
2091 'form1' : {
2092 'format' : '%(levelname)s ++ %(message)s',
2093 },
2094 },
2095 'handlers' : {
2096 'hand1' : {
2097 'class' : 'logging.StreamHandler',
2098 'formatter' : 'form1',
2099 'level' : 'NTOSET',
2100 'stream' : 'ext://sys.stdout',
2101 },
2102 },
2103 'loggers' : {
2104 'compiler.parser' : {
2105 'level' : 'DEBUG',
2106 'handlers' : ['hand1'],
2107 },
2108 },
2109 'root' : {
2110 'level' : 'WARNING',
2111 },
2112 }
2113
2114
Mike53f7a7c2017-12-14 14:04:53 +03002115 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002116 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002117 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002118 'formatters': {
2119 'form1' : {
2120 'format' : '%(levelname)s ++ %(message)s',
2121 },
2122 },
2123 'handlers' : {
2124 'hand1' : {
2125 'class' : 'logging.StreamHandler',
2126 'formatter' : 'form1',
2127 'level' : 'NOTSET',
2128 'stream' : 'ext://sys.stdout',
2129 },
2130 },
2131 'loggers' : {
2132 'compiler.parser' : {
2133 'level' : 'DEBUG',
2134 'handlers' : ['hand1'],
2135 },
2136 },
2137 'root' : {
2138 'level' : 'WRANING',
2139 },
2140 }
2141
2142 # config3 has a less subtle configuration error
2143 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002144 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002145 'formatters': {
2146 'form1' : {
2147 'format' : '%(levelname)s ++ %(message)s',
2148 },
2149 },
2150 'handlers' : {
2151 'hand1' : {
2152 'class' : 'logging.StreamHandler',
2153 'formatter' : 'misspelled_name',
2154 'level' : 'NOTSET',
2155 'stream' : 'ext://sys.stdout',
2156 },
2157 },
2158 'loggers' : {
2159 'compiler.parser' : {
2160 'level' : 'DEBUG',
2161 'handlers' : ['hand1'],
2162 },
2163 },
2164 'root' : {
2165 'level' : 'WARNING',
2166 },
2167 }
2168
2169 # config4 specifies a custom formatter class to be loaded
2170 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002171 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002172 'formatters': {
2173 'form1' : {
2174 '()' : __name__ + '.ExceptionFormatter',
2175 'format' : '%(levelname)s:%(name)s:%(message)s',
2176 },
2177 },
2178 'handlers' : {
2179 'hand1' : {
2180 'class' : 'logging.StreamHandler',
2181 'formatter' : 'form1',
2182 'level' : 'NOTSET',
2183 'stream' : 'ext://sys.stdout',
2184 },
2185 },
2186 'root' : {
2187 'level' : 'NOTSET',
2188 'handlers' : ['hand1'],
2189 },
2190 }
2191
2192 # As config4 but using an actual callable rather than a string
2193 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002194 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002195 'formatters': {
2196 'form1' : {
2197 '()' : ExceptionFormatter,
2198 'format' : '%(levelname)s:%(name)s:%(message)s',
2199 },
2200 'form2' : {
2201 '()' : __name__ + '.formatFunc',
2202 'format' : '%(levelname)s:%(name)s:%(message)s',
2203 },
2204 'form3' : {
2205 '()' : formatFunc,
2206 'format' : '%(levelname)s:%(name)s:%(message)s',
2207 },
2208 },
2209 'handlers' : {
2210 'hand1' : {
2211 'class' : 'logging.StreamHandler',
2212 'formatter' : 'form1',
2213 'level' : 'NOTSET',
2214 'stream' : 'ext://sys.stdout',
2215 },
2216 'hand2' : {
2217 '()' : handlerFunc,
2218 },
2219 },
2220 'root' : {
2221 'level' : 'NOTSET',
2222 'handlers' : ['hand1'],
2223 },
2224 }
2225
2226 # config5 specifies a custom handler class to be loaded
2227 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002228 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002229 'formatters': {
2230 'form1' : {
2231 'format' : '%(levelname)s ++ %(message)s',
2232 },
2233 },
2234 'handlers' : {
2235 'hand1' : {
2236 'class' : __name__ + '.CustomHandler',
2237 'formatter' : 'form1',
2238 'level' : 'NOTSET',
2239 'stream' : 'ext://sys.stdout',
2240 },
2241 },
2242 'loggers' : {
2243 'compiler.parser' : {
2244 'level' : 'DEBUG',
2245 'handlers' : ['hand1'],
2246 },
2247 },
2248 'root' : {
2249 'level' : 'WARNING',
2250 },
2251 }
2252
2253 # config6 specifies a custom handler class to be loaded
2254 # but has bad arguments
2255 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002256 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002257 'formatters': {
2258 'form1' : {
2259 'format' : '%(levelname)s ++ %(message)s',
2260 },
2261 },
2262 'handlers' : {
2263 'hand1' : {
2264 'class' : __name__ + '.CustomHandler',
2265 'formatter' : 'form1',
2266 'level' : 'NOTSET',
2267 'stream' : 'ext://sys.stdout',
2268 '9' : 'invalid parameter name',
2269 },
2270 },
2271 'loggers' : {
2272 'compiler.parser' : {
2273 'level' : 'DEBUG',
2274 'handlers' : ['hand1'],
2275 },
2276 },
2277 'root' : {
2278 'level' : 'WARNING',
2279 },
2280 }
2281
Mike53f7a7c2017-12-14 14:04:53 +03002282 # config 7 does not define compiler.parser but defines compiler.lexer
2283 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002284 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002285 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002286 'formatters': {
2287 'form1' : {
2288 'format' : '%(levelname)s ++ %(message)s',
2289 },
2290 },
2291 'handlers' : {
2292 'hand1' : {
2293 'class' : 'logging.StreamHandler',
2294 'formatter' : 'form1',
2295 'level' : 'NOTSET',
2296 'stream' : 'ext://sys.stdout',
2297 },
2298 },
2299 'loggers' : {
2300 'compiler.lexer' : {
2301 'level' : 'DEBUG',
2302 'handlers' : ['hand1'],
2303 },
2304 },
2305 'root' : {
2306 'level' : 'WARNING',
2307 },
2308 }
2309
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002310 # config8 defines both compiler and compiler.lexer
2311 # so compiler.parser should not be disabled (since
2312 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002313 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002314 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002315 'disable_existing_loggers' : False,
2316 'formatters': {
2317 'form1' : {
2318 'format' : '%(levelname)s ++ %(message)s',
2319 },
2320 },
2321 'handlers' : {
2322 'hand1' : {
2323 'class' : 'logging.StreamHandler',
2324 'formatter' : 'form1',
2325 'level' : 'NOTSET',
2326 'stream' : 'ext://sys.stdout',
2327 },
2328 },
2329 'loggers' : {
2330 'compiler' : {
2331 'level' : 'DEBUG',
2332 'handlers' : ['hand1'],
2333 },
2334 'compiler.lexer' : {
2335 },
2336 },
2337 'root' : {
2338 'level' : 'WARNING',
2339 },
2340 }
2341
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002342 # config8a disables existing loggers
2343 config8a = {
2344 'version': 1,
2345 'disable_existing_loggers' : True,
2346 'formatters': {
2347 'form1' : {
2348 'format' : '%(levelname)s ++ %(message)s',
2349 },
2350 },
2351 'handlers' : {
2352 'hand1' : {
2353 'class' : 'logging.StreamHandler',
2354 'formatter' : 'form1',
2355 'level' : 'NOTSET',
2356 'stream' : 'ext://sys.stdout',
2357 },
2358 },
2359 'loggers' : {
2360 'compiler' : {
2361 'level' : 'DEBUG',
2362 'handlers' : ['hand1'],
2363 },
2364 'compiler.lexer' : {
2365 },
2366 },
2367 'root' : {
2368 'level' : 'WARNING',
2369 },
2370 }
2371
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002372 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002373 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002374 'formatters': {
2375 'form1' : {
2376 'format' : '%(levelname)s ++ %(message)s',
2377 },
2378 },
2379 'handlers' : {
2380 'hand1' : {
2381 'class' : 'logging.StreamHandler',
2382 'formatter' : 'form1',
2383 'level' : 'WARNING',
2384 'stream' : 'ext://sys.stdout',
2385 },
2386 },
2387 'loggers' : {
2388 'compiler.parser' : {
2389 'level' : 'WARNING',
2390 'handlers' : ['hand1'],
2391 },
2392 },
2393 'root' : {
2394 'level' : 'NOTSET',
2395 },
2396 }
2397
2398 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002399 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002400 'incremental' : True,
2401 'handlers' : {
2402 'hand1' : {
2403 'level' : 'WARNING',
2404 },
2405 },
2406 'loggers' : {
2407 'compiler.parser' : {
2408 'level' : 'INFO',
2409 },
2410 },
2411 }
2412
2413 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002414 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002415 'incremental' : True,
2416 'handlers' : {
2417 'hand1' : {
2418 'level' : 'INFO',
2419 },
2420 },
2421 'loggers' : {
2422 'compiler.parser' : {
2423 'level' : 'INFO',
2424 },
2425 },
2426 }
2427
Mike53f7a7c2017-12-14 14:04:53 +03002428 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002429 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002430 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002431 'formatters': {
2432 'form1' : {
2433 'format' : '%(levelname)s ++ %(message)s',
2434 },
2435 },
2436 'filters' : {
2437 'filt1' : {
2438 'name' : 'compiler.parser',
2439 },
2440 },
2441 'handlers' : {
2442 'hand1' : {
2443 'class' : 'logging.StreamHandler',
2444 'formatter' : 'form1',
2445 'level' : 'NOTSET',
2446 'stream' : 'ext://sys.stdout',
2447 'filters' : ['filt1'],
2448 },
2449 },
2450 'loggers' : {
2451 'compiler.parser' : {
2452 'level' : 'DEBUG',
2453 'filters' : ['filt1'],
2454 },
2455 },
2456 'root' : {
2457 'level' : 'WARNING',
2458 'handlers' : ['hand1'],
2459 },
2460 }
2461
Mike53f7a7c2017-12-14 14:04:53 +03002462 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002463 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002464 'version': 1,
2465 'true_formatters': {
2466 'form1' : {
2467 'format' : '%(levelname)s ++ %(message)s',
2468 },
2469 },
2470 'handler_configs': {
2471 'hand1' : {
2472 'class' : 'logging.StreamHandler',
2473 'formatter' : 'form1',
2474 'level' : 'NOTSET',
2475 'stream' : 'ext://sys.stdout',
2476 },
2477 },
2478 'formatters' : 'cfg://true_formatters',
2479 'handlers' : {
2480 'hand1' : 'cfg://handler_configs[hand1]',
2481 },
2482 'loggers' : {
2483 'compiler.parser' : {
2484 'level' : 'DEBUG',
2485 'handlers' : ['hand1'],
2486 },
2487 },
2488 'root' : {
2489 'level' : 'WARNING',
2490 },
2491 }
2492
Mike53f7a7c2017-12-14 14:04:53 +03002493 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002494 config12 = {
2495 'true_formatters': {
2496 'form1' : {
2497 'format' : '%(levelname)s ++ %(message)s',
2498 },
2499 },
2500 'handler_configs': {
2501 'hand1' : {
2502 'class' : 'logging.StreamHandler',
2503 'formatter' : 'form1',
2504 'level' : 'NOTSET',
2505 'stream' : 'ext://sys.stdout',
2506 },
2507 },
2508 'formatters' : 'cfg://true_formatters',
2509 'handlers' : {
2510 'hand1' : 'cfg://handler_configs[hand1]',
2511 },
2512 'loggers' : {
2513 'compiler.parser' : {
2514 'level' : 'DEBUG',
2515 'handlers' : ['hand1'],
2516 },
2517 },
2518 'root' : {
2519 'level' : 'WARNING',
2520 },
2521 }
2522
Mike53f7a7c2017-12-14 14:04:53 +03002523 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002524 config13 = {
2525 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002526 'true_formatters': {
2527 'form1' : {
2528 'format' : '%(levelname)s ++ %(message)s',
2529 },
2530 },
2531 'handler_configs': {
2532 'hand1' : {
2533 'class' : 'logging.StreamHandler',
2534 'formatter' : 'form1',
2535 'level' : 'NOTSET',
2536 'stream' : 'ext://sys.stdout',
2537 },
2538 },
2539 'formatters' : 'cfg://true_formatters',
2540 'handlers' : {
2541 'hand1' : 'cfg://handler_configs[hand1]',
2542 },
2543 'loggers' : {
2544 'compiler.parser' : {
2545 'level' : 'DEBUG',
2546 'handlers' : ['hand1'],
2547 },
2548 },
2549 'root' : {
2550 'level' : 'WARNING',
2551 },
2552 }
2553
Vinay Sajip8d270232012-11-15 14:20:18 +00002554 # As config0, but with properties
2555 config14 = {
2556 'version': 1,
2557 'formatters': {
2558 'form1' : {
2559 'format' : '%(levelname)s ++ %(message)s',
2560 },
2561 },
2562 'handlers' : {
2563 'hand1' : {
2564 'class' : 'logging.StreamHandler',
2565 'formatter' : 'form1',
2566 'level' : 'NOTSET',
2567 'stream' : 'ext://sys.stdout',
2568 '.': {
2569 'foo': 'bar',
2570 'terminator': '!\n',
2571 }
2572 },
2573 },
2574 'root' : {
2575 'level' : 'WARNING',
2576 'handlers' : ['hand1'],
2577 },
2578 }
2579
Vinay Sajip3f885b52013-03-22 15:19:54 +00002580 out_of_order = {
2581 "version": 1,
2582 "formatters": {
2583 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002584 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2585 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002586 }
2587 },
2588 "handlers": {
2589 "fileGlobal": {
2590 "class": "logging.StreamHandler",
2591 "level": "DEBUG",
2592 "formatter": "mySimpleFormatter"
2593 },
2594 "bufferGlobal": {
2595 "class": "logging.handlers.MemoryHandler",
2596 "capacity": 5,
2597 "formatter": "mySimpleFormatter",
2598 "target": "fileGlobal",
2599 "level": "DEBUG"
2600 }
2601 },
2602 "loggers": {
2603 "mymodule": {
2604 "level": "DEBUG",
2605 "handlers": ["bufferGlobal"],
2606 "propagate": "true"
2607 }
2608 }
2609 }
2610
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002611 def apply_config(self, conf):
2612 logging.config.dictConfig(conf)
2613
2614 def test_config0_ok(self):
2615 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002616 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002617 self.apply_config(self.config0)
2618 logger = logging.getLogger()
2619 # Won't output anything
2620 logger.info(self.next_message())
2621 # Outputs a message
2622 logger.error(self.next_message())
2623 self.assert_log_lines([
2624 ('ERROR', '2'),
2625 ], stream=output)
2626 # Original logger output is empty.
2627 self.assert_log_lines([])
2628
2629 def test_config1_ok(self, config=config1):
2630 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002631 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002632 self.apply_config(config)
2633 logger = logging.getLogger("compiler.parser")
2634 # Both will output a message
2635 logger.info(self.next_message())
2636 logger.error(self.next_message())
2637 self.assert_log_lines([
2638 ('INFO', '1'),
2639 ('ERROR', '2'),
2640 ], stream=output)
2641 # Original logger output is empty.
2642 self.assert_log_lines([])
2643
2644 def test_config2_failure(self):
2645 # A simple config which overrides the default settings.
2646 self.assertRaises(Exception, self.apply_config, self.config2)
2647
2648 def test_config2a_failure(self):
2649 # A simple config which overrides the default settings.
2650 self.assertRaises(Exception, self.apply_config, self.config2a)
2651
2652 def test_config2b_failure(self):
2653 # A simple config which overrides the default settings.
2654 self.assertRaises(Exception, self.apply_config, self.config2b)
2655
2656 def test_config3_failure(self):
2657 # A simple config which overrides the default settings.
2658 self.assertRaises(Exception, self.apply_config, self.config3)
2659
2660 def test_config4_ok(self):
2661 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002662 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002663 self.apply_config(self.config4)
2664 #logger = logging.getLogger()
2665 try:
2666 raise RuntimeError()
2667 except RuntimeError:
2668 logging.exception("just testing")
2669 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002670 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002671 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2672 # Original logger output is empty
2673 self.assert_log_lines([])
2674
2675 def test_config4a_ok(self):
2676 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002677 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 self.apply_config(self.config4a)
2679 #logger = logging.getLogger()
2680 try:
2681 raise RuntimeError()
2682 except RuntimeError:
2683 logging.exception("just testing")
2684 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002685 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002686 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2687 # Original logger output is empty
2688 self.assert_log_lines([])
2689
2690 def test_config5_ok(self):
2691 self.test_config1_ok(config=self.config5)
2692
2693 def test_config6_failure(self):
2694 self.assertRaises(Exception, self.apply_config, self.config6)
2695
2696 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002697 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002698 self.apply_config(self.config1)
2699 logger = logging.getLogger("compiler.parser")
2700 # Both will output a message
2701 logger.info(self.next_message())
2702 logger.error(self.next_message())
2703 self.assert_log_lines([
2704 ('INFO', '1'),
2705 ('ERROR', '2'),
2706 ], stream=output)
2707 # Original logger output is empty.
2708 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002709 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002710 self.apply_config(self.config7)
2711 logger = logging.getLogger("compiler.parser")
2712 self.assertTrue(logger.disabled)
2713 logger = logging.getLogger("compiler.lexer")
2714 # Both will output a message
2715 logger.info(self.next_message())
2716 logger.error(self.next_message())
2717 self.assert_log_lines([
2718 ('INFO', '3'),
2719 ('ERROR', '4'),
2720 ], stream=output)
2721 # Original logger output is empty.
2722 self.assert_log_lines([])
2723
Mike53f7a7c2017-12-14 14:04:53 +03002724 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002725 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002726 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002727 self.apply_config(self.config1)
2728 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002729 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002730 logger.info(self.next_message())
2731 logger.error(self.next_message())
2732 self.assert_log_lines([
2733 ('INFO', '1'),
2734 ('ERROR', '2'),
2735 ], stream=output)
2736 # Original logger output is empty.
2737 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002738 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002739 self.apply_config(self.config8)
2740 logger = logging.getLogger("compiler.parser")
2741 self.assertFalse(logger.disabled)
2742 # Both will output a message
2743 logger.info(self.next_message())
2744 logger.error(self.next_message())
2745 logger = logging.getLogger("compiler.lexer")
2746 # Both will output a message
2747 logger.info(self.next_message())
2748 logger.error(self.next_message())
2749 self.assert_log_lines([
2750 ('INFO', '3'),
2751 ('ERROR', '4'),
2752 ('INFO', '5'),
2753 ('ERROR', '6'),
2754 ], stream=output)
2755 # Original logger output is empty.
2756 self.assert_log_lines([])
2757
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002758 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002759 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002760 self.apply_config(self.config1a)
2761 logger = logging.getLogger("compiler.parser")
2762 # See issue #11424. compiler-hyphenated sorts
2763 # between compiler and compiler.xyz and this
2764 # was preventing compiler.xyz from being included
2765 # in the child loggers of compiler because of an
2766 # overzealous loop termination condition.
2767 hyphenated = logging.getLogger('compiler-hyphenated')
2768 # All will output a message
2769 logger.info(self.next_message())
2770 logger.error(self.next_message())
2771 hyphenated.critical(self.next_message())
2772 self.assert_log_lines([
2773 ('INFO', '1'),
2774 ('ERROR', '2'),
2775 ('CRITICAL', '3'),
2776 ], stream=output)
2777 # Original logger output is empty.
2778 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002779 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002780 self.apply_config(self.config8a)
2781 logger = logging.getLogger("compiler.parser")
2782 self.assertFalse(logger.disabled)
2783 # Both will output a message
2784 logger.info(self.next_message())
2785 logger.error(self.next_message())
2786 logger = logging.getLogger("compiler.lexer")
2787 # Both will output a message
2788 logger.info(self.next_message())
2789 logger.error(self.next_message())
2790 # Will not appear
2791 hyphenated.critical(self.next_message())
2792 self.assert_log_lines([
2793 ('INFO', '4'),
2794 ('ERROR', '5'),
2795 ('INFO', '6'),
2796 ('ERROR', '7'),
2797 ], stream=output)
2798 # Original logger output is empty.
2799 self.assert_log_lines([])
2800
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002801 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002802 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002803 self.apply_config(self.config9)
2804 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03002805 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002806 logger.info(self.next_message())
2807 self.assert_log_lines([], stream=output)
2808 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03002809 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002810 logger.info(self.next_message())
2811 self.assert_log_lines([], stream=output)
2812 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03002813 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002814 logger.info(self.next_message())
2815 self.assert_log_lines([
2816 ('INFO', '3'),
2817 ], stream=output)
2818
2819 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002820 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002821 self.apply_config(self.config10)
2822 logger = logging.getLogger("compiler.parser")
2823 logger.warning(self.next_message())
2824 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002825 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002826 logger.warning(self.next_message())
2827 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002828 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002829 logger.warning(self.next_message())
2830 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002831 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002832 logger.error(self.next_message())
2833 self.assert_log_lines([
2834 ('WARNING', '1'),
2835 ('ERROR', '4'),
2836 ], stream=output)
2837
2838 def test_config11_ok(self):
2839 self.test_config1_ok(self.config11)
2840
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002841 def test_config12_failure(self):
2842 self.assertRaises(Exception, self.apply_config, self.config12)
2843
2844 def test_config13_failure(self):
2845 self.assertRaises(Exception, self.apply_config, self.config13)
2846
Vinay Sajip8d270232012-11-15 14:20:18 +00002847 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002848 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002849 self.apply_config(self.config14)
2850 h = logging._handlers['hand1']
2851 self.assertEqual(h.foo, 'bar')
2852 self.assertEqual(h.terminator, '!\n')
2853 logging.warning('Exclamation')
2854 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2855
Vinay Sajip4ded5512012-10-02 15:56:16 +01002856 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002857 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002858 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002859 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002860 t.start()
2861 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002862 # Now get the port allocated
2863 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002864 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002865 try:
2866 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2867 sock.settimeout(2.0)
2868 sock.connect(('localhost', port))
2869
2870 slen = struct.pack('>L', len(text))
2871 s = slen + text
2872 sentsofar = 0
2873 left = len(s)
2874 while left > 0:
2875 sent = sock.send(s[sentsofar:])
2876 sentsofar += sent
2877 left -= sent
2878 sock.close()
2879 finally:
2880 t.ready.wait(2.0)
2881 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07002882 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002883
2884 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002885 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002886 self.setup_via_listener(json.dumps(self.config10))
2887 logger = logging.getLogger("compiler.parser")
2888 logger.warning(self.next_message())
2889 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002890 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002891 logger.warning(self.next_message())
2892 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002893 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002894 logger.warning(self.next_message())
2895 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002896 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002897 logger.error(self.next_message())
2898 self.assert_log_lines([
2899 ('WARNING', '1'),
2900 ('ERROR', '4'),
2901 ], stream=output)
2902
2903 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002904 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002905 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2906 logger = logging.getLogger("compiler.parser")
2907 # Both will output a message
2908 logger.info(self.next_message())
2909 logger.error(self.next_message())
2910 self.assert_log_lines([
2911 ('INFO', '1'),
2912 ('ERROR', '2'),
2913 ], stream=output)
2914 # Original logger output is empty.
2915 self.assert_log_lines([])
2916
Vinay Sajip4ded5512012-10-02 15:56:16 +01002917 def test_listen_verify(self):
2918
2919 def verify_fail(stuff):
2920 return None
2921
2922 def verify_reverse(stuff):
2923 return stuff[::-1]
2924
2925 logger = logging.getLogger("compiler.parser")
2926 to_send = textwrap.dedent(ConfigFileTest.config1)
2927 # First, specify a verification function that will fail.
2928 # We expect to see no output, since our configuration
2929 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002930 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002931 self.setup_via_listener(to_send, verify_fail)
2932 # Both will output a message
2933 logger.info(self.next_message())
2934 logger.error(self.next_message())
2935 self.assert_log_lines([], stream=output)
2936 # Original logger output has the stuff we logged.
2937 self.assert_log_lines([
2938 ('INFO', '1'),
2939 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002940 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002941
2942 # Now, perform no verification. Our configuration
2943 # should take effect.
2944
Vinay Sajip1feedb42014-05-31 08:19:12 +01002945 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002946 self.setup_via_listener(to_send) # no verify callable specified
2947 logger = logging.getLogger("compiler.parser")
2948 # Both will output a message
2949 logger.info(self.next_message())
2950 logger.error(self.next_message())
2951 self.assert_log_lines([
2952 ('INFO', '3'),
2953 ('ERROR', '4'),
2954 ], stream=output)
2955 # Original logger output still has the stuff we logged before.
2956 self.assert_log_lines([
2957 ('INFO', '1'),
2958 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002959 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002960
2961 # Now, perform verification which transforms the bytes.
2962
Vinay Sajip1feedb42014-05-31 08:19:12 +01002963 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002964 self.setup_via_listener(to_send[::-1], verify_reverse)
2965 logger = logging.getLogger("compiler.parser")
2966 # Both will output a message
2967 logger.info(self.next_message())
2968 logger.error(self.next_message())
2969 self.assert_log_lines([
2970 ('INFO', '5'),
2971 ('ERROR', '6'),
2972 ], stream=output)
2973 # Original logger output still has the stuff we logged before.
2974 self.assert_log_lines([
2975 ('INFO', '1'),
2976 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002977 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002978
Vinay Sajip3f885b52013-03-22 15:19:54 +00002979 def test_out_of_order(self):
2980 self.apply_config(self.out_of_order)
2981 handler = logging.getLogger('mymodule').handlers[0]
2982 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002983 self.assertIsInstance(handler.formatter._style,
2984 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002985
Vinay Sajip373baef2011-04-26 20:05:24 +01002986 def test_baseconfig(self):
2987 d = {
2988 'atuple': (1, 2, 3),
2989 'alist': ['a', 'b', 'c'],
2990 'adict': {'d': 'e', 'f': 3 },
2991 'nest1': ('g', ('h', 'i'), 'j'),
2992 'nest2': ['k', ['l', 'm'], 'n'],
2993 'nest3': ['o', 'cfg://alist', 'p'],
2994 }
2995 bc = logging.config.BaseConfigurator(d)
2996 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
2997 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
2998 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
2999 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3000 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3001 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3002 v = bc.convert('cfg://nest3')
3003 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3004 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3005 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3006 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003007
3008class ManagerTest(BaseTest):
3009 def test_manager_loggerclass(self):
3010 logged = []
3011
3012 class MyLogger(logging.Logger):
3013 def _log(self, level, msg, args, exc_info=None, extra=None):
3014 logged.append(msg)
3015
3016 man = logging.Manager(None)
3017 self.assertRaises(TypeError, man.setLoggerClass, int)
3018 man.setLoggerClass(MyLogger)
3019 logger = man.getLogger('test')
3020 logger.warning('should appear in logged')
3021 logging.warning('should not appear in logged')
3022
3023 self.assertEqual(logged, ['should appear in logged'])
3024
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003025 def test_set_log_record_factory(self):
3026 man = logging.Manager(None)
3027 expected = object()
3028 man.setLogRecordFactory(expected)
3029 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003030
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003031class ChildLoggerTest(BaseTest):
3032 def test_child_loggers(self):
3033 r = logging.getLogger()
3034 l1 = logging.getLogger('abc')
3035 l2 = logging.getLogger('def.ghi')
3036 c1 = r.getChild('xyz')
3037 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003038 self.assertIs(c1, logging.getLogger('xyz'))
3039 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003040 c1 = l1.getChild('def')
3041 c2 = c1.getChild('ghi')
3042 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003043 self.assertIs(c1, logging.getLogger('abc.def'))
3044 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3045 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003046
3047
Vinay Sajip6fac8172010-10-19 20:44:14 +00003048class DerivedLogRecord(logging.LogRecord):
3049 pass
3050
Vinay Sajip61561522010-12-03 11:50:38 +00003051class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003052
3053 def setUp(self):
3054 class CheckingFilter(logging.Filter):
3055 def __init__(self, cls):
3056 self.cls = cls
3057
3058 def filter(self, record):
3059 t = type(record)
3060 if t is not self.cls:
3061 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3062 self.cls)
3063 raise TypeError(msg)
3064 return True
3065
3066 BaseTest.setUp(self)
3067 self.filter = CheckingFilter(DerivedLogRecord)
3068 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003069 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003070
3071 def tearDown(self):
3072 self.root_logger.removeFilter(self.filter)
3073 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003074 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003075
3076 def test_logrecord_class(self):
3077 self.assertRaises(TypeError, self.root_logger.warning,
3078 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003079 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003080 self.root_logger.error(self.next_message())
3081 self.assert_log_lines([
3082 ('root', 'ERROR', '2'),
3083 ])
3084
3085
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003086class QueueHandlerTest(BaseTest):
3087 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003088 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003089
3090 def setUp(self):
3091 BaseTest.setUp(self)
3092 self.queue = queue.Queue(-1)
3093 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003094 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003095 self.que_logger = logging.getLogger('que')
3096 self.que_logger.propagate = False
3097 self.que_logger.setLevel(logging.WARNING)
3098 self.que_logger.addHandler(self.que_hdlr)
3099
3100 def tearDown(self):
3101 self.que_hdlr.close()
3102 BaseTest.tearDown(self)
3103
3104 def test_queue_handler(self):
3105 self.que_logger.debug(self.next_message())
3106 self.assertRaises(queue.Empty, self.queue.get_nowait)
3107 self.que_logger.info(self.next_message())
3108 self.assertRaises(queue.Empty, self.queue.get_nowait)
3109 msg = self.next_message()
3110 self.que_logger.warning(msg)
3111 data = self.queue.get_nowait()
3112 self.assertTrue(isinstance(data, logging.LogRecord))
3113 self.assertEqual(data.name, self.que_logger.name)
3114 self.assertEqual((data.msg, data.args), (msg, None))
3115
favlladfe3442017-08-01 20:12:26 +02003116 def test_formatting(self):
3117 msg = self.next_message()
3118 levelname = logging.getLevelName(logging.WARNING)
3119 log_format_str = '{name} -> {levelname}: {message}'
3120 formatted_msg = log_format_str.format(name=self.name,
3121 levelname=levelname, message=msg)
3122 formatter = logging.Formatter(self.log_format)
3123 self.que_hdlr.setFormatter(formatter)
3124 self.que_logger.warning(msg)
3125 log_record = self.queue.get_nowait()
3126 self.assertEqual(formatted_msg, log_record.msg)
3127 self.assertEqual(formatted_msg, log_record.message)
3128
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003129 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3130 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003131 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003132 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003133 listener = logging.handlers.QueueListener(self.queue, handler)
3134 listener.start()
3135 try:
3136 self.que_logger.warning(self.next_message())
3137 self.que_logger.error(self.next_message())
3138 self.que_logger.critical(self.next_message())
3139 finally:
3140 listener.stop()
3141 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3142 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3143 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003144 handler.close()
3145
3146 # Now test with respect_handler_level set
3147
3148 handler = support.TestHandler(support.Matcher())
3149 handler.setLevel(logging.CRITICAL)
3150 listener = logging.handlers.QueueListener(self.queue, handler,
3151 respect_handler_level=True)
3152 listener.start()
3153 try:
3154 self.que_logger.warning(self.next_message())
3155 self.que_logger.error(self.next_message())
3156 self.que_logger.critical(self.next_message())
3157 finally:
3158 listener.stop()
3159 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3160 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3161 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3162
Vinay Sajipd61910c2016-09-08 01:13:39 +01003163if hasattr(logging.handlers, 'QueueListener'):
3164 import multiprocessing
3165 from unittest.mock import patch
3166
3167 class QueueListenerTest(BaseTest):
3168 """
3169 Tests based on patch submitted for issue #27930. Ensure that
3170 QueueListener handles all log messages.
3171 """
3172
3173 repeat = 20
3174
3175 @staticmethod
3176 def setup_and_log(log_queue, ident):
3177 """
3178 Creates a logger with a QueueHandler that logs to a queue read by a
3179 QueueListener. Starts the listener, logs five messages, and stops
3180 the listener.
3181 """
3182 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3183 logger.setLevel(logging.DEBUG)
3184 handler = logging.handlers.QueueHandler(log_queue)
3185 logger.addHandler(handler)
3186 listener = logging.handlers.QueueListener(log_queue)
3187 listener.start()
3188
3189 logger.info('one')
3190 logger.info('two')
3191 logger.info('three')
3192 logger.info('four')
3193 logger.info('five')
3194
3195 listener.stop()
3196 logger.removeHandler(handler)
3197 handler.close()
3198
3199 @patch.object(logging.handlers.QueueListener, 'handle')
3200 def test_handle_called_with_queue_queue(self, mock_handle):
3201 for i in range(self.repeat):
3202 log_queue = queue.Queue()
3203 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3204 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3205 'correct number of handled log messages')
3206
3207 @patch.object(logging.handlers.QueueListener, 'handle')
3208 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003209 # Issue 28668: The multiprocessing (mp) module is not functional
3210 # when the mp.synchronize module cannot be imported.
3211 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003212 for i in range(self.repeat):
3213 log_queue = multiprocessing.Queue()
3214 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003215 log_queue.close()
3216 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003217 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3218 'correct number of handled log messages')
3219
3220 @staticmethod
3221 def get_all_from_queue(log_queue):
3222 try:
3223 while True:
3224 yield log_queue.get_nowait()
3225 except queue.Empty:
3226 return []
3227
3228 def test_no_messages_in_queue_after_stop(self):
3229 """
3230 Five messages are logged then the QueueListener is stopped. This
3231 test then gets everything off the queue. Failure of this test
3232 indicates that messages were not registered on the queue until
3233 _after_ the QueueListener stopped.
3234 """
xdegayebf2b65e2017-12-01 08:08:49 +01003235 # Issue 28668: The multiprocessing (mp) module is not functional
3236 # when the mp.synchronize module cannot be imported.
3237 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003238 for i in range(self.repeat):
3239 queue = multiprocessing.Queue()
3240 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3241 # time.sleep(1)
3242 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003243 queue.close()
3244 queue.join_thread()
3245
Vinay Sajipd61910c2016-09-08 01:13:39 +01003246 expected = [[], [logging.handlers.QueueListener._sentinel]]
3247 self.assertIn(items, expected,
3248 'Found unexpected messages in queue: %s' % (
3249 [m.msg if isinstance(m, logging.LogRecord)
3250 else m for m in items]))
3251
Vinay Sajipe723e962011-04-15 22:27:17 +01003252
Vinay Sajip37eb3382011-04-26 20:26:41 +01003253ZERO = datetime.timedelta(0)
3254
3255class UTC(datetime.tzinfo):
3256 def utcoffset(self, dt):
3257 return ZERO
3258
3259 dst = utcoffset
3260
3261 def tzname(self, dt):
3262 return 'UTC'
3263
3264utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003265
Vinay Sajipa39c5712010-10-25 13:57:39 +00003266class FormatterTest(unittest.TestCase):
3267 def setUp(self):
3268 self.common = {
3269 'name': 'formatter.test',
3270 'level': logging.DEBUG,
3271 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3272 'lineno': 42,
3273 'exc_info': None,
3274 'func': None,
3275 'msg': 'Message with %d %s',
3276 'args': (2, 'placeholders'),
3277 }
3278 self.variants = {
3279 }
3280
3281 def get_record(self, name=None):
3282 result = dict(self.common)
3283 if name is not None:
3284 result.update(self.variants[name])
3285 return logging.makeLogRecord(result)
3286
3287 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003288 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003289 r = self.get_record()
3290 f = logging.Formatter('${%(message)s}')
3291 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3292 f = logging.Formatter('%(random)s')
3293 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003294 self.assertFalse(f.usesTime())
3295 f = logging.Formatter('%(asctime)s')
3296 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003297 f = logging.Formatter('%(asctime)-15s')
3298 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003299 f = logging.Formatter('asctime')
3300 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003301
3302 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003303 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003304 r = self.get_record()
3305 f = logging.Formatter('$%{message}%$', style='{')
3306 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3307 f = logging.Formatter('{random}', style='{')
3308 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003309 self.assertFalse(f.usesTime())
3310 f = logging.Formatter('{asctime}', style='{')
3311 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003312 f = logging.Formatter('{asctime!s:15}', style='{')
3313 self.assertTrue(f.usesTime())
3314 f = logging.Formatter('{asctime:15}', style='{')
3315 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003316 f = logging.Formatter('asctime', style='{')
3317 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003318
3319 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003320 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003321 r = self.get_record()
3322 f = logging.Formatter('$message', style='$')
3323 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3324 f = logging.Formatter('$$%${message}%$$', style='$')
3325 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3326 f = logging.Formatter('${random}', style='$')
3327 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003328 self.assertFalse(f.usesTime())
3329 f = logging.Formatter('${asctime}', style='$')
3330 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003331 f = logging.Formatter('${asctime', style='$')
3332 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003333 f = logging.Formatter('$asctime', style='$')
3334 self.assertTrue(f.usesTime())
3335 f = logging.Formatter('asctime', style='$')
3336 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003337
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003338 def test_invalid_style(self):
3339 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3340
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003341 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003342 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003343 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3344 # We use None to indicate we want the local timezone
3345 # We're essentially converting a UTC time to local time
3346 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003347 r.msecs = 123
3348 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003349 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003350 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3351 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003352 f.format(r)
3353 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3354
3355class TestBufferingFormatter(logging.BufferingFormatter):
3356 def formatHeader(self, records):
3357 return '[(%d)' % len(records)
3358
3359 def formatFooter(self, records):
3360 return '(%d)]' % len(records)
3361
3362class BufferingFormatterTest(unittest.TestCase):
3363 def setUp(self):
3364 self.records = [
3365 logging.makeLogRecord({'msg': 'one'}),
3366 logging.makeLogRecord({'msg': 'two'}),
3367 ]
3368
3369 def test_default(self):
3370 f = logging.BufferingFormatter()
3371 self.assertEqual('', f.format([]))
3372 self.assertEqual('onetwo', f.format(self.records))
3373
3374 def test_custom(self):
3375 f = TestBufferingFormatter()
3376 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3377 lf = logging.Formatter('<%(message)s>')
3378 f = TestBufferingFormatter(lf)
3379 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003380
3381class ExceptionTest(BaseTest):
3382 def test_formatting(self):
3383 r = self.root_logger
3384 h = RecordingHandler()
3385 r.addHandler(h)
3386 try:
3387 raise RuntimeError('deliberate mistake')
3388 except:
3389 logging.exception('failed', stack_info=True)
3390 r.removeHandler(h)
3391 h.close()
3392 r = h.records[0]
3393 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3394 'call last):\n'))
3395 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3396 'deliberate mistake'))
3397 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3398 'call last):\n'))
3399 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3400 'stack_info=True)'))
3401
3402
Vinay Sajip5a27d402010-12-10 11:42:57 +00003403class LastResortTest(BaseTest):
3404 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003405 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003406 root = self.root_logger
3407 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003408 old_lastresort = logging.lastResort
3409 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003410
Vinay Sajip5a27d402010-12-10 11:42:57 +00003411 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003412 with support.captured_stderr() as stderr:
3413 root.debug('This should not appear')
3414 self.assertEqual(stderr.getvalue(), '')
3415 root.warning('Final chance!')
3416 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3417
3418 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003419 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003420 with support.captured_stderr() as stderr:
3421 root.warning('Final chance!')
3422 msg = 'No handlers could be found for logger "root"\n'
3423 self.assertEqual(stderr.getvalue(), msg)
3424
Vinay Sajip5a27d402010-12-10 11:42:57 +00003425 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003426 with support.captured_stderr() as stderr:
3427 root.warning('Final chance!')
3428 self.assertEqual(stderr.getvalue(), '')
3429
3430 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003431 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003432 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003433 with support.captured_stderr() as stderr:
3434 root.warning('Final chance!')
3435 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003436 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003437 root.addHandler(self.root_hdlr)
3438 logging.lastResort = old_lastresort
3439 logging.raiseExceptions = old_raise_exceptions
3440
3441
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003442class FakeHandler:
3443
3444 def __init__(self, identifier, called):
3445 for method in ('acquire', 'flush', 'close', 'release'):
3446 setattr(self, method, self.record_call(identifier, method, called))
3447
3448 def record_call(self, identifier, method_name, called):
3449 def inner():
3450 called.append('{} - {}'.format(identifier, method_name))
3451 return inner
3452
3453
3454class RecordingHandler(logging.NullHandler):
3455
3456 def __init__(self, *args, **kwargs):
3457 super(RecordingHandler, self).__init__(*args, **kwargs)
3458 self.records = []
3459
3460 def handle(self, record):
3461 """Keep track of all the emitted records."""
3462 self.records.append(record)
3463
3464
3465class ShutdownTest(BaseTest):
3466
Vinay Sajip5e66b162011-04-20 15:41:14 +01003467 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003468
3469 def setUp(self):
3470 super(ShutdownTest, self).setUp()
3471 self.called = []
3472
3473 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003474 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003475
3476 def raise_error(self, error):
3477 def inner():
3478 raise error()
3479 return inner
3480
3481 def test_no_failure(self):
3482 # create some fake handlers
3483 handler0 = FakeHandler(0, self.called)
3484 handler1 = FakeHandler(1, self.called)
3485 handler2 = FakeHandler(2, self.called)
3486
3487 # create live weakref to those handlers
3488 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3489
3490 logging.shutdown(handlerList=list(handlers))
3491
3492 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3493 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3494 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3495 self.assertEqual(expected, self.called)
3496
3497 def _test_with_failure_in_method(self, method, error):
3498 handler = FakeHandler(0, self.called)
3499 setattr(handler, method, self.raise_error(error))
3500 handlers = [logging.weakref.ref(handler)]
3501
3502 logging.shutdown(handlerList=list(handlers))
3503
3504 self.assertEqual('0 - release', self.called[-1])
3505
3506 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003507 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003508
3509 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003510 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003511
3512 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003513 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003514
3515 def test_with_valueerror_in_acquire(self):
3516 self._test_with_failure_in_method('acquire', ValueError)
3517
3518 def test_with_valueerror_in_flush(self):
3519 self._test_with_failure_in_method('flush', ValueError)
3520
3521 def test_with_valueerror_in_close(self):
3522 self._test_with_failure_in_method('close', ValueError)
3523
3524 def test_with_other_error_in_acquire_without_raise(self):
3525 logging.raiseExceptions = False
3526 self._test_with_failure_in_method('acquire', IndexError)
3527
3528 def test_with_other_error_in_flush_without_raise(self):
3529 logging.raiseExceptions = False
3530 self._test_with_failure_in_method('flush', IndexError)
3531
3532 def test_with_other_error_in_close_without_raise(self):
3533 logging.raiseExceptions = False
3534 self._test_with_failure_in_method('close', IndexError)
3535
3536 def test_with_other_error_in_acquire_with_raise(self):
3537 logging.raiseExceptions = True
3538 self.assertRaises(IndexError, self._test_with_failure_in_method,
3539 'acquire', IndexError)
3540
3541 def test_with_other_error_in_flush_with_raise(self):
3542 logging.raiseExceptions = True
3543 self.assertRaises(IndexError, self._test_with_failure_in_method,
3544 'flush', IndexError)
3545
3546 def test_with_other_error_in_close_with_raise(self):
3547 logging.raiseExceptions = True
3548 self.assertRaises(IndexError, self._test_with_failure_in_method,
3549 'close', IndexError)
3550
3551
3552class ModuleLevelMiscTest(BaseTest):
3553
Vinay Sajip5e66b162011-04-20 15:41:14 +01003554 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003555
3556 def test_disable(self):
3557 old_disable = logging.root.manager.disable
3558 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003559 self.assertEqual(old_disable, 0)
3560 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003561
3562 logging.disable(83)
3563 self.assertEqual(logging.root.manager.disable, 83)
3564
Vinay Sajipd489ac92016-12-31 11:40:11 +00003565 # test the default value introduced in 3.7
3566 # (Issue #28524)
3567 logging.disable()
3568 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3569
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003570 def _test_log(self, method, level=None):
3571 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003572 support.patch(self, logging, 'basicConfig',
3573 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003574
3575 recording = RecordingHandler()
3576 logging.root.addHandler(recording)
3577
3578 log_method = getattr(logging, method)
3579 if level is not None:
3580 log_method(level, "test me: %r", recording)
3581 else:
3582 log_method("test me: %r", recording)
3583
3584 self.assertEqual(len(recording.records), 1)
3585 record = recording.records[0]
3586 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3587
3588 expected_level = level if level is not None else getattr(logging, method.upper())
3589 self.assertEqual(record.levelno, expected_level)
3590
3591 # basicConfig was not called!
3592 self.assertEqual(called, [])
3593
3594 def test_log(self):
3595 self._test_log('log', logging.ERROR)
3596
3597 def test_debug(self):
3598 self._test_log('debug')
3599
3600 def test_info(self):
3601 self._test_log('info')
3602
3603 def test_warning(self):
3604 self._test_log('warning')
3605
3606 def test_error(self):
3607 self._test_log('error')
3608
3609 def test_critical(self):
3610 self._test_log('critical')
3611
3612 def test_set_logger_class(self):
3613 self.assertRaises(TypeError, logging.setLoggerClass, object)
3614
3615 class MyLogger(logging.Logger):
3616 pass
3617
3618 logging.setLoggerClass(MyLogger)
3619 self.assertEqual(logging.getLoggerClass(), MyLogger)
3620
3621 logging.setLoggerClass(logging.Logger)
3622 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3623
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003624 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003625 def test_logging_at_shutdown(self):
3626 # Issue #20037
3627 code = """if 1:
3628 import logging
3629
3630 class A:
3631 def __del__(self):
3632 try:
3633 raise ValueError("some error")
3634 except Exception:
3635 logging.exception("exception in __del__")
3636
3637 a = A()"""
3638 rc, out, err = assert_python_ok("-c", code)
3639 err = err.decode()
3640 self.assertIn("exception in __del__", err)
3641 self.assertIn("ValueError: some error", err)
3642
3643
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003644class LogRecordTest(BaseTest):
3645 def test_str_rep(self):
3646 r = logging.makeLogRecord({})
3647 s = str(r)
3648 self.assertTrue(s.startswith('<LogRecord: '))
3649 self.assertTrue(s.endswith('>'))
3650
3651 def test_dict_arg(self):
3652 h = RecordingHandler()
3653 r = logging.getLogger()
3654 r.addHandler(h)
3655 d = {'less' : 'more' }
3656 logging.warning('less is %(less)s', d)
3657 self.assertIs(h.records[0].args, d)
3658 self.assertEqual(h.records[0].message, 'less is more')
3659 r.removeHandler(h)
3660 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003661
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003662 def test_multiprocessing(self):
3663 r = logging.makeLogRecord({})
3664 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003665 try:
3666 import multiprocessing as mp
3667 r = logging.makeLogRecord({})
3668 self.assertEqual(r.processName, mp.current_process().name)
3669 except ImportError:
3670 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003671
3672 def test_optional(self):
3673 r = logging.makeLogRecord({})
3674 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003675 NOT_NONE(r.thread)
3676 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003677 NOT_NONE(r.process)
3678 NOT_NONE(r.processName)
3679 log_threads = logging.logThreads
3680 log_processes = logging.logProcesses
3681 log_multiprocessing = logging.logMultiprocessing
3682 try:
3683 logging.logThreads = False
3684 logging.logProcesses = False
3685 logging.logMultiprocessing = False
3686 r = logging.makeLogRecord({})
3687 NONE = self.assertIsNone
3688 NONE(r.thread)
3689 NONE(r.threadName)
3690 NONE(r.process)
3691 NONE(r.processName)
3692 finally:
3693 logging.logThreads = log_threads
3694 logging.logProcesses = log_processes
3695 logging.logMultiprocessing = log_multiprocessing
3696
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003697class BasicConfigTest(unittest.TestCase):
3698
Vinay Sajip95bf5042011-04-20 11:50:56 +01003699 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003700
3701 def setUp(self):
3702 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003703 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003704 self.saved_handlers = logging._handlers.copy()
3705 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003706 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003707 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003708 logging.root.handlers = []
3709
3710 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003711 for h in logging.root.handlers[:]:
3712 logging.root.removeHandler(h)
3713 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003714 super(BasicConfigTest, self).tearDown()
3715
Vinay Sajip3def7e02011-04-20 10:58:06 +01003716 def cleanup(self):
3717 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003718 logging._handlers.clear()
3719 logging._handlers.update(self.saved_handlers)
3720 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003721 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003722
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003723 def test_no_kwargs(self):
3724 logging.basicConfig()
3725
3726 # handler defaults to a StreamHandler to sys.stderr
3727 self.assertEqual(len(logging.root.handlers), 1)
3728 handler = logging.root.handlers[0]
3729 self.assertIsInstance(handler, logging.StreamHandler)
3730 self.assertEqual(handler.stream, sys.stderr)
3731
3732 formatter = handler.formatter
3733 # format defaults to logging.BASIC_FORMAT
3734 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3735 # datefmt defaults to None
3736 self.assertIsNone(formatter.datefmt)
3737 # style defaults to %
3738 self.assertIsInstance(formatter._style, logging.PercentStyle)
3739
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003740 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003741 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003742
Vinay Sajip1fd12022014-01-13 21:59:56 +00003743 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003744 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003745 logging.basicConfig(stream=sys.stdout, style="{")
3746 logging.error("Log an error")
3747 sys.stdout.seek(0)
3748 self.assertEqual(output.getvalue().strip(),
3749 "ERROR:root:Log an error")
3750
3751 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003752 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003753 logging.basicConfig(stream=sys.stdout, style="$")
3754 logging.error("Log an error")
3755 sys.stdout.seek(0)
3756 self.assertEqual(output.getvalue().strip(),
3757 "ERROR:root:Log an error")
3758
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003759 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003760
3761 def cleanup(h1, h2, fn):
3762 h1.close()
3763 h2.close()
3764 os.remove(fn)
3765
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003766 logging.basicConfig(filename='test.log')
3767
3768 self.assertEqual(len(logging.root.handlers), 1)
3769 handler = logging.root.handlers[0]
3770 self.assertIsInstance(handler, logging.FileHandler)
3771
3772 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003773 self.assertEqual(handler.stream.mode, expected.stream.mode)
3774 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003775 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003776
3777 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003778
3779 def cleanup(h1, h2, fn):
3780 h1.close()
3781 h2.close()
3782 os.remove(fn)
3783
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003784 logging.basicConfig(filename='test.log', filemode='wb')
3785
3786 handler = logging.root.handlers[0]
3787 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003788 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003789 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003790
3791 def test_stream(self):
3792 stream = io.StringIO()
3793 self.addCleanup(stream.close)
3794 logging.basicConfig(stream=stream)
3795
3796 self.assertEqual(len(logging.root.handlers), 1)
3797 handler = logging.root.handlers[0]
3798 self.assertIsInstance(handler, logging.StreamHandler)
3799 self.assertEqual(handler.stream, stream)
3800
3801 def test_format(self):
3802 logging.basicConfig(format='foo')
3803
3804 formatter = logging.root.handlers[0].formatter
3805 self.assertEqual(formatter._style._fmt, 'foo')
3806
3807 def test_datefmt(self):
3808 logging.basicConfig(datefmt='bar')
3809
3810 formatter = logging.root.handlers[0].formatter
3811 self.assertEqual(formatter.datefmt, 'bar')
3812
3813 def test_style(self):
3814 logging.basicConfig(style='$')
3815
3816 formatter = logging.root.handlers[0].formatter
3817 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3818
3819 def test_level(self):
3820 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003821 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003822
3823 logging.basicConfig(level=57)
3824 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003825 # Test that second call has no effect
3826 logging.basicConfig(level=58)
3827 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003828
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003829 def test_incompatible(self):
3830 assertRaises = self.assertRaises
3831 handlers = [logging.StreamHandler()]
3832 stream = sys.stderr
3833 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3834 stream=stream)
3835 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3836 handlers=handlers)
3837 assertRaises(ValueError, logging.basicConfig, stream=stream,
3838 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003839 # Issue 23207: test for invalid kwargs
3840 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3841 # Should pop both filename and filemode even if filename is None
3842 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003843
3844 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003845 handlers = [
3846 logging.StreamHandler(),
3847 logging.StreamHandler(sys.stdout),
3848 logging.StreamHandler(),
3849 ]
3850 f = logging.Formatter()
3851 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003852 logging.basicConfig(handlers=handlers)
3853 self.assertIs(handlers[0], logging.root.handlers[0])
3854 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003855 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003856 self.assertIsNotNone(handlers[0].formatter)
3857 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003858 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003859 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3860
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003861 def _test_log(self, method, level=None):
3862 # logging.root has no handlers so basicConfig should be called
3863 called = []
3864
3865 old_basic_config = logging.basicConfig
3866 def my_basic_config(*a, **kw):
3867 old_basic_config()
3868 old_level = logging.root.level
3869 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003870 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003871 called.append((a, kw))
3872
Vinay Sajip1feedb42014-05-31 08:19:12 +01003873 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003874
3875 log_method = getattr(logging, method)
3876 if level is not None:
3877 log_method(level, "test me")
3878 else:
3879 log_method("test me")
3880
3881 # basicConfig was called with no arguments
3882 self.assertEqual(called, [((), {})])
3883
3884 def test_log(self):
3885 self._test_log('log', logging.WARNING)
3886
3887 def test_debug(self):
3888 self._test_log('debug')
3889
3890 def test_info(self):
3891 self._test_log('info')
3892
3893 def test_warning(self):
3894 self._test_log('warning')
3895
3896 def test_error(self):
3897 self._test_log('error')
3898
3899 def test_critical(self):
3900 self._test_log('critical')
3901
3902
3903class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003904 def setUp(self):
3905 super(LoggerAdapterTest, self).setUp()
3906 old_handler_list = logging._handlerList[:]
3907
3908 self.recording = RecordingHandler()
3909 self.logger = logging.root
3910 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003911 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003912 self.addCleanup(self.recording.close)
3913
3914 def cleanup():
3915 logging._handlerList[:] = old_handler_list
3916
3917 self.addCleanup(cleanup)
3918 self.addCleanup(logging.shutdown)
3919 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3920
3921 def test_exception(self):
3922 msg = 'testing exception: %r'
3923 exc = None
3924 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003925 1 / 0
3926 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003927 exc = e
3928 self.adapter.exception(msg, self.recording)
3929
3930 self.assertEqual(len(self.recording.records), 1)
3931 record = self.recording.records[0]
3932 self.assertEqual(record.levelno, logging.ERROR)
3933 self.assertEqual(record.msg, msg)
3934 self.assertEqual(record.args, (self.recording,))
3935 self.assertEqual(record.exc_info,
3936 (exc.__class__, exc, exc.__traceback__))
3937
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003938 def test_exception_excinfo(self):
3939 try:
3940 1 / 0
3941 except ZeroDivisionError as e:
3942 exc = e
3943
3944 self.adapter.exception('exc_info test', exc_info=exc)
3945
3946 self.assertEqual(len(self.recording.records), 1)
3947 record = self.recording.records[0]
3948 self.assertEqual(record.exc_info,
3949 (exc.__class__, exc, exc.__traceback__))
3950
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003951 def test_critical(self):
3952 msg = 'critical test! %r'
3953 self.adapter.critical(msg, self.recording)
3954
3955 self.assertEqual(len(self.recording.records), 1)
3956 record = self.recording.records[0]
3957 self.assertEqual(record.levelno, logging.CRITICAL)
3958 self.assertEqual(record.msg, msg)
3959 self.assertEqual(record.args, (self.recording,))
3960
3961 def test_is_enabled_for(self):
3962 old_disable = self.adapter.logger.manager.disable
3963 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003964 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3965 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003966 self.assertFalse(self.adapter.isEnabledFor(32))
3967
3968 def test_has_handlers(self):
3969 self.assertTrue(self.adapter.hasHandlers())
3970
3971 for handler in self.logger.handlers:
3972 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003973
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003974 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003975 self.assertFalse(self.adapter.hasHandlers())
3976
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003977 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07003978 class Adapter(logging.LoggerAdapter):
3979 prefix = 'Adapter'
3980
3981 def process(self, msg, kwargs):
3982 return f"{self.prefix} {msg}", kwargs
3983
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003984 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07003985 adapter = Adapter(logger=self.logger, extra=None)
3986 adapter_adapter = Adapter(logger=adapter, extra=None)
3987 adapter_adapter.prefix = 'AdapterAdapter'
3988 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003989 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003990 self.assertEqual(len(self.recording.records), 1)
3991 record = self.recording.records[0]
3992 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07003993 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003994 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07003995 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07003996 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07003997 self.assertIs(self.logger.manager, orig_manager)
3998 temp_manager = object()
3999 try:
4000 adapter_adapter.manager = temp_manager
4001 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004002 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004003 self.assertIs(self.logger.manager, temp_manager)
4004 finally:
4005 adapter_adapter.manager = orig_manager
4006 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004007 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004008 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004009
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004010
4011class LoggerTest(BaseTest):
4012
4013 def setUp(self):
4014 super(LoggerTest, self).setUp()
4015 self.recording = RecordingHandler()
4016 self.logger = logging.Logger(name='blah')
4017 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004018 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004019 self.addCleanup(self.recording.close)
4020 self.addCleanup(logging.shutdown)
4021
4022 def test_set_invalid_level(self):
4023 self.assertRaises(TypeError, self.logger.setLevel, object())
4024
4025 def test_exception(self):
4026 msg = 'testing exception: %r'
4027 exc = None
4028 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004029 1 / 0
4030 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004031 exc = e
4032 self.logger.exception(msg, self.recording)
4033
4034 self.assertEqual(len(self.recording.records), 1)
4035 record = self.recording.records[0]
4036 self.assertEqual(record.levelno, logging.ERROR)
4037 self.assertEqual(record.msg, msg)
4038 self.assertEqual(record.args, (self.recording,))
4039 self.assertEqual(record.exc_info,
4040 (exc.__class__, exc, exc.__traceback__))
4041
4042 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004043 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004044 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004045
4046 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004047 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004048 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004049
4050 def test_find_caller_with_stack_info(self):
4051 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004052 support.patch(self, logging.traceback, 'print_stack',
4053 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004054
4055 self.logger.findCaller(stack_info=True)
4056
4057 self.assertEqual(len(called), 1)
4058 self.assertEqual('Stack (most recent call last):\n', called[0])
4059
4060 def test_make_record_with_extra_overwrite(self):
4061 name = 'my record'
4062 level = 13
4063 fn = lno = msg = args = exc_info = func = sinfo = None
4064 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4065 exc_info, func, sinfo)
4066
4067 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4068 extra = {key: 'some value'}
4069 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4070 fn, lno, msg, args, exc_info,
4071 extra=extra, sinfo=sinfo)
4072
4073 def test_make_record_with_extra_no_overwrite(self):
4074 name = 'my record'
4075 level = 13
4076 fn = lno = msg = args = exc_info = func = sinfo = None
4077 extra = {'valid_key': 'some value'}
4078 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4079 exc_info, extra=extra, sinfo=sinfo)
4080 self.assertIn('valid_key', result.__dict__)
4081
4082 def test_has_handlers(self):
4083 self.assertTrue(self.logger.hasHandlers())
4084
4085 for handler in self.logger.handlers:
4086 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004087 self.assertFalse(self.logger.hasHandlers())
4088
4089 def test_has_handlers_no_propagate(self):
4090 child_logger = logging.getLogger('blah.child')
4091 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004092 self.assertFalse(child_logger.hasHandlers())
4093
4094 def test_is_enabled_for(self):
4095 old_disable = self.logger.manager.disable
4096 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004097 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004098 self.assertFalse(self.logger.isEnabledFor(22))
4099
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004100 def test_root_logger_aliases(self):
4101 root = logging.getLogger()
4102 self.assertIs(root, logging.root)
4103 self.assertIs(root, logging.getLogger(None))
4104 self.assertIs(root, logging.getLogger(''))
4105 self.assertIs(root, logging.getLogger('foo').root)
4106 self.assertIs(root, logging.getLogger('foo.bar').root)
4107 self.assertIs(root, logging.getLogger('foo').parent)
4108
4109 self.assertIsNot(root, logging.getLogger('\0'))
4110 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4111
4112 def test_invalid_names(self):
4113 self.assertRaises(TypeError, logging.getLogger, any)
4114 self.assertRaises(TypeError, logging.getLogger, b'foo')
4115
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004116 def test_pickling(self):
4117 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4118 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4119 logger = logging.getLogger(name)
4120 s = pickle.dumps(logger, proto)
4121 unpickled = pickle.loads(s)
4122 self.assertIs(unpickled, logger)
4123
Avram Lubkin78c18a92017-07-30 05:36:33 -04004124 def test_caching(self):
4125 root = self.root_logger
4126 logger1 = logging.getLogger("abc")
4127 logger2 = logging.getLogger("abc.def")
4128
4129 # Set root logger level and ensure cache is empty
4130 root.setLevel(logging.ERROR)
4131 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4132 self.assertEqual(logger2._cache, {})
4133
4134 # Ensure cache is populated and calls are consistent
4135 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4136 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4137 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4138 self.assertEqual(root._cache, {})
4139 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4140
4141 # Ensure root cache gets populated
4142 self.assertEqual(root._cache, {})
4143 self.assertTrue(root.isEnabledFor(logging.ERROR))
4144 self.assertEqual(root._cache, {logging.ERROR: True})
4145
4146 # Set parent logger level and ensure caches are emptied
4147 logger1.setLevel(logging.CRITICAL)
4148 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4149 self.assertEqual(logger2._cache, {})
4150
4151 # Ensure logger2 uses parent logger's effective level
4152 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4153
4154 # Set level to NOTSET and ensure caches are empty
4155 logger2.setLevel(logging.NOTSET)
4156 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4157 self.assertEqual(logger2._cache, {})
4158 self.assertEqual(logger1._cache, {})
4159 self.assertEqual(root._cache, {})
4160
4161 # Verify logger2 follows parent and not root
4162 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4163 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4164 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4165 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4166 self.assertTrue(root.isEnabledFor(logging.ERROR))
4167
4168 # Disable logging in manager and ensure caches are clear
4169 logging.disable()
4170 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4171 self.assertEqual(logger2._cache, {})
4172 self.assertEqual(logger1._cache, {})
4173 self.assertEqual(root._cache, {})
4174
4175 # Ensure no loggers are enabled
4176 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4177 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4178 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4179
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004180
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004181class BaseFileTest(BaseTest):
4182 "Base class for handler tests that write log files"
4183
4184 def setUp(self):
4185 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004186 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4187 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004188 self.rmfiles = []
4189
4190 def tearDown(self):
4191 for fn in self.rmfiles:
4192 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004193 if os.path.exists(self.fn):
4194 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004195 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004196
4197 def assertLogFile(self, filename):
4198 "Assert a log file is there and register it for deletion"
4199 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004200 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004201 self.rmfiles.append(filename)
4202
4203
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004204class FileHandlerTest(BaseFileTest):
4205 def test_delay(self):
4206 os.unlink(self.fn)
4207 fh = logging.FileHandler(self.fn, delay=True)
4208 self.assertIsNone(fh.stream)
4209 self.assertFalse(os.path.exists(self.fn))
4210 fh.handle(logging.makeLogRecord({}))
4211 self.assertIsNotNone(fh.stream)
4212 self.assertTrue(os.path.exists(self.fn))
4213 fh.close()
4214
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004215class RotatingFileHandlerTest(BaseFileTest):
4216 def next_rec(self):
4217 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4218 self.next_message(), None, None, None)
4219
4220 def test_should_not_rollover(self):
4221 # If maxbytes is zero rollover never occurs
4222 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4223 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004224 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004225
4226 def test_should_rollover(self):
4227 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4228 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004229 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004230
4231 def test_file_created(self):
4232 # checks that the file is created and assumes it was created
4233 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004234 rh = logging.handlers.RotatingFileHandler(self.fn)
4235 rh.emit(self.next_rec())
4236 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004237 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004238
4239 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004240 def namer(name):
4241 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004242 rh = logging.handlers.RotatingFileHandler(
4243 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004244 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004245 rh.emit(self.next_rec())
4246 self.assertLogFile(self.fn)
4247 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004248 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004249 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004250 self.assertLogFile(namer(self.fn + ".2"))
4251 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4252 rh.close()
4253
Vinay Sajip1feedb42014-05-31 08:19:12 +01004254 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004255 def test_rotator(self):
4256 def namer(name):
4257 return name + ".gz"
4258
4259 def rotator(source, dest):
4260 with open(source, "rb") as sf:
4261 data = sf.read()
4262 compressed = zlib.compress(data, 9)
4263 with open(dest, "wb") as df:
4264 df.write(compressed)
4265 os.remove(source)
4266
4267 rh = logging.handlers.RotatingFileHandler(
4268 self.fn, backupCount=2, maxBytes=1)
4269 rh.rotator = rotator
4270 rh.namer = namer
4271 m1 = self.next_rec()
4272 rh.emit(m1)
4273 self.assertLogFile(self.fn)
4274 m2 = self.next_rec()
4275 rh.emit(m2)
4276 fn = namer(self.fn + ".1")
4277 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004278 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004279 with open(fn, "rb") as f:
4280 compressed = f.read()
4281 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004282 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004283 rh.emit(self.next_rec())
4284 fn = namer(self.fn + ".2")
4285 self.assertLogFile(fn)
4286 with open(fn, "rb") as f:
4287 compressed = f.read()
4288 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004289 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004290 rh.emit(self.next_rec())
4291 fn = namer(self.fn + ".2")
4292 with open(fn, "rb") as f:
4293 compressed = f.read()
4294 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004295 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004296 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004297 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004298
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004299class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004300 # other test methods added below
4301 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004302 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4303 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004304 fmt = logging.Formatter('%(asctime)s %(message)s')
4305 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004306 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004307 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004308 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004309 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004310 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004311 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004312 fh.close()
4313 # At this point, we should have a recent rotated file which we
4314 # can test for the existence of. However, in practice, on some
4315 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004316 # in time to go to look for the log file. So, we go back a fair
4317 # bit, and stop as soon as we see a rotated file. In theory this
4318 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004319 found = False
4320 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004321 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004322 for secs in range(GO_BACK):
4323 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004324 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4325 found = os.path.exists(fn)
4326 if found:
4327 self.rmfiles.append(fn)
4328 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004329 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4330 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004331 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004332 dn, fn = os.path.split(self.fn)
4333 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004334 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4335 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004336 for f in files:
4337 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004338 path = os.path.join(dn, f)
4339 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004340 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004341 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004342
Vinay Sajip0372e102011-05-05 12:59:14 +01004343 def test_invalid(self):
4344 assertRaises = self.assertRaises
4345 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004346 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004347 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004348 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004349 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004350 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004351
Vinay Sajipa7130792013-04-12 17:04:23 +01004352 def test_compute_rollover_daily_attime(self):
4353 currentTime = 0
4354 atTime = datetime.time(12, 0, 0)
4355 rh = logging.handlers.TimedRotatingFileHandler(
4356 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4357 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004358 try:
4359 actual = rh.computeRollover(currentTime)
4360 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004361
Vinay Sajipd86ac962013-04-14 12:20:46 +01004362 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4363 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4364 finally:
4365 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004366
Vinay Sajip10e8c492013-05-18 10:19:54 -07004367 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004368 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004369 currentTime = int(time.time())
4370 today = currentTime - currentTime % 86400
4371
Vinay Sajipa7130792013-04-12 17:04:23 +01004372 atTime = datetime.time(12, 0, 0)
4373
Vinay Sajip10e8c492013-05-18 10:19:54 -07004374 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004375 for day in range(7):
4376 rh = logging.handlers.TimedRotatingFileHandler(
4377 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4378 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004379 try:
4380 if wday > day:
4381 # The rollover day has already passed this week, so we
4382 # go over into next week
4383 expected = (7 - wday + day)
4384 else:
4385 expected = (day - wday)
4386 # At this point expected is in days from now, convert to seconds
4387 expected *= 24 * 60 * 60
4388 # Add in the rollover time
4389 expected += 12 * 60 * 60
4390 # Add in adjustment for today
4391 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004392 actual = rh.computeRollover(today)
4393 if actual != expected:
4394 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004395 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004396 self.assertEqual(actual, expected)
4397 if day == wday:
4398 # goes into following week
4399 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004400 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004401 if actual != expected:
4402 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004403 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004404 self.assertEqual(actual, expected)
4405 finally:
4406 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004407
4408
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004409def secs(**kw):
4410 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4411
4412for when, exp in (('S', 1),
4413 ('M', 60),
4414 ('H', 60 * 60),
4415 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004416 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004417 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004418 ('W0', secs(days=4, hours=24)),
4419 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004420 def test_compute_rollover(self, when=when, exp=exp):
4421 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004422 self.fn, when=when, interval=1, backupCount=0, utc=True)
4423 currentTime = 0.0
4424 actual = rh.computeRollover(currentTime)
4425 if exp != actual:
4426 # Failures occur on some systems for MIDNIGHT and W0.
4427 # Print detailed calculation for MIDNIGHT so we can try to see
4428 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004429 if when == 'MIDNIGHT':
4430 try:
4431 if rh.utc:
4432 t = time.gmtime(currentTime)
4433 else:
4434 t = time.localtime(currentTime)
4435 currentHour = t[3]
4436 currentMinute = t[4]
4437 currentSecond = t[5]
4438 # r is the number of seconds left between now and midnight
4439 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4440 currentMinute) * 60 +
4441 currentSecond)
4442 result = currentTime + r
4443 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4444 print('currentHour: %s' % currentHour, file=sys.stderr)
4445 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4446 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4447 print('r: %s' % r, file=sys.stderr)
4448 print('result: %s' % result, file=sys.stderr)
4449 except Exception:
4450 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4451 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004452 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004453 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4454
Vinay Sajip60ccd822011-05-09 17:32:09 +01004455
Vinay Sajip223349c2015-10-01 20:37:54 +01004456@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004457class NTEventLogHandlerTest(BaseTest):
4458 def test_basic(self):
4459 logtype = 'Application'
4460 elh = win32evtlog.OpenEventLog(None, logtype)
4461 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004462
4463 try:
4464 h = logging.handlers.NTEventLogHandler('test_logging')
4465 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004466 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004467 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004468 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004469
Vinay Sajip60ccd822011-05-09 17:32:09 +01004470 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4471 h.handle(r)
4472 h.close()
4473 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004474 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004475 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4476 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4477 found = False
4478 GO_BACK = 100
4479 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4480 for e in events:
4481 if e.SourceName != 'test_logging':
4482 continue
4483 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4484 if msg != 'Test Log Message\r\n':
4485 continue
4486 found = True
4487 break
4488 msg = 'Record not found in event log, went back %d records' % GO_BACK
4489 self.assertTrue(found, msg=msg)
4490
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004491
4492class MiscTestCase(unittest.TestCase):
4493 def test__all__(self):
4494 blacklist = {'logThreads', 'logMultiprocessing',
4495 'logProcesses', 'currentframe',
4496 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4497 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004498 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004499 support.check__all__(self, logging, blacklist=blacklist)
4500
4501
Christian Heimes180510d2008-03-03 19:15:45 +00004502# Set the locale to the platform-dependent default. I have no idea
4503# why the test does this, but in any case we save the current locale
4504# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004505@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004506def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004507 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004508 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4509 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4510 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4511 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4512 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4513 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4514 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4515 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004516 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004517 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004518 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004519 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004520 ]
4521 if hasattr(logging.handlers, 'QueueListener'):
4522 tests.append(QueueListenerTest)
4523 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004524
Christian Heimes180510d2008-03-03 19:15:45 +00004525if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004526 test_main()