blob: 7101e3b15760c2457b3252cfa821b9f5179a07d4 [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):
181 #Logging levels in a flat logger namespace.
182 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):
251 #Logging levels in a nested namespace, inherited from parent loggers.
252 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 """
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200776 try:
777 asyncore.loop(poll_interval, map=self._map)
778 except OSError:
779 # On FreeBSD 8, closing the server repeatably
780 # raises this error. We swallow it if the
781 # server has been closed.
782 if self.connected or self.accepting:
783 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100784
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200785 def stop(self, timeout=None):
786 """
787 Stop the thread by closing the server instance.
788 Wait for the server thread to terminate.
Vinay Sajipa463d252011-04-30 21:52:48 +0100789
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200790 :param timeout: How long to wait for the server thread
791 to terminate.
792 """
793 self.close()
Victor Stinnerb9b69002017-09-14 14:40:56 -0700794 support.join_thread(self._thread, timeout)
795 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200796 asyncore.close_all(map=self._map, ignore_all=True)
Vinay Sajipa463d252011-04-30 21:52:48 +0100797
Vinay Sajip7367d082011-05-02 13:17:27 +0100798
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200799class ControlMixin(object):
800 """
801 This mixin is used to start a server on a separate thread, and
802 shut it down programmatically. Request handling is simplified - instead
803 of needing to derive a suitable RequestHandler subclass, you just
804 provide a callable which will be passed each received request to be
805 processed.
Vinay Sajip7367d082011-05-02 13:17:27 +0100806
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200807 :param handler: A handler callable which will be called with a
808 single parameter - the request - in order to
809 process the request. This handler is called on the
810 server thread, effectively meaning that requests are
811 processed serially. While not quite Web scale ;-),
812 this should be fine for testing applications.
813 :param poll_interval: The polling interval in seconds.
814 """
815 def __init__(self, handler, poll_interval):
816 self._thread = None
817 self.poll_interval = poll_interval
818 self._handler = handler
819 self.ready = threading.Event()
Vinay Sajip7367d082011-05-02 13:17:27 +0100820
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200821 def start(self):
822 """
823 Create a daemon thread to run the server, and start it.
824 """
825 self._thread = t = threading.Thread(target=self.serve_forever,
826 args=(self.poll_interval,))
827 t.setDaemon(True)
828 t.start()
Vinay Sajip7367d082011-05-02 13:17:27 +0100829
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200830 def serve_forever(self, poll_interval):
831 """
832 Run the server. Set the ready flag before entering the
833 service loop.
834 """
835 self.ready.set()
836 super(ControlMixin, self).serve_forever(poll_interval)
837
838 def stop(self, timeout=None):
839 """
840 Tell the server thread to stop, and wait for it to do so.
841
842 :param timeout: How long to wait for the server thread
843 to terminate.
844 """
845 self.shutdown()
846 if self._thread is not None:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700847 support.join_thread(self._thread, timeout)
Vinay Sajip7367d082011-05-02 13:17:27 +0100848 self._thread = None
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200849 self.server_close()
850 self.ready.clear()
Vinay Sajip7367d082011-05-02 13:17:27 +0100851
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200852class TestHTTPServer(ControlMixin, HTTPServer):
853 """
854 An HTTP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100855
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200856 :param addr: A tuple with the IP address and port to listen on.
857 :param handler: A handler callable which will be called with a
858 single parameter - the request - in order to
859 process the request.
860 :param poll_interval: The polling interval in seconds.
861 :param log: Pass ``True`` to enable log messages.
862 """
863 def __init__(self, addr, handler, poll_interval=0.5,
864 log=False, sslctx=None):
865 class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
866 def __getattr__(self, name, default=None):
867 if name.startswith('do_'):
868 return self.process_request
869 raise AttributeError(name)
Vinay Sajip7367d082011-05-02 13:17:27 +0100870
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200871 def process_request(self):
872 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100873
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200874 def log_message(self, format, *args):
875 if log:
876 super(DelegatingHTTPRequestHandler,
877 self).log_message(format, *args)
878 HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler)
879 ControlMixin.__init__(self, handler, poll_interval)
880 self.sslctx = sslctx
Vinay Sajip7367d082011-05-02 13:17:27 +0100881
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200882 def get_request(self):
883 try:
884 sock, addr = self.socket.accept()
885 if self.sslctx:
886 sock = self.sslctx.wrap_socket(sock, server_side=True)
887 except OSError as e:
888 # socket errors are silenced by the caller, print them here
889 sys.stderr.write("Got an error:\n%s\n" % e)
890 raise
891 return sock, addr
Vinay Sajip7367d082011-05-02 13:17:27 +0100892
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200893class TestTCPServer(ControlMixin, ThreadingTCPServer):
894 """
895 A TCP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100896
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200897 :param addr: A tuple with the IP address and port to listen on.
898 :param handler: A handler callable which will be called with a single
899 parameter - the request - in order to process the request.
900 :param poll_interval: The polling interval in seconds.
901 :bind_and_activate: If True (the default), binds the server and starts it
902 listening. If False, you need to call
903 :meth:`server_bind` and :meth:`server_activate` at
904 some later time before calling :meth:`start`, so that
905 the server will set up the socket and listen on it.
906 """
Vinay Sajip7367d082011-05-02 13:17:27 +0100907
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200908 allow_reuse_address = True
Vinay Sajip7367d082011-05-02 13:17:27 +0100909
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200910 def __init__(self, addr, handler, poll_interval=0.5,
911 bind_and_activate=True):
912 class DelegatingTCPRequestHandler(StreamRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100913
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200914 def handle(self):
915 self.server._handler(self)
916 ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler,
917 bind_and_activate)
918 ControlMixin.__init__(self, handler, poll_interval)
Vinay Sajip32565b62011-05-21 00:34:51 +0100919
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200920 def server_bind(self):
921 super(TestTCPServer, self).server_bind()
922 self.port = self.socket.getsockname()[1]
Vinay Sajip7367d082011-05-02 13:17:27 +0100923
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200924class TestUDPServer(ControlMixin, ThreadingUDPServer):
925 """
926 A UDP server which is controllable using :class:`ControlMixin`.
Vinay Sajip7367d082011-05-02 13:17:27 +0100927
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200928 :param addr: A tuple with the IP address and port to listen on.
929 :param handler: A handler callable which will be called with a
930 single parameter - the request - in order to
931 process the request.
932 :param poll_interval: The polling interval for shutdown requests,
933 in seconds.
934 :bind_and_activate: If True (the default), binds the server and
935 starts it listening. If False, you need to
936 call :meth:`server_bind` and
937 :meth:`server_activate` at some later time
938 before calling :meth:`start`, so that the server will
939 set up the socket and listen on it.
940 """
941 def __init__(self, addr, handler, poll_interval=0.5,
942 bind_and_activate=True):
943 class DelegatingUDPRequestHandler(DatagramRequestHandler):
Vinay Sajip7367d082011-05-02 13:17:27 +0100944
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200945 def handle(self):
946 self.server._handler(self)
Vinay Sajip7367d082011-05-02 13:17:27 +0100947
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200948 def finish(self):
949 data = self.wfile.getvalue()
950 if data:
951 try:
952 super(DelegatingUDPRequestHandler, self).finish()
953 except OSError:
954 if not self.server._closed:
955 raise
Vinay Sajipce7c9782011-05-17 07:15:53 +0100956
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200957 ThreadingUDPServer.__init__(self, addr,
958 DelegatingUDPRequestHandler,
959 bind_and_activate)
960 ControlMixin.__init__(self, handler, poll_interval)
961 self._closed = False
Vinay Sajipce7c9782011-05-17 07:15:53 +0100962
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200963 def server_bind(self):
964 super(TestUDPServer, self).server_bind()
965 self.port = self.socket.getsockname()[1]
Vinay Sajipce7c9782011-05-17 07:15:53 +0100966
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200967 def server_close(self):
968 super(TestUDPServer, self).server_close()
969 self._closed = True
Vinay Sajipce7c9782011-05-17 07:15:53 +0100970
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200971if hasattr(socket, "AF_UNIX"):
972 class TestUnixStreamServer(TestTCPServer):
973 address_family = socket.AF_UNIX
Vinay Sajipce7c9782011-05-17 07:15:53 +0100974
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200975 class TestUnixDatagramServer(TestUDPServer):
976 address_family = socket.AF_UNIX
Vinay Sajip5421f352013-09-27 18:18:28 +0100977
Vinay Sajip7367d082011-05-02 13:17:27 +0100978# - end of server_helper section
Vinay Sajipa463d252011-04-30 21:52:48 +0100979
980class SMTPHandlerTest(BaseTest):
Vinay Sajip827f5d32013-12-03 11:28:55 +0000981 TIMEOUT = 8.0
Victor Stinner4bcfa3a2017-04-25 00:41:36 +0200982
Vinay Sajipa463d252011-04-30 21:52:48 +0100983 def test_basic(self):
Vinay Sajip7367d082011-05-02 13:17:27 +0100984 sockmap = {}
Ned Deily1e012e62015-01-17 16:57:19 -0800985 server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
Vinay Sajip7367d082011-05-02 13:17:27 +0100986 sockmap)
987 server.start()
Ned Deily1e012e62015-01-17 16:57:19 -0800988 addr = (support.HOST, server.port)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000989 h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log',
990 timeout=self.TIMEOUT)
Vinay Sajipa463d252011-04-30 21:52:48 +0100991 self.assertEqual(h.toaddrs, ['you'])
992 self.messages = []
Vinay Sajip277640a2015-10-17 16:13:10 +0100993 r = logging.makeLogRecord({'msg': 'Hello \u2713'})
Vinay Sajip7367d082011-05-02 13:17:27 +0100994 self.handled = threading.Event()
Vinay Sajipa463d252011-04-30 21:52:48 +0100995 h.handle(r)
Vinay Sajip827f5d32013-12-03 11:28:55 +0000996 self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
Vinay Sajipa463d252011-04-30 21:52:48 +0100997 server.stop()
Vinay Sajip17160fd2012-03-15 12:02:08 +0000998 self.assertTrue(self.handled.is_set())
Vinay Sajipa463d252011-04-30 21:52:48 +0100999 self.assertEqual(len(self.messages), 1)
1000 peer, mailfrom, rcpttos, data = self.messages[0]
1001 self.assertEqual(mailfrom, 'me')
1002 self.assertEqual(rcpttos, ['you'])
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001003 self.assertIn('\nSubject: Log\n', data)
Vinay Sajip277640a2015-10-17 16:13:10 +01001004 self.assertTrue(data.endswith('\n\nHello \u2713'))
Vinay Sajipa463d252011-04-30 21:52:48 +01001005 h.close()
1006
1007 def process_message(self, *args):
1008 self.messages.append(args)
Vinay Sajip7367d082011-05-02 13:17:27 +01001009 self.handled.set()
Vinay Sajipa463d252011-04-30 21:52:48 +01001010
Christian Heimes180510d2008-03-03 19:15:45 +00001011class MemoryHandlerTest(BaseTest):
1012
1013 """Tests for the MemoryHandler."""
1014
1015 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001016 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001017
1018 def setUp(self):
1019 BaseTest.setUp(self)
1020 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001021 self.root_hdlr)
Christian Heimes180510d2008-03-03 19:15:45 +00001022 self.mem_logger = logging.getLogger('mem')
1023 self.mem_logger.propagate = 0
1024 self.mem_logger.addHandler(self.mem_hdlr)
1025
1026 def tearDown(self):
1027 self.mem_hdlr.close()
Benjamin Peterson2a691a82008-03-31 01:51:45 +00001028 BaseTest.tearDown(self)
Christian Heimes180510d2008-03-03 19:15:45 +00001029
1030 def test_flush(self):
1031 # The memory handler flushes to its target handler based on specific
1032 # criteria (message count and message level).
1033 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001034 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001035 self.mem_logger.info(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001036 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001037 # This will flush because the level is >= logging.WARNING
Vinay Sajipb9e46e92011-10-26 13:17:20 +01001038 self.mem_logger.warning(self.next_message())
Christian Heimes180510d2008-03-03 19:15:45 +00001039 lines = [
1040 ('DEBUG', '1'),
1041 ('INFO', '2'),
1042 ('WARNING', '3'),
1043 ]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001044 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001045 for n in (4, 14):
1046 for i in range(9):
1047 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001048 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001049 # This will flush because it's the 10th message since the last
1050 # flush.
1051 self.mem_logger.debug(self.next_message())
1052 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001053 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001054
1055 self.mem_logger.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001056 self.assert_log_lines(lines)
Christian Heimes180510d2008-03-03 19:15:45 +00001057
Vinay Sajipdb8f4632016-09-08 01:37:03 +01001058 def test_flush_on_close(self):
1059 """
1060 Test that the flush-on-close configuration works as expected.
1061 """
1062 self.mem_logger.debug(self.next_message())
1063 self.assert_log_lines([])
1064 self.mem_logger.info(self.next_message())
1065 self.assert_log_lines([])
1066 self.mem_logger.removeHandler(self.mem_hdlr)
1067 # Default behaviour is to flush on close. Check that it happens.
1068 self.mem_hdlr.close()
1069 lines = [
1070 ('DEBUG', '1'),
1071 ('INFO', '2'),
1072 ]
1073 self.assert_log_lines(lines)
1074 # Now configure for flushing not to be done on close.
1075 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
1076 self.root_hdlr,
1077 False)
1078 self.mem_logger.addHandler(self.mem_hdlr)
1079 self.mem_logger.debug(self.next_message())
1080 self.assert_log_lines(lines) # no change
1081 self.mem_logger.info(self.next_message())
1082 self.assert_log_lines(lines) # no change
1083 self.mem_logger.removeHandler(self.mem_hdlr)
1084 self.mem_hdlr.close()
1085 # assert that no new lines have been added
1086 self.assert_log_lines(lines) # no change
1087
Christian Heimes180510d2008-03-03 19:15:45 +00001088
1089class ExceptionFormatter(logging.Formatter):
1090 """A special exception formatter."""
1091 def formatException(self, ei):
1092 return "Got a [%s]" % ei[0].__name__
1093
1094
1095class ConfigFileTest(BaseTest):
1096
1097 """Reading logging config from a .ini-style config file."""
1098
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001099 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Christian Heimes180510d2008-03-03 19:15:45 +00001100
1101 # config0 is a standard configuration.
1102 config0 = """
1103 [loggers]
1104 keys=root
1105
1106 [handlers]
1107 keys=hand1
1108
1109 [formatters]
1110 keys=form1
1111
1112 [logger_root]
1113 level=WARNING
1114 handlers=hand1
1115
1116 [handler_hand1]
1117 class=StreamHandler
1118 level=NOTSET
1119 formatter=form1
1120 args=(sys.stdout,)
1121
1122 [formatter_form1]
1123 format=%(levelname)s ++ %(message)s
1124 datefmt=
1125 """
1126
1127 # config1 adds a little to the standard configuration.
1128 config1 = """
1129 [loggers]
1130 keys=root,parser
1131
1132 [handlers]
1133 keys=hand1
1134
1135 [formatters]
1136 keys=form1
1137
1138 [logger_root]
1139 level=WARNING
1140 handlers=
1141
1142 [logger_parser]
1143 level=DEBUG
1144 handlers=hand1
1145 propagate=1
1146 qualname=compiler.parser
1147
1148 [handler_hand1]
1149 class=StreamHandler
1150 level=NOTSET
1151 formatter=form1
1152 args=(sys.stdout,)
1153
1154 [formatter_form1]
1155 format=%(levelname)s ++ %(message)s
1156 datefmt=
1157 """
1158
Vinay Sajip3f84b072011-03-07 17:49:33 +00001159 # config1a moves the handler to the root.
1160 config1a = """
1161 [loggers]
1162 keys=root,parser
1163
1164 [handlers]
1165 keys=hand1
1166
1167 [formatters]
1168 keys=form1
1169
1170 [logger_root]
1171 level=WARNING
1172 handlers=hand1
1173
1174 [logger_parser]
1175 level=DEBUG
1176 handlers=
1177 propagate=1
1178 qualname=compiler.parser
1179
1180 [handler_hand1]
1181 class=StreamHandler
1182 level=NOTSET
1183 formatter=form1
1184 args=(sys.stdout,)
1185
1186 [formatter_form1]
1187 format=%(levelname)s ++ %(message)s
1188 datefmt=
1189 """
1190
Christian Heimes180510d2008-03-03 19:15:45 +00001191 # config2 has a subtle configuration error that should be reported
1192 config2 = config1.replace("sys.stdout", "sys.stbout")
1193
1194 # config3 has a less subtle configuration error
1195 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
1196
1197 # config4 specifies a custom formatter class to be loaded
1198 config4 = """
1199 [loggers]
1200 keys=root
1201
1202 [handlers]
1203 keys=hand1
1204
1205 [formatters]
1206 keys=form1
1207
1208 [logger_root]
1209 level=NOTSET
1210 handlers=hand1
1211
1212 [handler_hand1]
1213 class=StreamHandler
1214 level=NOTSET
1215 formatter=form1
1216 args=(sys.stdout,)
1217
1218 [formatter_form1]
1219 class=""" + __name__ + """.ExceptionFormatter
1220 format=%(levelname)s:%(name)s:%(message)s
1221 datefmt=
1222 """
1223
Georg Brandl3dbca812008-07-23 16:10:53 +00001224 # config5 specifies a custom handler class to be loaded
1225 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
1226
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001227 # config6 uses ', ' delimiters in the handlers and formatters sections
1228 config6 = """
1229 [loggers]
1230 keys=root,parser
1231
1232 [handlers]
1233 keys=hand1, hand2
1234
1235 [formatters]
1236 keys=form1, form2
1237
1238 [logger_root]
1239 level=WARNING
1240 handlers=
1241
1242 [logger_parser]
1243 level=DEBUG
1244 handlers=hand1
1245 propagate=1
1246 qualname=compiler.parser
1247
1248 [handler_hand1]
1249 class=StreamHandler
1250 level=NOTSET
1251 formatter=form1
1252 args=(sys.stdout,)
1253
1254 [handler_hand2]
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001255 class=StreamHandler
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001256 level=NOTSET
1257 formatter=form1
Benjamin Peterson9aa42992008-09-10 21:57:34 +00001258 args=(sys.stderr,)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001259
1260 [formatter_form1]
1261 format=%(levelname)s ++ %(message)s
1262 datefmt=
1263
1264 [formatter_form2]
1265 format=%(message)s
1266 datefmt=
1267 """
1268
Preston Landers6ea56d22017-08-02 15:44:28 -05001269 # config7 adds a compiler logger, and uses kwargs instead of args.
Vinay Sajip3f84b072011-03-07 17:49:33 +00001270 config7 = """
1271 [loggers]
1272 keys=root,parser,compiler
1273
1274 [handlers]
1275 keys=hand1
1276
1277 [formatters]
1278 keys=form1
1279
1280 [logger_root]
1281 level=WARNING
1282 handlers=hand1
1283
1284 [logger_compiler]
1285 level=DEBUG
1286 handlers=
1287 propagate=1
1288 qualname=compiler
1289
1290 [logger_parser]
1291 level=DEBUG
1292 handlers=
1293 propagate=1
1294 qualname=compiler.parser
1295
1296 [handler_hand1]
1297 class=StreamHandler
1298 level=NOTSET
1299 formatter=form1
Preston Landers6ea56d22017-08-02 15:44:28 -05001300 kwargs={'stream': sys.stdout,}
Vinay Sajip3f84b072011-03-07 17:49:33 +00001301
1302 [formatter_form1]
1303 format=%(levelname)s ++ %(message)s
1304 datefmt=
1305 """
1306
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001307 disable_test = """
1308 [loggers]
1309 keys=root
1310
1311 [handlers]
1312 keys=screen
1313
1314 [formatters]
1315 keys=
1316
1317 [logger_root]
1318 level=DEBUG
1319 handlers=screen
1320
1321 [handler_screen]
1322 level=DEBUG
1323 class=StreamHandler
1324 args=(sys.stdout,)
1325 formatter=
1326 """
1327
1328 def apply_config(self, conf, **kwargs):
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001329 file = io.StringIO(textwrap.dedent(conf))
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001330 logging.config.fileConfig(file, **kwargs)
Christian Heimes180510d2008-03-03 19:15:45 +00001331
1332 def test_config0_ok(self):
1333 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001334 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001335 self.apply_config(self.config0)
1336 logger = logging.getLogger()
1337 # Won't output anything
1338 logger.info(self.next_message())
1339 # Outputs a message
1340 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001341 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001342 ('ERROR', '2'),
1343 ], stream=output)
1344 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001345 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001346
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001347 def test_config0_using_cp_ok(self):
1348 # A simple config file which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001349 with support.captured_stdout() as output:
Vinay Sajipcf9e2f22012-10-09 09:06:03 +01001350 file = io.StringIO(textwrap.dedent(self.config0))
1351 cp = configparser.ConfigParser()
1352 cp.read_file(file)
1353 logging.config.fileConfig(cp)
1354 logger = logging.getLogger()
1355 # Won't output anything
1356 logger.info(self.next_message())
1357 # Outputs a message
1358 logger.error(self.next_message())
1359 self.assert_log_lines([
1360 ('ERROR', '2'),
1361 ], stream=output)
1362 # Original logger output is empty.
1363 self.assert_log_lines([])
1364
Georg Brandl3dbca812008-07-23 16:10:53 +00001365 def test_config1_ok(self, config=config1):
Christian Heimes180510d2008-03-03 19:15:45 +00001366 # A config file defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001367 with support.captured_stdout() as output:
Georg Brandl3dbca812008-07-23 16:10:53 +00001368 self.apply_config(config)
Christian Heimes180510d2008-03-03 19:15:45 +00001369 logger = logging.getLogger("compiler.parser")
1370 # Both will output a message
1371 logger.info(self.next_message())
1372 logger.error(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001373 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001374 ('INFO', '1'),
1375 ('ERROR', '2'),
1376 ], stream=output)
1377 # Original logger output is empty.
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001378 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001379
1380 def test_config2_failure(self):
1381 # A simple config file which overrides the default settings.
1382 self.assertRaises(Exception, self.apply_config, self.config2)
1383
1384 def test_config3_failure(self):
1385 # A simple config file which overrides the default settings.
1386 self.assertRaises(Exception, self.apply_config, self.config3)
1387
1388 def test_config4_ok(self):
1389 # A config file specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01001390 with support.captured_stdout() as output:
Christian Heimes180510d2008-03-03 19:15:45 +00001391 self.apply_config(self.config4)
1392 logger = logging.getLogger()
1393 try:
1394 raise RuntimeError()
1395 except RuntimeError:
1396 logging.exception("just testing")
1397 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001398 self.assertEqual(output.getvalue(),
Christian Heimes180510d2008-03-03 19:15:45 +00001399 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1400 # Original logger output is empty
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001401 self.assert_log_lines([])
Christian Heimes180510d2008-03-03 19:15:45 +00001402
Georg Brandl3dbca812008-07-23 16:10:53 +00001403 def test_config5_ok(self):
1404 self.test_config1_ok(config=self.config5)
Christian Heimes180510d2008-03-03 19:15:45 +00001405
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001406 def test_config6_ok(self):
1407 self.test_config1_ok(config=self.config6)
1408
Vinay Sajip3f84b072011-03-07 17:49:33 +00001409 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01001410 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001411 self.apply_config(self.config1a)
1412 logger = logging.getLogger("compiler.parser")
1413 # See issue #11424. compiler-hyphenated sorts
1414 # between compiler and compiler.xyz and this
1415 # was preventing compiler.xyz from being included
1416 # in the child loggers of compiler because of an
1417 # overzealous loop termination condition.
1418 hyphenated = logging.getLogger('compiler-hyphenated')
1419 # All will output a message
1420 logger.info(self.next_message())
1421 logger.error(self.next_message())
1422 hyphenated.critical(self.next_message())
1423 self.assert_log_lines([
1424 ('INFO', '1'),
1425 ('ERROR', '2'),
1426 ('CRITICAL', '3'),
1427 ], stream=output)
1428 # Original logger output is empty.
1429 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01001430 with support.captured_stdout() as output:
Vinay Sajip3f84b072011-03-07 17:49:33 +00001431 self.apply_config(self.config7)
1432 logger = logging.getLogger("compiler.parser")
1433 self.assertFalse(logger.disabled)
1434 # Both will output a message
1435 logger.info(self.next_message())
1436 logger.error(self.next_message())
1437 logger = logging.getLogger("compiler.lexer")
1438 # Both will output a message
1439 logger.info(self.next_message())
1440 logger.error(self.next_message())
1441 # Will not appear
1442 hyphenated.critical(self.next_message())
1443 self.assert_log_lines([
1444 ('INFO', '4'),
1445 ('ERROR', '5'),
1446 ('INFO', '6'),
1447 ('ERROR', '7'),
1448 ], stream=output)
1449 # Original logger output is empty.
1450 self.assert_log_lines([])
1451
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001452 def test_logger_disabling(self):
1453 self.apply_config(self.disable_test)
Antoine Pitrou04d4d6a2013-09-14 21:16:39 +02001454 logger = logging.getLogger('some_pristine_logger')
Vinay Sajip68b4cc82013-03-23 11:18:45 +00001455 self.assertFalse(logger.disabled)
1456 self.apply_config(self.disable_test)
1457 self.assertTrue(logger.disabled)
1458 self.apply_config(self.disable_test, disable_existing_loggers=False)
1459 self.assertFalse(logger.disabled)
1460
Guido van Rossum2a1d5162003-01-21 21:05:22 +00001461
Christian Heimes180510d2008-03-03 19:15:45 +00001462class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001463
Christian Heimes180510d2008-03-03 19:15:45 +00001464 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001465
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001466 server_class = TestTCPServer
1467 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001468
Christian Heimes180510d2008-03-03 19:15:45 +00001469 def setUp(self):
1470 """Set up a TCP server to receive log messages, and a SocketHandler
1471 pointing to that server's address and port."""
1472 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001473 # Issue #29177: deal with errors that happen during setup
1474 self.server = self.sock_hdlr = self.server_exception = None
1475 try:
1476 self.server = server = self.server_class(self.address,
1477 self.handle_socket, 0.01)
1478 server.start()
1479 # Uncomment next line to test error recovery in setUp()
1480 # raise OSError('dummy error raised')
1481 except OSError as e:
1482 self.server_exception = e
1483 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001484 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001485 hcls = logging.handlers.SocketHandler
1486 if isinstance(server.server_address, tuple):
1487 self.sock_hdlr = hcls('localhost', server.port)
1488 else:
1489 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001490 self.log_output = ''
Christian Heimes180510d2008-03-03 19:15:45 +00001491 self.root_logger.removeHandler(self.root_logger.handlers[0])
1492 self.root_logger.addHandler(self.sock_hdlr)
Vinay Sajip7367d082011-05-02 13:17:27 +01001493 self.handled = threading.Semaphore(0)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001494
Christian Heimes180510d2008-03-03 19:15:45 +00001495 def tearDown(self):
1496 """Shutdown the TCP server."""
1497 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001498 if self.sock_hdlr:
1499 self.root_logger.removeHandler(self.sock_hdlr)
1500 self.sock_hdlr.close()
Victor Stinnerb8f41632017-09-13 01:47:22 -07001501 if self.server:
1502 self.server.stop(2.0)
Christian Heimes180510d2008-03-03 19:15:45 +00001503 finally:
1504 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001505
Vinay Sajip7367d082011-05-02 13:17:27 +01001506 def handle_socket(self, request):
1507 conn = request.connection
1508 while True:
1509 chunk = conn.recv(4)
1510 if len(chunk) < 4:
1511 break
1512 slen = struct.unpack(">L", chunk)[0]
1513 chunk = conn.recv(slen)
1514 while len(chunk) < slen:
1515 chunk = chunk + conn.recv(slen - len(chunk))
1516 obj = pickle.loads(chunk)
1517 record = logging.makeLogRecord(obj)
1518 self.log_output += record.msg + '\n'
1519 self.handled.release()
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001520
Christian Heimes180510d2008-03-03 19:15:45 +00001521 def test_output(self):
1522 # The log message sent to the SocketHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001523 if self.server_exception:
1524 self.skipTest(self.server_exception)
Christian Heimes180510d2008-03-03 19:15:45 +00001525 logger = logging.getLogger("tcp")
1526 logger.error("spam")
Vinay Sajip7367d082011-05-02 13:17:27 +01001527 self.handled.acquire()
Christian Heimes180510d2008-03-03 19:15:45 +00001528 logger.debug("eggs")
Vinay Sajip7367d082011-05-02 13:17:27 +01001529 self.handled.acquire()
1530 self.assertEqual(self.log_output, "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001531
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001532 def test_noserver(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001533 if self.server_exception:
1534 self.skipTest(self.server_exception)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001535 # Avoid timing-related failures due to SocketHandler's own hard-wired
1536 # one-second timeout on socket.create_connection() (issue #16264).
1537 self.sock_hdlr.retryStart = 2.5
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001538 # Kill the server
Vinay Sajip7367d082011-05-02 13:17:27 +01001539 self.server.stop(2.0)
Antoine Pitrouda201fa2012-10-21 17:18:27 +02001540 # The logging call should try to connect, which should fail
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001541 try:
1542 raise RuntimeError('Deliberate mistake')
1543 except RuntimeError:
1544 self.root_logger.exception('Never sent')
1545 self.root_logger.error('Never sent, either')
1546 now = time.time()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001547 self.assertGreater(self.sock_hdlr.retryTime, now)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01001548 time.sleep(self.sock_hdlr.retryTime - now + 0.001)
1549 self.root_logger.error('Nor this')
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001550
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001551def _get_temp_domain_socket():
1552 fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock')
1553 os.close(fd)
1554 # just need a name - file can't be present, or we'll get an
1555 # 'address already in use' error.
1556 os.remove(fn)
1557 return fn
Vinay Sajip7367d082011-05-02 13:17:27 +01001558
Victor Stinnerec5a8602014-06-02 14:41:51 +02001559@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001560class UnixSocketHandlerTest(SocketHandlerTest):
1561
1562 """Test for SocketHandler with unix sockets."""
1563
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001564 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001565 server_class = TestUnixStreamServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001566
1567 def setUp(self):
1568 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001569 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001570 SocketHandlerTest.setUp(self)
1571
1572 def tearDown(self):
1573 SocketHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001574 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001575
Vinay Sajip7367d082011-05-02 13:17:27 +01001576class DatagramHandlerTest(BaseTest):
1577
1578 """Test for DatagramHandler."""
1579
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001580 server_class = TestUDPServer
1581 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001582
Vinay Sajip7367d082011-05-02 13:17:27 +01001583 def setUp(self):
1584 """Set up a UDP server to receive log messages, and a DatagramHandler
1585 pointing to that server's address and port."""
1586 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001587 # Issue #29177: deal with errors that happen during setup
1588 self.server = self.sock_hdlr = self.server_exception = None
1589 try:
1590 self.server = server = self.server_class(self.address,
1591 self.handle_datagram, 0.01)
1592 server.start()
1593 # Uncomment next line to test error recovery in setUp()
1594 # raise OSError('dummy error raised')
1595 except OSError as e:
1596 self.server_exception = e
1597 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001598 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001599 hcls = logging.handlers.DatagramHandler
1600 if isinstance(server.server_address, tuple):
1601 self.sock_hdlr = hcls('localhost', server.port)
1602 else:
1603 self.sock_hdlr = hcls(server.server_address, None)
Vinay Sajip7367d082011-05-02 13:17:27 +01001604 self.log_output = ''
1605 self.root_logger.removeHandler(self.root_logger.handlers[0])
1606 self.root_logger.addHandler(self.sock_hdlr)
1607 self.handled = threading.Event()
1608
1609 def tearDown(self):
1610 """Shutdown the UDP server."""
1611 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001612 if self.server:
1613 self.server.stop(2.0)
1614 if self.sock_hdlr:
1615 self.root_logger.removeHandler(self.sock_hdlr)
1616 self.sock_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001617 finally:
1618 BaseTest.tearDown(self)
1619
1620 def handle_datagram(self, request):
1621 slen = struct.pack('>L', 0) # length of prefix
1622 packet = request.packet[len(slen):]
1623 obj = pickle.loads(packet)
1624 record = logging.makeLogRecord(obj)
1625 self.log_output += record.msg + '\n'
1626 self.handled.set()
1627
1628 def test_output(self):
1629 # The log message sent to the DatagramHandler is properly received.
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001630 if self.server_exception:
1631 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001632 logger = logging.getLogger("udp")
1633 logger.error("spam")
1634 self.handled.wait()
Vinay Sajip714b8dc2011-05-02 14:43:00 +01001635 self.handled.clear()
1636 logger.error("eggs")
1637 self.handled.wait()
1638 self.assertEqual(self.log_output, "spam\neggs\n")
Vinay Sajip7367d082011-05-02 13:17:27 +01001639
Victor Stinnerec5a8602014-06-02 14:41:51 +02001640@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001641class UnixDatagramHandlerTest(DatagramHandlerTest):
1642
1643 """Test for DatagramHandler using Unix sockets."""
1644
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001645 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001646 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001647
1648 def setUp(self):
1649 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001650 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001651 DatagramHandlerTest.setUp(self)
1652
1653 def tearDown(self):
1654 DatagramHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001655 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001656
Vinay Sajip7367d082011-05-02 13:17:27 +01001657class SysLogHandlerTest(BaseTest):
1658
1659 """Test for SysLogHandler using UDP."""
1660
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001661 server_class = TestUDPServer
1662 address = ('localhost', 0)
Vinay Sajip5421f352013-09-27 18:18:28 +01001663
Vinay Sajip7367d082011-05-02 13:17:27 +01001664 def setUp(self):
1665 """Set up a UDP server to receive log messages, and a SysLogHandler
1666 pointing to that server's address and port."""
1667 BaseTest.setUp(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001668 # Issue #29177: deal with errors that happen during setup
1669 self.server = self.sl_hdlr = self.server_exception = None
1670 try:
1671 self.server = server = self.server_class(self.address,
1672 self.handle_datagram, 0.01)
1673 server.start()
1674 # Uncomment next line to test error recovery in setUp()
1675 # raise OSError('dummy error raised')
1676 except OSError as e:
1677 self.server_exception = e
1678 return
Vinay Sajip7367d082011-05-02 13:17:27 +01001679 server.ready.wait()
Vinay Sajip5421f352013-09-27 18:18:28 +01001680 hcls = logging.handlers.SysLogHandler
1681 if isinstance(server.server_address, tuple):
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001682 self.sl_hdlr = hcls((server.server_address[0], server.port))
Vinay Sajip5421f352013-09-27 18:18:28 +01001683 else:
1684 self.sl_hdlr = hcls(server.server_address)
Vinay Sajip7367d082011-05-02 13:17:27 +01001685 self.log_output = ''
1686 self.root_logger.removeHandler(self.root_logger.handlers[0])
1687 self.root_logger.addHandler(self.sl_hdlr)
1688 self.handled = threading.Event()
1689
1690 def tearDown(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001691 """Shutdown the server."""
Vinay Sajip7367d082011-05-02 13:17:27 +01001692 try:
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001693 if self.server:
1694 self.server.stop(2.0)
1695 if self.sl_hdlr:
1696 self.root_logger.removeHandler(self.sl_hdlr)
1697 self.sl_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001698 finally:
1699 BaseTest.tearDown(self)
1700
1701 def handle_datagram(self, request):
1702 self.log_output = request.packet
1703 self.handled.set()
1704
1705 def test_output(self):
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001706 if self.server_exception:
1707 self.skipTest(self.server_exception)
Vinay Sajip7367d082011-05-02 13:17:27 +01001708 # The log message sent to the SysLogHandler is properly received.
1709 logger = logging.getLogger("slh")
1710 logger.error("sp\xe4m")
1711 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001712 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
Vinay Sajip8dd8d582011-06-09 16:55:23 +01001713 self.handled.clear()
1714 self.sl_hdlr.append_nul = False
1715 logger.error("sp\xe4m")
1716 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001717 self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m')
Vinay Sajip2353e352011-06-27 15:40:06 +01001718 self.handled.clear()
1719 self.sl_hdlr.ident = "h\xe4m-"
1720 logger.error("sp\xe4m")
1721 self.handled.wait()
Vinay Sajip7706d9a2012-04-16 16:22:38 +01001722 self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
Vinay Sajip7367d082011-05-02 13:17:27 +01001723
Victor Stinnerec5a8602014-06-02 14:41:51 +02001724@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
Vinay Sajip5421f352013-09-27 18:18:28 +01001725class UnixSysLogHandlerTest(SysLogHandlerTest):
1726
1727 """Test for SysLogHandler with Unix sockets."""
1728
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001729 if hasattr(socket, "AF_UNIX"):
Vinay Sajipcb2c4fe2013-09-27 19:08:24 +01001730 server_class = TestUnixDatagramServer
Vinay Sajip5421f352013-09-27 18:18:28 +01001731
1732 def setUp(self):
1733 # override the definition in the base class
Vinay Sajipf6cdffe2013-09-27 18:41:12 +01001734 self.address = _get_temp_domain_socket()
Vinay Sajip5421f352013-09-27 18:18:28 +01001735 SysLogHandlerTest.setUp(self)
1736
1737 def tearDown(self):
1738 SysLogHandlerTest.tearDown(self)
Vinay Sajip1e6499c2017-01-09 16:54:12 +00001739 support.unlink(self.address)
Vinay Sajip5421f352013-09-27 18:18:28 +01001740
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001741@unittest.skipUnless(support.IPV6_ENABLED,
1742 'IPv6 support required for this test.')
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08001743class IPv6SysLogHandlerTest(SysLogHandlerTest):
1744
1745 """Test for SysLogHandler with IPv6 host."""
1746
1747 server_class = TestUDPServer
1748 address = ('::1', 0)
1749
1750 def setUp(self):
1751 self.server_class.address_family = socket.AF_INET6
1752 super(IPv6SysLogHandlerTest, self).setUp()
1753
1754 def tearDown(self):
1755 self.server_class.address_family = socket.AF_INET
1756 super(IPv6SysLogHandlerTest, self).tearDown()
1757
Vinay Sajip7367d082011-05-02 13:17:27 +01001758class HTTPHandlerTest(BaseTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01001759 """Test for HTTPHandler."""
1760
1761 def setUp(self):
1762 """Set up an HTTP server to receive log messages, and a HTTPHandler
1763 pointing to that server's address and port."""
1764 BaseTest.setUp(self)
Vinay Sajip7367d082011-05-02 13:17:27 +01001765 self.handled = threading.Event()
1766
Vinay Sajip7367d082011-05-02 13:17:27 +01001767 def handle_request(self, request):
Vinay Sajip0372e102011-05-05 12:59:14 +01001768 self.command = request.command
Vinay Sajip7367d082011-05-02 13:17:27 +01001769 self.log_data = urlparse(request.path)
Vinay Sajip0372e102011-05-05 12:59:14 +01001770 if self.command == 'POST':
1771 try:
1772 rlen = int(request.headers['Content-Length'])
1773 self.post_data = request.rfile.read(rlen)
1774 except:
1775 self.post_data = None
Vinay Sajip7367d082011-05-02 13:17:27 +01001776 request.send_response(200)
Vinay Sajip463ac512011-05-10 09:10:08 +01001777 request.end_headers()
Vinay Sajip7367d082011-05-02 13:17:27 +01001778 self.handled.set()
1779
1780 def test_output(self):
Vinay Sajipf2231162011-05-09 22:05:50 +01001781 # The log message sent to the HTTPHandler is properly received.
Vinay Sajip7367d082011-05-02 13:17:27 +01001782 logger = logging.getLogger("http")
Vinay Sajip9ba87612011-05-21 11:32:15 +01001783 root_logger = self.root_logger
1784 root_logger.removeHandler(self.root_logger.handlers[0])
1785 for secure in (False, True):
1786 addr = ('localhost', 0)
1787 if secure:
Vinay Sajip39e35282011-05-21 16:46:41 +01001788 try:
1789 import ssl
Vinay Sajip39e35282011-05-21 16:46:41 +01001790 except ImportError:
1791 sslctx = None
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001792 else:
1793 here = os.path.dirname(__file__)
1794 localhost_cert = os.path.join(here, "keycert.pem")
Christian Heimesa170fa12017-09-15 20:27:30 +02001795 sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Benjamin Peterson4ffb0752014-11-03 14:29:33 -05001796 sslctx.load_cert_chain(localhost_cert)
Benjamin Peterson43052a12014-11-23 20:36:44 -06001797
1798 context = ssl.create_default_context(cafile=localhost_cert)
Vinay Sajip0372e102011-05-05 12:59:14 +01001799 else:
Vinay Sajip9ba87612011-05-21 11:32:15 +01001800 sslctx = None
Benjamin Peterson43052a12014-11-23 20:36:44 -06001801 context = None
Vinay Sajip9ba87612011-05-21 11:32:15 +01001802 self.server = server = TestHTTPServer(addr, self.handle_request,
1803 0.01, sslctx=sslctx)
1804 server.start()
1805 server.ready.wait()
1806 host = 'localhost:%d' % server.server_port
Vinay Sajip39e35282011-05-21 16:46:41 +01001807 secure_client = secure and sslctx
1808 self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
Benjamin Peterson43052a12014-11-23 20:36:44 -06001809 secure=secure_client,
Vinay Sajip1bf197e2016-06-07 21:19:55 +01001810 context=context,
1811 credentials=('foo', 'bar'))
Vinay Sajip9ba87612011-05-21 11:32:15 +01001812 self.log_data = None
1813 root_logger.addHandler(self.h_hdlr)
1814
1815 for method in ('GET', 'POST'):
1816 self.h_hdlr.method = method
1817 self.handled.clear()
1818 msg = "sp\xe4m"
1819 logger.error(msg)
1820 self.handled.wait()
1821 self.assertEqual(self.log_data.path, '/frob')
1822 self.assertEqual(self.command, method)
1823 if method == 'GET':
1824 d = parse_qs(self.log_data.query)
1825 else:
1826 d = parse_qs(self.post_data.decode('utf-8'))
1827 self.assertEqual(d['name'], ['http'])
1828 self.assertEqual(d['funcName'], ['test_output'])
1829 self.assertEqual(d['msg'], [msg])
1830
1831 self.server.stop(2.0)
1832 self.root_logger.removeHandler(self.h_hdlr)
1833 self.h_hdlr.close()
Vinay Sajip7367d082011-05-02 13:17:27 +01001834
Christian Heimes180510d2008-03-03 19:15:45 +00001835class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001836
Christian Heimes180510d2008-03-03 19:15:45 +00001837 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001838
Christian Heimes180510d2008-03-03 19:15:45 +00001839 def setUp(self):
1840 """Create a dict to remember potentially destroyed objects."""
1841 BaseTest.setUp(self)
1842 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001843
Christian Heimes180510d2008-03-03 19:15:45 +00001844 def _watch_for_survival(self, *args):
1845 """Watch the given objects for survival, by creating weakrefs to
1846 them."""
1847 for obj in args:
1848 key = id(obj), repr(obj)
1849 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001850
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001851 def _assertTruesurvival(self):
Christian Heimes180510d2008-03-03 19:15:45 +00001852 """Assert that all objects watched for survival have survived."""
1853 # Trigger cycle breaking.
1854 gc.collect()
1855 dead = []
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001856 for (id_, repr_), ref in self._survivors.items():
Christian Heimes180510d2008-03-03 19:15:45 +00001857 if ref() is None:
1858 dead.append(repr_)
1859 if dead:
1860 self.fail("%d objects should have survived "
1861 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001862
Christian Heimes180510d2008-03-03 19:15:45 +00001863 def test_persistent_loggers(self):
1864 # Logger objects are persistent and retain their configuration, even
1865 # if visible references are destroyed.
1866 self.root_logger.setLevel(logging.INFO)
1867 foo = logging.getLogger("foo")
1868 self._watch_for_survival(foo)
1869 foo.setLevel(logging.DEBUG)
1870 self.root_logger.debug(self.next_message())
1871 foo.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001872 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001873 ('foo', 'DEBUG', '2'),
1874 ])
1875 del foo
1876 # foo has survived.
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001877 self._assertTruesurvival()
Christian Heimes180510d2008-03-03 19:15:45 +00001878 # foo has retained its settings.
1879 bar = logging.getLogger("foo")
1880 bar.debug(self.next_message())
Benjamin Peterson77108eb2009-07-01 00:43:10 +00001881 self.assert_log_lines([
Christian Heimes180510d2008-03-03 19:15:45 +00001882 ('foo', 'DEBUG', '2'),
1883 ('foo', 'DEBUG', '3'),
1884 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001885
Benjamin Petersonf91df042009-02-13 02:50:59 +00001886
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001887class EncodingTest(BaseTest):
1888 def test_encoding_plain_file(self):
1889 # In Python 2.x, a plain file object is treated as having no encoding.
1890 log = logging.getLogger("test")
Vinay Sajip60b4df12010-12-27 11:18:52 +00001891 fd, fn = tempfile.mkstemp(".log", "test_logging-1-")
1892 os.close(fd)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001893 # the non-ascii data we write to the log.
1894 data = "foo\x80"
1895 try:
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001896 handler = logging.FileHandler(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001897 log.addHandler(handler)
1898 try:
1899 # write non-ascii data to the log.
1900 log.warning(data)
1901 finally:
1902 log.removeHandler(handler)
1903 handler.close()
1904 # check we wrote exactly those bytes, ignoring trailing \n etc
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001905 f = open(fn, encoding="utf-8")
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001906 try:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001907 self.assertEqual(f.read().rstrip(), data)
Benjamin Petersonae5360b2008-09-08 23:05:23 +00001908 finally:
1909 f.close()
1910 finally:
1911 if os.path.isfile(fn):
1912 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001913
Benjamin Petersonf91df042009-02-13 02:50:59 +00001914 def test_encoding_cyrillic_unicode(self):
1915 log = logging.getLogger("test")
1916 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1917 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1918 #Ensure it's written in a Cyrillic encoding
1919 writer_class = codecs.getwriter('cp1251')
Benjamin Peterson25c95f12009-05-08 20:42:26 +00001920 writer_class.encoding = 'cp1251'
Benjamin Petersonf91df042009-02-13 02:50:59 +00001921 stream = io.BytesIO()
1922 writer = writer_class(stream, 'strict')
1923 handler = logging.StreamHandler(writer)
1924 log.addHandler(handler)
1925 try:
1926 log.warning(message)
1927 finally:
1928 log.removeHandler(handler)
1929 handler.close()
1930 # check we wrote exactly those bytes, ignoring trailing \n etc
1931 s = stream.getvalue()
1932 #Compare against what the data should be when encoded in CP-1251
1933 self.assertEqual(s, b'\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1934
1935
Georg Brandlf9734072008-12-07 15:30:06 +00001936class WarningsTest(BaseTest):
Brett Cannondf8709d2009-04-01 20:01:47 +00001937
Georg Brandlf9734072008-12-07 15:30:06 +00001938 def test_warnings(self):
Brett Cannondf8709d2009-04-01 20:01:47 +00001939 with warnings.catch_warnings():
Brett Cannon5b9082a2009-04-05 18:57:32 +00001940 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001941 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001942 warnings.filterwarnings("always", category=UserWarning)
1943 stream = io.StringIO()
1944 h = logging.StreamHandler(stream)
1945 logger = logging.getLogger("py.warnings")
1946 logger.addHandler(h)
1947 warnings.warn("I'm warning you...")
1948 logger.removeHandler(h)
1949 s = stream.getvalue()
1950 h.close()
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02001951 self.assertGreater(s.find("UserWarning: I'm warning you...\n"), 0)
Georg Brandlf9734072008-12-07 15:30:06 +00001952
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001953 #See if an explicit file uses the original implementation
1954 a_file = io.StringIO()
1955 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1956 a_file, "Dummy line")
1957 s = a_file.getvalue()
1958 a_file.close()
1959 self.assertEqual(s,
1960 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1961
1962 def test_warnings_no_handlers(self):
1963 with warnings.catch_warnings():
1964 logging.captureWarnings(True)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001965 self.addCleanup(logging.captureWarnings, False)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001966
1967 # confirm our assumption: no loggers are set
1968 logger = logging.getLogger("py.warnings")
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001969 self.assertEqual(logger.handlers, [])
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001970
1971 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01001972 self.assertEqual(len(logger.handlers), 1)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01001973 self.assertIsInstance(logger.handlers[0], logging.NullHandler)
Georg Brandlf9734072008-12-07 15:30:06 +00001974
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001975
1976def formatFunc(format, datefmt=None):
1977 return logging.Formatter(format, datefmt)
1978
1979def handlerFunc():
1980 return logging.StreamHandler()
1981
1982class CustomHandler(logging.StreamHandler):
1983 pass
1984
1985class ConfigDictTest(BaseTest):
1986
1987 """Reading logging config from a dictionary."""
1988
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03001989 expected_log_pat = r"^(\w+) \+\+ (\w+)$"
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001990
1991 # config0 is a standard configuration.
1992 config0 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00001993 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00001994 'formatters': {
1995 'form1' : {
1996 'format' : '%(levelname)s ++ %(message)s',
1997 },
1998 },
1999 'handlers' : {
2000 'hand1' : {
2001 'class' : 'logging.StreamHandler',
2002 'formatter' : 'form1',
2003 'level' : 'NOTSET',
2004 'stream' : 'ext://sys.stdout',
2005 },
2006 },
2007 'root' : {
2008 'level' : 'WARNING',
2009 'handlers' : ['hand1'],
2010 },
2011 }
2012
2013 # config1 adds a little to the standard configuration.
2014 config1 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002015 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002016 'formatters': {
2017 'form1' : {
2018 'format' : '%(levelname)s ++ %(message)s',
2019 },
2020 },
2021 'handlers' : {
2022 'hand1' : {
2023 'class' : 'logging.StreamHandler',
2024 'formatter' : 'form1',
2025 'level' : 'NOTSET',
2026 'stream' : 'ext://sys.stdout',
2027 },
2028 },
2029 'loggers' : {
2030 'compiler.parser' : {
2031 'level' : 'DEBUG',
2032 'handlers' : ['hand1'],
2033 },
2034 },
2035 'root' : {
2036 'level' : 'WARNING',
2037 },
2038 }
2039
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002040 # config1a moves the handler to the root. Used with config8a
2041 config1a = {
2042 'version': 1,
2043 'formatters': {
2044 'form1' : {
2045 'format' : '%(levelname)s ++ %(message)s',
2046 },
2047 },
2048 'handlers' : {
2049 'hand1' : {
2050 'class' : 'logging.StreamHandler',
2051 'formatter' : 'form1',
2052 'level' : 'NOTSET',
2053 'stream' : 'ext://sys.stdout',
2054 },
2055 },
2056 'loggers' : {
2057 'compiler.parser' : {
2058 'level' : 'DEBUG',
2059 },
2060 },
2061 'root' : {
2062 'level' : 'WARNING',
2063 'handlers' : ['hand1'],
2064 },
2065 }
2066
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002067 # config2 has a subtle configuration error that should be reported
2068 config2 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002069 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002070 'formatters': {
2071 'form1' : {
2072 'format' : '%(levelname)s ++ %(message)s',
2073 },
2074 },
2075 'handlers' : {
2076 'hand1' : {
2077 'class' : 'logging.StreamHandler',
2078 'formatter' : 'form1',
2079 'level' : 'NOTSET',
2080 'stream' : 'ext://sys.stdbout',
2081 },
2082 },
2083 'loggers' : {
2084 'compiler.parser' : {
2085 'level' : 'DEBUG',
2086 'handlers' : ['hand1'],
2087 },
2088 },
2089 'root' : {
2090 'level' : 'WARNING',
2091 },
2092 }
2093
2094 #As config1 but with a misspelt level on a handler
2095 config2a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002096 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002097 'formatters': {
2098 'form1' : {
2099 'format' : '%(levelname)s ++ %(message)s',
2100 },
2101 },
2102 'handlers' : {
2103 'hand1' : {
2104 'class' : 'logging.StreamHandler',
2105 'formatter' : 'form1',
2106 'level' : 'NTOSET',
2107 'stream' : 'ext://sys.stdout',
2108 },
2109 },
2110 'loggers' : {
2111 'compiler.parser' : {
2112 'level' : 'DEBUG',
2113 'handlers' : ['hand1'],
2114 },
2115 },
2116 'root' : {
2117 'level' : 'WARNING',
2118 },
2119 }
2120
2121
2122 #As config1 but with a misspelt level on a logger
2123 config2b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002124 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002125 'formatters': {
2126 'form1' : {
2127 'format' : '%(levelname)s ++ %(message)s',
2128 },
2129 },
2130 'handlers' : {
2131 'hand1' : {
2132 'class' : 'logging.StreamHandler',
2133 'formatter' : 'form1',
2134 'level' : 'NOTSET',
2135 'stream' : 'ext://sys.stdout',
2136 },
2137 },
2138 'loggers' : {
2139 'compiler.parser' : {
2140 'level' : 'DEBUG',
2141 'handlers' : ['hand1'],
2142 },
2143 },
2144 'root' : {
2145 'level' : 'WRANING',
2146 },
2147 }
2148
2149 # config3 has a less subtle configuration error
2150 config3 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002151 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002152 'formatters': {
2153 'form1' : {
2154 'format' : '%(levelname)s ++ %(message)s',
2155 },
2156 },
2157 'handlers' : {
2158 'hand1' : {
2159 'class' : 'logging.StreamHandler',
2160 'formatter' : 'misspelled_name',
2161 'level' : 'NOTSET',
2162 'stream' : 'ext://sys.stdout',
2163 },
2164 },
2165 'loggers' : {
2166 'compiler.parser' : {
2167 'level' : 'DEBUG',
2168 'handlers' : ['hand1'],
2169 },
2170 },
2171 'root' : {
2172 'level' : 'WARNING',
2173 },
2174 }
2175
2176 # config4 specifies a custom formatter class to be loaded
2177 config4 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002178 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002179 'formatters': {
2180 'form1' : {
2181 '()' : __name__ + '.ExceptionFormatter',
2182 'format' : '%(levelname)s:%(name)s:%(message)s',
2183 },
2184 },
2185 'handlers' : {
2186 'hand1' : {
2187 'class' : 'logging.StreamHandler',
2188 'formatter' : 'form1',
2189 'level' : 'NOTSET',
2190 'stream' : 'ext://sys.stdout',
2191 },
2192 },
2193 'root' : {
2194 'level' : 'NOTSET',
2195 'handlers' : ['hand1'],
2196 },
2197 }
2198
2199 # As config4 but using an actual callable rather than a string
2200 config4a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002201 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002202 'formatters': {
2203 'form1' : {
2204 '()' : ExceptionFormatter,
2205 'format' : '%(levelname)s:%(name)s:%(message)s',
2206 },
2207 'form2' : {
2208 '()' : __name__ + '.formatFunc',
2209 'format' : '%(levelname)s:%(name)s:%(message)s',
2210 },
2211 'form3' : {
2212 '()' : formatFunc,
2213 'format' : '%(levelname)s:%(name)s:%(message)s',
2214 },
2215 },
2216 'handlers' : {
2217 'hand1' : {
2218 'class' : 'logging.StreamHandler',
2219 'formatter' : 'form1',
2220 'level' : 'NOTSET',
2221 'stream' : 'ext://sys.stdout',
2222 },
2223 'hand2' : {
2224 '()' : handlerFunc,
2225 },
2226 },
2227 'root' : {
2228 'level' : 'NOTSET',
2229 'handlers' : ['hand1'],
2230 },
2231 }
2232
2233 # config5 specifies a custom handler class to be loaded
2234 config5 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002235 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002236 'formatters': {
2237 'form1' : {
2238 'format' : '%(levelname)s ++ %(message)s',
2239 },
2240 },
2241 'handlers' : {
2242 'hand1' : {
2243 'class' : __name__ + '.CustomHandler',
2244 'formatter' : 'form1',
2245 'level' : 'NOTSET',
2246 'stream' : 'ext://sys.stdout',
2247 },
2248 },
2249 'loggers' : {
2250 'compiler.parser' : {
2251 'level' : 'DEBUG',
2252 'handlers' : ['hand1'],
2253 },
2254 },
2255 'root' : {
2256 'level' : 'WARNING',
2257 },
2258 }
2259
2260 # config6 specifies a custom handler class to be loaded
2261 # but has bad arguments
2262 config6 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002263 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002264 'formatters': {
2265 'form1' : {
2266 'format' : '%(levelname)s ++ %(message)s',
2267 },
2268 },
2269 'handlers' : {
2270 'hand1' : {
2271 'class' : __name__ + '.CustomHandler',
2272 'formatter' : 'form1',
2273 'level' : 'NOTSET',
2274 'stream' : 'ext://sys.stdout',
2275 '9' : 'invalid parameter name',
2276 },
2277 },
2278 'loggers' : {
2279 'compiler.parser' : {
2280 'level' : 'DEBUG',
2281 'handlers' : ['hand1'],
2282 },
2283 },
2284 'root' : {
2285 'level' : 'WARNING',
2286 },
2287 }
2288
2289 #config 7 does not define compiler.parser but defines compiler.lexer
2290 #so compiler.parser should be disabled after applying it
2291 config7 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002292 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002293 'formatters': {
2294 'form1' : {
2295 'format' : '%(levelname)s ++ %(message)s',
2296 },
2297 },
2298 'handlers' : {
2299 'hand1' : {
2300 'class' : 'logging.StreamHandler',
2301 'formatter' : 'form1',
2302 'level' : 'NOTSET',
2303 'stream' : 'ext://sys.stdout',
2304 },
2305 },
2306 'loggers' : {
2307 'compiler.lexer' : {
2308 'level' : 'DEBUG',
2309 'handlers' : ['hand1'],
2310 },
2311 },
2312 'root' : {
2313 'level' : 'WARNING',
2314 },
2315 }
2316
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002317 # config8 defines both compiler and compiler.lexer
2318 # so compiler.parser should not be disabled (since
2319 # compiler is defined)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002320 config8 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002321 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002322 'disable_existing_loggers' : False,
2323 'formatters': {
2324 'form1' : {
2325 'format' : '%(levelname)s ++ %(message)s',
2326 },
2327 },
2328 'handlers' : {
2329 'hand1' : {
2330 'class' : 'logging.StreamHandler',
2331 'formatter' : 'form1',
2332 'level' : 'NOTSET',
2333 'stream' : 'ext://sys.stdout',
2334 },
2335 },
2336 'loggers' : {
2337 'compiler' : {
2338 'level' : 'DEBUG',
2339 'handlers' : ['hand1'],
2340 },
2341 'compiler.lexer' : {
2342 },
2343 },
2344 'root' : {
2345 'level' : 'WARNING',
2346 },
2347 }
2348
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002349 # config8a disables existing loggers
2350 config8a = {
2351 'version': 1,
2352 'disable_existing_loggers' : True,
2353 'formatters': {
2354 'form1' : {
2355 'format' : '%(levelname)s ++ %(message)s',
2356 },
2357 },
2358 'handlers' : {
2359 'hand1' : {
2360 'class' : 'logging.StreamHandler',
2361 'formatter' : 'form1',
2362 'level' : 'NOTSET',
2363 'stream' : 'ext://sys.stdout',
2364 },
2365 },
2366 'loggers' : {
2367 'compiler' : {
2368 'level' : 'DEBUG',
2369 'handlers' : ['hand1'],
2370 },
2371 'compiler.lexer' : {
2372 },
2373 },
2374 'root' : {
2375 'level' : 'WARNING',
2376 },
2377 }
2378
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002379 config9 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002380 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002381 'formatters': {
2382 'form1' : {
2383 'format' : '%(levelname)s ++ %(message)s',
2384 },
2385 },
2386 'handlers' : {
2387 'hand1' : {
2388 'class' : 'logging.StreamHandler',
2389 'formatter' : 'form1',
2390 'level' : 'WARNING',
2391 'stream' : 'ext://sys.stdout',
2392 },
2393 },
2394 'loggers' : {
2395 'compiler.parser' : {
2396 'level' : 'WARNING',
2397 'handlers' : ['hand1'],
2398 },
2399 },
2400 'root' : {
2401 'level' : 'NOTSET',
2402 },
2403 }
2404
2405 config9a = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002406 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002407 'incremental' : True,
2408 'handlers' : {
2409 'hand1' : {
2410 'level' : 'WARNING',
2411 },
2412 },
2413 'loggers' : {
2414 'compiler.parser' : {
2415 'level' : 'INFO',
2416 },
2417 },
2418 }
2419
2420 config9b = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002421 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002422 'incremental' : True,
2423 'handlers' : {
2424 'hand1' : {
2425 'level' : 'INFO',
2426 },
2427 },
2428 'loggers' : {
2429 'compiler.parser' : {
2430 'level' : 'INFO',
2431 },
2432 },
2433 }
2434
2435 #As config1 but with a filter added
2436 config10 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002437 'version': 1,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002438 'formatters': {
2439 'form1' : {
2440 'format' : '%(levelname)s ++ %(message)s',
2441 },
2442 },
2443 'filters' : {
2444 'filt1' : {
2445 'name' : 'compiler.parser',
2446 },
2447 },
2448 'handlers' : {
2449 'hand1' : {
2450 'class' : 'logging.StreamHandler',
2451 'formatter' : 'form1',
2452 'level' : 'NOTSET',
2453 'stream' : 'ext://sys.stdout',
2454 'filters' : ['filt1'],
2455 },
2456 },
2457 'loggers' : {
2458 'compiler.parser' : {
2459 'level' : 'DEBUG',
2460 'filters' : ['filt1'],
2461 },
2462 },
2463 'root' : {
2464 'level' : 'WARNING',
2465 'handlers' : ['hand1'],
2466 },
2467 }
2468
2469 #As config1 but using cfg:// references
2470 config11 = {
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002471 'version': 1,
2472 'true_formatters': {
2473 'form1' : {
2474 'format' : '%(levelname)s ++ %(message)s',
2475 },
2476 },
2477 'handler_configs': {
2478 'hand1' : {
2479 'class' : 'logging.StreamHandler',
2480 'formatter' : 'form1',
2481 'level' : 'NOTSET',
2482 'stream' : 'ext://sys.stdout',
2483 },
2484 },
2485 'formatters' : 'cfg://true_formatters',
2486 'handlers' : {
2487 'hand1' : 'cfg://handler_configs[hand1]',
2488 },
2489 'loggers' : {
2490 'compiler.parser' : {
2491 'level' : 'DEBUG',
2492 'handlers' : ['hand1'],
2493 },
2494 },
2495 'root' : {
2496 'level' : 'WARNING',
2497 },
2498 }
2499
2500 #As config11 but missing the version key
2501 config12 = {
2502 'true_formatters': {
2503 'form1' : {
2504 'format' : '%(levelname)s ++ %(message)s',
2505 },
2506 },
2507 'handler_configs': {
2508 'hand1' : {
2509 'class' : 'logging.StreamHandler',
2510 'formatter' : 'form1',
2511 'level' : 'NOTSET',
2512 'stream' : 'ext://sys.stdout',
2513 },
2514 },
2515 'formatters' : 'cfg://true_formatters',
2516 'handlers' : {
2517 'hand1' : 'cfg://handler_configs[hand1]',
2518 },
2519 'loggers' : {
2520 'compiler.parser' : {
2521 'level' : 'DEBUG',
2522 'handlers' : ['hand1'],
2523 },
2524 },
2525 'root' : {
2526 'level' : 'WARNING',
2527 },
2528 }
2529
2530 #As config11 but using an unsupported version
2531 config13 = {
2532 'version': 2,
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002533 'true_formatters': {
2534 'form1' : {
2535 'format' : '%(levelname)s ++ %(message)s',
2536 },
2537 },
2538 'handler_configs': {
2539 'hand1' : {
2540 'class' : 'logging.StreamHandler',
2541 'formatter' : 'form1',
2542 'level' : 'NOTSET',
2543 'stream' : 'ext://sys.stdout',
2544 },
2545 },
2546 'formatters' : 'cfg://true_formatters',
2547 'handlers' : {
2548 'hand1' : 'cfg://handler_configs[hand1]',
2549 },
2550 'loggers' : {
2551 'compiler.parser' : {
2552 'level' : 'DEBUG',
2553 'handlers' : ['hand1'],
2554 },
2555 },
2556 'root' : {
2557 'level' : 'WARNING',
2558 },
2559 }
2560
Vinay Sajip8d270232012-11-15 14:20:18 +00002561 # As config0, but with properties
2562 config14 = {
2563 'version': 1,
2564 'formatters': {
2565 'form1' : {
2566 'format' : '%(levelname)s ++ %(message)s',
2567 },
2568 },
2569 'handlers' : {
2570 'hand1' : {
2571 'class' : 'logging.StreamHandler',
2572 'formatter' : 'form1',
2573 'level' : 'NOTSET',
2574 'stream' : 'ext://sys.stdout',
2575 '.': {
2576 'foo': 'bar',
2577 'terminator': '!\n',
2578 }
2579 },
2580 },
2581 'root' : {
2582 'level' : 'WARNING',
2583 'handlers' : ['hand1'],
2584 },
2585 }
2586
Vinay Sajip3f885b52013-03-22 15:19:54 +00002587 out_of_order = {
2588 "version": 1,
2589 "formatters": {
2590 "mySimpleFormatter": {
Vinay Sajip28421c62013-03-29 17:56:54 +00002591 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s",
2592 "style": "$"
Vinay Sajip3f885b52013-03-22 15:19:54 +00002593 }
2594 },
2595 "handlers": {
2596 "fileGlobal": {
2597 "class": "logging.StreamHandler",
2598 "level": "DEBUG",
2599 "formatter": "mySimpleFormatter"
2600 },
2601 "bufferGlobal": {
2602 "class": "logging.handlers.MemoryHandler",
2603 "capacity": 5,
2604 "formatter": "mySimpleFormatter",
2605 "target": "fileGlobal",
2606 "level": "DEBUG"
2607 }
2608 },
2609 "loggers": {
2610 "mymodule": {
2611 "level": "DEBUG",
2612 "handlers": ["bufferGlobal"],
2613 "propagate": "true"
2614 }
2615 }
2616 }
2617
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002618 def apply_config(self, conf):
2619 logging.config.dictConfig(conf)
2620
2621 def test_config0_ok(self):
2622 # A simple config which overrides the default settings.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002623 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002624 self.apply_config(self.config0)
2625 logger = logging.getLogger()
2626 # Won't output anything
2627 logger.info(self.next_message())
2628 # Outputs a message
2629 logger.error(self.next_message())
2630 self.assert_log_lines([
2631 ('ERROR', '2'),
2632 ], stream=output)
2633 # Original logger output is empty.
2634 self.assert_log_lines([])
2635
2636 def test_config1_ok(self, config=config1):
2637 # A config defining a sub-parser as well.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002638 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002639 self.apply_config(config)
2640 logger = logging.getLogger("compiler.parser")
2641 # Both will output a message
2642 logger.info(self.next_message())
2643 logger.error(self.next_message())
2644 self.assert_log_lines([
2645 ('INFO', '1'),
2646 ('ERROR', '2'),
2647 ], stream=output)
2648 # Original logger output is empty.
2649 self.assert_log_lines([])
2650
2651 def test_config2_failure(self):
2652 # A simple config which overrides the default settings.
2653 self.assertRaises(Exception, self.apply_config, self.config2)
2654
2655 def test_config2a_failure(self):
2656 # A simple config which overrides the default settings.
2657 self.assertRaises(Exception, self.apply_config, self.config2a)
2658
2659 def test_config2b_failure(self):
2660 # A simple config which overrides the default settings.
2661 self.assertRaises(Exception, self.apply_config, self.config2b)
2662
2663 def test_config3_failure(self):
2664 # A simple config which overrides the default settings.
2665 self.assertRaises(Exception, self.apply_config, self.config3)
2666
2667 def test_config4_ok(self):
2668 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002669 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002670 self.apply_config(self.config4)
2671 #logger = logging.getLogger()
2672 try:
2673 raise RuntimeError()
2674 except RuntimeError:
2675 logging.exception("just testing")
2676 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002677 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002678 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2679 # Original logger output is empty
2680 self.assert_log_lines([])
2681
2682 def test_config4a_ok(self):
2683 # A config specifying a custom formatter class.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002684 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002685 self.apply_config(self.config4a)
2686 #logger = logging.getLogger()
2687 try:
2688 raise RuntimeError()
2689 except RuntimeError:
2690 logging.exception("just testing")
2691 sys.stdout.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002692 self.assertEqual(output.getvalue(),
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002693 "ERROR:root:just testing\nGot a [RuntimeError]\n")
2694 # Original logger output is empty
2695 self.assert_log_lines([])
2696
2697 def test_config5_ok(self):
2698 self.test_config1_ok(config=self.config5)
2699
2700 def test_config6_failure(self):
2701 self.assertRaises(Exception, self.apply_config, self.config6)
2702
2703 def test_config7_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002704 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002705 self.apply_config(self.config1)
2706 logger = logging.getLogger("compiler.parser")
2707 # Both will output a message
2708 logger.info(self.next_message())
2709 logger.error(self.next_message())
2710 self.assert_log_lines([
2711 ('INFO', '1'),
2712 ('ERROR', '2'),
2713 ], stream=output)
2714 # Original logger output is empty.
2715 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002716 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002717 self.apply_config(self.config7)
2718 logger = logging.getLogger("compiler.parser")
2719 self.assertTrue(logger.disabled)
2720 logger = logging.getLogger("compiler.lexer")
2721 # Both will output a message
2722 logger.info(self.next_message())
2723 logger.error(self.next_message())
2724 self.assert_log_lines([
2725 ('INFO', '3'),
2726 ('ERROR', '4'),
2727 ], stream=output)
2728 # Original logger output is empty.
2729 self.assert_log_lines([])
2730
2731 #Same as test_config_7_ok but don't disable old loggers.
2732 def test_config_8_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002733 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002734 self.apply_config(self.config1)
2735 logger = logging.getLogger("compiler.parser")
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002736 # All will output a message
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002737 logger.info(self.next_message())
2738 logger.error(self.next_message())
2739 self.assert_log_lines([
2740 ('INFO', '1'),
2741 ('ERROR', '2'),
2742 ], stream=output)
2743 # Original logger output is empty.
2744 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002745 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002746 self.apply_config(self.config8)
2747 logger = logging.getLogger("compiler.parser")
2748 self.assertFalse(logger.disabled)
2749 # Both will output a message
2750 logger.info(self.next_message())
2751 logger.error(self.next_message())
2752 logger = logging.getLogger("compiler.lexer")
2753 # Both will output a message
2754 logger.info(self.next_message())
2755 logger.error(self.next_message())
2756 self.assert_log_lines([
2757 ('INFO', '3'),
2758 ('ERROR', '4'),
2759 ('INFO', '5'),
2760 ('ERROR', '6'),
2761 ], stream=output)
2762 # Original logger output is empty.
2763 self.assert_log_lines([])
2764
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002765 def test_config_8a_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002766 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002767 self.apply_config(self.config1a)
2768 logger = logging.getLogger("compiler.parser")
2769 # See issue #11424. compiler-hyphenated sorts
2770 # between compiler and compiler.xyz and this
2771 # was preventing compiler.xyz from being included
2772 # in the child loggers of compiler because of an
2773 # overzealous loop termination condition.
2774 hyphenated = logging.getLogger('compiler-hyphenated')
2775 # All will output a message
2776 logger.info(self.next_message())
2777 logger.error(self.next_message())
2778 hyphenated.critical(self.next_message())
2779 self.assert_log_lines([
2780 ('INFO', '1'),
2781 ('ERROR', '2'),
2782 ('CRITICAL', '3'),
2783 ], stream=output)
2784 # Original logger output is empty.
2785 self.assert_log_lines([])
Vinay Sajip1feedb42014-05-31 08:19:12 +01002786 with support.captured_stdout() as output:
Vinay Sajip9f9991c2011-03-07 18:02:57 +00002787 self.apply_config(self.config8a)
2788 logger = logging.getLogger("compiler.parser")
2789 self.assertFalse(logger.disabled)
2790 # Both will output a message
2791 logger.info(self.next_message())
2792 logger.error(self.next_message())
2793 logger = logging.getLogger("compiler.lexer")
2794 # Both will output a message
2795 logger.info(self.next_message())
2796 logger.error(self.next_message())
2797 # Will not appear
2798 hyphenated.critical(self.next_message())
2799 self.assert_log_lines([
2800 ('INFO', '4'),
2801 ('ERROR', '5'),
2802 ('INFO', '6'),
2803 ('ERROR', '7'),
2804 ], stream=output)
2805 # Original logger output is empty.
2806 self.assert_log_lines([])
2807
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002808 def test_config_9_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002809 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002810 self.apply_config(self.config9)
2811 logger = logging.getLogger("compiler.parser")
2812 #Nothing will be output since both handler and logger are set to WARNING
2813 logger.info(self.next_message())
2814 self.assert_log_lines([], stream=output)
2815 self.apply_config(self.config9a)
2816 #Nothing will be output since both handler is still set to WARNING
2817 logger.info(self.next_message())
2818 self.assert_log_lines([], stream=output)
2819 self.apply_config(self.config9b)
2820 #Message should now be output
2821 logger.info(self.next_message())
2822 self.assert_log_lines([
2823 ('INFO', '3'),
2824 ], stream=output)
2825
2826 def test_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002827 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002828 self.apply_config(self.config10)
2829 logger = logging.getLogger("compiler.parser")
2830 logger.warning(self.next_message())
2831 logger = logging.getLogger('compiler')
2832 #Not output, because filtered
2833 logger.warning(self.next_message())
2834 logger = logging.getLogger('compiler.lexer')
2835 #Not output, because filtered
2836 logger.warning(self.next_message())
2837 logger = logging.getLogger("compiler.parser.codegen")
2838 #Output, as not filtered
2839 logger.error(self.next_message())
2840 self.assert_log_lines([
2841 ('WARNING', '1'),
2842 ('ERROR', '4'),
2843 ], stream=output)
2844
2845 def test_config11_ok(self):
2846 self.test_config1_ok(self.config11)
2847
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002848 def test_config12_failure(self):
2849 self.assertRaises(Exception, self.apply_config, self.config12)
2850
2851 def test_config13_failure(self):
2852 self.assertRaises(Exception, self.apply_config, self.config13)
2853
Vinay Sajip8d270232012-11-15 14:20:18 +00002854 def test_config14_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002855 with support.captured_stdout() as output:
Vinay Sajip8d270232012-11-15 14:20:18 +00002856 self.apply_config(self.config14)
2857 h = logging._handlers['hand1']
2858 self.assertEqual(h.foo, 'bar')
2859 self.assertEqual(h.terminator, '!\n')
2860 logging.warning('Exclamation')
2861 self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
2862
Vinay Sajip4ded5512012-10-02 15:56:16 +01002863 def setup_via_listener(self, text, verify=None):
Benjamin Peterson9451a1c2010-03-13 22:30:34 +00002864 text = text.encode("utf-8")
Florent Xiclunadc692742010-08-15 20:16:27 +00002865 # Ask for a randomly assigned port (by using port 0)
Vinay Sajip4ded5512012-10-02 15:56:16 +01002866 t = logging.config.listen(0, verify)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002867 t.start()
2868 t.ready.wait()
Benjamin Petersona82addb2010-06-27 20:54:28 +00002869 # Now get the port allocated
2870 port = t.port
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002871 t.ready.clear()
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002872 try:
2873 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2874 sock.settimeout(2.0)
2875 sock.connect(('localhost', port))
2876
2877 slen = struct.pack('>L', len(text))
2878 s = slen + text
2879 sentsofar = 0
2880 left = len(s)
2881 while left > 0:
2882 sent = sock.send(s[sentsofar:])
2883 sentsofar += sent
2884 left -= sent
2885 sock.close()
2886 finally:
2887 t.ready.wait(2.0)
2888 logging.config.stopListening()
Victor Stinnerb9b69002017-09-14 14:40:56 -07002889 support.join_thread(t, 2.0)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002890
2891 def test_listen_config_10_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002892 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002893 self.setup_via_listener(json.dumps(self.config10))
2894 logger = logging.getLogger("compiler.parser")
2895 logger.warning(self.next_message())
2896 logger = logging.getLogger('compiler')
2897 #Not output, because filtered
2898 logger.warning(self.next_message())
2899 logger = logging.getLogger('compiler.lexer')
2900 #Not output, because filtered
2901 logger.warning(self.next_message())
2902 logger = logging.getLogger("compiler.parser.codegen")
2903 #Output, as not filtered
2904 logger.error(self.next_message())
2905 self.assert_log_lines([
2906 ('WARNING', '1'),
2907 ('ERROR', '4'),
2908 ], stream=output)
2909
2910 def test_listen_config_1_ok(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01002911 with support.captured_stdout() as output:
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002912 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
2913 logger = logging.getLogger("compiler.parser")
2914 # Both will output a message
2915 logger.info(self.next_message())
2916 logger.error(self.next_message())
2917 self.assert_log_lines([
2918 ('INFO', '1'),
2919 ('ERROR', '2'),
2920 ], stream=output)
2921 # Original logger output is empty.
2922 self.assert_log_lines([])
2923
Vinay Sajip4ded5512012-10-02 15:56:16 +01002924 def test_listen_verify(self):
2925
2926 def verify_fail(stuff):
2927 return None
2928
2929 def verify_reverse(stuff):
2930 return stuff[::-1]
2931
2932 logger = logging.getLogger("compiler.parser")
2933 to_send = textwrap.dedent(ConfigFileTest.config1)
2934 # First, specify a verification function that will fail.
2935 # We expect to see no output, since our configuration
2936 # never took effect.
Vinay Sajip1feedb42014-05-31 08:19:12 +01002937 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002938 self.setup_via_listener(to_send, verify_fail)
2939 # Both will output a message
2940 logger.info(self.next_message())
2941 logger.error(self.next_message())
2942 self.assert_log_lines([], stream=output)
2943 # Original logger output has the stuff we logged.
2944 self.assert_log_lines([
2945 ('INFO', '1'),
2946 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002947 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002948
2949 # Now, perform no verification. Our configuration
2950 # should take effect.
2951
Vinay Sajip1feedb42014-05-31 08:19:12 +01002952 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002953 self.setup_via_listener(to_send) # no verify callable specified
2954 logger = logging.getLogger("compiler.parser")
2955 # Both will output a message
2956 logger.info(self.next_message())
2957 logger.error(self.next_message())
2958 self.assert_log_lines([
2959 ('INFO', '3'),
2960 ('ERROR', '4'),
2961 ], stream=output)
2962 # Original logger output still has the stuff we logged before.
2963 self.assert_log_lines([
2964 ('INFO', '1'),
2965 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002966 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002967
2968 # Now, perform verification which transforms the bytes.
2969
Vinay Sajip1feedb42014-05-31 08:19:12 +01002970 with support.captured_stdout() as output:
Vinay Sajip4ded5512012-10-02 15:56:16 +01002971 self.setup_via_listener(to_send[::-1], verify_reverse)
2972 logger = logging.getLogger("compiler.parser")
2973 # Both will output a message
2974 logger.info(self.next_message())
2975 logger.error(self.next_message())
2976 self.assert_log_lines([
2977 ('INFO', '5'),
2978 ('ERROR', '6'),
2979 ], stream=output)
2980 # Original logger output still has the stuff we logged before.
2981 self.assert_log_lines([
2982 ('INFO', '1'),
2983 ('ERROR', '2'),
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03002984 ], pat=r"^[\w.]+ -> (\w+): (\d+)$")
Vinay Sajip4ded5512012-10-02 15:56:16 +01002985
Vinay Sajip3f885b52013-03-22 15:19:54 +00002986 def test_out_of_order(self):
2987 self.apply_config(self.out_of_order)
2988 handler = logging.getLogger('mymodule').handlers[0]
2989 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28421c62013-03-29 17:56:54 +00002990 self.assertIsInstance(handler.formatter._style,
2991 logging.StringTemplateStyle)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00002992
Vinay Sajip373baef2011-04-26 20:05:24 +01002993 def test_baseconfig(self):
2994 d = {
2995 'atuple': (1, 2, 3),
2996 'alist': ['a', 'b', 'c'],
2997 'adict': {'d': 'e', 'f': 3 },
2998 'nest1': ('g', ('h', 'i'), 'j'),
2999 'nest2': ['k', ['l', 'm'], 'n'],
3000 'nest3': ['o', 'cfg://alist', 'p'],
3001 }
3002 bc = logging.config.BaseConfigurator(d)
3003 self.assertEqual(bc.convert('cfg://atuple[1]'), 2)
3004 self.assertEqual(bc.convert('cfg://alist[1]'), 'b')
3005 self.assertEqual(bc.convert('cfg://nest1[1][0]'), 'h')
3006 self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
3007 self.assertEqual(bc.convert('cfg://adict.d'), 'e')
3008 self.assertEqual(bc.convert('cfg://adict[f]'), 3)
3009 v = bc.convert('cfg://nest3')
3010 self.assertEqual(v.pop(1), ['a', 'b', 'c'])
3011 self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
3012 self.assertRaises(ValueError, bc.convert, 'cfg://!')
3013 self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003014
3015class ManagerTest(BaseTest):
3016 def test_manager_loggerclass(self):
3017 logged = []
3018
3019 class MyLogger(logging.Logger):
3020 def _log(self, level, msg, args, exc_info=None, extra=None):
3021 logged.append(msg)
3022
3023 man = logging.Manager(None)
3024 self.assertRaises(TypeError, man.setLoggerClass, int)
3025 man.setLoggerClass(MyLogger)
3026 logger = man.getLogger('test')
3027 logger.warning('should appear in logged')
3028 logging.warning('should not appear in logged')
3029
3030 self.assertEqual(logged, ['should appear in logged'])
3031
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003032 def test_set_log_record_factory(self):
3033 man = logging.Manager(None)
3034 expected = object()
3035 man.setLogRecordFactory(expected)
3036 self.assertEqual(man.logRecordFactory, expected)
Vinay Sajipdb81c4c2010-02-25 23:13:06 +00003037
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003038class ChildLoggerTest(BaseTest):
3039 def test_child_loggers(self):
3040 r = logging.getLogger()
3041 l1 = logging.getLogger('abc')
3042 l2 = logging.getLogger('def.ghi')
3043 c1 = r.getChild('xyz')
3044 c2 = r.getChild('uvw.xyz')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003045 self.assertIs(c1, logging.getLogger('xyz'))
3046 self.assertIs(c2, logging.getLogger('uvw.xyz'))
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003047 c1 = l1.getChild('def')
3048 c2 = c1.getChild('ghi')
3049 c3 = l1.getChild('def.ghi')
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02003050 self.assertIs(c1, logging.getLogger('abc.def'))
3051 self.assertIs(c2, logging.getLogger('abc.def.ghi'))
3052 self.assertIs(c2, c3)
Benjamin Peterson22005fc2010-04-11 16:25:06 +00003053
3054
Vinay Sajip6fac8172010-10-19 20:44:14 +00003055class DerivedLogRecord(logging.LogRecord):
3056 pass
3057
Vinay Sajip61561522010-12-03 11:50:38 +00003058class LogRecordFactoryTest(BaseTest):
Vinay Sajip6fac8172010-10-19 20:44:14 +00003059
3060 def setUp(self):
3061 class CheckingFilter(logging.Filter):
3062 def __init__(self, cls):
3063 self.cls = cls
3064
3065 def filter(self, record):
3066 t = type(record)
3067 if t is not self.cls:
3068 msg = 'Unexpected LogRecord type %s, expected %s' % (t,
3069 self.cls)
3070 raise TypeError(msg)
3071 return True
3072
3073 BaseTest.setUp(self)
3074 self.filter = CheckingFilter(DerivedLogRecord)
3075 self.root_logger.addFilter(self.filter)
Vinay Sajip61561522010-12-03 11:50:38 +00003076 self.orig_factory = logging.getLogRecordFactory()
Vinay Sajip6fac8172010-10-19 20:44:14 +00003077
3078 def tearDown(self):
3079 self.root_logger.removeFilter(self.filter)
3080 BaseTest.tearDown(self)
Vinay Sajip61561522010-12-03 11:50:38 +00003081 logging.setLogRecordFactory(self.orig_factory)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003082
3083 def test_logrecord_class(self):
3084 self.assertRaises(TypeError, self.root_logger.warning,
3085 self.next_message())
Vinay Sajip61561522010-12-03 11:50:38 +00003086 logging.setLogRecordFactory(DerivedLogRecord)
Vinay Sajip6fac8172010-10-19 20:44:14 +00003087 self.root_logger.error(self.next_message())
3088 self.assert_log_lines([
3089 ('root', 'ERROR', '2'),
3090 ])
3091
3092
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003093class QueueHandlerTest(BaseTest):
3094 # Do not bother with a logger name group.
Ezio Melotti3ffd29b2012-10-02 19:45:00 +03003095 expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003096
3097 def setUp(self):
3098 BaseTest.setUp(self)
3099 self.queue = queue.Queue(-1)
3100 self.que_hdlr = logging.handlers.QueueHandler(self.queue)
favlladfe3442017-08-01 20:12:26 +02003101 self.name = 'que'
Vinay Sajip8552d1f2010-09-14 09:34:09 +00003102 self.que_logger = logging.getLogger('que')
3103 self.que_logger.propagate = False
3104 self.que_logger.setLevel(logging.WARNING)
3105 self.que_logger.addHandler(self.que_hdlr)
3106
3107 def tearDown(self):
3108 self.que_hdlr.close()
3109 BaseTest.tearDown(self)
3110
3111 def test_queue_handler(self):
3112 self.que_logger.debug(self.next_message())
3113 self.assertRaises(queue.Empty, self.queue.get_nowait)
3114 self.que_logger.info(self.next_message())
3115 self.assertRaises(queue.Empty, self.queue.get_nowait)
3116 msg = self.next_message()
3117 self.que_logger.warning(msg)
3118 data = self.queue.get_nowait()
3119 self.assertTrue(isinstance(data, logging.LogRecord))
3120 self.assertEqual(data.name, self.que_logger.name)
3121 self.assertEqual((data.msg, data.args), (msg, None))
3122
favlladfe3442017-08-01 20:12:26 +02003123 def test_formatting(self):
3124 msg = self.next_message()
3125 levelname = logging.getLevelName(logging.WARNING)
3126 log_format_str = '{name} -> {levelname}: {message}'
3127 formatted_msg = log_format_str.format(name=self.name,
3128 levelname=levelname, message=msg)
3129 formatter = logging.Formatter(self.log_format)
3130 self.que_hdlr.setFormatter(formatter)
3131 self.que_logger.warning(msg)
3132 log_record = self.queue.get_nowait()
3133 self.assertEqual(formatted_msg, log_record.msg)
3134 self.assertEqual(formatted_msg, log_record.message)
3135
Victor Stinnercafa2ef2011-05-02 16:11:28 +02003136 @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
3137 'logging.handlers.QueueListener required for this test')
Vinay Sajipe723e962011-04-15 22:27:17 +01003138 def test_queue_listener(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003139 handler = support.TestHandler(support.Matcher())
Vinay Sajipe723e962011-04-15 22:27:17 +01003140 listener = logging.handlers.QueueListener(self.queue, handler)
3141 listener.start()
3142 try:
3143 self.que_logger.warning(self.next_message())
3144 self.que_logger.error(self.next_message())
3145 self.que_logger.critical(self.next_message())
3146 finally:
3147 listener.stop()
3148 self.assertTrue(handler.matches(levelno=logging.WARNING, message='1'))
3149 self.assertTrue(handler.matches(levelno=logging.ERROR, message='2'))
3150 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3'))
Vinay Sajip365701a2015-02-09 19:49:00 +00003151 handler.close()
3152
3153 # Now test with respect_handler_level set
3154
3155 handler = support.TestHandler(support.Matcher())
3156 handler.setLevel(logging.CRITICAL)
3157 listener = logging.handlers.QueueListener(self.queue, handler,
3158 respect_handler_level=True)
3159 listener.start()
3160 try:
3161 self.que_logger.warning(self.next_message())
3162 self.que_logger.error(self.next_message())
3163 self.que_logger.critical(self.next_message())
3164 finally:
3165 listener.stop()
3166 self.assertFalse(handler.matches(levelno=logging.WARNING, message='4'))
3167 self.assertFalse(handler.matches(levelno=logging.ERROR, message='5'))
3168 self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6'))
3169
Vinay Sajipd61910c2016-09-08 01:13:39 +01003170if hasattr(logging.handlers, 'QueueListener'):
3171 import multiprocessing
3172 from unittest.mock import patch
3173
3174 class QueueListenerTest(BaseTest):
3175 """
3176 Tests based on patch submitted for issue #27930. Ensure that
3177 QueueListener handles all log messages.
3178 """
3179
3180 repeat = 20
3181
3182 @staticmethod
3183 def setup_and_log(log_queue, ident):
3184 """
3185 Creates a logger with a QueueHandler that logs to a queue read by a
3186 QueueListener. Starts the listener, logs five messages, and stops
3187 the listener.
3188 """
3189 logger = logging.getLogger('test_logger_with_id_%s' % ident)
3190 logger.setLevel(logging.DEBUG)
3191 handler = logging.handlers.QueueHandler(log_queue)
3192 logger.addHandler(handler)
3193 listener = logging.handlers.QueueListener(log_queue)
3194 listener.start()
3195
3196 logger.info('one')
3197 logger.info('two')
3198 logger.info('three')
3199 logger.info('four')
3200 logger.info('five')
3201
3202 listener.stop()
3203 logger.removeHandler(handler)
3204 handler.close()
3205
3206 @patch.object(logging.handlers.QueueListener, 'handle')
3207 def test_handle_called_with_queue_queue(self, mock_handle):
3208 for i in range(self.repeat):
3209 log_queue = queue.Queue()
3210 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
3211 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3212 'correct number of handled log messages')
3213
3214 @patch.object(logging.handlers.QueueListener, 'handle')
3215 def test_handle_called_with_mp_queue(self, mock_handle):
xdegayebf2b65e2017-12-01 08:08:49 +01003216 # Issue 28668: The multiprocessing (mp) module is not functional
3217 # when the mp.synchronize module cannot be imported.
3218 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003219 for i in range(self.repeat):
3220 log_queue = multiprocessing.Queue()
3221 self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003222 log_queue.close()
3223 log_queue.join_thread()
Vinay Sajipd61910c2016-09-08 01:13:39 +01003224 self.assertEqual(mock_handle.call_count, 5 * self.repeat,
3225 'correct number of handled log messages')
3226
3227 @staticmethod
3228 def get_all_from_queue(log_queue):
3229 try:
3230 while True:
3231 yield log_queue.get_nowait()
3232 except queue.Empty:
3233 return []
3234
3235 def test_no_messages_in_queue_after_stop(self):
3236 """
3237 Five messages are logged then the QueueListener is stopped. This
3238 test then gets everything off the queue. Failure of this test
3239 indicates that messages were not registered on the queue until
3240 _after_ the QueueListener stopped.
3241 """
xdegayebf2b65e2017-12-01 08:08:49 +01003242 # Issue 28668: The multiprocessing (mp) module is not functional
3243 # when the mp.synchronize module cannot be imported.
3244 support.import_module('multiprocessing.synchronize')
Vinay Sajipd61910c2016-09-08 01:13:39 +01003245 for i in range(self.repeat):
3246 queue = multiprocessing.Queue()
3247 self.setup_and_log(queue, '%s_%s' %(self.id(), i))
3248 # time.sleep(1)
3249 items = list(self.get_all_from_queue(queue))
Victor Stinner8ca2f2f2017-04-26 15:56:25 +02003250 queue.close()
3251 queue.join_thread()
3252
Vinay Sajipd61910c2016-09-08 01:13:39 +01003253 expected = [[], [logging.handlers.QueueListener._sentinel]]
3254 self.assertIn(items, expected,
3255 'Found unexpected messages in queue: %s' % (
3256 [m.msg if isinstance(m, logging.LogRecord)
3257 else m for m in items]))
3258
Vinay Sajipe723e962011-04-15 22:27:17 +01003259
Vinay Sajip37eb3382011-04-26 20:26:41 +01003260ZERO = datetime.timedelta(0)
3261
3262class UTC(datetime.tzinfo):
3263 def utcoffset(self, dt):
3264 return ZERO
3265
3266 dst = utcoffset
3267
3268 def tzname(self, dt):
3269 return 'UTC'
3270
3271utc = UTC()
Vinay Sajipe723e962011-04-15 22:27:17 +01003272
Vinay Sajipa39c5712010-10-25 13:57:39 +00003273class FormatterTest(unittest.TestCase):
3274 def setUp(self):
3275 self.common = {
3276 'name': 'formatter.test',
3277 'level': logging.DEBUG,
3278 'pathname': os.path.join('path', 'to', 'dummy.ext'),
3279 'lineno': 42,
3280 'exc_info': None,
3281 'func': None,
3282 'msg': 'Message with %d %s',
3283 'args': (2, 'placeholders'),
3284 }
3285 self.variants = {
3286 }
3287
3288 def get_record(self, name=None):
3289 result = dict(self.common)
3290 if name is not None:
3291 result.update(self.variants[name])
3292 return logging.makeLogRecord(result)
3293
3294 def test_percent(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003295 # Test %-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003296 r = self.get_record()
3297 f = logging.Formatter('${%(message)s}')
3298 self.assertEqual(f.format(r), '${Message with 2 placeholders}')
3299 f = logging.Formatter('%(random)s')
3300 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003301 self.assertFalse(f.usesTime())
3302 f = logging.Formatter('%(asctime)s')
3303 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003304 f = logging.Formatter('%(asctime)-15s')
3305 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003306 f = logging.Formatter('asctime')
3307 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003308
3309 def test_braces(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003310 # Test {}-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003311 r = self.get_record()
3312 f = logging.Formatter('$%{message}%$', style='{')
3313 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3314 f = logging.Formatter('{random}', style='{')
3315 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003316 self.assertFalse(f.usesTime())
3317 f = logging.Formatter('{asctime}', style='{')
3318 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003319 f = logging.Formatter('{asctime!s:15}', style='{')
3320 self.assertTrue(f.usesTime())
3321 f = logging.Formatter('{asctime:15}', style='{')
3322 self.assertTrue(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003323 f = logging.Formatter('asctime', style='{')
3324 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003325
3326 def test_dollars(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003327 # Test $-formatting
Vinay Sajipa39c5712010-10-25 13:57:39 +00003328 r = self.get_record()
3329 f = logging.Formatter('$message', style='$')
3330 self.assertEqual(f.format(r), 'Message with 2 placeholders')
3331 f = logging.Formatter('$$%${message}%$$', style='$')
3332 self.assertEqual(f.format(r), '$%Message with 2 placeholders%$')
3333 f = logging.Formatter('${random}', style='$')
3334 self.assertRaises(KeyError, f.format, r)
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003335 self.assertFalse(f.usesTime())
3336 f = logging.Formatter('${asctime}', style='$')
3337 self.assertTrue(f.usesTime())
Vinay Sajip89807a52011-02-26 16:06:02 +00003338 f = logging.Formatter('${asctime', style='$')
3339 self.assertFalse(f.usesTime())
Vinay Sajip6a65c5d2010-10-26 13:16:11 +00003340 f = logging.Formatter('$asctime', style='$')
3341 self.assertTrue(f.usesTime())
3342 f = logging.Formatter('asctime', style='$')
3343 self.assertFalse(f.usesTime())
Vinay Sajipa39c5712010-10-25 13:57:39 +00003344
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003345 def test_invalid_style(self):
3346 self.assertRaises(ValueError, logging.Formatter, None, None, 'x')
3347
Vinay Sajip86a96ce2011-04-27 08:30:30 +01003348 def test_time(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003349 r = self.get_record()
Vinay Sajiped1f7c82012-07-03 21:36:36 +01003350 dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc)
3351 # We use None to indicate we want the local timezone
3352 # We're essentially converting a UTC time to local time
3353 r.created = time.mktime(dt.astimezone(None).timetuple())
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003354 r.msecs = 123
3355 f = logging.Formatter('%(asctime)s %(message)s')
Vinay Sajip37eb3382011-04-26 20:26:41 +01003356 f.converter = time.gmtime
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003357 self.assertEqual(f.formatTime(r), '1993-04-21 08:03:00,123')
3358 self.assertEqual(f.formatTime(r, '%Y:%d'), '1993:21')
Vinay Sajip985ef872011-04-26 19:34:04 +01003359 f.format(r)
3360 self.assertEqual(r.asctime, '1993-04-21 08:03:00,123')
3361
3362class TestBufferingFormatter(logging.BufferingFormatter):
3363 def formatHeader(self, records):
3364 return '[(%d)' % len(records)
3365
3366 def formatFooter(self, records):
3367 return '(%d)]' % len(records)
3368
3369class BufferingFormatterTest(unittest.TestCase):
3370 def setUp(self):
3371 self.records = [
3372 logging.makeLogRecord({'msg': 'one'}),
3373 logging.makeLogRecord({'msg': 'two'}),
3374 ]
3375
3376 def test_default(self):
3377 f = logging.BufferingFormatter()
3378 self.assertEqual('', f.format([]))
3379 self.assertEqual('onetwo', f.format(self.records))
3380
3381 def test_custom(self):
3382 f = TestBufferingFormatter()
3383 self.assertEqual('[(2)onetwo(2)]', f.format(self.records))
3384 lf = logging.Formatter('<%(message)s>')
3385 f = TestBufferingFormatter(lf)
3386 self.assertEqual('[(2)<one><two>(2)]', f.format(self.records))
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003387
3388class ExceptionTest(BaseTest):
3389 def test_formatting(self):
3390 r = self.root_logger
3391 h = RecordingHandler()
3392 r.addHandler(h)
3393 try:
3394 raise RuntimeError('deliberate mistake')
3395 except:
3396 logging.exception('failed', stack_info=True)
3397 r.removeHandler(h)
3398 h.close()
3399 r = h.records[0]
3400 self.assertTrue(r.exc_text.startswith('Traceback (most recent '
3401 'call last):\n'))
3402 self.assertTrue(r.exc_text.endswith('\nRuntimeError: '
3403 'deliberate mistake'))
3404 self.assertTrue(r.stack_info.startswith('Stack (most recent '
3405 'call last):\n'))
3406 self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', '
3407 'stack_info=True)'))
3408
3409
Vinay Sajip5a27d402010-12-10 11:42:57 +00003410class LastResortTest(BaseTest):
3411 def test_last_resort(self):
Vinay Sajip60b4df12010-12-27 11:18:52 +00003412 # Test the last resort handler
Vinay Sajip5a27d402010-12-10 11:42:57 +00003413 root = self.root_logger
3414 root.removeHandler(self.root_hdlr)
Vinay Sajip5a27d402010-12-10 11:42:57 +00003415 old_lastresort = logging.lastResort
3416 old_raise_exceptions = logging.raiseExceptions
Vinay Sajip1feedb42014-05-31 08:19:12 +01003417
Vinay Sajip5a27d402010-12-10 11:42:57 +00003418 try:
Vinay Sajip1feedb42014-05-31 08:19:12 +01003419 with support.captured_stderr() as stderr:
3420 root.debug('This should not appear')
3421 self.assertEqual(stderr.getvalue(), '')
3422 root.warning('Final chance!')
3423 self.assertEqual(stderr.getvalue(), 'Final chance!\n')
3424
3425 # No handlers and no last resort, so 'No handlers' message
Vinay Sajip5a27d402010-12-10 11:42:57 +00003426 logging.lastResort = None
Vinay Sajip1feedb42014-05-31 08:19:12 +01003427 with support.captured_stderr() as stderr:
3428 root.warning('Final chance!')
3429 msg = 'No handlers could be found for logger "root"\n'
3430 self.assertEqual(stderr.getvalue(), msg)
3431
Vinay Sajip5a27d402010-12-10 11:42:57 +00003432 # 'No handlers' message only printed once
Vinay Sajip1feedb42014-05-31 08:19:12 +01003433 with support.captured_stderr() as stderr:
3434 root.warning('Final chance!')
3435 self.assertEqual(stderr.getvalue(), '')
3436
3437 # If raiseExceptions is False, no message is printed
Vinay Sajip5a27d402010-12-10 11:42:57 +00003438 root.manager.emittedNoHandlerWarning = False
Vinay Sajip5a27d402010-12-10 11:42:57 +00003439 logging.raiseExceptions = False
Vinay Sajip1feedb42014-05-31 08:19:12 +01003440 with support.captured_stderr() as stderr:
3441 root.warning('Final chance!')
3442 self.assertEqual(stderr.getvalue(), '')
Vinay Sajip5a27d402010-12-10 11:42:57 +00003443 finally:
Vinay Sajip5a27d402010-12-10 11:42:57 +00003444 root.addHandler(self.root_hdlr)
3445 logging.lastResort = old_lastresort
3446 logging.raiseExceptions = old_raise_exceptions
3447
3448
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003449class FakeHandler:
3450
3451 def __init__(self, identifier, called):
3452 for method in ('acquire', 'flush', 'close', 'release'):
3453 setattr(self, method, self.record_call(identifier, method, called))
3454
3455 def record_call(self, identifier, method_name, called):
3456 def inner():
3457 called.append('{} - {}'.format(identifier, method_name))
3458 return inner
3459
3460
3461class RecordingHandler(logging.NullHandler):
3462
3463 def __init__(self, *args, **kwargs):
3464 super(RecordingHandler, self).__init__(*args, **kwargs)
3465 self.records = []
3466
3467 def handle(self, record):
3468 """Keep track of all the emitted records."""
3469 self.records.append(record)
3470
3471
3472class ShutdownTest(BaseTest):
3473
Vinay Sajip5e66b162011-04-20 15:41:14 +01003474 """Test suite for the shutdown method."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003475
3476 def setUp(self):
3477 super(ShutdownTest, self).setUp()
3478 self.called = []
3479
3480 raise_exceptions = logging.raiseExceptions
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003481 self.addCleanup(setattr, logging, 'raiseExceptions', raise_exceptions)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003482
3483 def raise_error(self, error):
3484 def inner():
3485 raise error()
3486 return inner
3487
3488 def test_no_failure(self):
3489 # create some fake handlers
3490 handler0 = FakeHandler(0, self.called)
3491 handler1 = FakeHandler(1, self.called)
3492 handler2 = FakeHandler(2, self.called)
3493
3494 # create live weakref to those handlers
3495 handlers = map(logging.weakref.ref, [handler0, handler1, handler2])
3496
3497 logging.shutdown(handlerList=list(handlers))
3498
3499 expected = ['2 - acquire', '2 - flush', '2 - close', '2 - release',
3500 '1 - acquire', '1 - flush', '1 - close', '1 - release',
3501 '0 - acquire', '0 - flush', '0 - close', '0 - release']
3502 self.assertEqual(expected, self.called)
3503
3504 def _test_with_failure_in_method(self, method, error):
3505 handler = FakeHandler(0, self.called)
3506 setattr(handler, method, self.raise_error(error))
3507 handlers = [logging.weakref.ref(handler)]
3508
3509 logging.shutdown(handlerList=list(handlers))
3510
3511 self.assertEqual('0 - release', self.called[-1])
3512
3513 def test_with_ioerror_in_acquire(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003514 self._test_with_failure_in_method('acquire', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003515
3516 def test_with_ioerror_in_flush(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003517 self._test_with_failure_in_method('flush', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003518
3519 def test_with_ioerror_in_close(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02003520 self._test_with_failure_in_method('close', OSError)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003521
3522 def test_with_valueerror_in_acquire(self):
3523 self._test_with_failure_in_method('acquire', ValueError)
3524
3525 def test_with_valueerror_in_flush(self):
3526 self._test_with_failure_in_method('flush', ValueError)
3527
3528 def test_with_valueerror_in_close(self):
3529 self._test_with_failure_in_method('close', ValueError)
3530
3531 def test_with_other_error_in_acquire_without_raise(self):
3532 logging.raiseExceptions = False
3533 self._test_with_failure_in_method('acquire', IndexError)
3534
3535 def test_with_other_error_in_flush_without_raise(self):
3536 logging.raiseExceptions = False
3537 self._test_with_failure_in_method('flush', IndexError)
3538
3539 def test_with_other_error_in_close_without_raise(self):
3540 logging.raiseExceptions = False
3541 self._test_with_failure_in_method('close', IndexError)
3542
3543 def test_with_other_error_in_acquire_with_raise(self):
3544 logging.raiseExceptions = True
3545 self.assertRaises(IndexError, self._test_with_failure_in_method,
3546 'acquire', IndexError)
3547
3548 def test_with_other_error_in_flush_with_raise(self):
3549 logging.raiseExceptions = True
3550 self.assertRaises(IndexError, self._test_with_failure_in_method,
3551 'flush', IndexError)
3552
3553 def test_with_other_error_in_close_with_raise(self):
3554 logging.raiseExceptions = True
3555 self.assertRaises(IndexError, self._test_with_failure_in_method,
3556 'close', IndexError)
3557
3558
3559class ModuleLevelMiscTest(BaseTest):
3560
Vinay Sajip5e66b162011-04-20 15:41:14 +01003561 """Test suite for some module level methods."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003562
3563 def test_disable(self):
3564 old_disable = logging.root.manager.disable
3565 # confirm our assumptions are correct
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003566 self.assertEqual(old_disable, 0)
3567 self.addCleanup(logging.disable, old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003568
3569 logging.disable(83)
3570 self.assertEqual(logging.root.manager.disable, 83)
3571
Vinay Sajipd489ac92016-12-31 11:40:11 +00003572 # test the default value introduced in 3.7
3573 # (Issue #28524)
3574 logging.disable()
3575 self.assertEqual(logging.root.manager.disable, logging.CRITICAL)
3576
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003577 def _test_log(self, method, level=None):
3578 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01003579 support.patch(self, logging, 'basicConfig',
3580 lambda *a, **kw: called.append((a, kw)))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003581
3582 recording = RecordingHandler()
3583 logging.root.addHandler(recording)
3584
3585 log_method = getattr(logging, method)
3586 if level is not None:
3587 log_method(level, "test me: %r", recording)
3588 else:
3589 log_method("test me: %r", recording)
3590
3591 self.assertEqual(len(recording.records), 1)
3592 record = recording.records[0]
3593 self.assertEqual(record.getMessage(), "test me: %r" % recording)
3594
3595 expected_level = level if level is not None else getattr(logging, method.upper())
3596 self.assertEqual(record.levelno, expected_level)
3597
3598 # basicConfig was not called!
3599 self.assertEqual(called, [])
3600
3601 def test_log(self):
3602 self._test_log('log', logging.ERROR)
3603
3604 def test_debug(self):
3605 self._test_log('debug')
3606
3607 def test_info(self):
3608 self._test_log('info')
3609
3610 def test_warning(self):
3611 self._test_log('warning')
3612
3613 def test_error(self):
3614 self._test_log('error')
3615
3616 def test_critical(self):
3617 self._test_log('critical')
3618
3619 def test_set_logger_class(self):
3620 self.assertRaises(TypeError, logging.setLoggerClass, object)
3621
3622 class MyLogger(logging.Logger):
3623 pass
3624
3625 logging.setLoggerClass(MyLogger)
3626 self.assertEqual(logging.getLoggerClass(), MyLogger)
3627
3628 logging.setLoggerClass(logging.Logger)
3629 self.assertEqual(logging.getLoggerClass(), logging.Logger)
3630
Serhiy Storchakaa7930372016-07-03 22:27:26 +03003631 @support.requires_type_collecting
Antoine Pitrou712cb732013-12-21 15:51:54 +01003632 def test_logging_at_shutdown(self):
3633 # Issue #20037
3634 code = """if 1:
3635 import logging
3636
3637 class A:
3638 def __del__(self):
3639 try:
3640 raise ValueError("some error")
3641 except Exception:
3642 logging.exception("exception in __del__")
3643
3644 a = A()"""
3645 rc, out, err = assert_python_ok("-c", code)
3646 err = err.decode()
3647 self.assertIn("exception in __del__", err)
3648 self.assertIn("ValueError: some error", err)
3649
3650
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003651class LogRecordTest(BaseTest):
3652 def test_str_rep(self):
3653 r = logging.makeLogRecord({})
3654 s = str(r)
3655 self.assertTrue(s.startswith('<LogRecord: '))
3656 self.assertTrue(s.endswith('>'))
3657
3658 def test_dict_arg(self):
3659 h = RecordingHandler()
3660 r = logging.getLogger()
3661 r.addHandler(h)
3662 d = {'less' : 'more' }
3663 logging.warning('less is %(less)s', d)
3664 self.assertIs(h.records[0].args, d)
3665 self.assertEqual(h.records[0].message, 'less is more')
3666 r.removeHandler(h)
3667 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003668
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003669 def test_multiprocessing(self):
3670 r = logging.makeLogRecord({})
3671 self.assertEqual(r.processName, 'MainProcess')
Vinay Sajipbd3d5cf2011-05-17 07:41:18 +01003672 try:
3673 import multiprocessing as mp
3674 r = logging.makeLogRecord({})
3675 self.assertEqual(r.processName, mp.current_process().name)
3676 except ImportError:
3677 pass
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003678
3679 def test_optional(self):
3680 r = logging.makeLogRecord({})
3681 NOT_NONE = self.assertIsNotNone
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02003682 NOT_NONE(r.thread)
3683 NOT_NONE(r.threadName)
Vinay Sajip7fe1d512011-04-28 12:04:58 +01003684 NOT_NONE(r.process)
3685 NOT_NONE(r.processName)
3686 log_threads = logging.logThreads
3687 log_processes = logging.logProcesses
3688 log_multiprocessing = logging.logMultiprocessing
3689 try:
3690 logging.logThreads = False
3691 logging.logProcesses = False
3692 logging.logMultiprocessing = False
3693 r = logging.makeLogRecord({})
3694 NONE = self.assertIsNone
3695 NONE(r.thread)
3696 NONE(r.threadName)
3697 NONE(r.process)
3698 NONE(r.processName)
3699 finally:
3700 logging.logThreads = log_threads
3701 logging.logProcesses = log_processes
3702 logging.logMultiprocessing = log_multiprocessing
3703
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003704class BasicConfigTest(unittest.TestCase):
3705
Vinay Sajip95bf5042011-04-20 11:50:56 +01003706 """Test suite for logging.basicConfig."""
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003707
3708 def setUp(self):
3709 super(BasicConfigTest, self).setUp()
Vinay Sajip3def7e02011-04-20 10:58:06 +01003710 self.handlers = logging.root.handlers
Vinay Sajip95bf5042011-04-20 11:50:56 +01003711 self.saved_handlers = logging._handlers.copy()
3712 self.saved_handler_list = logging._handlerList[:]
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003713 self.original_logging_level = logging.root.level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003714 self.addCleanup(self.cleanup)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003715 logging.root.handlers = []
3716
3717 def tearDown(self):
Vinay Sajip3def7e02011-04-20 10:58:06 +01003718 for h in logging.root.handlers[:]:
3719 logging.root.removeHandler(h)
3720 h.close()
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003721 super(BasicConfigTest, self).tearDown()
3722
Vinay Sajip3def7e02011-04-20 10:58:06 +01003723 def cleanup(self):
3724 setattr(logging.root, 'handlers', self.handlers)
Vinay Sajip95bf5042011-04-20 11:50:56 +01003725 logging._handlers.clear()
3726 logging._handlers.update(self.saved_handlers)
3727 logging._handlerList[:] = self.saved_handler_list
Vinay Sajip1e42f9e2011-04-20 12:20:44 +01003728 logging.root.level = self.original_logging_level
Vinay Sajip3def7e02011-04-20 10:58:06 +01003729
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003730 def test_no_kwargs(self):
3731 logging.basicConfig()
3732
3733 # handler defaults to a StreamHandler to sys.stderr
3734 self.assertEqual(len(logging.root.handlers), 1)
3735 handler = logging.root.handlers[0]
3736 self.assertIsInstance(handler, logging.StreamHandler)
3737 self.assertEqual(handler.stream, sys.stderr)
3738
3739 formatter = handler.formatter
3740 # format defaults to logging.BASIC_FORMAT
3741 self.assertEqual(formatter._style._fmt, logging.BASIC_FORMAT)
3742 # datefmt defaults to None
3743 self.assertIsNone(formatter.datefmt)
3744 # style defaults to %
3745 self.assertIsInstance(formatter._style, logging.PercentStyle)
3746
Florent Xiclunae41f0de2011-11-11 19:39:25 +01003747 # level is not explicitly set
Vinay Sajip5b9eecf2011-04-20 12:50:42 +01003748 self.assertEqual(logging.root.level, self.original_logging_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003749
Vinay Sajip1fd12022014-01-13 21:59:56 +00003750 def test_strformatstyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003751 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003752 logging.basicConfig(stream=sys.stdout, style="{")
3753 logging.error("Log an error")
3754 sys.stdout.seek(0)
3755 self.assertEqual(output.getvalue().strip(),
3756 "ERROR:root:Log an error")
3757
3758 def test_stringtemplatestyle(self):
Vinay Sajip1feedb42014-05-31 08:19:12 +01003759 with support.captured_stdout() as output:
Vinay Sajip1fd12022014-01-13 21:59:56 +00003760 logging.basicConfig(stream=sys.stdout, style="$")
3761 logging.error("Log an error")
3762 sys.stdout.seek(0)
3763 self.assertEqual(output.getvalue().strip(),
3764 "ERROR:root:Log an error")
3765
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003766 def test_filename(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003767
3768 def cleanup(h1, h2, fn):
3769 h1.close()
3770 h2.close()
3771 os.remove(fn)
3772
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003773 logging.basicConfig(filename='test.log')
3774
3775 self.assertEqual(len(logging.root.handlers), 1)
3776 handler = logging.root.handlers[0]
3777 self.assertIsInstance(handler, logging.FileHandler)
3778
3779 expected = logging.FileHandler('test.log', 'a')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003780 self.assertEqual(handler.stream.mode, expected.stream.mode)
3781 self.assertEqual(handler.stream.name, expected.stream.name)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003782 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003783
3784 def test_filemode(self):
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003785
3786 def cleanup(h1, h2, fn):
3787 h1.close()
3788 h2.close()
3789 os.remove(fn)
3790
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003791 logging.basicConfig(filename='test.log', filemode='wb')
3792
3793 handler = logging.root.handlers[0]
3794 expected = logging.FileHandler('test.log', 'wb')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003795 self.assertEqual(handler.stream.mode, expected.stream.mode)
Vinay Sajipbecf5c62013-03-08 09:50:57 +00003796 self.addCleanup(cleanup, handler, expected, 'test.log')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003797
3798 def test_stream(self):
3799 stream = io.StringIO()
3800 self.addCleanup(stream.close)
3801 logging.basicConfig(stream=stream)
3802
3803 self.assertEqual(len(logging.root.handlers), 1)
3804 handler = logging.root.handlers[0]
3805 self.assertIsInstance(handler, logging.StreamHandler)
3806 self.assertEqual(handler.stream, stream)
3807
3808 def test_format(self):
3809 logging.basicConfig(format='foo')
3810
3811 formatter = logging.root.handlers[0].formatter
3812 self.assertEqual(formatter._style._fmt, 'foo')
3813
3814 def test_datefmt(self):
3815 logging.basicConfig(datefmt='bar')
3816
3817 formatter = logging.root.handlers[0].formatter
3818 self.assertEqual(formatter.datefmt, 'bar')
3819
3820 def test_style(self):
3821 logging.basicConfig(style='$')
3822
3823 formatter = logging.root.handlers[0].formatter
3824 self.assertIsInstance(formatter._style, logging.StringTemplateStyle)
3825
3826 def test_level(self):
3827 old_level = logging.root.level
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003828 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003829
3830 logging.basicConfig(level=57)
3831 self.assertEqual(logging.root.level, 57)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003832 # Test that second call has no effect
3833 logging.basicConfig(level=58)
3834 self.assertEqual(logging.root.level, 57)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003835
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003836 def test_incompatible(self):
3837 assertRaises = self.assertRaises
3838 handlers = [logging.StreamHandler()]
3839 stream = sys.stderr
3840 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3841 stream=stream)
3842 assertRaises(ValueError, logging.basicConfig, filename='test.log',
3843 handlers=handlers)
3844 assertRaises(ValueError, logging.basicConfig, stream=stream,
3845 handlers=handlers)
Vinay Sajipd55436a2015-03-18 08:47:58 +00003846 # Issue 23207: test for invalid kwargs
3847 assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
3848 # Should pop both filename and filemode even if filename is None
3849 logging.basicConfig(filename=None, filemode='a')
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003850
3851 def test_handlers(self):
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003852 handlers = [
3853 logging.StreamHandler(),
3854 logging.StreamHandler(sys.stdout),
3855 logging.StreamHandler(),
3856 ]
3857 f = logging.Formatter()
3858 handlers[2].setFormatter(f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003859 logging.basicConfig(handlers=handlers)
3860 self.assertIs(handlers[0], logging.root.handlers[0])
3861 self.assertIs(handlers[1], logging.root.handlers[1])
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003862 self.assertIs(handlers[2], logging.root.handlers[2])
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003863 self.assertIsNotNone(handlers[0].formatter)
3864 self.assertIsNotNone(handlers[1].formatter)
Vinay Sajip26fe4b72011-04-26 18:43:05 +01003865 self.assertIs(handlers[2].formatter, f)
Vinay Sajip4a0a31d2011-04-11 08:42:07 +01003866 self.assertIs(handlers[0].formatter, handlers[1].formatter)
3867
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003868 def _test_log(self, method, level=None):
3869 # logging.root has no handlers so basicConfig should be called
3870 called = []
3871
3872 old_basic_config = logging.basicConfig
3873 def my_basic_config(*a, **kw):
3874 old_basic_config()
3875 old_level = logging.root.level
3876 logging.root.setLevel(100) # avoid having messages in stderr
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003877 self.addCleanup(logging.root.setLevel, old_level)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003878 called.append((a, kw))
3879
Vinay Sajip1feedb42014-05-31 08:19:12 +01003880 support.patch(self, logging, 'basicConfig', my_basic_config)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003881
3882 log_method = getattr(logging, method)
3883 if level is not None:
3884 log_method(level, "test me")
3885 else:
3886 log_method("test me")
3887
3888 # basicConfig was called with no arguments
3889 self.assertEqual(called, [((), {})])
3890
3891 def test_log(self):
3892 self._test_log('log', logging.WARNING)
3893
3894 def test_debug(self):
3895 self._test_log('debug')
3896
3897 def test_info(self):
3898 self._test_log('info')
3899
3900 def test_warning(self):
3901 self._test_log('warning')
3902
3903 def test_error(self):
3904 self._test_log('error')
3905
3906 def test_critical(self):
3907 self._test_log('critical')
3908
3909
3910class LoggerAdapterTest(unittest.TestCase):
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003911 def setUp(self):
3912 super(LoggerAdapterTest, self).setUp()
3913 old_handler_list = logging._handlerList[:]
3914
3915 self.recording = RecordingHandler()
3916 self.logger = logging.root
3917 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003918 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003919 self.addCleanup(self.recording.close)
3920
3921 def cleanup():
3922 logging._handlerList[:] = old_handler_list
3923
3924 self.addCleanup(cleanup)
3925 self.addCleanup(logging.shutdown)
3926 self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
3927
3928 def test_exception(self):
3929 msg = 'testing exception: %r'
3930 exc = None
3931 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003932 1 / 0
3933 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003934 exc = e
3935 self.adapter.exception(msg, self.recording)
3936
3937 self.assertEqual(len(self.recording.records), 1)
3938 record = self.recording.records[0]
3939 self.assertEqual(record.levelno, logging.ERROR)
3940 self.assertEqual(record.msg, msg)
3941 self.assertEqual(record.args, (self.recording,))
3942 self.assertEqual(record.exc_info,
3943 (exc.__class__, exc, exc.__traceback__))
3944
Vinay Sajip02a8f9e2014-09-14 21:29:11 +01003945 def test_exception_excinfo(self):
3946 try:
3947 1 / 0
3948 except ZeroDivisionError as e:
3949 exc = e
3950
3951 self.adapter.exception('exc_info test', exc_info=exc)
3952
3953 self.assertEqual(len(self.recording.records), 1)
3954 record = self.recording.records[0]
3955 self.assertEqual(record.exc_info,
3956 (exc.__class__, exc, exc.__traceback__))
3957
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003958 def test_critical(self):
3959 msg = 'critical test! %r'
3960 self.adapter.critical(msg, self.recording)
3961
3962 self.assertEqual(len(self.recording.records), 1)
3963 record = self.recording.records[0]
3964 self.assertEqual(record.levelno, logging.CRITICAL)
3965 self.assertEqual(record.msg, msg)
3966 self.assertEqual(record.args, (self.recording,))
3967
3968 def test_is_enabled_for(self):
3969 old_disable = self.adapter.logger.manager.disable
3970 self.adapter.logger.manager.disable = 33
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003971 self.addCleanup(setattr, self.adapter.logger.manager, 'disable',
3972 old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003973 self.assertFalse(self.adapter.isEnabledFor(32))
3974
3975 def test_has_handlers(self):
3976 self.assertTrue(self.adapter.hasHandlers())
3977
3978 for handler in self.logger.handlers:
3979 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003980
Vinay Sajip5056c8c2011-06-05 09:31:34 +01003981 self.assertFalse(self.logger.hasHandlers())
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01003982 self.assertFalse(self.adapter.hasHandlers())
3983
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003984 def test_nested(self):
Łukasz Langace9e6252017-10-19 10:24:55 -07003985 class Adapter(logging.LoggerAdapter):
3986 prefix = 'Adapter'
3987
3988 def process(self, msg, kwargs):
3989 return f"{self.prefix} {msg}", kwargs
3990
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003991 msg = 'Adapters can be nested, yo.'
Łukasz Langace9e6252017-10-19 10:24:55 -07003992 adapter = Adapter(logger=self.logger, extra=None)
3993 adapter_adapter = Adapter(logger=adapter, extra=None)
3994 adapter_adapter.prefix = 'AdapterAdapter'
3995 self.assertEqual(repr(adapter), repr(adapter_adapter))
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003996 adapter_adapter.log(logging.CRITICAL, msg, self.recording)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04003997 self.assertEqual(len(self.recording.records), 1)
3998 record = self.recording.records[0]
3999 self.assertEqual(record.levelno, logging.CRITICAL)
Łukasz Langace9e6252017-10-19 10:24:55 -07004000 self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004001 self.assertEqual(record.args, (self.recording,))
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004002 orig_manager = adapter_adapter.manager
Łukasz Langace9e6252017-10-19 10:24:55 -07004003 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004004 self.assertIs(self.logger.manager, orig_manager)
4005 temp_manager = object()
4006 try:
4007 adapter_adapter.manager = temp_manager
4008 self.assertIs(adapter_adapter.manager, temp_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004009 self.assertIs(adapter.manager, temp_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004010 self.assertIs(self.logger.manager, temp_manager)
4011 finally:
4012 adapter_adapter.manager = orig_manager
4013 self.assertIs(adapter_adapter.manager, orig_manager)
Łukasz Langace9e6252017-10-19 10:24:55 -07004014 self.assertIs(adapter.manager, orig_manager)
Łukasz Langa0b6a1182017-10-18 17:28:51 -07004015 self.assertIs(self.logger.manager, orig_manager)
Łukasz Langa1bbd4822017-09-14 11:34:47 -04004016
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004017
4018class LoggerTest(BaseTest):
4019
4020 def setUp(self):
4021 super(LoggerTest, self).setUp()
4022 self.recording = RecordingHandler()
4023 self.logger = logging.Logger(name='blah')
4024 self.logger.addHandler(self.recording)
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004025 self.addCleanup(self.logger.removeHandler, self.recording)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004026 self.addCleanup(self.recording.close)
4027 self.addCleanup(logging.shutdown)
4028
4029 def test_set_invalid_level(self):
4030 self.assertRaises(TypeError, self.logger.setLevel, object())
4031
4032 def test_exception(self):
4033 msg = 'testing exception: %r'
4034 exc = None
4035 try:
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004036 1 / 0
4037 except ZeroDivisionError as e:
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004038 exc = e
4039 self.logger.exception(msg, self.recording)
4040
4041 self.assertEqual(len(self.recording.records), 1)
4042 record = self.recording.records[0]
4043 self.assertEqual(record.levelno, logging.ERROR)
4044 self.assertEqual(record.msg, msg)
4045 self.assertEqual(record.args, (self.recording,))
4046 self.assertEqual(record.exc_info,
4047 (exc.__class__, exc, exc.__traceback__))
4048
4049 def test_log_invalid_level_with_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004050 with support.swap_attr(logging, 'raiseExceptions', True):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004051 self.assertRaises(TypeError, self.logger.log, '10', 'test message')
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004052
4053 def test_log_invalid_level_no_raise(self):
Serhiy Storchaka296b3472015-07-21 22:40:18 +03004054 with support.swap_attr(logging, 'raiseExceptions', False):
Serhiy Storchaka750eae12015-07-21 22:39:26 +03004055 self.logger.log('10', 'test message') # no exception happens
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004056
4057 def test_find_caller_with_stack_info(self):
4058 called = []
Vinay Sajip1feedb42014-05-31 08:19:12 +01004059 support.patch(self, logging.traceback, 'print_stack',
4060 lambda f, file: called.append(file.getvalue()))
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004061
4062 self.logger.findCaller(stack_info=True)
4063
4064 self.assertEqual(len(called), 1)
4065 self.assertEqual('Stack (most recent call last):\n', called[0])
4066
4067 def test_make_record_with_extra_overwrite(self):
4068 name = 'my record'
4069 level = 13
4070 fn = lno = msg = args = exc_info = func = sinfo = None
4071 rv = logging._logRecordFactory(name, level, fn, lno, msg, args,
4072 exc_info, func, sinfo)
4073
4074 for key in ('message', 'asctime') + tuple(rv.__dict__.keys()):
4075 extra = {key: 'some value'}
4076 self.assertRaises(KeyError, self.logger.makeRecord, name, level,
4077 fn, lno, msg, args, exc_info,
4078 extra=extra, sinfo=sinfo)
4079
4080 def test_make_record_with_extra_no_overwrite(self):
4081 name = 'my record'
4082 level = 13
4083 fn = lno = msg = args = exc_info = func = sinfo = None
4084 extra = {'valid_key': 'some value'}
4085 result = self.logger.makeRecord(name, level, fn, lno, msg, args,
4086 exc_info, extra=extra, sinfo=sinfo)
4087 self.assertIn('valid_key', result.__dict__)
4088
4089 def test_has_handlers(self):
4090 self.assertTrue(self.logger.hasHandlers())
4091
4092 for handler in self.logger.handlers:
4093 self.logger.removeHandler(handler)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004094 self.assertFalse(self.logger.hasHandlers())
4095
4096 def test_has_handlers_no_propagate(self):
4097 child_logger = logging.getLogger('blah.child')
4098 child_logger.propagate = False
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004099 self.assertFalse(child_logger.hasHandlers())
4100
4101 def test_is_enabled_for(self):
4102 old_disable = self.logger.manager.disable
4103 self.logger.manager.disable = 23
Vinay Sajip5056c8c2011-06-05 09:31:34 +01004104 self.addCleanup(setattr, self.logger.manager, 'disable', old_disable)
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004105 self.assertFalse(self.logger.isEnabledFor(22))
4106
Florent Xicluna5252f9f2011-11-07 19:43:05 +01004107 def test_root_logger_aliases(self):
4108 root = logging.getLogger()
4109 self.assertIs(root, logging.root)
4110 self.assertIs(root, logging.getLogger(None))
4111 self.assertIs(root, logging.getLogger(''))
4112 self.assertIs(root, logging.getLogger('foo').root)
4113 self.assertIs(root, logging.getLogger('foo.bar').root)
4114 self.assertIs(root, logging.getLogger('foo').parent)
4115
4116 self.assertIsNot(root, logging.getLogger('\0'))
4117 self.assertIsNot(root, logging.getLogger('foo.bar').parent)
4118
4119 def test_invalid_names(self):
4120 self.assertRaises(TypeError, logging.getLogger, any)
4121 self.assertRaises(TypeError, logging.getLogger, b'foo')
4122
Vinay Sajip6260d9f2017-06-06 16:34:29 +01004123 def test_pickling(self):
4124 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4125 for name in ('', 'root', 'foo', 'foo.bar', 'baz.bar'):
4126 logger = logging.getLogger(name)
4127 s = pickle.dumps(logger, proto)
4128 unpickled = pickle.loads(s)
4129 self.assertIs(unpickled, logger)
4130
Avram Lubkin78c18a92017-07-30 05:36:33 -04004131 def test_caching(self):
4132 root = self.root_logger
4133 logger1 = logging.getLogger("abc")
4134 logger2 = logging.getLogger("abc.def")
4135
4136 # Set root logger level and ensure cache is empty
4137 root.setLevel(logging.ERROR)
4138 self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
4139 self.assertEqual(logger2._cache, {})
4140
4141 # Ensure cache is populated and calls are consistent
4142 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4143 self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
4144 self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
4145 self.assertEqual(root._cache, {})
4146 self.assertTrue(logger2.isEnabledFor(logging.ERROR))
4147
4148 # Ensure root cache gets populated
4149 self.assertEqual(root._cache, {})
4150 self.assertTrue(root.isEnabledFor(logging.ERROR))
4151 self.assertEqual(root._cache, {logging.ERROR: True})
4152
4153 # Set parent logger level and ensure caches are emptied
4154 logger1.setLevel(logging.CRITICAL)
4155 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4156 self.assertEqual(logger2._cache, {})
4157
4158 # Ensure logger2 uses parent logger's effective level
4159 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4160
4161 # Set level to NOTSET and ensure caches are empty
4162 logger2.setLevel(logging.NOTSET)
4163 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4164 self.assertEqual(logger2._cache, {})
4165 self.assertEqual(logger1._cache, {})
4166 self.assertEqual(root._cache, {})
4167
4168 # Verify logger2 follows parent and not root
4169 self.assertFalse(logger2.isEnabledFor(logging.ERROR))
4170 self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
4171 self.assertFalse(logger1.isEnabledFor(logging.ERROR))
4172 self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
4173 self.assertTrue(root.isEnabledFor(logging.ERROR))
4174
4175 # Disable logging in manager and ensure caches are clear
4176 logging.disable()
4177 self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
4178 self.assertEqual(logger2._cache, {})
4179 self.assertEqual(logger1._cache, {})
4180 self.assertEqual(root._cache, {})
4181
4182 # Ensure no loggers are enabled
4183 self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
4184 self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
4185 self.assertFalse(root.isEnabledFor(logging.CRITICAL))
4186
Vinay Sajipe6c1eb92011-03-29 17:20:34 +01004187
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004188class BaseFileTest(BaseTest):
4189 "Base class for handler tests that write log files"
4190
4191 def setUp(self):
4192 BaseTest.setUp(self)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004193 fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-")
4194 os.close(fd)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004195 self.rmfiles = []
4196
4197 def tearDown(self):
4198 for fn in self.rmfiles:
4199 os.unlink(fn)
Vinay Sajip60b4df12010-12-27 11:18:52 +00004200 if os.path.exists(self.fn):
4201 os.unlink(self.fn)
Hirokazu Yamamoto2cdacd72010-09-18 03:54:32 +00004202 BaseTest.tearDown(self)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004203
4204 def assertLogFile(self, filename):
4205 "Assert a log file is there and register it for deletion"
4206 self.assertTrue(os.path.exists(filename),
Vinay Sajip7367d082011-05-02 13:17:27 +01004207 msg="Log file %r does not exist" % filename)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004208 self.rmfiles.append(filename)
4209
4210
Vinay Sajip26fe4b72011-04-26 18:43:05 +01004211class FileHandlerTest(BaseFileTest):
4212 def test_delay(self):
4213 os.unlink(self.fn)
4214 fh = logging.FileHandler(self.fn, delay=True)
4215 self.assertIsNone(fh.stream)
4216 self.assertFalse(os.path.exists(self.fn))
4217 fh.handle(logging.makeLogRecord({}))
4218 self.assertIsNotNone(fh.stream)
4219 self.assertTrue(os.path.exists(self.fn))
4220 fh.close()
4221
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004222class RotatingFileHandlerTest(BaseFileTest):
4223 def next_rec(self):
4224 return logging.LogRecord('n', logging.DEBUG, 'p', 1,
4225 self.next_message(), None, None, None)
4226
4227 def test_should_not_rollover(self):
4228 # If maxbytes is zero rollover never occurs
4229 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=0)
4230 self.assertFalse(rh.shouldRollover(None))
Vinay Sajipb046b802010-10-30 09:50:18 +00004231 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004232
4233 def test_should_rollover(self):
4234 rh = logging.handlers.RotatingFileHandler(self.fn, maxBytes=1)
4235 self.assertTrue(rh.shouldRollover(self.next_rec()))
Vinay Sajipb046b802010-10-30 09:50:18 +00004236 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004237
4238 def test_file_created(self):
4239 # checks that the file is created and assumes it was created
4240 # by us
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004241 rh = logging.handlers.RotatingFileHandler(self.fn)
4242 rh.emit(self.next_rec())
4243 self.assertLogFile(self.fn)
Vinay Sajipb046b802010-10-30 09:50:18 +00004244 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004245
4246 def test_rollover_filenames(self):
Vinay Sajip23b94d02012-01-04 12:02:26 +00004247 def namer(name):
4248 return name + ".test"
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004249 rh = logging.handlers.RotatingFileHandler(
4250 self.fn, backupCount=2, maxBytes=1)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004251 rh.namer = namer
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004252 rh.emit(self.next_rec())
4253 self.assertLogFile(self.fn)
4254 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004255 self.assertLogFile(namer(self.fn + ".1"))
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004256 rh.emit(self.next_rec())
Vinay Sajip23b94d02012-01-04 12:02:26 +00004257 self.assertLogFile(namer(self.fn + ".2"))
4258 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
4259 rh.close()
4260
Vinay Sajip1feedb42014-05-31 08:19:12 +01004261 @support.requires_zlib
Vinay Sajip23b94d02012-01-04 12:02:26 +00004262 def test_rotator(self):
4263 def namer(name):
4264 return name + ".gz"
4265
4266 def rotator(source, dest):
4267 with open(source, "rb") as sf:
4268 data = sf.read()
4269 compressed = zlib.compress(data, 9)
4270 with open(dest, "wb") as df:
4271 df.write(compressed)
4272 os.remove(source)
4273
4274 rh = logging.handlers.RotatingFileHandler(
4275 self.fn, backupCount=2, maxBytes=1)
4276 rh.rotator = rotator
4277 rh.namer = namer
4278 m1 = self.next_rec()
4279 rh.emit(m1)
4280 self.assertLogFile(self.fn)
4281 m2 = self.next_rec()
4282 rh.emit(m2)
4283 fn = namer(self.fn + ".1")
4284 self.assertLogFile(fn)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004285 newline = os.linesep
Vinay Sajip23b94d02012-01-04 12:02:26 +00004286 with open(fn, "rb") as f:
4287 compressed = f.read()
4288 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004289 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004290 rh.emit(self.next_rec())
4291 fn = namer(self.fn + ".2")
4292 self.assertLogFile(fn)
4293 with open(fn, "rb") as f:
4294 compressed = f.read()
4295 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004296 self.assertEqual(data.decode("ascii"), m1.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004297 rh.emit(self.next_rec())
4298 fn = namer(self.fn + ".2")
4299 with open(fn, "rb") as f:
4300 compressed = f.read()
4301 data = zlib.decompress(compressed)
Vinay Sajip2c94cdd2012-01-07 23:26:17 +00004302 self.assertEqual(data.decode("ascii"), m2.msg + newline)
Vinay Sajip23b94d02012-01-04 12:02:26 +00004303 self.assertFalse(os.path.exists(namer(self.fn + ".3")))
Vinay Sajipb046b802010-10-30 09:50:18 +00004304 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004305
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004306class TimedRotatingFileHandlerTest(BaseFileTest):
Vinay Sajip7367d082011-05-02 13:17:27 +01004307 # other test methods added below
4308 def test_rollover(self):
Vinay Sajip0372e102011-05-05 12:59:14 +01004309 fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S',
4310 backupCount=1)
Vinay Sajipb6f66702012-03-05 09:43:47 +00004311 fmt = logging.Formatter('%(asctime)s %(message)s')
4312 fh.setFormatter(fmt)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004313 r1 = logging.makeLogRecord({'msg': 'testing - initial'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004314 fh.emit(r1)
Vinay Sajipfd285022011-05-07 17:01:22 +01004315 self.assertLogFile(self.fn)
Vinay Sajip8d217c62012-03-05 12:45:51 +00004316 time.sleep(1.1) # a little over a second ...
Vinay Sajipb2fcd3a2012-03-05 20:02:53 +00004317 r2 = logging.makeLogRecord({'msg': 'testing - after delay'})
Vinay Sajip8d217c62012-03-05 12:45:51 +00004318 fh.emit(r2)
Vinay Sajipfd285022011-05-07 17:01:22 +01004319 fh.close()
4320 # At this point, we should have a recent rotated file which we
4321 # can test for the existence of. However, in practice, on some
4322 # machines which run really slowly, we don't know how far back
Vinay Sajip672c5812011-05-13 07:09:40 +01004323 # in time to go to look for the log file. So, we go back a fair
4324 # bit, and stop as soon as we see a rotated file. In theory this
4325 # could of course still fail, but the chances are lower.
Vinay Sajipfd285022011-05-07 17:01:22 +01004326 found = False
4327 now = datetime.datetime.now()
Vinay Sajip252048c2011-05-13 16:41:57 +01004328 GO_BACK = 5 * 60 # seconds
Vinay Sajip672c5812011-05-13 07:09:40 +01004329 for secs in range(GO_BACK):
4330 prev = now - datetime.timedelta(seconds=secs)
Vinay Sajipfd285022011-05-07 17:01:22 +01004331 fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S")
4332 found = os.path.exists(fn)
4333 if found:
4334 self.rmfiles.append(fn)
4335 break
Vinay Sajip672c5812011-05-13 07:09:40 +01004336 msg = 'No rotated files found, went back %d seconds' % GO_BACK
4337 if not found:
4338 #print additional diagnostics
Vinay Sajipa171f9c2011-05-13 14:45:08 +01004339 dn, fn = os.path.split(self.fn)
4340 files = [f for f in os.listdir(dn) if f.startswith(fn)]
Victor Stinner949c8902011-05-23 01:16:44 +02004341 print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S"), file=sys.stderr)
4342 print('The only matching files are: %s' % files, file=sys.stderr)
Vinay Sajip19b1d502012-02-28 19:02:43 +00004343 for f in files:
4344 print('Contents of %s:' % f)
Vinay Sajipd263d182012-03-03 16:20:37 +00004345 path = os.path.join(dn, f)
4346 with open(path, 'r') as tf:
Vinay Sajip19b1d502012-02-28 19:02:43 +00004347 print(tf.read())
Vinay Sajipfd285022011-05-07 17:01:22 +01004348 self.assertTrue(found, msg=msg)
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004349
Vinay Sajip0372e102011-05-05 12:59:14 +01004350 def test_invalid(self):
4351 assertRaises = self.assertRaises
4352 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004353 self.fn, 'X', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004354 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004355 self.fn, 'W', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004356 assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Vinay Sajipfd285022011-05-07 17:01:22 +01004357 self.fn, 'W7', delay=True)
Vinay Sajip0372e102011-05-05 12:59:14 +01004358
Vinay Sajipa7130792013-04-12 17:04:23 +01004359 def test_compute_rollover_daily_attime(self):
4360 currentTime = 0
4361 atTime = datetime.time(12, 0, 0)
4362 rh = logging.handlers.TimedRotatingFileHandler(
4363 self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
4364 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004365 try:
4366 actual = rh.computeRollover(currentTime)
4367 self.assertEqual(actual, currentTime + 12 * 60 * 60)
Vinay Sajipa7130792013-04-12 17:04:23 +01004368
Vinay Sajipd86ac962013-04-14 12:20:46 +01004369 actual = rh.computeRollover(currentTime + 13 * 60 * 60)
4370 self.assertEqual(actual, currentTime + 36 * 60 * 60)
4371 finally:
4372 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004373
Vinay Sajip10e8c492013-05-18 10:19:54 -07004374 #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.')
Vinay Sajipa7130792013-04-12 17:04:23 +01004375 def test_compute_rollover_weekly_attime(self):
Vinay Sajipd86ac962013-04-14 12:20:46 +01004376 currentTime = int(time.time())
4377 today = currentTime - currentTime % 86400
4378
Vinay Sajipa7130792013-04-12 17:04:23 +01004379 atTime = datetime.time(12, 0, 0)
4380
Vinay Sajip10e8c492013-05-18 10:19:54 -07004381 wday = time.gmtime(today).tm_wday
Vinay Sajipa7130792013-04-12 17:04:23 +01004382 for day in range(7):
4383 rh = logging.handlers.TimedRotatingFileHandler(
4384 self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
4385 atTime=atTime)
Vinay Sajipd86ac962013-04-14 12:20:46 +01004386 try:
4387 if wday > day:
4388 # The rollover day has already passed this week, so we
4389 # go over into next week
4390 expected = (7 - wday + day)
4391 else:
4392 expected = (day - wday)
4393 # At this point expected is in days from now, convert to seconds
4394 expected *= 24 * 60 * 60
4395 # Add in the rollover time
4396 expected += 12 * 60 * 60
4397 # Add in adjustment for today
4398 expected += today
Vinay Sajip66940a12013-04-15 11:59:35 +01004399 actual = rh.computeRollover(today)
4400 if actual != expected:
4401 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004402 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004403 self.assertEqual(actual, expected)
4404 if day == wday:
4405 # goes into following week
4406 expected += 7 * 24 * 60 * 60
Vinay Sajip8b4c7192013-04-14 12:25:25 +01004407 actual = rh.computeRollover(today + 13 * 60 * 60)
Vinay Sajip66940a12013-04-15 11:59:35 +01004408 if actual != expected:
4409 print('failed in timezone: %d' % time.timezone)
Vinay Sajipcaf9eb82013-05-12 00:04:58 +01004410 print('local vars: %s' % locals())
Vinay Sajipd86ac962013-04-14 12:20:46 +01004411 self.assertEqual(actual, expected)
4412 finally:
4413 rh.close()
Vinay Sajipa7130792013-04-12 17:04:23 +01004414
4415
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004416def secs(**kw):
4417 return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
4418
4419for when, exp in (('S', 1),
4420 ('M', 60),
4421 ('H', 60 * 60),
4422 ('D', 60 * 60 * 24),
Vinay Sajiped0473c2011-02-26 15:35:38 +00004423 ('MIDNIGHT', 60 * 60 * 24),
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004424 # current time (epoch start) is a Thursday, W0 means Monday
Vinay Sajiped0473c2011-02-26 15:35:38 +00004425 ('W0', secs(days=4, hours=24)),
4426 ):
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004427 def test_compute_rollover(self, when=when, exp=exp):
4428 rh = logging.handlers.TimedRotatingFileHandler(
Vinay Sajiped0473c2011-02-26 15:35:38 +00004429 self.fn, when=when, interval=1, backupCount=0, utc=True)
4430 currentTime = 0.0
4431 actual = rh.computeRollover(currentTime)
4432 if exp != actual:
4433 # Failures occur on some systems for MIDNIGHT and W0.
4434 # Print detailed calculation for MIDNIGHT so we can try to see
4435 # what's going on
Vinay Sajiped0473c2011-02-26 15:35:38 +00004436 if when == 'MIDNIGHT':
4437 try:
4438 if rh.utc:
4439 t = time.gmtime(currentTime)
4440 else:
4441 t = time.localtime(currentTime)
4442 currentHour = t[3]
4443 currentMinute = t[4]
4444 currentSecond = t[5]
4445 # r is the number of seconds left between now and midnight
4446 r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
4447 currentMinute) * 60 +
4448 currentSecond)
4449 result = currentTime + r
4450 print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
4451 print('currentHour: %s' % currentHour, file=sys.stderr)
4452 print('currentMinute: %s' % currentMinute, file=sys.stderr)
4453 print('currentSecond: %s' % currentSecond, file=sys.stderr)
4454 print('r: %s' % r, file=sys.stderr)
4455 print('result: %s' % result, file=sys.stderr)
4456 except Exception:
4457 print('exception in diagnostic code: %s' % sys.exc_info()[1], file=sys.stderr)
4458 self.assertEqual(exp, actual)
Vinay Sajipb046b802010-10-30 09:50:18 +00004459 rh.close()
Vinay Sajip19ec67a2010-09-17 18:57:36 +00004460 setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
4461
Vinay Sajip60ccd822011-05-09 17:32:09 +01004462
Vinay Sajip223349c2015-10-01 20:37:54 +01004463@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Vinay Sajip60ccd822011-05-09 17:32:09 +01004464class NTEventLogHandlerTest(BaseTest):
4465 def test_basic(self):
4466 logtype = 'Application'
4467 elh = win32evtlog.OpenEventLog(None, logtype)
4468 num_recs = win32evtlog.GetNumberOfEventLogRecords(elh)
Vinay Sajip223349c2015-10-01 20:37:54 +01004469
4470 try:
4471 h = logging.handlers.NTEventLogHandler('test_logging')
4472 except pywintypes.error as e:
Zachary Ware22226c52015-10-06 15:22:13 -05004473 if e.winerror == 5: # access denied
Vinay Sajip223349c2015-10-01 20:37:54 +01004474 raise unittest.SkipTest('Insufficient privileges to run test')
Zachary Ware106ddf02015-10-06 15:28:43 -05004475 raise
Vinay Sajip223349c2015-10-01 20:37:54 +01004476
Vinay Sajip60ccd822011-05-09 17:32:09 +01004477 r = logging.makeLogRecord({'msg': 'Test Log Message'})
4478 h.handle(r)
4479 h.close()
4480 # Now see if the event is recorded
Giampaolo Rodola'284529d2012-10-17 13:24:27 +02004481 self.assertLess(num_recs, win32evtlog.GetNumberOfEventLogRecords(elh))
Vinay Sajip60ccd822011-05-09 17:32:09 +01004482 flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \
4483 win32evtlog.EVENTLOG_SEQUENTIAL_READ
4484 found = False
4485 GO_BACK = 100
4486 events = win32evtlog.ReadEventLog(elh, flags, GO_BACK)
4487 for e in events:
4488 if e.SourceName != 'test_logging':
4489 continue
4490 msg = win32evtlogutil.SafeFormatMessage(e, logtype)
4491 if msg != 'Test Log Message\r\n':
4492 continue
4493 found = True
4494 break
4495 msg = 'Record not found in event log, went back %d records' % GO_BACK
4496 self.assertTrue(found, msg=msg)
4497
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004498
4499class MiscTestCase(unittest.TestCase):
4500 def test__all__(self):
4501 blacklist = {'logThreads', 'logMultiprocessing',
4502 'logProcesses', 'currentframe',
4503 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
4504 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
Martin Panter94332cb2016-10-20 05:10:44 +00004505 'root', 'threading'}
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004506 support.check__all__(self, logging, blacklist=blacklist)
4507
4508
Christian Heimes180510d2008-03-03 19:15:45 +00004509# Set the locale to the platform-dependent default. I have no idea
4510# why the test does this, but in any case we save the current locale
4511# first and restore it at the end.
Vinay Sajip1feedb42014-05-31 08:19:12 +01004512@support.run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00004513def test_main():
Vinay Sajipd61910c2016-09-08 01:13:39 +01004514 tests = [
Vinay Sajip1feedb42014-05-31 08:19:12 +01004515 BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest,
4516 HandlerTest, MemoryHandlerTest, ConfigFileTest, SocketHandlerTest,
4517 DatagramHandlerTest, MemoryTest, EncodingTest, WarningsTest,
4518 ConfigDictTest, ManagerTest, FormatterTest, BufferingFormatterTest,
4519 StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest,
4520 QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, BasicConfigTest,
4521 LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest,
4522 RotatingFileHandlerTest, LastResortTest, LogRecordTest,
Xiang Zhang0b4b57d2017-06-01 21:11:56 +08004523 ExceptionTest, SysLogHandlerTest, IPv6SysLogHandlerTest, HTTPHandlerTest,
Vinay Sajip1feedb42014-05-31 08:19:12 +01004524 NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
Vinay Sajipd61910c2016-09-08 01:13:39 +01004525 UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
Vinay Sajipdb8f4632016-09-08 01:37:03 +01004526 MiscTestCase
Vinay Sajipd61910c2016-09-08 01:13:39 +01004527 ]
4528 if hasattr(logging.handlers, 'QueueListener'):
4529 tests.append(QueueListenerTest)
4530 support.run_unittest(*tests)
Jeremy Hylton096d9862003-07-18 03:19:20 +00004531
Christian Heimes180510d2008-03-03 19:15:45 +00004532if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00004533 test_main()