blob: ba70b117d1e69cf208fb2af557788739cbc48373 [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
Łukasz Langa214f18e2018-06-08 04:02:48 -07001454 def test_defaults_do_no_interpolation(self):
1455 """bpo-33802 defaults should not get interpolated"""
1456 ini = textwrap.dedent("""
1457 [formatters]
1458 keys=default
1459
1460 [formatter_default]
1461
1462 [handlers]
1463 keys=console
1464
1465 [handler_console]
1466 class=logging.StreamHandler
1467 args=tuple()
1468
1469 [loggers]
1470 keys=root
1471
1472 [logger_root]
1473 formatter=default
1474 handlers=console
1475 """).strip()
1476 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
1477 try:
1478 os.write(fd, ini.encode('ascii'))
1479 os.close(fd)
1480 logging.config.fileConfig(
1481 fn,
1482 defaults=dict(
1483 version=1,
1484 disable_existing_loggers=False,
1485 formatters={
1486 "generic": {
1487 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
1488 "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
1489 "class": "logging.Formatter"
1490 },
1491 },
1492 )
1493 )
1494 finally:
1495 os.unlink(fn)
1496
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001497
Christian Heimes180510d2008-03-03 19:15:45 +00001498class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001499
Christian Heimes180510d2008-03-03 19:15:45 +00001500 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001501
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001502 server_class = TestTCPServer
1503 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001504
Christian Heimes180510d2008-03-03 19:15:45 +00001505 def setUp(self):
1506 """Set up a TCP server to receive log messages, and a SocketHandler
1507 pointing to that server's address and port."""
1508 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001509 # Issue #29177: deal with errors that happen during setup
1510 self.server = self.sock_hdlr = self.server_exception = None
1511 try:
1512 self.server = server = self.server_class(self.address,
1513 self.handle_socket, 0.01)
1514 server.start()
1515 # Uncomment next line to test error recovery in setUp()
1516 # raise OSError('dummy error raised')
1517 except OSError as e:
1518 self.server_exception = e
1519 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001520 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001521 hcls = logging.handlers.SocketHandler
1522 if isinstance(server.server_address, tuple):
1523 self.sock_hdlr = hcls('localhost', server.port)
1524 else:
1525 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001526 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001527 self.root_logger.removeHandler(self.root_logger.handlers[0])
1528 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001529 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001530
Christian Heimes180510d2008-03-03 19:15:45 +00001531 def tearDown(self):
1532 """Shutdown the TCP server."""
1533 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001534 if self.sock_hdlr:
1535 self.root_logger.removeHandler(self.sock_hdlr)
1536 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001537 if self.server:
1538 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001539 finally:
1540 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001541
Vinay Sajip7367d082011-05-02 13:17:27 +01001542 def handle_socket(self, request):
1543 conn = request.connection
1544 while True:
1545 chunk = conn.recv(4)
1546 if len(chunk) < 4:
1547 break
1548 slen = struct.unpack(">L", chunk)[0]
1549 chunk = conn.recv(slen)
1550 while len(chunk) < slen:
1551 chunk = chunk + conn.recv(slen - len(chunk))
1552 obj = pickle.loads(chunk)
1553 record = logging.makeLogRecord(obj)
1554 self.log_output += record.msg + '\n'
1555 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001556
Christian Heimes180510d2008-03-03 19:15:45 +00001557 def test_output(self):
1558 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001559 if self.server_exception:
1560 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001561 logger = logging.getLogger("tcp")
1562 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001563 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001564 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001565 self.handled.acquire()
1566 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001567
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001568 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001569 if self.server_exception:
1570 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001571 # Avoid timing-related failures due to SocketHandler's own hard-wired
1572 # one-second timeout on socket.create_connection() (issue #16264).
1573 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001574 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001575 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001576 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001577 try:
1578 raise RuntimeError('Deliberate mistake')
1579 except RuntimeError:
1580 self.root_logger.exception('Never sent')
1581 self.root_logger.error('Never sent, either')
1582 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001583 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001584 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1585 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001586
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001587def _get_temp_domain_socket():
1588 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1589 os.close(fd)
1590 # just need a name - file can't be present, or we'll get an
1591 # 'address already in use' error.
1592 os.remove(fn)
1593 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001594
Victor Stinnerec5a8602014-06-02 14:41:51 +02001595@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001596class UnixSocketHandlerTest(SocketHandlerTest):
1597
1598 """Test for SocketHandler with unix sockets."""
1599
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001600 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001601 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001602
1603 def setUp(self):
1604 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001605 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001606 SocketHandlerTest.setUp(self)
1607
1608 def tearDown(self):
1609 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001610 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001611
Vinay Sajip7367d082011-05-02 13:17:27 +01001612class DatagramHandlerTest(BaseTest):
1613
1614 """Test for DatagramHandler."""
1615
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001616 server_class = TestUDPServer
1617 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001618
Vinay Sajip7367d082011-05-02 13:17:27 +01001619 def setUp(self):
1620 """Set up a UDP server to receive log messages, and a DatagramHandler
1621 pointing to that server's address and port."""
1622 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001623 # Issue #29177: deal with errors that happen during setup
1624 self.server = self.sock_hdlr = self.server_exception = None
1625 try:
1626 self.server = server = self.server_class(self.address,
1627 self.handle_datagram, 0.01)
1628 server.start()
1629 # Uncomment next line to test error recovery in setUp()
1630 # raise OSError('dummy error raised')
1631 except OSError as e:
1632 self.server_exception = e
1633 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001634 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001635 hcls = logging.handlers.DatagramHandler
1636 if isinstance(server.server_address, tuple):
1637 self.sock_hdlr = hcls('localhost', server.port)
1638 else:
1639 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001640 self.log_output = ''
1641 self.root_logger.removeHandler(self.root_logger.handlers[0])
1642 self.root_logger.addHandler(self.sock_hdlr)
1643 self.handled = threading.Event()
1644
1645 def tearDown(self):
1646 """Shutdown the UDP server."""
1647 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001648 if self.server:
1649 self.server.stop(2.0)
1650 if self.sock_hdlr:
1651 self.root_logger.removeHandler(self.sock_hdlr)
1652 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001653 finally:
1654 BaseTest.tearDown(self)
1655
1656 def handle_datagram(self, request):
1657 slen = struct.pack('>L', 0) # length of prefix
1658 packet = request.packet[len(slen):]
1659 obj = pickle.loads(packet)
1660 record = logging.makeLogRecord(obj)
1661 self.log_output += record.msg + '\n'
1662 self.handled.set()
1663
1664 def test_output(self):
1665 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001666 if self.server_exception:
1667 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001668 logger = logging.getLogger("udp")
1669 logger.error("spam")
1670 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001671 self.handled.clear()
1672 logger.error("eggs")
1673 self.handled.wait()
1674 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001675
Victor Stinnerec5a8602014-06-02 14:41:51 +02001676@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001677class UnixDatagramHandlerTest(DatagramHandlerTest):
1678
1679 """Test for DatagramHandler using Unix sockets."""
1680
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001681 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001682 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001683
1684 def setUp(self):
1685 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001686 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001687 DatagramHandlerTest.setUp(self)
1688
1689 def tearDown(self):
1690 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001691 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001692
Vinay Sajip7367d082011-05-02 13:17:27 +01001693class SysLogHandlerTest(BaseTest):
1694
1695 """Test for SysLogHandler using UDP."""
1696
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001697 server_class = TestUDPServer
1698 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001699
Vinay Sajip7367d082011-05-02 13:17:27 +01001700 def setUp(self):
1701 """Set up a UDP server to receive log messages, and a SysLogHandler
1702 pointing to that server's address and port."""
1703 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001704 # Issue #29177: deal with errors that happen during setup
1705 self.server = self.sl_hdlr = self.server_exception = None
1706 try:
1707 self.server = server = self.server_class(self.address,
1708 self.handle_datagram, 0.01)
1709 server.start()
1710 # Uncomment next line to test error recovery in setUp()
1711 # raise OSError('dummy error raised')
1712 except OSError as e:
1713 self.server_exception = e
1714 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001715 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001716 hcls = logging.handlers.SysLogHandler
1717 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001718 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001719 else:
1720 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001721 self.log_output = ''
1722 self.root_logger.removeHandler(self.root_logger.handlers[0])
1723 self.root_logger.addHandler(self.sl_hdlr)
1724 self.handled = threading.Event()
1725
1726 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001727 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001728 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001729 if self.server:
1730 self.server.stop(2.0)
1731 if self.sl_hdlr:
1732 self.root_logger.removeHandler(self.sl_hdlr)
1733 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001734 finally:
1735 BaseTest.tearDown(self)
1736
1737 def handle_datagram(self, request):
1738 self.log_output = request.packet
1739 self.handled.set()
1740
1741 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001742 if self.server_exception:
1743 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001744 # The log message sent to the SysLogHandler is properly received.
1745 logger = logging.getLogger("slh")
1746 logger.error("sp\xe4m")
1747 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001748 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001749 self.handled.clear()
1750 self.sl_hdlr.append_nul = False
1751 logger.error("sp\xe4m")
1752 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001753 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001754 self.handled.clear()
1755 self.sl_hdlr.ident = "h\xe4m-"
1756 logger.error("sp\xe4m")
1757 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001758 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001759
Victor Stinnerec5a8602014-06-02 14:41:51 +02001760@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001761class UnixSysLogHandlerTest(SysLogHandlerTest):
1762
1763 """Test for SysLogHandler with Unix sockets."""
1764
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001765 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001766 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001767
1768 def setUp(self):
1769 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001770 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001771 SysLogHandlerTest.setUp(self)
1772
1773 def tearDown(self):
1774 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001775 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001776
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001777@unittest.skipUnless(support.IPV6_ENABLED,
1778 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001779class IPv6SysLogHandlerTest(SysLogHandlerTest):
1780
1781 """Test for SysLogHandler with IPv6 host."""
1782
1783 server_class = TestUDPServer
1784 address = ('::1', 0)
1785
1786 def setUp(self):
1787 self.server_class.address_family = socket.AF_INET6
1788 super(IPv6SysLogHandlerTest, self).setUp()
1789
1790 def tearDown(self):
1791 self.server_class.address_family = socket.AF_INET
1792 super(IPv6SysLogHandlerTest, self).tearDown()
1793
Vinay Sajip7367d082011-05-02 13:17:27 +01001794class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001795 """Test for HTTPHandler."""
1796
1797 def setUp(self):
1798 """Set up an HTTP server to receive log messages, and a HTTPHandler
1799 pointing to that server's address and port."""
1800 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001801 self.handled = threading.Event()
1802
Vinay Sajip7367d082011-05-02 13:17:27 +01001803 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001804 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001805 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001806 if self.command == 'POST':
1807 try:
1808 rlen = int(request.headers['Content-Length'])
1809 self.post_data = request.rfile.read(rlen)
1810 except:
1811 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001812 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001813 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001814 self.handled.set()
1815
1816 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001817 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001818 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001819 root_logger = self.root_logger
1820 root_logger.removeHandler(self.root_logger.handlers[0])
1821 for secure in (False, True):
1822 addr = ('localhost', 0)
1823 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001824 try:
1825 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001826 except ImportError:
1827 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001828 else:
1829 here = os.path.dirname(__file__)
1830 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001831 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001832 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001833
1834 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001835 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001836 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001837 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001838 self.server = server = TestHTTPServer(addr, self.handle_request,
1839 0.01, sslctx=sslctx)
1840 server.start()
1841 server.ready.wait()
1842 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001843 secure_client = secure and sslctx
1844 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001845 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001846 context=context,
1847 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001848 self.log_data = None
1849 root_logger.addHandler(self.h_hdlr)
1850
1851 for method in ('GET', 'POST'):
1852 self.h_hdlr.method = method
1853 self.handled.clear()
1854 msg = "sp\xe4m"
1855 logger.error(msg)
1856 self.handled.wait()
1857 self.assertEqual(self.log_data.path, '/frob')
1858 self.assertEqual(self.command, method)
1859 if method == 'GET':
1860 d = parse_qs(self.log_data.query)
1861 else:
1862 d = parse_qs(self.post_data.decode('utf-8'))
1863 self.assertEqual(d['name'], ['http'])
1864 self.assertEqual(d['funcName'], ['test_output'])
1865 self.assertEqual(d['msg'], [msg])
1866
1867 self.server.stop(2.0)
1868 self.root_logger.removeHandler(self.h_hdlr)
1869 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001870
Christian Heimes180510d2008-03-03 19:15:45 +00001871class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001872
Christian Heimes180510d2008-03-03 19:15:45 +00001873 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001874
Christian Heimes180510d2008-03-03 19:15:45 +00001875 def setUp(self):
1876 """Create a dict to remember potentially destroyed objects."""
1877 BaseTest.setUp(self)
1878 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001879
Christian Heimes180510d2008-03-03 19:15:45 +00001880 def _watch_for_survival(self, *args):
1881 """Watch the given objects for survival, by creating weakrefs to
1882 them."""
1883 for obj in args:
1884 key = id(obj), repr(obj)
1885 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001886
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001887 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001888 """Assert that all objects watched for survival have survived."""
1889 # Trigger cycle breaking.
1890 gc.collect()
1891 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001892 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001893 if ref() is None:
1894 dead.append(repr_)
1895 if dead:
1896 self.fail("%d objects should have survived "
1897 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001898
Christian Heimes180510d2008-03-03 19:15:45 +00001899 def test_persistent_loggers(self):
1900 # Logger objects are persistent and retain their configuration, even
1901 # if visible references are destroyed.
1902 self.root_logger.setLevel(logging.INFO)
1903 foo = logging.getLogger("foo")
1904 self._watch_for_survival(foo)
1905 foo.setLevel(logging.DEBUG)
1906 self.root_logger.debug(self.next_message())
1907 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001908 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001909 ('foo', 'DEBUG', '2'),
1910 ])
1911 del foo
1912 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001913 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001914 # foo has retained its settings.
1915 bar = logging.getLogger("foo")
1916 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001917 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001918 ('foo', 'DEBUG', '2'),
1919 ('foo', 'DEBUG', '3'),
1920 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001921
Benjamin Petersonf91df042009-02-13 02:50:59 +00001922
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001923class EncodingTest(BaseTest):
1924 def test_encoding_plain_file(self):
1925 # In Python 2.x, a plain file object is treated as having no encoding.
1926 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001927 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1928 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001929 # the non-ascii data we write to the log.
1930 data = "foo\x80"
1931 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001932 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001933 log.addHandler(handler)
1934 try:
1935 # write non-ascii data to the log.
1936 log.warning(data)
1937 finally:
1938 log.removeHandler(handler)
1939 handler.close()
1940 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001941 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001942 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001943 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001944 finally:
1945 f.close()
1946 finally:
1947 if os.path.isfile(fn):
1948 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001949
Benjamin Petersonf91df042009-02-13 02:50:59 +00001950 def test_encoding_cyrillic_unicode(self):
1951 log = logging.getLogger("test")
Mike53f7a7c2017-12-14 14:04:53 +03001952 # Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
Benjamin Petersonf91df042009-02-13 02:50:59 +00001953 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
Mike53f7a7c2017-12-14 14:04:53 +03001954 # Ensure it's written in a Cyrillic encoding
Benjamin Petersonf91df042009-02-13 02:50:59 +00001955 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001956 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001957 stream = io.BytesIO()
1958 writer = writer_class(stream, 'strict')
1959 handler = logging.StreamHandler(writer)
1960 log.addHandler(handler)
1961 try:
1962 log.warning(message)
1963 finally:
1964 log.removeHandler(handler)
1965 handler.close()
1966 # check we wrote exactly those bytes, ignoring trailing \n etc
1967 s = stream.getvalue()
Mike53f7a7c2017-12-14 14:04:53 +03001968 # Compare against what the data should be when encoded in CP-1251
Benjamin Petersonf91df042009-02-13 02:50:59 +00001969 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1970
1971
Georg Brandlf9734072008-12-07 15:30:06 +00001972class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001973
Georg Brandlf9734072008-12-07 15:30:06 +00001974 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001975 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001976 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001977 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001978 warnings.filterwarnings("always", category=UserWarning)
1979 stream = io.StringIO()
1980 h = logging.StreamHandler(stream)
1981 logger = logging.getLogger("py.warnings")
1982 logger.addHandler(h)
1983 warnings.warn("I'm warning you...")
1984 logger.removeHandler(h)
1985 s = stream.getvalue()
1986 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001987 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001988
Mike53f7a7c2017-12-14 14:04:53 +03001989 # See if an explicit file uses the original implementation
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001990 a_file = io.StringIO()
1991 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1992 a_file, "Dummy line")
1993 s = a_file.getvalue()
1994 a_file.close()
1995 self.assertEqual(s,
1996 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1997
1998 def test_warnings_no_handlers(self):
1999 with warnings.catch_warnings():
2000 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002001 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002002
2003 # confirm our assumption: no loggers are set
2004 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002005 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002006
2007 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01002008 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01002009 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00002010
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002011
2012def formatFunc(format, datefmt=None):
2013 return logging.Formatter(format, datefmt)
2014
2015def handlerFunc():
2016 return logging.StreamHandler()
2017
2018class CustomHandler(logging.StreamHandler):
2019 pass
2020
2021class ConfigDictTest(BaseTest):
2022
2023 """Reading logging config from a dictionary."""
2024
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002025 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002026
2027 # config0 is a standard configuration.
2028 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002029 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002030 'formatters': {
2031 'form1' : {
2032 'format' : '%(levelname)s ++ %(message)s',
2033 },
2034 },
2035 'handlers' : {
2036 'hand1' : {
2037 'class' : 'logging.StreamHandler',
2038 'formatter' : 'form1',
2039 'level' : 'NOTSET',
2040 'stream' : 'ext://sys.stdout',
2041 },
2042 },
2043 'root' : {
2044 'level' : 'WARNING',
2045 'handlers' : ['hand1'],
2046 },
2047 }
2048
2049 # config1 adds a little to the standard configuration.
2050 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002051 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002052 'formatters': {
2053 'form1' : {
2054 'format' : '%(levelname)s ++ %(message)s',
2055 },
2056 },
2057 'handlers' : {
2058 'hand1' : {
2059 'class' : 'logging.StreamHandler',
2060 'formatter' : 'form1',
2061 'level' : 'NOTSET',
2062 'stream' : 'ext://sys.stdout',
2063 },
2064 },
2065 'loggers' : {
2066 'compiler.parser' : {
2067 'level' : 'DEBUG',
2068 'handlers' : ['hand1'],
2069 },
2070 },
2071 'root' : {
2072 'level' : 'WARNING',
2073 },
2074 }
2075
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002076 # config1a moves the handler to the root. Used with config8a
2077 config1a = {
2078 'version': 1,
2079 'formatters': {
2080 'form1' : {
2081 'format' : '%(levelname)s ++ %(message)s',
2082 },
2083 },
2084 'handlers' : {
2085 'hand1' : {
2086 'class' : 'logging.StreamHandler',
2087 'formatter' : 'form1',
2088 'level' : 'NOTSET',
2089 'stream' : 'ext://sys.stdout',
2090 },
2091 },
2092 'loggers' : {
2093 'compiler.parser' : {
2094 'level' : 'DEBUG',
2095 },
2096 },
2097 'root' : {
2098 'level' : 'WARNING',
2099 'handlers' : ['hand1'],
2100 },
2101 }
2102
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002103 # config2 has a subtle configuration error that should be reported
2104 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002105 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002106 'formatters': {
2107 'form1' : {
2108 'format' : '%(levelname)s ++ %(message)s',
2109 },
2110 },
2111 'handlers' : {
2112 'hand1' : {
2113 'class' : 'logging.StreamHandler',
2114 'formatter' : 'form1',
2115 'level' : 'NOTSET',
2116 'stream' : 'ext://sys.stdbout',
2117 },
2118 },
2119 'loggers' : {
2120 'compiler.parser' : {
2121 'level' : 'DEBUG',
2122 'handlers' : ['hand1'],
2123 },
2124 },
2125 'root' : {
2126 'level' : 'WARNING',
2127 },
2128 }
2129
Mike53f7a7c2017-12-14 14:04:53 +03002130 # As config1 but with a misspelt level on a handler
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002131 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002132 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002133 'formatters': {
2134 'form1' : {
2135 'format' : '%(levelname)s ++ %(message)s',
2136 },
2137 },
2138 'handlers' : {
2139 'hand1' : {
2140 'class' : 'logging.StreamHandler',
2141 'formatter' : 'form1',
2142 'level' : 'NTOSET',
2143 'stream' : 'ext://sys.stdout',
2144 },
2145 },
2146 'loggers' : {
2147 'compiler.parser' : {
2148 'level' : 'DEBUG',
2149 'handlers' : ['hand1'],
2150 },
2151 },
2152 'root' : {
2153 'level' : 'WARNING',
2154 },
2155 }
2156
2157
Mike53f7a7c2017-12-14 14:04:53 +03002158 # As config1 but with a misspelt level on a logger
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002159 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002160 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002161 'formatters': {
2162 'form1' : {
2163 'format' : '%(levelname)s ++ %(message)s',
2164 },
2165 },
2166 'handlers' : {
2167 'hand1' : {
2168 'class' : 'logging.StreamHandler',
2169 'formatter' : 'form1',
2170 'level' : 'NOTSET',
2171 'stream' : 'ext://sys.stdout',
2172 },
2173 },
2174 'loggers' : {
2175 'compiler.parser' : {
2176 'level' : 'DEBUG',
2177 'handlers' : ['hand1'],
2178 },
2179 },
2180 'root' : {
2181 'level' : 'WRANING',
2182 },
2183 }
2184
2185 # config3 has a less subtle configuration error
2186 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002187 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002188 'formatters': {
2189 'form1' : {
2190 'format' : '%(levelname)s ++ %(message)s',
2191 },
2192 },
2193 'handlers' : {
2194 'hand1' : {
2195 'class' : 'logging.StreamHandler',
2196 'formatter' : 'misspelled_name',
2197 'level' : 'NOTSET',
2198 'stream' : 'ext://sys.stdout',
2199 },
2200 },
2201 'loggers' : {
2202 'compiler.parser' : {
2203 'level' : 'DEBUG',
2204 'handlers' : ['hand1'],
2205 },
2206 },
2207 'root' : {
2208 'level' : 'WARNING',
2209 },
2210 }
2211
2212 # config4 specifies a custom formatter class to be loaded
2213 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002214 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002215 'formatters': {
2216 'form1' : {
2217 '()' : __name__ + '.ExceptionFormatter',
2218 'format' : '%(levelname)s:%(name)s:%(message)s',
2219 },
2220 },
2221 'handlers' : {
2222 'hand1' : {
2223 'class' : 'logging.StreamHandler',
2224 'formatter' : 'form1',
2225 'level' : 'NOTSET',
2226 'stream' : 'ext://sys.stdout',
2227 },
2228 },
2229 'root' : {
2230 'level' : 'NOTSET',
2231 'handlers' : ['hand1'],
2232 },
2233 }
2234
2235 # As config4 but using an actual callable rather than a string
2236 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002237 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002238 'formatters': {
2239 'form1' : {
2240 '()' : ExceptionFormatter,
2241 'format' : '%(levelname)s:%(name)s:%(message)s',
2242 },
2243 'form2' : {
2244 '()' : __name__ + '.formatFunc',
2245 'format' : '%(levelname)s:%(name)s:%(message)s',
2246 },
2247 'form3' : {
2248 '()' : formatFunc,
2249 'format' : '%(levelname)s:%(name)s:%(message)s',
2250 },
2251 },
2252 'handlers' : {
2253 'hand1' : {
2254 'class' : 'logging.StreamHandler',
2255 'formatter' : 'form1',
2256 'level' : 'NOTSET',
2257 'stream' : 'ext://sys.stdout',
2258 },
2259 'hand2' : {
2260 '()' : handlerFunc,
2261 },
2262 },
2263 'root' : {
2264 'level' : 'NOTSET',
2265 'handlers' : ['hand1'],
2266 },
2267 }
2268
2269 # config5 specifies a custom handler class to be loaded
2270 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002271 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002272 'formatters': {
2273 'form1' : {
2274 'format' : '%(levelname)s ++ %(message)s',
2275 },
2276 },
2277 'handlers' : {
2278 'hand1' : {
2279 'class' : __name__ + '.CustomHandler',
2280 'formatter' : 'form1',
2281 'level' : 'NOTSET',
2282 'stream' : 'ext://sys.stdout',
2283 },
2284 },
2285 'loggers' : {
2286 'compiler.parser' : {
2287 'level' : 'DEBUG',
2288 'handlers' : ['hand1'],
2289 },
2290 },
2291 'root' : {
2292 'level' : 'WARNING',
2293 },
2294 }
2295
2296 # config6 specifies a custom handler class to be loaded
2297 # but has bad arguments
2298 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002299 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002300 'formatters': {
2301 'form1' : {
2302 'format' : '%(levelname)s ++ %(message)s',
2303 },
2304 },
2305 'handlers' : {
2306 'hand1' : {
2307 'class' : __name__ + '.CustomHandler',
2308 'formatter' : 'form1',
2309 'level' : 'NOTSET',
2310 'stream' : 'ext://sys.stdout',
2311 '9' : 'invalid parameter name',
2312 },
2313 },
2314 'loggers' : {
2315 'compiler.parser' : {
2316 'level' : 'DEBUG',
2317 'handlers' : ['hand1'],
2318 },
2319 },
2320 'root' : {
2321 'level' : 'WARNING',
2322 },
2323 }
2324
Mike53f7a7c2017-12-14 14:04:53 +03002325 # config 7 does not define compiler.parser but defines compiler.lexer
2326 # so compiler.parser should be disabled after applying it
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002327 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002328 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002329 'formatters': {
2330 'form1' : {
2331 'format' : '%(levelname)s ++ %(message)s',
2332 },
2333 },
2334 'handlers' : {
2335 'hand1' : {
2336 'class' : 'logging.StreamHandler',
2337 'formatter' : 'form1',
2338 'level' : 'NOTSET',
2339 'stream' : 'ext://sys.stdout',
2340 },
2341 },
2342 'loggers' : {
2343 'compiler.lexer' : {
2344 'level' : 'DEBUG',
2345 'handlers' : ['hand1'],
2346 },
2347 },
2348 'root' : {
2349 'level' : 'WARNING',
2350 },
2351 }
2352
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002353 # config8 defines both compiler and compiler.lexer
2354 # so compiler.parser should not be disabled (since
2355 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002356 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002357 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002358 'disable_existing_loggers' : False,
2359 'formatters': {
2360 'form1' : {
2361 'format' : '%(levelname)s ++ %(message)s',
2362 },
2363 },
2364 'handlers' : {
2365 'hand1' : {
2366 'class' : 'logging.StreamHandler',
2367 'formatter' : 'form1',
2368 'level' : 'NOTSET',
2369 'stream' : 'ext://sys.stdout',
2370 },
2371 },
2372 'loggers' : {
2373 'compiler' : {
2374 'level' : 'DEBUG',
2375 'handlers' : ['hand1'],
2376 },
2377 'compiler.lexer' : {
2378 },
2379 },
2380 'root' : {
2381 'level' : 'WARNING',
2382 },
2383 }
2384
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002385 # config8a disables existing loggers
2386 config8a = {
2387 'version': 1,
2388 'disable_existing_loggers' : True,
2389 'formatters': {
2390 'form1' : {
2391 'format' : '%(levelname)s ++ %(message)s',
2392 },
2393 },
2394 'handlers' : {
2395 'hand1' : {
2396 'class' : 'logging.StreamHandler',
2397 'formatter' : 'form1',
2398 'level' : 'NOTSET',
2399 'stream' : 'ext://sys.stdout',
2400 },
2401 },
2402 'loggers' : {
2403 'compiler' : {
2404 'level' : 'DEBUG',
2405 'handlers' : ['hand1'],
2406 },
2407 'compiler.lexer' : {
2408 },
2409 },
2410 'root' : {
2411 'level' : 'WARNING',
2412 },
2413 }
2414
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002415 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002416 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002417 'formatters': {
2418 'form1' : {
2419 'format' : '%(levelname)s ++ %(message)s',
2420 },
2421 },
2422 'handlers' : {
2423 'hand1' : {
2424 'class' : 'logging.StreamHandler',
2425 'formatter' : 'form1',
2426 'level' : 'WARNING',
2427 'stream' : 'ext://sys.stdout',
2428 },
2429 },
2430 'loggers' : {
2431 'compiler.parser' : {
2432 'level' : 'WARNING',
2433 'handlers' : ['hand1'],
2434 },
2435 },
2436 'root' : {
2437 'level' : 'NOTSET',
2438 },
2439 }
2440
2441 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002442 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002443 'incremental' : True,
2444 'handlers' : {
2445 'hand1' : {
2446 'level' : 'WARNING',
2447 },
2448 },
2449 'loggers' : {
2450 'compiler.parser' : {
2451 'level' : 'INFO',
2452 },
2453 },
2454 }
2455
2456 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002457 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002458 'incremental' : True,
2459 'handlers' : {
2460 'hand1' : {
2461 'level' : 'INFO',
2462 },
2463 },
2464 'loggers' : {
2465 'compiler.parser' : {
2466 'level' : 'INFO',
2467 },
2468 },
2469 }
2470
Mike53f7a7c2017-12-14 14:04:53 +03002471 # As config1 but with a filter added
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002472 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002473 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002474 'formatters': {
2475 'form1' : {
2476 'format' : '%(levelname)s ++ %(message)s',
2477 },
2478 },
2479 'filters' : {
2480 'filt1' : {
2481 'name' : 'compiler.parser',
2482 },
2483 },
2484 'handlers' : {
2485 'hand1' : {
2486 'class' : 'logging.StreamHandler',
2487 'formatter' : 'form1',
2488 'level' : 'NOTSET',
2489 'stream' : 'ext://sys.stdout',
2490 'filters' : ['filt1'],
2491 },
2492 },
2493 'loggers' : {
2494 'compiler.parser' : {
2495 'level' : 'DEBUG',
2496 'filters' : ['filt1'],
2497 },
2498 },
2499 'root' : {
2500 'level' : 'WARNING',
2501 'handlers' : ['hand1'],
2502 },
2503 }
2504
Mike53f7a7c2017-12-14 14:04:53 +03002505 # As config1 but using cfg:// references
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002506 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002507 'version': 1,
2508 'true_formatters': {
2509 'form1' : {
2510 'format' : '%(levelname)s ++ %(message)s',
2511 },
2512 },
2513 'handler_configs': {
2514 'hand1' : {
2515 'class' : 'logging.StreamHandler',
2516 'formatter' : 'form1',
2517 'level' : 'NOTSET',
2518 'stream' : 'ext://sys.stdout',
2519 },
2520 },
2521 'formatters' : 'cfg://true_formatters',
2522 'handlers' : {
2523 'hand1' : 'cfg://handler_configs[hand1]',
2524 },
2525 'loggers' : {
2526 'compiler.parser' : {
2527 'level' : 'DEBUG',
2528 'handlers' : ['hand1'],
2529 },
2530 },
2531 'root' : {
2532 'level' : 'WARNING',
2533 },
2534 }
2535
Mike53f7a7c2017-12-14 14:04:53 +03002536 # As config11 but missing the version key
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002537 config12 = {
2538 'true_formatters': {
2539 'form1' : {
2540 'format' : '%(levelname)s ++ %(message)s',
2541 },
2542 },
2543 'handler_configs': {
2544 'hand1' : {
2545 'class' : 'logging.StreamHandler',
2546 'formatter' : 'form1',
2547 'level' : 'NOTSET',
2548 'stream' : 'ext://sys.stdout',
2549 },
2550 },
2551 'formatters' : 'cfg://true_formatters',
2552 'handlers' : {
2553 'hand1' : 'cfg://handler_configs[hand1]',
2554 },
2555 'loggers' : {
2556 'compiler.parser' : {
2557 'level' : 'DEBUG',
2558 'handlers' : ['hand1'],
2559 },
2560 },
2561 'root' : {
2562 'level' : 'WARNING',
2563 },
2564 }
2565
Mike53f7a7c2017-12-14 14:04:53 +03002566 # As config11 but using an unsupported version
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002567 config13 = {
2568 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002569 'true_formatters': {
2570 'form1' : {
2571 'format' : '%(levelname)s ++ %(message)s',
2572 },
2573 },
2574 'handler_configs': {
2575 'hand1' : {
2576 'class' : 'logging.StreamHandler',
2577 'formatter' : 'form1',
2578 'level' : 'NOTSET',
2579 'stream' : 'ext://sys.stdout',
2580 },
2581 },
2582 'formatters' : 'cfg://true_formatters',
2583 'handlers' : {
2584 'hand1' : 'cfg://handler_configs[hand1]',
2585 },
2586 'loggers' : {
2587 'compiler.parser' : {
2588 'level' : 'DEBUG',
2589 'handlers' : ['hand1'],
2590 },
2591 },
2592 'root' : {
2593 'level' : 'WARNING',
2594 },
2595 }
2596
Vinay Sajip8d270232012-11-15 14:20:18 +00002597 # As config0, but with properties
2598 config14 = {
2599 'version': 1,
2600 'formatters': {
2601 'form1' : {
2602 'format' : '%(levelname)s ++ %(message)s',
2603 },
2604 },
2605 'handlers' : {
2606 'hand1' : {
2607 'class' : 'logging.StreamHandler',
2608 'formatter' : 'form1',
2609 'level' : 'NOTSET',
2610 'stream' : 'ext://sys.stdout',
2611 '.': {
2612 'foo': 'bar',
2613 'terminator': '!\n',
2614 }
2615 },
2616 },
2617 'root' : {
2618 'level' : 'WARNING',
2619 'handlers' : ['hand1'],
2620 },
2621 }
2622
Vinay Sajip3f885b52013-03-22 15:19:54 +00002623 out_of_order = {
2624 "version": 1,
2625 "formatters": {
2626 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002627 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2628 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002629 }
2630 },
2631 "handlers": {
2632 "fileGlobal": {
2633 "class": "logging.StreamHandler",
2634 "level": "DEBUG",
2635 "formatter": "mySimpleFormatter"
2636 },
2637 "bufferGlobal": {
2638 "class": "logging.handlers.MemoryHandler",
2639 "capacity": 5,
2640 "formatter": "mySimpleFormatter",
2641 "target": "fileGlobal",
2642 "level": "DEBUG"
2643 }
2644 },
2645 "loggers": {
2646 "mymodule": {
2647 "level": "DEBUG",
2648 "handlers": ["bufferGlobal"],
2649 "propagate": "true"
2650 }
2651 }
2652 }
2653
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002654 def apply_config(self, conf):
2655 logging.config.dictConfig(conf)
2656
2657 def test_config0_ok(self):
2658 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002659 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002660 self.apply_config(self.config0)
2661 logger = logging.getLogger()
2662 # Won't output anything
2663 logger.info(self.next_message())
2664 # Outputs a message
2665 logger.error(self.next_message())
2666 self.assert_log_lines([
2667 ('ERROR', '2'),
2668 ], stream=output)
2669 # Original logger output is empty.
2670 self.assert_log_lines([])
2671
2672 def test_config1_ok(self, config=config1):
2673 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002674 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002675 self.apply_config(config)
2676 logger = logging.getLogger("compiler.parser")
2677 # Both will output a message
2678 logger.info(self.next_message())
2679 logger.error(self.next_message())
2680 self.assert_log_lines([
2681 ('INFO', '1'),
2682 ('ERROR', '2'),
2683 ], stream=output)
2684 # Original logger output is empty.
2685 self.assert_log_lines([])
2686
2687 def test_config2_failure(self):
2688 # A simple config which overrides the default settings.
2689 self.assertRaises(Exception, self.apply_config, self.config2)
2690
2691 def test_config2a_failure(self):
2692 # A simple config which overrides the default settings.
2693 self.assertRaises(Exception, self.apply_config, self.config2a)
2694
2695 def test_config2b_failure(self):
2696 # A simple config which overrides the default settings.
2697 self.assertRaises(Exception, self.apply_config, self.config2b)
2698
2699 def test_config3_failure(self):
2700 # A simple config which overrides the default settings.
2701 self.assertRaises(Exception, self.apply_config, self.config3)
2702
2703 def test_config4_ok(self):
2704 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002705 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002706 self.apply_config(self.config4)
2707 #logger = logging.getLogger()
2708 try:
2709 raise RuntimeError()
2710 except RuntimeError:
2711 logging.exception("just testing")
2712 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002713 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002714 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2715 # Original logger output is empty
2716 self.assert_log_lines([])
2717
2718 def test_config4a_ok(self):
2719 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002720 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002721 self.apply_config(self.config4a)
2722 #logger = logging.getLogger()
2723 try:
2724 raise RuntimeError()
2725 except RuntimeError:
2726 logging.exception("just testing")
2727 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002728 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002729 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2730 # Original logger output is empty
2731 self.assert_log_lines([])
2732
2733 def test_config5_ok(self):
2734 self.test_config1_ok(config=self.config5)
2735
2736 def test_config6_failure(self):
2737 self.assertRaises(Exception, self.apply_config, self.config6)
2738
2739 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002740 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002741 self.apply_config(self.config1)
2742 logger = logging.getLogger("compiler.parser")
2743 # Both will output a message
2744 logger.info(self.next_message())
2745 logger.error(self.next_message())
2746 self.assert_log_lines([
2747 ('INFO', '1'),
2748 ('ERROR', '2'),
2749 ], stream=output)
2750 # Original logger output is empty.
2751 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002752 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002753 self.apply_config(self.config7)
2754 logger = logging.getLogger("compiler.parser")
2755 self.assertTrue(logger.disabled)
2756 logger = logging.getLogger("compiler.lexer")
2757 # Both will output a message
2758 logger.info(self.next_message())
2759 logger.error(self.next_message())
2760 self.assert_log_lines([
2761 ('INFO', '3'),
2762 ('ERROR', '4'),
2763 ], stream=output)
2764 # Original logger output is empty.
2765 self.assert_log_lines([])
2766
Mike53f7a7c2017-12-14 14:04:53 +03002767 # Same as test_config_7_ok but don't disable old loggers.
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002768 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002769 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002770 self.apply_config(self.config1)
2771 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002772 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002773 logger.info(self.next_message())
2774 logger.error(self.next_message())
2775 self.assert_log_lines([
2776 ('INFO', '1'),
2777 ('ERROR', '2'),
2778 ], stream=output)
2779 # Original logger output is empty.
2780 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002781 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002782 self.apply_config(self.config8)
2783 logger = logging.getLogger("compiler.parser")
2784 self.assertFalse(logger.disabled)
2785 # Both will output a message
2786 logger.info(self.next_message())
2787 logger.error(self.next_message())
2788 logger = logging.getLogger("compiler.lexer")
2789 # Both will output a message
2790 logger.info(self.next_message())
2791 logger.error(self.next_message())
2792 self.assert_log_lines([
2793 ('INFO', '3'),
2794 ('ERROR', '4'),
2795 ('INFO', '5'),
2796 ('ERROR', '6'),
2797 ], stream=output)
2798 # Original logger output is empty.
2799 self.assert_log_lines([])
2800
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002801 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002802 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002803 self.apply_config(self.config1a)
2804 logger = logging.getLogger("compiler.parser")
2805 # See issue #11424. compiler-hyphenated sorts
2806 # between compiler and compiler.xyz and this
2807 # was preventing compiler.xyz from being included
2808 # in the child loggers of compiler because of an
2809 # overzealous loop termination condition.
2810 hyphenated = logging.getLogger('compiler-hyphenated')
2811 # All will output a message
2812 logger.info(self.next_message())
2813 logger.error(self.next_message())
2814 hyphenated.critical(self.next_message())
2815 self.assert_log_lines([
2816 ('INFO', '1'),
2817 ('ERROR', '2'),
2818 ('CRITICAL', '3'),
2819 ], stream=output)
2820 # Original logger output is empty.
2821 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002822 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002823 self.apply_config(self.config8a)
2824 logger = logging.getLogger("compiler.parser")
2825 self.assertFalse(logger.disabled)
2826 # Both will output a message
2827 logger.info(self.next_message())
2828 logger.error(self.next_message())
2829 logger = logging.getLogger("compiler.lexer")
2830 # Both will output a message
2831 logger.info(self.next_message())
2832 logger.error(self.next_message())
2833 # Will not appear
2834 hyphenated.critical(self.next_message())
2835 self.assert_log_lines([
2836 ('INFO', '4'),
2837 ('ERROR', '5'),
2838 ('INFO', '6'),
2839 ('ERROR', '7'),
2840 ], stream=output)
2841 # Original logger output is empty.
2842 self.assert_log_lines([])
2843
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002844 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002845 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002846 self.apply_config(self.config9)
2847 logger = logging.getLogger("compiler.parser")
Mike53f7a7c2017-12-14 14:04:53 +03002848 # Nothing will be output since both handler and logger are set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002849 logger.info(self.next_message())
2850 self.assert_log_lines([], stream=output)
2851 self.apply_config(self.config9a)
Mike53f7a7c2017-12-14 14:04:53 +03002852 # Nothing will be output since handler is still set to WARNING
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002853 logger.info(self.next_message())
2854 self.assert_log_lines([], stream=output)
2855 self.apply_config(self.config9b)
Mike53f7a7c2017-12-14 14:04:53 +03002856 # Message should now be output
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002857 logger.info(self.next_message())
2858 self.assert_log_lines([
2859 ('INFO', '3'),
2860 ], stream=output)
2861
2862 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002863 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002864 self.apply_config(self.config10)
2865 logger = logging.getLogger("compiler.parser")
2866 logger.warning(self.next_message())
2867 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002868 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002869 logger.warning(self.next_message())
2870 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002871 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002872 logger.warning(self.next_message())
2873 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002874 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002875 logger.error(self.next_message())
2876 self.assert_log_lines([
2877 ('WARNING', '1'),
2878 ('ERROR', '4'),
2879 ], stream=output)
2880
2881 def test_config11_ok(self):
2882 self.test_config1_ok(self.config11)
2883
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002884 def test_config12_failure(self):
2885 self.assertRaises(Exception, self.apply_config, self.config12)
2886
2887 def test_config13_failure(self):
2888 self.assertRaises(Exception, self.apply_config, self.config13)
2889
Vinay Sajip8d270232012-11-15 14:20:18 +00002890 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002891 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002892 self.apply_config(self.config14)
2893 h = logging._handlers['hand1']
2894 self.assertEqual(h.foo, 'bar')
2895 self.assertEqual(h.terminator, '!\n')
2896 logging.warning('Exclamation')
2897 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2898
Vinay Sajip4ded5512012-10-02 15:56:16 +01002899 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002900 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002901 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002902 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002903 t.start()
2904 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002905 # Now get the port allocated
2906 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002907 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002908 try:
2909 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2910 sock.settimeout(2.0)
2911 sock.connect(('localhost', port))
2912
2913 slen = struct.pack('>L', len(text))
2914 s = slen + text
2915 sentsofar = 0
2916 left = len(s)
2917 while left > 0:
2918 sent = sock.send(s[sentsofar:])
2919 sentsofar += sent
2920 left -= sent
2921 sock.close()
2922 finally:
2923 t.ready.wait(2.0)
2924 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07002925 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002926
2927 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002928 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002929 self.setup_via_listener(json.dumps(self.config10))
2930 logger = logging.getLogger("compiler.parser")
2931 logger.warning(self.next_message())
2932 logger = logging.getLogger('compiler')
Mike53f7a7c2017-12-14 14:04:53 +03002933 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002934 logger.warning(self.next_message())
2935 logger = logging.getLogger('compiler.lexer')
Mike53f7a7c2017-12-14 14:04:53 +03002936 # Not output, because filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002937 logger.warning(self.next_message())
2938 logger = logging.getLogger("compiler.parser.codegen")
Mike53f7a7c2017-12-14 14:04:53 +03002939 # Output, as not filtered
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002940 logger.error(self.next_message())
2941 self.assert_log_lines([
2942 ('WARNING', '1'),
2943 ('ERROR', '4'),
2944 ], stream=output)
2945
2946 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002947 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002948 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2949 logger = logging.getLogger("compiler.parser")
2950 # Both will output a message
2951 logger.info(self.next_message())
2952 logger.error(self.next_message())
2953 self.assert_log_lines([
2954 ('INFO', '1'),
2955 ('ERROR', '2'),
2956 ], stream=output)
2957 # Original logger output is empty.
2958 self.assert_log_lines([])
2959
Vinay Sajip4ded5512012-10-02 15:56:16 +01002960 def test_listen_verify(self):
2961
2962 def verify_fail(stuff):
2963 return None
2964
2965 def verify_reverse(stuff):
2966 return stuff[::-1]
2967
2968 logger = logging.getLogger("compiler.parser")
2969 to_send = textwrap.dedent(ConfigFileTest.config1)
2970 # First, specify a verification function that will fail.
2971 # We expect to see no output, since our configuration
2972 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002973 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002974 self.setup_via_listener(to_send, verify_fail)
2975 # Both will output a message
2976 logger.info(self.next_message())
2977 logger.error(self.next_message())
2978 self.assert_log_lines([], stream=output)
2979 # Original logger output has the stuff we logged.
2980 self.assert_log_lines([
2981 ('INFO', '1'),
2982 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002983 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002984
2985 # Now, perform no verification. Our configuration
2986 # should take effect.
2987
Vinay Sajip1feedb42014-05-31 08:19:12 +01002988 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002989 self.setup_via_listener(to_send) # no verify callable specified
2990 logger = logging.getLogger("compiler.parser")
2991 # Both will output a message
2992 logger.info(self.next_message())
2993 logger.error(self.next_message())
2994 self.assert_log_lines([
2995 ('INFO', '3'),
2996 ('ERROR', '4'),
2997 ], stream=output)
2998 # Original logger output still has the stuff we logged before.
2999 self.assert_log_lines([
3000 ('INFO', '1'),
3001 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003002 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003003
3004 # Now, perform verification which transforms the bytes.
3005
Vinay Sajip1feedb42014-05-31 08:19:12 +01003006 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01003007 self.setup_via_listener(to_send[::-1], verify_reverse)
3008 logger = logging.getLogger("compiler.parser")
3009 # Both will output a message
3010 logger.info(self.next_message())
3011 logger.error(self.next_message())
3012 self.assert_log_lines([
3013 ('INFO', '5'),
3014 ('ERROR', '6'),
3015 ], stream=output)
3016 # Original logger output still has the stuff we logged before.
3017 self.assert_log_lines([
3018 ('INFO', '1'),
3019 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003020 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01003021
Vinay Sajip3f885b52013-03-22 15:19:54 +00003022 def test_out_of_order(self):
3023 self.apply_config(self.out_of_order)
3024 handler = logging.getLogger('mymodule').handlers[0]
3025 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00003026 self.assertIsInstance(handler.formatter._style,
3027 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003028
Vinay Sajip373baef2011-04-26 20:05:24 +01003029 def test_baseconfig(self):
3030 d = {
3031 'atuple': (1, 2, 3),
3032 'alist': ['a', 'b', 'c'],
3033 'adict': {'d': 'e', 'f': 3 },
3034 'nest1': ('g', ('h', 'i'), 'j'),
3035 'nest2': ['k', ['l', 'm'], 'n'],
3036 'nest3': ['o', 'cfg://alist', 'p'],
3037 }
3038 bc = logging.config.BaseConfigurator(d)
3039 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3040 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3041 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3042 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3043 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3044 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3045 v = bc.convert('cfg://nest3')
3046 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3047 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3048 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3049 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003050
3051class ManagerTest(BaseTest):
3052 def test_manager_loggerclass(self):
3053 logged = []
3054
3055 class MyLogger(logging.Logger):
3056 def _log(self, level, msg, args, exc_info=None, extra=None):
3057 logged.append(msg)
3058
3059 man = logging.Manager(None)
3060 self.assertRaises(TypeError, man.setLoggerClass, int)
3061 man.setLoggerClass(MyLogger)
3062 logger = man.getLogger('test')
3063 logger.warning('should appear in logged')
3064 logging.warning('should not appear in logged')
3065
3066 self.assertEqual(logged, ['should appear in logged'])
3067
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003068 def test_set_log_record_factory(self):
3069 man = logging.Manager(None)
3070 expected = object()
3071 man.setLogRecordFactory(expected)
3072 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003073
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003074class ChildLoggerTest(BaseTest):
3075 def test_child_loggers(self):
3076 r = logging.getLogger()
3077 l1 = logging.getLogger('abc')
3078 l2 = logging.getLogger('def.ghi')
3079 c1 = r.getChild('xyz')
3080 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003081 self.assertIs(c1, logging.getLogger('xyz'))
3082 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003083 c1 = l1.getChild('def')
3084 c2 = c1.getChild('ghi')
3085 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003086 self.assertIs(c1, logging.getLogger('abc.def'))
3087 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3088 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003089
3090
Vinay Sajip6fac8172010-10-19 20:44:14 +00003091class DerivedLogRecord(logging.LogRecord):
3092 pass
3093
Vinay Sajip61561522010-12-03 11:50:38 +00003094class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003095
3096 def setUp(self):
3097 class CheckingFilter(logging.Filter):
3098 def __init__(self, cls):
3099 self.cls = cls
3100
3101 def filter(self, record):
3102 t = type(record)
3103 if t is not self.cls:
3104 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3105 self.cls)
3106 raise TypeError(msg)
3107 return True
3108
3109 BaseTest.setUp(self)
3110 self.filter = CheckingFilter(DerivedLogRecord)
3111 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003112 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003113
3114 def tearDown(self):
3115 self.root_logger.removeFilter(self.filter)
3116 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003117 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003118
3119 def test_logrecord_class(self):
3120 self.assertRaises(TypeError, self.root_logger.warning,
3121 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003122 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003123 self.root_logger.error(self.next_message())
3124 self.assert_log_lines([
3125 ('root', 'ERROR', '2'),
3126 ])
3127
3128
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003129class QueueHandlerTest(BaseTest):
3130 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003131 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003132
3133 def setUp(self):
3134 BaseTest.setUp(self)
3135 self.queue = queue.Queue(-1)
3136 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003137 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003138 self.que_logger = logging.getLogger('que')
3139 self.que_logger.propagate = False
3140 self.que_logger.setLevel(logging.WARNING)
3141 self.que_logger.addHandler(self.que_hdlr)
3142
3143 def tearDown(self):
3144 self.que_hdlr.close()
3145 BaseTest.tearDown(self)
3146
3147 def test_queue_handler(self):
3148 self.que_logger.debug(self.next_message())
3149 self.assertRaises(queue.Empty, self.queue.get_nowait)
3150 self.que_logger.info(self.next_message())
3151 self.assertRaises(queue.Empty, self.queue.get_nowait)
3152 msg = self.next_message()
3153 self.que_logger.warning(msg)
3154 data = self.queue.get_nowait()
3155 self.assertTrue(isinstance(data, logging.LogRecord))
3156 self.assertEqual(data.name, self.que_logger.name)
3157 self.assertEqual((data.msg, data.args), (msg, None))
3158
favlladfe3442017-08-01 20:12:26 +02003159 def test_formatting(self):
3160 msg = self.next_message()
3161 levelname = logging.getLevelName(logging.WARNING)
3162 log_format_str = '{name} -> {levelname}: {message}'
3163 formatted_msg = log_format_str.format(name=self.name,
3164 levelname=levelname, message=msg)
3165 formatter = logging.Formatter(self.log_format)
3166 self.que_hdlr.setFormatter(formatter)
3167 self.que_logger.warning(msg)
3168 log_record = self.queue.get_nowait()
3169 self.assertEqual(formatted_msg, log_record.msg)
3170 self.assertEqual(formatted_msg, log_record.message)
3171
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003172 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3173 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003174 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003175 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003176 listener = logging.handlers.QueueListener(self.queue, handler)
3177 listener.start()
3178 try:
3179 self.que_logger.warning(self.next_message())
3180 self.que_logger.error(self.next_message())
3181 self.que_logger.critical(self.next_message())
3182 finally:
3183 listener.stop()
3184 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3185 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3186 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003187 handler.close()
3188
3189 # Now test with respect_handler_level set
3190
3191 handler = support.TestHandler(support.Matcher())
3192 handler.setLevel(logging.CRITICAL)
3193 listener = logging.handlers.QueueListener(self.queue, handler,
3194 respect_handler_level=True)
3195 listener.start()
3196 try:
3197 self.que_logger.warning(self.next_message())
3198 self.que_logger.error(self.next_message())
3199 self.que_logger.critical(self.next_message())
3200 finally:
3201 listener.stop()
3202 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3203 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3204 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3205
Vinay Sajipd61910c2016-09-08 01:13:39 +01003206if hasattr(logging.handlers, 'QueueListener'):
3207 import multiprocessing
3208 from unittest.mock import patch
3209
3210 class QueueListenerTest(BaseTest):
3211 """
3212 Tests based on patch submitted for issue #27930. Ensure that
3213 QueueListener handles all log messages.
3214 """
3215
3216 repeat = 20
3217
3218 @staticmethod
3219 def setup_and_log(log_queue, ident):
3220 """
3221 Creates a logger with a QueueHandler that logs to a queue read by a
3222 QueueListener. Starts the listener, logs five messages, and stops
3223 the listener.
3224 """
3225 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3226 logger.setLevel(logging.DEBUG)
3227 handler = logging.handlers.QueueHandler(log_queue)
3228 logger.addHandler(handler)
3229 listener = logging.handlers.QueueListener(log_queue)
3230 listener.start()
3231
3232 logger.info('one')
3233 logger.info('two')
3234 logger.info('three')
3235 logger.info('four')
3236 logger.info('five')
3237
3238 listener.stop()
3239 logger.removeHandler(handler)
3240 handler.close()
3241
3242 @patch.object(logging.handlers.QueueListener, 'handle')
3243 def test_handle_called_with_queue_queue(self, mock_handle):
3244 for i in range(self.repeat):
3245 log_queue = queue.Queue()
3246 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3247 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3248 'correct number of handled log messages')
3249
3250 @patch.object(logging.handlers.QueueListener, 'handle')
3251 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003252 # Issue 28668: The multiprocessing (mp) module is not functional
3253 # when the mp.synchronize module cannot be imported.
3254 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003255 for i in range(self.repeat):
3256 log_queue = multiprocessing.Queue()
3257 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003258 log_queue.close()
3259 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003260 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3261 'correct number of handled log messages')
3262
3263 @staticmethod
3264 def get_all_from_queue(log_queue):
3265 try:
3266 while True:
3267 yield log_queue.get_nowait()
3268 except queue.Empty:
3269 return []
3270
3271 def test_no_messages_in_queue_after_stop(self):
3272 """
3273 Five messages are logged then the QueueListener is stopped. This
3274 test then gets everything off the queue. Failure of this test
3275 indicates that messages were not registered on the queue until
3276 _after_ the QueueListener stopped.
3277 """
xdegayebf2b65e2017-12-01 08:08:49 +01003278 # Issue 28668: The multiprocessing (mp) module is not functional
3279 # when the mp.synchronize module cannot be imported.
3280 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003281 for i in range(self.repeat):
3282 queue = multiprocessing.Queue()
3283 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3284 # time.sleep(1)
3285 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003286 queue.close()
3287 queue.join_thread()
3288
Vinay Sajipd61910c2016-09-08 01:13:39 +01003289 expected = [[], [logging.handlers.QueueListener._sentinel]]
3290 self.assertIn(items, expected,
3291 'Found unexpected messages in queue: %s' % (
3292 [m.msg if isinstance(m, logging.LogRecord)
3293 else m for m in items]))
3294
Vinay Sajipe723e962011-04-15 22:27:17 +01003295
Vinay Sajip37eb3382011-04-26 20:26:41 +01003296ZERO = datetime.timedelta(0)
3297
3298class UTC(datetime.tzinfo):
3299 def utcoffset(self, dt):
3300 return ZERO
3301
3302 dst = utcoffset
3303
3304 def tzname(self, dt):
3305 return 'UTC'
3306
3307utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003308
Vinay Sajipa39c5712010-10-25 13:57:39 +00003309class FormatterTest(unittest.TestCase):
3310 def setUp(self):
3311 self.common = {
3312 'name': 'formatter.test',
3313 'level': logging.DEBUG,
3314 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3315 'lineno': 42,
3316 'exc_info': None,
3317 'func': None,
3318 'msg': 'Message with %d %s',
3319 'args': (2, 'placeholders'),
3320 }
3321 self.variants = {
3322 }
3323
3324 def get_record(self, name=None):
3325 result = dict(self.common)
3326 if name is not None:
3327 result.update(self.variants[name])
3328 return logging.makeLogRecord(result)
3329
3330 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003331 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003332 r = self.get_record()
3333 f = logging.Formatter('${%(message)s}')
3334 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3335 f = logging.Formatter('%(random)s')
3336 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003337 self.assertFalse(f.usesTime())
3338 f = logging.Formatter('%(asctime)s')
3339 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003340 f = logging.Formatter('%(asctime)-15s')
3341 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003342 f = logging.Formatter('asctime')
3343 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003344
3345 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003346 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003347 r = self.get_record()
3348 f = logging.Formatter('$%{message}%$', style='{')
3349 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3350 f = logging.Formatter('{random}', style='{')
3351 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003352 self.assertFalse(f.usesTime())
3353 f = logging.Formatter('{asctime}', style='{')
3354 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003355 f = logging.Formatter('{asctime!s:15}', style='{')
3356 self.assertTrue(f.usesTime())
3357 f = logging.Formatter('{asctime:15}', style='{')
3358 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003359 f = logging.Formatter('asctime', style='{')
3360 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003361
3362 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003363 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003364 r = self.get_record()
3365 f = logging.Formatter('$message', style='$')
3366 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3367 f = logging.Formatter('$$%${message}%$$', style='$')
3368 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3369 f = logging.Formatter('${random}', style='$')
3370 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003371 self.assertFalse(f.usesTime())
3372 f = logging.Formatter('${asctime}', style='$')
3373 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003374 f = logging.Formatter('${asctime', style='$')
3375 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003376 f = logging.Formatter('$asctime', style='$')
3377 self.assertTrue(f.usesTime())
3378 f = logging.Formatter('asctime', style='$')
3379 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003380
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003381 def test_invalid_style(self):
3382 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3383
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003384 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003385 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003386 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3387 # We use None to indicate we want the local timezone
3388 # We're essentially converting a UTC time to local time
3389 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003390 r.msecs = 123
3391 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003392 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003393 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3394 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003395 f.format(r)
3396 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3397
3398class TestBufferingFormatter(logging.BufferingFormatter):
3399 def formatHeader(self, records):
3400 return '[(%d)' % len(records)
3401
3402 def formatFooter(self, records):
3403 return '(%d)]' % len(records)
3404
3405class BufferingFormatterTest(unittest.TestCase):
3406 def setUp(self):
3407 self.records = [
3408 logging.makeLogRecord({'msg': 'one'}),
3409 logging.makeLogRecord({'msg': 'two'}),
3410 ]
3411
3412 def test_default(self):
3413 f = logging.BufferingFormatter()
3414 self.assertEqual('', f.format([]))
3415 self.assertEqual('onetwo', f.format(self.records))
3416
3417 def test_custom(self):
3418 f = TestBufferingFormatter()
3419 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3420 lf = logging.Formatter('<%(message)s>')
3421 f = TestBufferingFormatter(lf)
3422 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003423
3424class ExceptionTest(BaseTest):
3425 def test_formatting(self):
3426 r = self.root_logger
3427 h = RecordingHandler()
3428 r.addHandler(h)
3429 try:
3430 raise RuntimeError('deliberate mistake')
3431 except:
3432 logging.exception('failed', stack_info=True)
3433 r.removeHandler(h)
3434 h.close()
3435 r = h.records[0]
3436 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3437 'call last):\n'))
3438 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3439 'deliberate mistake'))
3440 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3441 'call last):\n'))
3442 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3443 'stack_info=True)'))
3444
3445
Vinay Sajip5a27d402010-12-10 11:42:57 +00003446class LastResortTest(BaseTest):
3447 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003448 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003449 root = self.root_logger
3450 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003451 old_lastresort = logging.lastResort
3452 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003453
Vinay Sajip5a27d402010-12-10 11:42:57 +00003454 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003455 with support.captured_stderr() as stderr:
3456 root.debug('This should not appear')
3457 self.assertEqual(stderr.getvalue(), '')
3458 root.warning('Final chance!')
3459 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3460
3461 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003462 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003463 with support.captured_stderr() as stderr:
3464 root.warning('Final chance!')
3465 msg = 'No handlers could be found for logger "root"\n'
3466 self.assertEqual(stderr.getvalue(), msg)
3467
Vinay Sajip5a27d402010-12-10 11:42:57 +00003468 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003469 with support.captured_stderr() as stderr:
3470 root.warning('Final chance!')
3471 self.assertEqual(stderr.getvalue(), '')
3472
3473 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003474 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003475 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003476 with support.captured_stderr() as stderr:
3477 root.warning('Final chance!')
3478 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003479 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003480 root.addHandler(self.root_hdlr)
3481 logging.lastResort = old_lastresort
3482 logging.raiseExceptions = old_raise_exceptions
3483
3484
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003485class FakeHandler:
3486
3487 def __init__(self, identifier, called):
3488 for method in ('acquire', 'flush', 'close', 'release'):
3489 setattr(self, method, self.record_call(identifier, method, called))
3490
3491 def record_call(self, identifier, method_name, called):
3492 def inner():
3493 called.append('{} - {}'.format(identifier, method_name))
3494 return inner
3495
3496
3497class RecordingHandler(logging.NullHandler):
3498
3499 def __init__(self, *args, **kwargs):
3500 super(RecordingHandler, self).__init__(*args, **kwargs)
3501 self.records = []
3502
3503 def handle(self, record):
3504 """Keep track of all the emitted records."""
3505 self.records.append(record)
3506
3507
3508class ShutdownTest(BaseTest):
3509
Vinay Sajip5e66b162011-04-20 15:41:14 +01003510 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003511
3512 def setUp(self):
3513 super(ShutdownTest, self).setUp()
3514 self.called = []
3515
3516 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003517 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518
3519 def raise_error(self, error):
3520 def inner():
3521 raise error()
3522 return inner
3523
3524 def test_no_failure(self):
3525 # create some fake handlers
3526 handler0 = FakeHandler(0, self.called)
3527 handler1 = FakeHandler(1, self.called)
3528 handler2 = FakeHandler(2, self.called)
3529
3530 # create live weakref to those handlers
3531 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3532
3533 logging.shutdown(handlerList=list(handlers))
3534
3535 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3536 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3537 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3538 self.assertEqual(expected, self.called)
3539
3540 def _test_with_failure_in_method(self, method, error):
3541 handler = FakeHandler(0, self.called)
3542 setattr(handler, method, self.raise_error(error))
3543 handlers = [logging.weakref.ref(handler)]
3544
3545 logging.shutdown(handlerList=list(handlers))
3546
3547 self.assertEqual('0 - release', self.called[-1])
3548
3549 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003550 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003551
3552 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003553 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003554
3555 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003556 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003557
3558 def test_with_valueerror_in_acquire(self):
3559 self._test_with_failure_in_method('acquire', ValueError)
3560
3561 def test_with_valueerror_in_flush(self):
3562 self._test_with_failure_in_method('flush', ValueError)
3563
3564 def test_with_valueerror_in_close(self):
3565 self._test_with_failure_in_method('close', ValueError)
3566
3567 def test_with_other_error_in_acquire_without_raise(self):
3568 logging.raiseExceptions = False
3569 self._test_with_failure_in_method('acquire', IndexError)
3570
3571 def test_with_other_error_in_flush_without_raise(self):
3572 logging.raiseExceptions = False
3573 self._test_with_failure_in_method('flush', IndexError)
3574
3575 def test_with_other_error_in_close_without_raise(self):
3576 logging.raiseExceptions = False
3577 self._test_with_failure_in_method('close', IndexError)
3578
3579 def test_with_other_error_in_acquire_with_raise(self):
3580 logging.raiseExceptions = True
3581 self.assertRaises(IndexError, self._test_with_failure_in_method,
3582 'acquire', IndexError)
3583
3584 def test_with_other_error_in_flush_with_raise(self):
3585 logging.raiseExceptions = True
3586 self.assertRaises(IndexError, self._test_with_failure_in_method,
3587 'flush', IndexError)
3588
3589 def test_with_other_error_in_close_with_raise(self):
3590 logging.raiseExceptions = True
3591 self.assertRaises(IndexError, self._test_with_failure_in_method,
3592 'close', IndexError)
3593
3594
3595class ModuleLevelMiscTest(BaseTest):
3596
Vinay Sajip5e66b162011-04-20 15:41:14 +01003597 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003598
3599 def test_disable(self):
3600 old_disable = logging.root.manager.disable
3601 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003602 self.assertEqual(old_disable, 0)
3603 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003604
3605 logging.disable(83)
3606 self.assertEqual(logging.root.manager.disable, 83)
3607
Vinay Sajipd489ac92016-12-31 11:40:11 +00003608 # test the default value introduced in 3.7
3609 # (Issue #28524)
3610 logging.disable()
3611 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3612
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003613 def _test_log(self, method, level=None):
3614 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003615 support.patch(self, logging, 'basicConfig',
3616 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003617
3618 recording = RecordingHandler()
3619 logging.root.addHandler(recording)
3620
3621 log_method = getattr(logging, method)
3622 if level is not None:
3623 log_method(level, "test me: %r", recording)
3624 else:
3625 log_method("test me: %r", recording)
3626
3627 self.assertEqual(len(recording.records), 1)
3628 record = recording.records[0]
3629 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3630
3631 expected_level = level if level is not None else getattr(logging, method.upper())
3632 self.assertEqual(record.levelno, expected_level)
3633
3634 # basicConfig was not called!
3635 self.assertEqual(called, [])
3636
3637 def test_log(self):
3638 self._test_log('log', logging.ERROR)
3639
3640 def test_debug(self):
3641 self._test_log('debug')
3642
3643 def test_info(self):
3644 self._test_log('info')
3645
3646 def test_warning(self):
3647 self._test_log('warning')
3648
3649 def test_error(self):
3650 self._test_log('error')
3651
3652 def test_critical(self):
3653 self._test_log('critical')
3654
3655 def test_set_logger_class(self):
3656 self.assertRaises(TypeError, logging.setLoggerClass, object)
3657
3658 class MyLogger(logging.Logger):
3659 pass
3660
3661 logging.setLoggerClass(MyLogger)
3662 self.assertEqual(logging.getLoggerClass(), MyLogger)
3663
3664 logging.setLoggerClass(logging.Logger)
3665 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3666
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003667 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003668 def test_logging_at_shutdown(self):
3669 # Issue #20037
3670 code = """if 1:
3671 import logging
3672
3673 class A:
3674 def __del__(self):
3675 try:
3676 raise ValueError("some error")
3677 except Exception:
3678 logging.exception("exception in __del__")
3679
3680 a = A()"""
3681 rc, out, err = assert_python_ok("-c", code)
3682 err = err.decode()
3683 self.assertIn("exception in __del__", err)
3684 self.assertIn("ValueError: some error", err)
3685
3686
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003687class LogRecordTest(BaseTest):
3688 def test_str_rep(self):
3689 r = logging.makeLogRecord({})
3690 s = str(r)
3691 self.assertTrue(s.startswith('<LogRecord: '))
3692 self.assertTrue(s.endswith('>'))
3693
3694 def test_dict_arg(self):
3695 h = RecordingHandler()
3696 r = logging.getLogger()
3697 r.addHandler(h)
3698 d = {'less' : 'more' }
3699 logging.warning('less is %(less)s', d)
3700 self.assertIs(h.records[0].args, d)
3701 self.assertEqual(h.records[0].message, 'less is more')
3702 r.removeHandler(h)
3703 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003704
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003705 def test_multiprocessing(self):
3706 r = logging.makeLogRecord({})
3707 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003708 try:
3709 import multiprocessing as mp
3710 r = logging.makeLogRecord({})
3711 self.assertEqual(r.processName, mp.current_process().name)
3712 except ImportError:
3713 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003714
3715 def test_optional(self):
3716 r = logging.makeLogRecord({})
3717 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003718 NOT_NONE(r.thread)
3719 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003720 NOT_NONE(r.process)
3721 NOT_NONE(r.processName)
3722 log_threads = logging.logThreads
3723 log_processes = logging.logProcesses
3724 log_multiprocessing = logging.logMultiprocessing
3725 try:
3726 logging.logThreads = False
3727 logging.logProcesses = False
3728 logging.logMultiprocessing = False
3729 r = logging.makeLogRecord({})
3730 NONE = self.assertIsNone
3731 NONE(r.thread)
3732 NONE(r.threadName)
3733 NONE(r.process)
3734 NONE(r.processName)
3735 finally:
3736 logging.logThreads = log_threads
3737 logging.logProcesses = log_processes
3738 logging.logMultiprocessing = log_multiprocessing
3739
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003740class BasicConfigTest(unittest.TestCase):
3741
Vinay Sajip95bf5042011-04-20 11:50:56 +01003742 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003743
3744 def setUp(self):
3745 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003746 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003747 self.saved_handlers = logging._handlers.copy()
3748 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003749 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003750 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003751 logging.root.handlers = []
3752
3753 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003754 for h in logging.root.handlers[:]:
3755 logging.root.removeHandler(h)
3756 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003757 super(BasicConfigTest, self).tearDown()
3758
Vinay Sajip3def7e02011-04-20 10:58:06 +01003759 def cleanup(self):
3760 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003761 logging._handlers.clear()
3762 logging._handlers.update(self.saved_handlers)
3763 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003764 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003765
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003766 def test_no_kwargs(self):
3767 logging.basicConfig()
3768
3769 # handler defaults to a StreamHandler to sys.stderr
3770 self.assertEqual(len(logging.root.handlers), 1)
3771 handler = logging.root.handlers[0]
3772 self.assertIsInstance(handler, logging.StreamHandler)
3773 self.assertEqual(handler.stream, sys.stderr)
3774
3775 formatter = handler.formatter
3776 # format defaults to logging.BASIC_FORMAT
3777 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3778 # datefmt defaults to None
3779 self.assertIsNone(formatter.datefmt)
3780 # style defaults to %
3781 self.assertIsInstance(formatter._style, logging.PercentStyle)
3782
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003783 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003784 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003785
Vinay Sajip1fd12022014-01-13 21:59:56 +00003786 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003787 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003788 logging.basicConfig(stream=sys.stdout, style="{")
3789 logging.error("Log an error")
3790 sys.stdout.seek(0)
3791 self.assertEqual(output.getvalue().strip(),
3792 "ERROR:root:Log an error")
3793
3794 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003795 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003796 logging.basicConfig(stream=sys.stdout, style="$")
3797 logging.error("Log an error")
3798 sys.stdout.seek(0)
3799 self.assertEqual(output.getvalue().strip(),
3800 "ERROR:root:Log an error")
3801
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003802 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003803
3804 def cleanup(h1, h2, fn):
3805 h1.close()
3806 h2.close()
3807 os.remove(fn)
3808
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003809 logging.basicConfig(filename='test.log')
3810
3811 self.assertEqual(len(logging.root.handlers), 1)
3812 handler = logging.root.handlers[0]
3813 self.assertIsInstance(handler, logging.FileHandler)
3814
3815 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003816 self.assertEqual(handler.stream.mode, expected.stream.mode)
3817 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003818 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003819
3820 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003821
3822 def cleanup(h1, h2, fn):
3823 h1.close()
3824 h2.close()
3825 os.remove(fn)
3826
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003827 logging.basicConfig(filename='test.log', filemode='wb')
3828
3829 handler = logging.root.handlers[0]
3830 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003831 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003832 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003833
3834 def test_stream(self):
3835 stream = io.StringIO()
3836 self.addCleanup(stream.close)
3837 logging.basicConfig(stream=stream)
3838
3839 self.assertEqual(len(logging.root.handlers), 1)
3840 handler = logging.root.handlers[0]
3841 self.assertIsInstance(handler, logging.StreamHandler)
3842 self.assertEqual(handler.stream, stream)
3843
3844 def test_format(self):
3845 logging.basicConfig(format='foo')
3846
3847 formatter = logging.root.handlers[0].formatter
3848 self.assertEqual(formatter._style._fmt, 'foo')
3849
3850 def test_datefmt(self):
3851 logging.basicConfig(datefmt='bar')
3852
3853 formatter = logging.root.handlers[0].formatter
3854 self.assertEqual(formatter.datefmt, 'bar')
3855
3856 def test_style(self):
3857 logging.basicConfig(style='$')
3858
3859 formatter = logging.root.handlers[0].formatter
3860 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3861
3862 def test_level(self):
3863 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003864 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003865
3866 logging.basicConfig(level=57)
3867 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003868 # Test that second call has no effect
3869 logging.basicConfig(level=58)
3870 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003871
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003872 def test_incompatible(self):
3873 assertRaises = self.assertRaises
3874 handlers = [logging.StreamHandler()]
3875 stream = sys.stderr
3876 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3877 stream=stream)
3878 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3879 handlers=handlers)
3880 assertRaises(ValueError, logging.basicConfig, stream=stream,
3881 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003882 # Issue 23207: test for invalid kwargs
3883 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3884 # Should pop both filename and filemode even if filename is None
3885 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003886
3887 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003888 handlers = [
3889 logging.StreamHandler(),
3890 logging.StreamHandler(sys.stdout),
3891 logging.StreamHandler(),
3892 ]
3893 f = logging.Formatter()
3894 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003895 logging.basicConfig(handlers=handlers)
3896 self.assertIs(handlers[0], logging.root.handlers[0])
3897 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003898 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003899 self.assertIsNotNone(handlers[0].formatter)
3900 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003901 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003902 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3903
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003904 def _test_log(self, method, level=None):
3905 # logging.root has no handlers so basicConfig should be called
3906 called = []
3907
3908 old_basic_config = logging.basicConfig
3909 def my_basic_config(*a, **kw):
3910 old_basic_config()
3911 old_level = logging.root.level
3912 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003913 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003914 called.append((a, kw))
3915
Vinay Sajip1feedb42014-05-31 08:19:12 +01003916 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003917
3918 log_method = getattr(logging, method)
3919 if level is not None:
3920 log_method(level, "test me")
3921 else:
3922 log_method("test me")
3923
3924 # basicConfig was called with no arguments
3925 self.assertEqual(called, [((), {})])
3926
3927 def test_log(self):
3928 self._test_log('log', logging.WARNING)
3929
3930 def test_debug(self):
3931 self._test_log('debug')
3932
3933 def test_info(self):
3934 self._test_log('info')
3935
3936 def test_warning(self):
3937 self._test_log('warning')
3938
3939 def test_error(self):
3940 self._test_log('error')
3941
3942 def test_critical(self):
3943 self._test_log('critical')
3944
3945
3946class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003947 def setUp(self):
3948 super(LoggerAdapterTest, self).setUp()
3949 old_handler_list = logging._handlerList[:]
3950
3951 self.recording = RecordingHandler()
3952 self.logger = logging.root
3953 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003954 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003955 self.addCleanup(self.recording.close)
3956
3957 def cleanup():
3958 logging._handlerList[:] = old_handler_list
3959
3960 self.addCleanup(cleanup)
3961 self.addCleanup(logging.shutdown)
3962 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3963
3964 def test_exception(self):
3965 msg = 'testing exception: %r'
3966 exc = None
3967 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003968 1 / 0
3969 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003970 exc = e
3971 self.adapter.exception(msg, self.recording)
3972
3973 self.assertEqual(len(self.recording.records), 1)
3974 record = self.recording.records[0]
3975 self.assertEqual(record.levelno, logging.ERROR)
3976 self.assertEqual(record.msg, msg)
3977 self.assertEqual(record.args, (self.recording,))
3978 self.assertEqual(record.exc_info,
3979 (exc.__class__, exc, exc.__traceback__))
3980
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003981 def test_exception_excinfo(self):
3982 try:
3983 1 / 0
3984 except ZeroDivisionError as e:
3985 exc = e
3986
3987 self.adapter.exception('exc_info test', exc_info=exc)
3988
3989 self.assertEqual(len(self.recording.records), 1)
3990 record = self.recording.records[0]
3991 self.assertEqual(record.exc_info,
3992 (exc.__class__, exc, exc.__traceback__))
3993
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003994 def test_critical(self):
3995 msg = 'critical test! %r'
3996 self.adapter.critical(msg, self.recording)
3997
3998 self.assertEqual(len(self.recording.records), 1)
3999 record = self.recording.records[0]
4000 self.assertEqual(record.levelno, logging.CRITICAL)
4001 self.assertEqual(record.msg, msg)
4002 self.assertEqual(record.args, (self.recording,))
4003
4004 def test_is_enabled_for(self):
4005 old_disable = self.adapter.logger.manager.disable
4006 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004007 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
4008 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004009 self.assertFalse(self.adapter.isEnabledFor(32))
4010
4011 def test_has_handlers(self):
4012 self.assertTrue(self.adapter.hasHandlers())
4013
4014 for handler in self.logger.handlers:
4015 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004016
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004017 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004018 self.assertFalse(self.adapter.hasHandlers())
4019
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004020 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07004021 class Adapter(logging.LoggerAdapter):
4022 prefix = 'Adapter'
4023
4024 def process(self, msg, kwargs):
4025 return f"{self.prefix} {msg}", kwargs
4026
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004027 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07004028 adapter = Adapter(logger=self.logger, extra=None)
4029 adapter_adapter = Adapter(logger=adapter, extra=None)
4030 adapter_adapter.prefix = 'AdapterAdapter'
4031 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004032 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004033 self.assertEqual(len(self.recording.records), 1)
4034 record = self.recording.records[0]
4035 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004036 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004037 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004038 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004039 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004040 self.assertIs(self.logger.manager, orig_manager)
4041 temp_manager = object()
4042 try:
4043 adapter_adapter.manager = temp_manager
4044 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004045 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004046 self.assertIs(self.logger.manager, temp_manager)
4047 finally:
4048 adapter_adapter.manager = orig_manager
4049 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004050 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004051 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004052
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004053
4054class LoggerTest(BaseTest):
4055
4056 def setUp(self):
4057 super(LoggerTest, self).setUp()
4058 self.recording = RecordingHandler()
4059 self.logger = logging.Logger(name='blah')
4060 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004061 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004062 self.addCleanup(self.recording.close)
4063 self.addCleanup(logging.shutdown)
4064
4065 def test_set_invalid_level(self):
4066 self.assertRaises(TypeError, self.logger.setLevel, object())
4067
4068 def test_exception(self):
4069 msg = 'testing exception: %r'
4070 exc = None
4071 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004072 1 / 0
4073 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004074 exc = e
4075 self.logger.exception(msg, self.recording)
4076
4077 self.assertEqual(len(self.recording.records), 1)
4078 record = self.recording.records[0]
4079 self.assertEqual(record.levelno, logging.ERROR)
4080 self.assertEqual(record.msg, msg)
4081 self.assertEqual(record.args, (self.recording,))
4082 self.assertEqual(record.exc_info,
4083 (exc.__class__, exc, exc.__traceback__))
4084
4085 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004086 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004087 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004088
4089 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004090 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004091 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004092
4093 def test_find_caller_with_stack_info(self):
4094 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004095 support.patch(self, logging.traceback, 'print_stack',
4096 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004097
4098 self.logger.findCaller(stack_info=True)
4099
4100 self.assertEqual(len(called), 1)
4101 self.assertEqual('Stack (most recent call last):\n', called[0])
4102
Vinay Sajipdde9fdb2018-06-05 17:24:18 +01004103 def test_find_caller_with_stacklevel(self):
4104 the_level = 1
4105
4106 def innermost():
4107 self.logger.warning('test', stacklevel=the_level)
4108
4109 def inner():
4110 innermost()
4111
4112 def outer():
4113 inner()
4114
4115 records = self.recording.records
4116 outer()
4117 self.assertEqual(records[-1].funcName, 'innermost')
4118 lineno = records[-1].lineno
4119 the_level += 1
4120 outer()
4121 self.assertEqual(records[-1].funcName, 'inner')
4122 self.assertGreater(records[-1].lineno, lineno)
4123 lineno = records[-1].lineno
4124 the_level += 1
4125 outer()
4126 self.assertEqual(records[-1].funcName, 'outer')
4127 self.assertGreater(records[-1].lineno, lineno)
4128 lineno = records[-1].lineno
4129 the_level += 1
4130 outer()
4131 self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
4132 self.assertGreater(records[-1].lineno, lineno)
4133
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004134 def test_make_record_with_extra_overwrite(self):
4135 name = 'my record'
4136 level = 13
4137 fn = lno = msg = args = exc_info = func = sinfo = None
4138 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4139 exc_info, func, sinfo)
4140
4141 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4142 extra = {key: 'some value'}
4143 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4144 fn, lno, msg, args, exc_info,
4145 extra=extra, sinfo=sinfo)
4146
4147 def test_make_record_with_extra_no_overwrite(self):
4148 name = 'my record'
4149 level = 13
4150 fn = lno = msg = args = exc_info = func = sinfo = None
4151 extra = {'valid_key': 'some value'}
4152 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4153 exc_info, extra=extra, sinfo=sinfo)
4154 self.assertIn('valid_key', result.__dict__)
4155
4156 def test_has_handlers(self):
4157 self.assertTrue(self.logger.hasHandlers())
4158
4159 for handler in self.logger.handlers:
4160 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004161 self.assertFalse(self.logger.hasHandlers())
4162
4163 def test_has_handlers_no_propagate(self):
4164 child_logger = logging.getLogger('blah.child')
4165 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004166 self.assertFalse(child_logger.hasHandlers())
4167
4168 def test_is_enabled_for(self):
4169 old_disable = self.logger.manager.disable
4170 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004171 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004172 self.assertFalse(self.logger.isEnabledFor(22))
4173
Timo Furrer6e3ca642018-06-01 09:29:46 +02004174 def test_is_enabled_for_disabled_logger(self):
4175 old_disabled = self.logger.disabled
4176 old_disable = self.logger.manager.disable
4177
4178 self.logger.disabled = True
4179 self.logger.manager.disable = 21
4180
4181 self.addCleanup(setattr, self.logger, 'disabled', old_disabled)
4182 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
4183
4184 self.assertFalse(self.logger.isEnabledFor(22))
4185
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004186 def test_root_logger_aliases(self):
4187 root = logging.getLogger()
4188 self.assertIs(root, logging.root)
4189 self.assertIs(root, logging.getLogger(None))
4190 self.assertIs(root, logging.getLogger(''))
4191 self.assertIs(root, logging.getLogger('foo').root)
4192 self.assertIs(root, logging.getLogger('foo.bar').root)
4193 self.assertIs(root, logging.getLogger('foo').parent)
4194
4195 self.assertIsNot(root, logging.getLogger('\0'))
4196 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4197
4198 def test_invalid_names(self):
4199 self.assertRaises(TypeError, logging.getLogger, any)
4200 self.assertRaises(TypeError, logging.getLogger, b'foo')
4201
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004202 def test_pickling(self):
4203 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4204 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4205 logger = logging.getLogger(name)
4206 s = pickle.dumps(logger, proto)
4207 unpickled = pickle.loads(s)
4208 self.assertIs(unpickled, logger)
4209
Avram Lubkin78c18a92017-07-30 05:36:33 -04004210 def test_caching(self):
4211 root = self.root_logger
4212 logger1 = logging.getLogger("abc")
4213 logger2 = logging.getLogger("abc.def")
4214
4215 # Set root logger level and ensure cache is empty
4216 root.setLevel(logging.ERROR)
4217 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4218 self.assertEqual(logger2._cache, {})
4219
4220 # Ensure cache is populated and calls are consistent
4221 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4222 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4223 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4224 self.assertEqual(root._cache, {})
4225 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4226
4227 # Ensure root cache gets populated
4228 self.assertEqual(root._cache, {})
4229 self.assertTrue(root.isEnabledFor(logging.ERROR))
4230 self.assertEqual(root._cache, {logging.ERROR: True})
4231
4232 # Set parent logger level and ensure caches are emptied
4233 logger1.setLevel(logging.CRITICAL)
4234 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4235 self.assertEqual(logger2._cache, {})
4236
4237 # Ensure logger2 uses parent logger's effective level
4238 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4239
4240 # Set level to NOTSET and ensure caches are empty
4241 logger2.setLevel(logging.NOTSET)
4242 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4243 self.assertEqual(logger2._cache, {})
4244 self.assertEqual(logger1._cache, {})
4245 self.assertEqual(root._cache, {})
4246
4247 # Verify logger2 follows parent and not root
4248 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4249 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4250 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4251 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4252 self.assertTrue(root.isEnabledFor(logging.ERROR))
4253
4254 # Disable logging in manager and ensure caches are clear
4255 logging.disable()
4256 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4257 self.assertEqual(logger2._cache, {})
4258 self.assertEqual(logger1._cache, {})
4259 self.assertEqual(root._cache, {})
4260
4261 # Ensure no loggers are enabled
4262 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4263 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4264 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4265
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004266
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004267class BaseFileTest(BaseTest):
4268 "Base class for handler tests that write log files"
4269
4270 def setUp(self):
4271 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004272 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4273 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004274 self.rmfiles = []
4275
4276 def tearDown(self):
4277 for fn in self.rmfiles:
4278 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004279 if os.path.exists(self.fn):
4280 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004281 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004282
4283 def assertLogFile(self, filename):
4284 "Assert a log file is there and register it for deletion"
4285 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004286 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004287 self.rmfiles.append(filename)
4288
4289
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004290class FileHandlerTest(BaseFileTest):
4291 def test_delay(self):
4292 os.unlink(self.fn)
4293 fh = logging.FileHandler(self.fn, delay=True)
4294 self.assertIsNone(fh.stream)
4295 self.assertFalse(os.path.exists(self.fn))
4296 fh.handle(logging.makeLogRecord({}))
4297 self.assertIsNotNone(fh.stream)
4298 self.assertTrue(os.path.exists(self.fn))
4299 fh.close()
4300
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004301class RotatingFileHandlerTest(BaseFileTest):
4302 def next_rec(self):
4303 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4304 self.next_message(), None, None, None)
4305
4306 def test_should_not_rollover(self):
4307 # If maxbytes is zero rollover never occurs
4308 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4309 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004310 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004311
4312 def test_should_rollover(self):
4313 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4314 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004315 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004316
4317 def test_file_created(self):
4318 # checks that the file is created and assumes it was created
4319 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004320 rh = logging.handlers.RotatingFileHandler(self.fn)
4321 rh.emit(self.next_rec())
4322 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004323 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004324
4325 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004326 def namer(name):
4327 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004328 rh = logging.handlers.RotatingFileHandler(
4329 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004330 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004331 rh.emit(self.next_rec())
4332 self.assertLogFile(self.fn)
4333 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004334 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004335 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004336 self.assertLogFile(namer(self.fn + ".2"))
4337 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4338 rh.close()
4339
Vinay Sajip1feedb42014-05-31 08:19:12 +01004340 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004341 def test_rotator(self):
4342 def namer(name):
4343 return name + ".gz"
4344
4345 def rotator(source, dest):
4346 with open(source, "rb") as sf:
4347 data = sf.read()
4348 compressed = zlib.compress(data, 9)
4349 with open(dest, "wb") as df:
4350 df.write(compressed)
4351 os.remove(source)
4352
4353 rh = logging.handlers.RotatingFileHandler(
4354 self.fn, backupCount=2, maxBytes=1)
4355 rh.rotator = rotator
4356 rh.namer = namer
4357 m1 = self.next_rec()
4358 rh.emit(m1)
4359 self.assertLogFile(self.fn)
4360 m2 = self.next_rec()
4361 rh.emit(m2)
4362 fn = namer(self.fn + ".1")
4363 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004364 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004365 with open(fn, "rb") as f:
4366 compressed = f.read()
4367 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004368 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004369 rh.emit(self.next_rec())
4370 fn = namer(self.fn + ".2")
4371 self.assertLogFile(fn)
4372 with open(fn, "rb") as f:
4373 compressed = f.read()
4374 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004375 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004376 rh.emit(self.next_rec())
4377 fn = namer(self.fn + ".2")
4378 with open(fn, "rb") as f:
4379 compressed = f.read()
4380 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004381 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004382 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004383 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004384
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004385class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004386 # other test methods added below
4387 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004388 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4389 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004390 fmt = logging.Formatter('%(asctime)s %(message)s')
4391 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004392 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004393 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004394 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004395 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004396 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004397 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004398 fh.close()
4399 # At this point, we should have a recent rotated file which we
4400 # can test for the existence of. However, in practice, on some
4401 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004402 # in time to go to look for the log file. So, we go back a fair
4403 # bit, and stop as soon as we see a rotated file. In theory this
4404 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004405 found = False
4406 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004407 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004408 for secs in range(GO_BACK):
4409 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004410 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4411 found = os.path.exists(fn)
4412 if found:
4413 self.rmfiles.append(fn)
4414 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004415 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4416 if not found:
Mike53f7a7c2017-12-14 14:04:53 +03004417 # print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004418 dn, fn = os.path.split(self.fn)
4419 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004420 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4421 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004422 for f in files:
4423 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004424 path = os.path.join(dn, f)
4425 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004426 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004427 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004428
Vinay Sajip0372e102011-05-05 12:59:14 +01004429 def test_invalid(self):
4430 assertRaises = self.assertRaises
4431 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004432 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004433 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004434 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004435 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004436 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004437
Vinay Sajipa7130792013-04-12 17:04:23 +01004438 def test_compute_rollover_daily_attime(self):
4439 currentTime = 0
4440 atTime = datetime.time(12, 0, 0)
4441 rh = logging.handlers.TimedRotatingFileHandler(
4442 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4443 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004444 try:
4445 actual = rh.computeRollover(currentTime)
4446 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004447
Vinay Sajipd86ac962013-04-14 12:20:46 +01004448 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4449 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4450 finally:
4451 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004452
Vinay Sajip10e8c492013-05-18 10:19:54 -07004453 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004454 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004455 currentTime = int(time.time())
4456 today = currentTime - currentTime % 86400
4457
Vinay Sajipa7130792013-04-12 17:04:23 +01004458 atTime = datetime.time(12, 0, 0)
4459
Vinay Sajip10e8c492013-05-18 10:19:54 -07004460 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004461 for day in range(7):
4462 rh = logging.handlers.TimedRotatingFileHandler(
4463 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4464 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004465 try:
4466 if wday > day:
4467 # The rollover day has already passed this week, so we
4468 # go over into next week
4469 expected = (7 - wday + day)
4470 else:
4471 expected = (day - wday)
4472 # At this point expected is in days from now, convert to seconds
4473 expected *= 24 * 60 * 60
4474 # Add in the rollover time
4475 expected += 12 * 60 * 60
4476 # Add in adjustment for today
4477 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004478 actual = rh.computeRollover(today)
4479 if actual != expected:
4480 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004481 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004482 self.assertEqual(actual, expected)
4483 if day == wday:
4484 # goes into following week
4485 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004486 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004487 if actual != expected:
4488 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004489 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004490 self.assertEqual(actual, expected)
4491 finally:
4492 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004493
4494
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004495def secs(**kw):
4496 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4497
4498for when, exp in (('S', 1),
4499 ('M', 60),
4500 ('H', 60 * 60),
4501 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004502 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004503 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004504 ('W0', secs(days=4, hours=24)),
4505 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004506 def test_compute_rollover(self, when=when, exp=exp):
4507 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004508 self.fn, when=when, interval=1, backupCount=0, utc=True)
4509 currentTime = 0.0
4510 actual = rh.computeRollover(currentTime)
4511 if exp != actual:
4512 # Failures occur on some systems for MIDNIGHT and W0.
4513 # Print detailed calculation for MIDNIGHT so we can try to see
4514 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004515 if when == 'MIDNIGHT':
4516 try:
4517 if rh.utc:
4518 t = time.gmtime(currentTime)
4519 else:
4520 t = time.localtime(currentTime)
4521 currentHour = t[3]
4522 currentMinute = t[4]
4523 currentSecond = t[5]
4524 # r is the number of seconds left between now and midnight
4525 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4526 currentMinute) * 60 +
4527 currentSecond)
4528 result = currentTime + r
4529 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4530 print('currentHour: %s' % currentHour, file=sys.stderr)
4531 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4532 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4533 print('r: %s' % r, file=sys.stderr)
4534 print('result: %s' % result, file=sys.stderr)
4535 except Exception:
4536 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4537 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004538 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004539 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4540
Vinay Sajip60ccd822011-05-09 17:32:09 +01004541
Vinay Sajip223349c2015-10-01 20:37:54 +01004542@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004543class NTEventLogHandlerTest(BaseTest):
4544 def test_basic(self):
4545 logtype = 'Application'
4546 elh = win32evtlog.OpenEventLog(None, logtype)
4547 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004548
4549 try:
4550 h = logging.handlers.NTEventLogHandler('test_logging')
4551 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004552 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004553 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004554 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004555
Vinay Sajip60ccd822011-05-09 17:32:09 +01004556 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4557 h.handle(r)
4558 h.close()
4559 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004560 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004561 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4562 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4563 found = False
4564 GO_BACK = 100
4565 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4566 for e in events:
4567 if e.SourceName != 'test_logging':
4568 continue
4569 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4570 if msg != 'Test Log Message\r\n':
4571 continue
4572 found = True
4573 break
4574 msg = 'Record not found in event log, went back %d records' % GO_BACK
4575 self.assertTrue(found, msg=msg)
4576
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004577
4578class MiscTestCase(unittest.TestCase):
4579 def test__all__(self):
4580 blacklist = {'logThreads', 'logMultiprocessing',
4581 'logProcesses', 'currentframe',
4582 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4583 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004584 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004585 support.check__all__(self, logging, blacklist=blacklist)
4586
4587
Christian Heimes180510d2008-03-03 19:15:45 +00004588# Set the locale to the platform-dependent default. I have no idea
4589# why the test does this, but in any case we save the current locale
4590# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004591@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004592def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004593 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004594 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4595 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4596 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4597 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4598 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4599 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4600 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4601 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004602 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004603 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004604 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004605 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004606 ]
4607 if hasattr(logging.handlers, 'QueueListener'):
4608 tests.append(QueueListenerTest)
4609 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004610
Christian Heimes180510d2008-03-03 19:15:45 +00004611if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004612 test_main()