blob: 677f013ea393c300b53d2ac9de170c96646a5f96 [file] [log] [blame]
Vinay Sajip8651a512013-03-22 15:19:24 +00001# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
Brett Cannon56c4deb2008-03-03 00:38:58 +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 Sajip8651a512013-03-22 15:19:24 +000019Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
Neal Norwitzb4a2df02003-01-02 14:56:39 +000020"""
21
Brett Cannon56c4deb2008-03-03 00:38:58 +000022import logging
23import logging.handlers
24import logging.config
Brett Cannonf9db8a32008-02-17 01:59:18 +000025
Vinay Sajipb20af942009-02-08 19:06:08 +000026import codecs
Brett Cannon56c4deb2008-03-03 00:38:58 +000027import cPickle
28import cStringIO
29import gc
Vinay Sajip28c382f2010-02-04 18:48:53 +000030import json
Brett Cannon56c4deb2008-03-03 00:38:58 +000031import os
Vinay Sajip885f6fd2012-04-24 23:15:10 +010032import random
Brett Cannon56c4deb2008-03-03 00:38:58 +000033import re
Guido van Rossum2a1d5162003-01-21 21:05:22 +000034import select
Brett Cannon56c4deb2008-03-03 00:38:58 +000035import socket
Georg Brandle152a772008-05-24 18:31:28 +000036from SocketServer import ThreadingTCPServer, StreamRequestHandler
Brett Cannon56c4deb2008-03-03 00:38:58 +000037import struct
38import sys
39import tempfile
Vinay Sajip27a13702010-05-03 15:11:53 +000040from test.test_support import captured_stdout, run_with_locale, run_unittest
Brett Cannon56c4deb2008-03-03 00:38:58 +000041import textwrap
Vinay Sajip885f6fd2012-04-24 23:15:10 +010042import time
Brett Cannon56c4deb2008-03-03 00:38:58 +000043import unittest
Vinay Sajip213faca2008-12-03 23:22:58 +000044import warnings
Brett Cannon56c4deb2008-03-03 00:38:58 +000045import weakref
Victor Stinner6a102812010-04-27 23:55:59 +000046try:
47 import threading
48except ImportError:
49 threading = None
Brett Cannonf9db8a32008-02-17 01:59:18 +000050
Brett Cannon56c4deb2008-03-03 00:38:58 +000051class BaseTest(unittest.TestCase):
52
53 """Base class for logging tests."""
54
55 log_format = "%(name)s -> %(levelname)s: %(message)s"
56 expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
57 message_num = 0
58
59 def setUp(self):
60 """Setup the default logging stream to an internal StringIO instance,
61 so that we can examine log output as we want."""
62 logger_dict = logging.getLogger().manager.loggerDict
Brett Cannonf9db8a32008-02-17 01:59:18 +000063 logging._acquireLock()
64 try:
Brett Cannon56c4deb2008-03-03 00:38:58 +000065 self.saved_handlers = logging._handlers.copy()
66 self.saved_handler_list = logging._handlerList[:]
67 self.saved_loggers = logger_dict.copy()
68 self.saved_level_names = logging._levelNames.copy()
Brett Cannonf9db8a32008-02-17 01:59:18 +000069 finally:
70 logging._releaseLock()
71
Vinay Sajip31e928e2010-03-22 13:02:28 +000072 # Set two unused loggers: one non-ASCII and one Unicode.
73 # This is to test correct operation when sorting existing
74 # loggers in the configuration code. See issue 8201.
75 logging.getLogger("\xab\xd7\xbb")
76 logging.getLogger(u"\u013f\u00d6\u0047")
77
Brett Cannon56c4deb2008-03-03 00:38:58 +000078 self.root_logger = logging.getLogger("")
79 self.original_logging_level = self.root_logger.getEffectiveLevel()
80
81 self.stream = cStringIO.StringIO()
82 self.root_logger.setLevel(logging.DEBUG)
83 self.root_hdlr = logging.StreamHandler(self.stream)
84 self.root_formatter = logging.Formatter(self.log_format)
85 self.root_hdlr.setFormatter(self.root_formatter)
86 self.root_logger.addHandler(self.root_hdlr)
87
88 def tearDown(self):
89 """Remove our logging stream, and restore the original logging
90 level."""
91 self.stream.close()
92 self.root_logger.removeHandler(self.root_hdlr)
Vinay Sajip28c382f2010-02-04 18:48:53 +000093 while self.root_logger.handlers:
94 h = self.root_logger.handlers[0]
95 self.root_logger.removeHandler(h)
96 h.close()
Brett Cannon56c4deb2008-03-03 00:38:58 +000097 self.root_logger.setLevel(self.original_logging_level)
98 logging._acquireLock()
99 try:
100 logging._levelNames.clear()
101 logging._levelNames.update(self.saved_level_names)
102 logging._handlers.clear()
103 logging._handlers.update(self.saved_handlers)
104 logging._handlerList[:] = self.saved_handler_list
105 loggerDict = logging.getLogger().manager.loggerDict
106 loggerDict.clear()
107 loggerDict.update(self.saved_loggers)
108 finally:
109 logging._releaseLock()
110
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000111 def assert_log_lines(self, expected_values, stream=None):
Brett Cannon56c4deb2008-03-03 00:38:58 +0000112 """Match the collected log lines against the regular expression
113 self.expected_log_pat, and compare the extracted group values to
114 the expected_values list of tuples."""
115 stream = stream or self.stream
116 pat = re.compile(self.expected_log_pat)
117 try:
118 stream.reset()
119 actual_lines = stream.readlines()
120 except AttributeError:
121 # StringIO.StringIO lacks a reset() method.
122 actual_lines = stream.getvalue().splitlines()
Ezio Melotti2623a372010-11-21 13:34:58 +0000123 self.assertEqual(len(actual_lines), len(expected_values))
Brett Cannon56c4deb2008-03-03 00:38:58 +0000124 for actual, expected in zip(actual_lines, expected_values):
125 match = pat.search(actual)
126 if not match:
127 self.fail("Log line does not match expected pattern:\n" +
128 actual)
Ezio Melotti2623a372010-11-21 13:34:58 +0000129 self.assertEqual(tuple(match.groups()), expected)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000130 s = stream.read()
131 if s:
132 self.fail("Remaining output at end of log stream:\n" + s)
133
134 def next_message(self):
135 """Generate a message consisting solely of an auto-incrementing
136 integer."""
137 self.message_num += 1
138 return "%d" % self.message_num
139
140
141class BuiltinLevelsTest(BaseTest):
142 """Test builtin levels and their inheritance."""
143
144 def test_flat(self):
145 #Logging levels in a flat logger namespace.
146 m = self.next_message
147
148 ERR = logging.getLogger("ERR")
149 ERR.setLevel(logging.ERROR)
150 INF = logging.getLogger("INF")
151 INF.setLevel(logging.INFO)
152 DEB = logging.getLogger("DEB")
153 DEB.setLevel(logging.DEBUG)
154
155 # These should log.
156 ERR.log(logging.CRITICAL, m())
157 ERR.error(m())
158
159 INF.log(logging.CRITICAL, m())
160 INF.error(m())
161 INF.warn(m())
162 INF.info(m())
163
164 DEB.log(logging.CRITICAL, m())
165 DEB.error(m())
166 DEB.warn (m())
167 DEB.info (m())
168 DEB.debug(m())
169
170 # These should not log.
171 ERR.warn(m())
172 ERR.info(m())
173 ERR.debug(m())
174
175 INF.debug(m())
176
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000177 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000178 ('ERR', 'CRITICAL', '1'),
179 ('ERR', 'ERROR', '2'),
180 ('INF', 'CRITICAL', '3'),
181 ('INF', 'ERROR', '4'),
182 ('INF', 'WARNING', '5'),
183 ('INF', 'INFO', '6'),
184 ('DEB', 'CRITICAL', '7'),
185 ('DEB', 'ERROR', '8'),
186 ('DEB', 'WARNING', '9'),
187 ('DEB', 'INFO', '10'),
188 ('DEB', 'DEBUG', '11'),
189 ])
190
191 def test_nested_explicit(self):
192 # Logging levels in a nested namespace, all explicitly set.
193 m = self.next_message
194
195 INF = logging.getLogger("INF")
196 INF.setLevel(logging.INFO)
197 INF_ERR = logging.getLogger("INF.ERR")
198 INF_ERR.setLevel(logging.ERROR)
199
200 # These should log.
201 INF_ERR.log(logging.CRITICAL, m())
202 INF_ERR.error(m())
203
204 # These should not log.
205 INF_ERR.warn(m())
206 INF_ERR.info(m())
207 INF_ERR.debug(m())
208
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000209 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000210 ('INF.ERR', 'CRITICAL', '1'),
211 ('INF.ERR', 'ERROR', '2'),
212 ])
213
214 def test_nested_inherited(self):
215 #Logging levels in a nested namespace, inherited from parent loggers.
216 m = self.next_message
217
218 INF = logging.getLogger("INF")
219 INF.setLevel(logging.INFO)
220 INF_ERR = logging.getLogger("INF.ERR")
221 INF_ERR.setLevel(logging.ERROR)
222 INF_UNDEF = logging.getLogger("INF.UNDEF")
223 INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
224 UNDEF = logging.getLogger("UNDEF")
225
226 # These should log.
227 INF_UNDEF.log(logging.CRITICAL, m())
228 INF_UNDEF.error(m())
229 INF_UNDEF.warn(m())
230 INF_UNDEF.info(m())
231 INF_ERR_UNDEF.log(logging.CRITICAL, m())
232 INF_ERR_UNDEF.error(m())
233
234 # These should not log.
235 INF_UNDEF.debug(m())
236 INF_ERR_UNDEF.warn(m())
237 INF_ERR_UNDEF.info(m())
238 INF_ERR_UNDEF.debug(m())
239
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000240 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000241 ('INF.UNDEF', 'CRITICAL', '1'),
242 ('INF.UNDEF', 'ERROR', '2'),
243 ('INF.UNDEF', 'WARNING', '3'),
244 ('INF.UNDEF', 'INFO', '4'),
245 ('INF.ERR.UNDEF', 'CRITICAL', '5'),
246 ('INF.ERR.UNDEF', 'ERROR', '6'),
247 ])
248
249 def test_nested_with_virtual_parent(self):
250 # Logging levels when some parent does not exist yet.
251 m = self.next_message
252
253 INF = logging.getLogger("INF")
254 GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
255 CHILD = logging.getLogger("INF.BADPARENT")
256 INF.setLevel(logging.INFO)
257
258 # These should log.
259 GRANDCHILD.log(logging.FATAL, m())
260 GRANDCHILD.info(m())
261 CHILD.log(logging.FATAL, m())
262 CHILD.info(m())
263
264 # These should not log.
265 GRANDCHILD.debug(m())
266 CHILD.debug(m())
267
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000268 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000269 ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
270 ('INF.BADPARENT.UNDEF', 'INFO', '2'),
271 ('INF.BADPARENT', 'CRITICAL', '3'),
272 ('INF.BADPARENT', 'INFO', '4'),
273 ])
274
Vinay Sajip74ab3442011-11-07 08:49:16 +0000275 def test_invalid_name(self):
Vinay Sajip53703d92011-11-07 10:13:18 +0000276 self.assertRaises(TypeError, logging.getLogger, any)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000277
278class BasicFilterTest(BaseTest):
279
280 """Test the bundled Filter class."""
281
282 def test_filter(self):
283 # Only messages satisfying the specified criteria pass through the
284 # filter.
285 filter_ = logging.Filter("spam.eggs")
286 handler = self.root_logger.handlers[0]
287 try:
288 handler.addFilter(filter_)
289 spam = logging.getLogger("spam")
290 spam_eggs = logging.getLogger("spam.eggs")
291 spam_eggs_fish = logging.getLogger("spam.eggs.fish")
292 spam_bakedbeans = logging.getLogger("spam.bakedbeans")
293
294 spam.info(self.next_message())
295 spam_eggs.info(self.next_message()) # Good.
296 spam_eggs_fish.info(self.next_message()) # Good.
297 spam_bakedbeans.info(self.next_message())
298
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000299 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000300 ('spam.eggs', 'INFO', '2'),
301 ('spam.eggs.fish', 'INFO', '3'),
302 ])
303 finally:
304 handler.removeFilter(filter_)
305
306
307#
308# First, we define our levels. There can be as many as you want - the only
309# limitations are that they should be integers, the lowest should be > 0 and
310# larger values mean less information being logged. If you need specific
311# level values which do not fit into these limitations, you can use a
312# mapping dictionary to convert between your application levels and the
313# logging system.
314#
315SILENT = 120
316TACITURN = 119
317TERSE = 118
318EFFUSIVE = 117
319SOCIABLE = 116
320VERBOSE = 115
321TALKATIVE = 114
322GARRULOUS = 113
323CHATTERBOX = 112
324BORING = 111
325
326LEVEL_RANGE = range(BORING, SILENT + 1)
327
328#
329# Next, we define names for our levels. You don't need to do this - in which
330# case the system will use "Level n" to denote the text for the level.
331#
332my_logging_levels = {
333 SILENT : 'Silent',
334 TACITURN : 'Taciturn',
335 TERSE : 'Terse',
336 EFFUSIVE : 'Effusive',
337 SOCIABLE : 'Sociable',
338 VERBOSE : 'Verbose',
339 TALKATIVE : 'Talkative',
340 GARRULOUS : 'Garrulous',
341 CHATTERBOX : 'Chatterbox',
342 BORING : 'Boring',
343}
344
345class GarrulousFilter(logging.Filter):
346
347 """A filter which blocks garrulous messages."""
348
349 def filter(self, record):
350 return record.levelno != GARRULOUS
351
352class VerySpecificFilter(logging.Filter):
353
354 """A filter which blocks sociable and taciturn messages."""
355
356 def filter(self, record):
357 return record.levelno not in [SOCIABLE, TACITURN]
358
359
360class CustomLevelsAndFiltersTest(BaseTest):
361
362 """Test various filtering possibilities with custom logging levels."""
363
364 # Skip the logger name group.
365 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
366
367 def setUp(self):
368 BaseTest.setUp(self)
369 for k, v in my_logging_levels.items():
370 logging.addLevelName(k, v)
371
372 def log_at_all_levels(self, logger):
373 for lvl in LEVEL_RANGE:
374 logger.log(lvl, self.next_message())
375
376 def test_logger_filter(self):
377 # Filter at logger level.
378 self.root_logger.setLevel(VERBOSE)
379 # Levels >= 'Verbose' are good.
380 self.log_at_all_levels(self.root_logger)
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000381 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000382 ('Verbose', '5'),
383 ('Sociable', '6'),
384 ('Effusive', '7'),
385 ('Terse', '8'),
386 ('Taciturn', '9'),
387 ('Silent', '10'),
388 ])
389
390 def test_handler_filter(self):
391 # Filter at handler level.
392 self.root_logger.handlers[0].setLevel(SOCIABLE)
393 try:
394 # Levels >= 'Sociable' are good.
395 self.log_at_all_levels(self.root_logger)
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000396 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000397 ('Sociable', '6'),
398 ('Effusive', '7'),
399 ('Terse', '8'),
400 ('Taciturn', '9'),
401 ('Silent', '10'),
402 ])
403 finally:
404 self.root_logger.handlers[0].setLevel(logging.NOTSET)
405
406 def test_specific_filters(self):
407 # Set a specific filter object on the handler, and then add another
408 # filter object on the logger itself.
409 handler = self.root_logger.handlers[0]
410 specific_filter = None
411 garr = GarrulousFilter()
412 handler.addFilter(garr)
413 try:
414 self.log_at_all_levels(self.root_logger)
415 first_lines = [
416 # Notice how 'Garrulous' is missing
417 ('Boring', '1'),
418 ('Chatterbox', '2'),
419 ('Talkative', '4'),
420 ('Verbose', '5'),
421 ('Sociable', '6'),
422 ('Effusive', '7'),
423 ('Terse', '8'),
424 ('Taciturn', '9'),
425 ('Silent', '10'),
426 ]
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000427 self.assert_log_lines(first_lines)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000428
429 specific_filter = VerySpecificFilter()
430 self.root_logger.addFilter(specific_filter)
431 self.log_at_all_levels(self.root_logger)
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000432 self.assert_log_lines(first_lines + [
Brett Cannon56c4deb2008-03-03 00:38:58 +0000433 # Not only 'Garrulous' is still missing, but also 'Sociable'
434 # and 'Taciturn'
435 ('Boring', '11'),
436 ('Chatterbox', '12'),
437 ('Talkative', '14'),
438 ('Verbose', '15'),
439 ('Effusive', '17'),
440 ('Terse', '18'),
441 ('Silent', '20'),
442 ])
443 finally:
444 if specific_filter:
445 self.root_logger.removeFilter(specific_filter)
446 handler.removeFilter(garr)
447
448
449class MemoryHandlerTest(BaseTest):
450
451 """Tests for the MemoryHandler."""
452
453 # Do not bother with a logger name group.
454 expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
455
456 def setUp(self):
457 BaseTest.setUp(self)
458 self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
459 self.root_hdlr)
460 self.mem_logger = logging.getLogger('mem')
461 self.mem_logger.propagate = 0
462 self.mem_logger.addHandler(self.mem_hdlr)
463
464 def tearDown(self):
465 self.mem_hdlr.close()
Amaury Forgeot d'Arc2aece572008-03-29 01:42:31 +0000466 BaseTest.tearDown(self)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000467
468 def test_flush(self):
469 # The memory handler flushes to its target handler based on specific
470 # criteria (message count and message level).
471 self.mem_logger.debug(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000472 self.assert_log_lines([])
Brett Cannon56c4deb2008-03-03 00:38:58 +0000473 self.mem_logger.info(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000474 self.assert_log_lines([])
Brett Cannon56c4deb2008-03-03 00:38:58 +0000475 # This will flush because the level is >= logging.WARNING
476 self.mem_logger.warn(self.next_message())
477 lines = [
478 ('DEBUG', '1'),
479 ('INFO', '2'),
480 ('WARNING', '3'),
481 ]
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000482 self.assert_log_lines(lines)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000483 for n in (4, 14):
484 for i in range(9):
485 self.mem_logger.debug(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000486 self.assert_log_lines(lines)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000487 # This will flush because it's the 10th message since the last
488 # flush.
489 self.mem_logger.debug(self.next_message())
490 lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000491 self.assert_log_lines(lines)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000492
493 self.mem_logger.debug(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000494 self.assert_log_lines(lines)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000495
496
497class ExceptionFormatter(logging.Formatter):
498 """A special exception formatter."""
499 def formatException(self, ei):
500 return "Got a [%s]" % ei[0].__name__
501
502
503class ConfigFileTest(BaseTest):
504
505 """Reading logging config from a .ini-style config file."""
506
507 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
508
509 # config0 is a standard configuration.
510 config0 = """
511 [loggers]
512 keys=root
513
514 [handlers]
515 keys=hand1
516
517 [formatters]
518 keys=form1
519
520 [logger_root]
521 level=WARNING
522 handlers=hand1
523
524 [handler_hand1]
525 class=StreamHandler
526 level=NOTSET
527 formatter=form1
528 args=(sys.stdout,)
529
530 [formatter_form1]
531 format=%(levelname)s ++ %(message)s
532 datefmt=
533 """
534
535 # config1 adds a little to the standard configuration.
536 config1 = """
537 [loggers]
538 keys=root,parser
539
540 [handlers]
541 keys=hand1
542
543 [formatters]
544 keys=form1
545
546 [logger_root]
547 level=WARNING
548 handlers=
549
550 [logger_parser]
551 level=DEBUG
552 handlers=hand1
553 propagate=1
554 qualname=compiler.parser
555
556 [handler_hand1]
557 class=StreamHandler
558 level=NOTSET
559 formatter=form1
560 args=(sys.stdout,)
561
562 [formatter_form1]
563 format=%(levelname)s ++ %(message)s
564 datefmt=
565 """
566
Vinay Sajip8dd2a402011-03-07 15:02:11 +0000567 # config1a moves the handler to the root.
568 config1a = """
569 [loggers]
570 keys=root,parser
571
572 [handlers]
573 keys=hand1
574
575 [formatters]
576 keys=form1
577
578 [logger_root]
579 level=WARNING
580 handlers=hand1
581
582 [logger_parser]
583 level=DEBUG
584 handlers=
585 propagate=1
586 qualname=compiler.parser
587
588 [handler_hand1]
589 class=StreamHandler
590 level=NOTSET
591 formatter=form1
592 args=(sys.stdout,)
593
594 [formatter_form1]
595 format=%(levelname)s ++ %(message)s
596 datefmt=
597 """
598
Brett Cannon56c4deb2008-03-03 00:38:58 +0000599 # config2 has a subtle configuration error that should be reported
600 config2 = config1.replace("sys.stdout", "sys.stbout")
601
602 # config3 has a less subtle configuration error
603 config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
604
605 # config4 specifies a custom formatter class to be loaded
606 config4 = """
607 [loggers]
608 keys=root
609
610 [handlers]
611 keys=hand1
612
613 [formatters]
614 keys=form1
615
616 [logger_root]
617 level=NOTSET
618 handlers=hand1
619
620 [handler_hand1]
621 class=StreamHandler
622 level=NOTSET
623 formatter=form1
624 args=(sys.stdout,)
625
626 [formatter_form1]
627 class=""" + __name__ + """.ExceptionFormatter
628 format=%(levelname)s:%(name)s:%(message)s
629 datefmt=
630 """
631
Vinay Sajip70fdc952008-07-18 09:00:00 +0000632 # config5 specifies a custom handler class to be loaded
633 config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
634
Vinay Sajip6a2fd812008-09-03 09:20:05 +0000635 # config6 uses ', ' delimiters in the handlers and formatters sections
636 config6 = """
637 [loggers]
638 keys=root,parser
639
640 [handlers]
641 keys=hand1, hand2
642
643 [formatters]
644 keys=form1, form2
645
646 [logger_root]
647 level=WARNING
648 handlers=
649
650 [logger_parser]
651 level=DEBUG
652 handlers=hand1
653 propagate=1
654 qualname=compiler.parser
655
656 [handler_hand1]
657 class=StreamHandler
658 level=NOTSET
659 formatter=form1
660 args=(sys.stdout,)
661
662 [handler_hand2]
Vinay Sajip844f7412008-09-09 13:42:08 +0000663 class=StreamHandler
Vinay Sajip6a2fd812008-09-03 09:20:05 +0000664 level=NOTSET
665 formatter=form1
Vinay Sajip844f7412008-09-09 13:42:08 +0000666 args=(sys.stderr,)
Vinay Sajip6a2fd812008-09-03 09:20:05 +0000667
668 [formatter_form1]
669 format=%(levelname)s ++ %(message)s
670 datefmt=
671
672 [formatter_form2]
673 format=%(message)s
674 datefmt=
675 """
676
Vinay Sajip8dd2a402011-03-07 15:02:11 +0000677 # config7 adds a compiler logger.
678 config7 = """
679 [loggers]
680 keys=root,parser,compiler
681
682 [handlers]
683 keys=hand1
684
685 [formatters]
686 keys=form1
687
688 [logger_root]
689 level=WARNING
690 handlers=hand1
691
692 [logger_compiler]
693 level=DEBUG
694 handlers=
695 propagate=1
696 qualname=compiler
697
698 [logger_parser]
699 level=DEBUG
700 handlers=
701 propagate=1
702 qualname=compiler.parser
703
704 [handler_hand1]
705 class=StreamHandler
706 level=NOTSET
707 formatter=form1
708 args=(sys.stdout,)
709
710 [formatter_form1]
711 format=%(levelname)s ++ %(message)s
712 datefmt=
713 """
714
Vinay Sajipbb2dad82013-03-23 11:18:10 +0000715 disable_test = """
716 [loggers]
717 keys=root
718
719 [handlers]
720 keys=screen
721
722 [formatters]
723 keys=
724
725 [logger_root]
726 level=DEBUG
727 handlers=screen
728
729 [handler_screen]
730 level=DEBUG
731 class=StreamHandler
732 args=(sys.stdout,)
733 formatter=
734 """
735
736 def apply_config(self, conf, **kwargs):
Vinay Sajip28c382f2010-02-04 18:48:53 +0000737 file = cStringIO.StringIO(textwrap.dedent(conf))
Vinay Sajipbb2dad82013-03-23 11:18:10 +0000738 logging.config.fileConfig(file, **kwargs)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000739
740 def test_config0_ok(self):
741 # A simple config file which overrides the default settings.
742 with captured_stdout() as output:
743 self.apply_config(self.config0)
744 logger = logging.getLogger()
745 # Won't output anything
746 logger.info(self.next_message())
747 # Outputs a message
748 logger.error(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000749 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000750 ('ERROR', '2'),
751 ], stream=output)
752 # Original logger output is empty.
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000753 self.assert_log_lines([])
Brett Cannon56c4deb2008-03-03 00:38:58 +0000754
Vinay Sajip70fdc952008-07-18 09:00:00 +0000755 def test_config1_ok(self, config=config1):
Brett Cannon56c4deb2008-03-03 00:38:58 +0000756 # A config file defining a sub-parser as well.
757 with captured_stdout() as output:
Vinay Sajip70fdc952008-07-18 09:00:00 +0000758 self.apply_config(config)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000759 logger = logging.getLogger("compiler.parser")
760 # Both will output a message
761 logger.info(self.next_message())
762 logger.error(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000763 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +0000764 ('INFO', '1'),
765 ('ERROR', '2'),
766 ], stream=output)
767 # Original logger output is empty.
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000768 self.assert_log_lines([])
Brett Cannon56c4deb2008-03-03 00:38:58 +0000769
770 def test_config2_failure(self):
771 # A simple config file which overrides the default settings.
772 self.assertRaises(StandardError, self.apply_config, self.config2)
773
774 def test_config3_failure(self):
775 # A simple config file which overrides the default settings.
776 self.assertRaises(StandardError, self.apply_config, self.config3)
777
778 def test_config4_ok(self):
779 # A config file specifying a custom formatter class.
780 with captured_stdout() as output:
781 self.apply_config(self.config4)
782 logger = logging.getLogger()
783 try:
784 raise RuntimeError()
785 except RuntimeError:
786 logging.exception("just testing")
787 sys.stdout.seek(0)
Ezio Melotti2623a372010-11-21 13:34:58 +0000788 self.assertEqual(output.getvalue(),
Brett Cannon56c4deb2008-03-03 00:38:58 +0000789 "ERROR:root:just testing\nGot a [RuntimeError]\n")
790 # Original logger output is empty
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000791 self.assert_log_lines([])
Brett Cannon56c4deb2008-03-03 00:38:58 +0000792
Vinay Sajip70fdc952008-07-18 09:00:00 +0000793 def test_config5_ok(self):
794 self.test_config1_ok(config=self.config5)
Brett Cannon56c4deb2008-03-03 00:38:58 +0000795
Vinay Sajip6a2fd812008-09-03 09:20:05 +0000796 def test_config6_ok(self):
797 self.test_config1_ok(config=self.config6)
798
Vinay Sajip8dd2a402011-03-07 15:02:11 +0000799 def test_config7_ok(self):
800 with captured_stdout() as output:
801 self.apply_config(self.config1a)
802 logger = logging.getLogger("compiler.parser")
803 # See issue #11424. compiler-hyphenated sorts
804 # between compiler and compiler.xyz and this
805 # was preventing compiler.xyz from being included
806 # in the child loggers of compiler because of an
807 # overzealous loop termination condition.
808 hyphenated = logging.getLogger('compiler-hyphenated')
809 # All will output a message
810 logger.info(self.next_message())
811 logger.error(self.next_message())
812 hyphenated.critical(self.next_message())
813 self.assert_log_lines([
814 ('INFO', '1'),
815 ('ERROR', '2'),
816 ('CRITICAL', '3'),
817 ], stream=output)
818 # Original logger output is empty.
819 self.assert_log_lines([])
820 with captured_stdout() as output:
821 self.apply_config(self.config7)
822 logger = logging.getLogger("compiler.parser")
823 self.assertFalse(logger.disabled)
824 # Both will output a message
825 logger.info(self.next_message())
826 logger.error(self.next_message())
827 logger = logging.getLogger("compiler.lexer")
828 # Both will output a message
829 logger.info(self.next_message())
830 logger.error(self.next_message())
831 # Will not appear
832 hyphenated.critical(self.next_message())
833 self.assert_log_lines([
834 ('INFO', '4'),
835 ('ERROR', '5'),
836 ('INFO', '6'),
837 ('ERROR', '7'),
838 ], stream=output)
839 # Original logger output is empty.
840 self.assert_log_lines([])
Vinay Sajip923e6d22011-03-07 18:20:27 +0000841
Vinay Sajipbb2dad82013-03-23 11:18:10 +0000842 def test_logger_disabling(self):
843 self.apply_config(self.disable_test)
844 logger = logging.getLogger('foo')
845 self.assertFalse(logger.disabled)
846 self.apply_config(self.disable_test)
847 self.assertTrue(logger.disabled)
848 self.apply_config(self.disable_test, disable_existing_loggers=False)
849 self.assertFalse(logger.disabled)
850
Brett Cannon56c4deb2008-03-03 00:38:58 +0000851class LogRecordStreamHandler(StreamRequestHandler):
852
853 """Handler for a streaming logging request. It saves the log message in the
854 TCP server's 'log_output' attribute."""
855
856 TCP_LOG_END = "!!!END!!!"
857
858 def handle(self):
859 """Handle multiple requests - each expected to be of 4-byte length,
860 followed by the LogRecord in pickle format. Logs the record
861 according to whatever policy is configured locally."""
862 while True:
863 chunk = self.connection.recv(4)
864 if len(chunk) < 4:
865 break
866 slen = struct.unpack(">L", chunk)[0]
867 chunk = self.connection.recv(slen)
868 while len(chunk) < slen:
869 chunk = chunk + self.connection.recv(slen - len(chunk))
870 obj = self.unpickle(chunk)
871 record = logging.makeLogRecord(obj)
872 self.handle_log_record(record)
873
874 def unpickle(self, data):
875 return cPickle.loads(data)
876
877 def handle_log_record(self, record):
878 # If the end-of-messages sentinel is seen, tell the server to
879 # terminate.
880 if self.TCP_LOG_END in record.msg:
881 self.server.abort = 1
882 return
883 self.server.log_output += record.msg + "\n"
884
Guido van Rossum376e6362003-04-25 14:22:00 +0000885
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000886class LogRecordSocketReceiver(ThreadingTCPServer):
Brett Cannon56c4deb2008-03-03 00:38:58 +0000887
888 """A simple-minded TCP socket-based logging receiver suitable for test
889 purposes."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000890
891 allow_reuse_address = 1
Brett Cannon56c4deb2008-03-03 00:38:58 +0000892 log_output = ""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000893
894 def __init__(self, host='localhost',
895 port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
896 handler=LogRecordStreamHandler):
897 ThreadingTCPServer.__init__(self, (host, port), handler)
Georg Brandl57826cf2008-02-23 15:06:25 +0000898 self.abort = False
Brett Cannon56c4deb2008-03-03 00:38:58 +0000899 self.timeout = 0.1
900 self.finished = threading.Event()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000901
902 def serve_until_stopped(self):
Neal Norwitz55cd82f2006-02-05 08:21:08 +0000903 while not self.abort:
Neal Norwitz5bab0f82006-03-05 02:16:12 +0000904 rd, wr, ex = select.select([self.socket.fileno()], [], [],
905 self.timeout)
906 if rd:
907 self.handle_request()
Brett Cannon56c4deb2008-03-03 00:38:58 +0000908 # Notify the main thread that we're about to exit
909 self.finished.set()
Martin v. Löwisf6848882006-01-29 19:55:18 +0000910 # close the listen socket
911 self.server_close()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000912
Guido van Rossum2a1d5162003-01-21 21:05:22 +0000913
Victor Stinner6a102812010-04-27 23:55:59 +0000914@unittest.skipUnless(threading, 'Threading required for this test.')
Brett Cannon56c4deb2008-03-03 00:38:58 +0000915class SocketHandlerTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000916
Brett Cannon56c4deb2008-03-03 00:38:58 +0000917 """Test for SocketHandler objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000918
Brett Cannon56c4deb2008-03-03 00:38:58 +0000919 def setUp(self):
920 """Set up a TCP server to receive log messages, and a SocketHandler
921 pointing to that server's address and port."""
922 BaseTest.setUp(self)
923 self.tcpserver = LogRecordSocketReceiver(port=0)
924 self.port = self.tcpserver.socket.getsockname()[1]
925 self.threads = [
926 threading.Thread(target=self.tcpserver.serve_until_stopped)]
927 for thread in self.threads:
928 thread.start()
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000929
Brett Cannon56c4deb2008-03-03 00:38:58 +0000930 self.sock_hdlr = logging.handlers.SocketHandler('localhost', self.port)
931 self.sock_hdlr.setFormatter(self.root_formatter)
932 self.root_logger.removeHandler(self.root_logger.handlers[0])
933 self.root_logger.addHandler(self.sock_hdlr)
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000934
Brett Cannon56c4deb2008-03-03 00:38:58 +0000935 def tearDown(self):
936 """Shutdown the TCP server."""
937 try:
938 self.tcpserver.abort = True
939 del self.tcpserver
940 self.root_logger.removeHandler(self.sock_hdlr)
941 self.sock_hdlr.close()
942 for thread in self.threads:
943 thread.join(2.0)
944 finally:
945 BaseTest.tearDown(self)
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000946
Brett Cannon56c4deb2008-03-03 00:38:58 +0000947 def get_output(self):
948 """Get the log output as received by the TCP server."""
949 # Signal the TCP receiver and wait for it to terminate.
950 self.root_logger.critical(LogRecordStreamHandler.TCP_LOG_END)
951 self.tcpserver.finished.wait(2.0)
952 return self.tcpserver.log_output
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000953
Brett Cannon56c4deb2008-03-03 00:38:58 +0000954 def test_output(self):
955 # The log message sent to the SocketHandler is properly received.
956 logger = logging.getLogger("tcp")
957 logger.error("spam")
958 logger.debug("eggs")
Ezio Melotti2623a372010-11-21 13:34:58 +0000959 self.assertEqual(self.get_output(), "spam\neggs\n")
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000960
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000961
Brett Cannon56c4deb2008-03-03 00:38:58 +0000962class MemoryTest(BaseTest):
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000963
Brett Cannon56c4deb2008-03-03 00:38:58 +0000964 """Test memory persistence of logger objects."""
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000965
Brett Cannon56c4deb2008-03-03 00:38:58 +0000966 def setUp(self):
967 """Create a dict to remember potentially destroyed objects."""
968 BaseTest.setUp(self)
969 self._survivors = {}
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000970
Brett Cannon56c4deb2008-03-03 00:38:58 +0000971 def _watch_for_survival(self, *args):
972 """Watch the given objects for survival, by creating weakrefs to
973 them."""
974 for obj in args:
975 key = id(obj), repr(obj)
976 self._survivors[key] = weakref.ref(obj)
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000977
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000978 def _assertTruesurvival(self):
Brett Cannon56c4deb2008-03-03 00:38:58 +0000979 """Assert that all objects watched for survival have survived."""
980 # Trigger cycle breaking.
981 gc.collect()
982 dead = []
983 for (id_, repr_), ref in self._survivors.items():
984 if ref() is None:
985 dead.append(repr_)
986 if dead:
987 self.fail("%d objects should have survived "
988 "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
Neal Norwitzb4a2df02003-01-02 14:56:39 +0000989
Brett Cannon56c4deb2008-03-03 00:38:58 +0000990 def test_persistent_loggers(self):
991 # Logger objects are persistent and retain their configuration, even
992 # if visible references are destroyed.
993 self.root_logger.setLevel(logging.INFO)
994 foo = logging.getLogger("foo")
995 self._watch_for_survival(foo)
996 foo.setLevel(logging.DEBUG)
997 self.root_logger.debug(self.next_message())
998 foo.debug(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +0000999 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +00001000 ('foo', 'DEBUG', '2'),
1001 ])
1002 del foo
1003 # foo has survived.
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001004 self._assertTruesurvival()
Brett Cannon56c4deb2008-03-03 00:38:58 +00001005 # foo has retained its settings.
1006 bar = logging.getLogger("foo")
1007 bar.debug(self.next_message())
Benjamin Peterson4d3f18f2009-07-01 00:36:41 +00001008 self.assert_log_lines([
Brett Cannon56c4deb2008-03-03 00:38:58 +00001009 ('foo', 'DEBUG', '2'),
1010 ('foo', 'DEBUG', '3'),
1011 ])
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001012
Vinay Sajipb20af942009-02-08 19:06:08 +00001013
Vinay Sajip65d66e12008-09-04 07:31:21 +00001014class EncodingTest(BaseTest):
1015 def test_encoding_plain_file(self):
1016 # In Python 2.x, a plain file object is treated as having no encoding.
1017 log = logging.getLogger("test")
1018 fn = tempfile.mktemp(".log")
1019 # the non-ascii data we write to the log.
1020 data = "foo\x80"
1021 try:
1022 handler = logging.FileHandler(fn)
1023 log.addHandler(handler)
1024 try:
1025 # write non-ascii data to the log.
1026 log.warning(data)
1027 finally:
1028 log.removeHandler(handler)
1029 handler.close()
1030 # check we wrote exactly those bytes, ignoring trailing \n etc
1031 f = open(fn)
1032 try:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001033 self.assertEqual(f.read().rstrip(), data)
Vinay Sajip65d66e12008-09-04 07:31:21 +00001034 finally:
1035 f.close()
1036 finally:
1037 if os.path.isfile(fn):
1038 os.remove(fn)
Neal Norwitzb4a2df02003-01-02 14:56:39 +00001039
Vinay Sajipb20af942009-02-08 19:06:08 +00001040 def test_encoding_cyrillic_unicode(self):
1041 log = logging.getLogger("test")
1042 #Get a message in Unicode: Do svidanya in Cyrillic (meaning goodbye)
1043 message = u'\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
1044 #Ensure it's written in a Cyrillic encoding
1045 writer_class = codecs.getwriter('cp1251')
Vinay Sajip74f04502009-04-16 19:07:37 +00001046 writer_class.encoding = 'cp1251'
Vinay Sajipb20af942009-02-08 19:06:08 +00001047 stream = cStringIO.StringIO()
1048 writer = writer_class(stream, 'strict')
1049 handler = logging.StreamHandler(writer)
1050 log.addHandler(handler)
1051 try:
1052 log.warning(message)
1053 finally:
1054 log.removeHandler(handler)
1055 handler.close()
1056 # check we wrote exactly those bytes, ignoring trailing \n etc
1057 s = stream.getvalue()
1058 #Compare against what the data should be when encoded in CP-1251
1059 self.assertEqual(s, '\xe4\xee \xf1\xe2\xe8\xe4\xe0\xed\xe8\xff\n')
1060
Victor Stinnera5cd2552013-10-15 23:36:56 +02001061 def test_encoding_utf16_unicode(self):
1062 # Issue #19267
1063 log = logging.getLogger("test")
1064 message = u'b\u0142\u0105d'
1065 writer_class = codecs.getwriter('utf-16-le')
1066 writer_class.encoding = 'utf-16-le'
1067 stream = cStringIO.StringIO()
1068 writer = writer_class(stream, 'strict')
1069 handler = logging.StreamHandler(writer)
1070 log.addHandler(handler)
1071 try:
1072 log.warning(message)
1073 finally:
1074 log.removeHandler(handler)
1075 handler.close()
1076 s = stream.getvalue()
1077 self.assertEqual(s, 'b\x00B\x01\x05\x01d\x00\n\x00')
1078
Vinay Sajipb20af942009-02-08 19:06:08 +00001079
Vinay Sajip213faca2008-12-03 23:22:58 +00001080class WarningsTest(BaseTest):
Brett Cannon2da4d622009-04-01 19:57:10 +00001081
Vinay Sajip213faca2008-12-03 23:22:58 +00001082 def test_warnings(self):
Brett Cannon2da4d622009-04-01 19:57:10 +00001083 with warnings.catch_warnings():
Vinay Sajip1e566ce2009-04-05 11:06:24 +00001084 logging.captureWarnings(True)
Brett Cannon2da4d622009-04-01 19:57:10 +00001085 try:
Vinay Sajip14bf0a02009-04-07 17:18:24 +00001086 warnings.filterwarnings("always", category=UserWarning)
Brett Cannon2da4d622009-04-01 19:57:10 +00001087 file = cStringIO.StringIO()
1088 h = logging.StreamHandler(file)
1089 logger = logging.getLogger("py.warnings")
1090 logger.addHandler(h)
1091 warnings.warn("I'm warning you...")
1092 logger.removeHandler(h)
1093 s = file.getvalue()
1094 h.close()
1095 self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
Vinay Sajip213faca2008-12-03 23:22:58 +00001096
Brett Cannon2da4d622009-04-01 19:57:10 +00001097 #See if an explicit file uses the original implementation
1098 file = cStringIO.StringIO()
1099 warnings.showwarning("Explicit", UserWarning, "dummy.py", 42,
1100 file, "Dummy line")
1101 s = file.getvalue()
1102 file.close()
1103 self.assertEqual(s,
1104 "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
1105 finally:
1106 logging.captureWarnings(False)
Vinay Sajip213faca2008-12-03 23:22:58 +00001107
Vinay Sajip28c382f2010-02-04 18:48:53 +00001108
1109def formatFunc(format, datefmt=None):
1110 return logging.Formatter(format, datefmt)
1111
1112def handlerFunc():
1113 return logging.StreamHandler()
1114
1115class CustomHandler(logging.StreamHandler):
1116 pass
1117
1118class ConfigDictTest(BaseTest):
1119
1120 """Reading logging config from a dictionary."""
1121
1122 expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
1123
1124 # config0 is a standard configuration.
1125 config0 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001126 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001127 'formatters': {
1128 'form1' : {
1129 'format' : '%(levelname)s ++ %(message)s',
1130 },
1131 },
1132 'handlers' : {
1133 'hand1' : {
1134 'class' : 'logging.StreamHandler',
1135 'formatter' : 'form1',
1136 'level' : 'NOTSET',
1137 'stream' : 'ext://sys.stdout',
1138 },
1139 },
1140 'root' : {
1141 'level' : 'WARNING',
1142 'handlers' : ['hand1'],
1143 },
1144 }
1145
1146 # config1 adds a little to the standard configuration.
1147 config1 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001148 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001149 'formatters': {
1150 'form1' : {
1151 'format' : '%(levelname)s ++ %(message)s',
1152 },
1153 },
1154 'handlers' : {
1155 'hand1' : {
1156 'class' : 'logging.StreamHandler',
1157 'formatter' : 'form1',
1158 'level' : 'NOTSET',
1159 'stream' : 'ext://sys.stdout',
1160 },
1161 },
1162 'loggers' : {
1163 'compiler.parser' : {
1164 'level' : 'DEBUG',
1165 'handlers' : ['hand1'],
1166 },
1167 },
1168 'root' : {
1169 'level' : 'WARNING',
1170 },
1171 }
1172
1173 # config2 has a subtle configuration error that should be reported
1174 config2 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001175 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001176 'formatters': {
1177 'form1' : {
1178 'format' : '%(levelname)s ++ %(message)s',
1179 },
1180 },
1181 'handlers' : {
1182 'hand1' : {
1183 'class' : 'logging.StreamHandler',
1184 'formatter' : 'form1',
1185 'level' : 'NOTSET',
1186 'stream' : 'ext://sys.stdbout',
1187 },
1188 },
1189 'loggers' : {
1190 'compiler.parser' : {
1191 'level' : 'DEBUG',
1192 'handlers' : ['hand1'],
1193 },
1194 },
1195 'root' : {
1196 'level' : 'WARNING',
1197 },
1198 }
1199
1200 #As config1 but with a misspelt level on a handler
1201 config2a = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001202 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001203 'formatters': {
1204 'form1' : {
1205 'format' : '%(levelname)s ++ %(message)s',
1206 },
1207 },
1208 'handlers' : {
1209 'hand1' : {
1210 'class' : 'logging.StreamHandler',
1211 'formatter' : 'form1',
1212 'level' : 'NTOSET',
1213 'stream' : 'ext://sys.stdout',
1214 },
1215 },
1216 'loggers' : {
1217 'compiler.parser' : {
1218 'level' : 'DEBUG',
1219 'handlers' : ['hand1'],
1220 },
1221 },
1222 'root' : {
1223 'level' : 'WARNING',
1224 },
1225 }
1226
1227
1228 #As config1 but with a misspelt level on a logger
1229 config2b = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001230 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001231 'formatters': {
1232 'form1' : {
1233 'format' : '%(levelname)s ++ %(message)s',
1234 },
1235 },
1236 'handlers' : {
1237 'hand1' : {
1238 'class' : 'logging.StreamHandler',
1239 'formatter' : 'form1',
1240 'level' : 'NOTSET',
1241 'stream' : 'ext://sys.stdout',
1242 },
1243 },
1244 'loggers' : {
1245 'compiler.parser' : {
1246 'level' : 'DEBUG',
1247 'handlers' : ['hand1'],
1248 },
1249 },
1250 'root' : {
1251 'level' : 'WRANING',
1252 },
1253 }
1254
1255 # config3 has a less subtle configuration error
1256 config3 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001257 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001258 'formatters': {
1259 'form1' : {
1260 'format' : '%(levelname)s ++ %(message)s',
1261 },
1262 },
1263 'handlers' : {
1264 'hand1' : {
1265 'class' : 'logging.StreamHandler',
1266 'formatter' : 'misspelled_name',
1267 'level' : 'NOTSET',
1268 'stream' : 'ext://sys.stdout',
1269 },
1270 },
1271 'loggers' : {
1272 'compiler.parser' : {
1273 'level' : 'DEBUG',
1274 'handlers' : ['hand1'],
1275 },
1276 },
1277 'root' : {
1278 'level' : 'WARNING',
1279 },
1280 }
1281
1282 # config4 specifies a custom formatter class to be loaded
1283 config4 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001284 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001285 'formatters': {
1286 'form1' : {
1287 '()' : __name__ + '.ExceptionFormatter',
1288 'format' : '%(levelname)s:%(name)s:%(message)s',
1289 },
1290 },
1291 'handlers' : {
1292 'hand1' : {
1293 'class' : 'logging.StreamHandler',
1294 'formatter' : 'form1',
1295 'level' : 'NOTSET',
1296 'stream' : 'ext://sys.stdout',
1297 },
1298 },
1299 'root' : {
1300 'level' : 'NOTSET',
1301 'handlers' : ['hand1'],
1302 },
1303 }
1304
1305 # As config4 but using an actual callable rather than a string
1306 config4a = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001307 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001308 'formatters': {
1309 'form1' : {
1310 '()' : ExceptionFormatter,
1311 'format' : '%(levelname)s:%(name)s:%(message)s',
1312 },
1313 'form2' : {
1314 '()' : __name__ + '.formatFunc',
1315 'format' : '%(levelname)s:%(name)s:%(message)s',
1316 },
1317 'form3' : {
1318 '()' : formatFunc,
1319 'format' : '%(levelname)s:%(name)s:%(message)s',
1320 },
1321 },
1322 'handlers' : {
1323 'hand1' : {
1324 'class' : 'logging.StreamHandler',
1325 'formatter' : 'form1',
1326 'level' : 'NOTSET',
1327 'stream' : 'ext://sys.stdout',
1328 },
1329 'hand2' : {
1330 '()' : handlerFunc,
1331 },
1332 },
1333 'root' : {
1334 'level' : 'NOTSET',
1335 'handlers' : ['hand1'],
1336 },
1337 }
1338
1339 # config5 specifies a custom handler class to be loaded
1340 config5 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001341 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001342 'formatters': {
1343 'form1' : {
1344 'format' : '%(levelname)s ++ %(message)s',
1345 },
1346 },
1347 'handlers' : {
1348 'hand1' : {
1349 'class' : __name__ + '.CustomHandler',
1350 'formatter' : 'form1',
1351 'level' : 'NOTSET',
1352 'stream' : 'ext://sys.stdout',
1353 },
1354 },
1355 'loggers' : {
1356 'compiler.parser' : {
1357 'level' : 'DEBUG',
1358 'handlers' : ['hand1'],
1359 },
1360 },
1361 'root' : {
1362 'level' : 'WARNING',
1363 },
1364 }
1365
1366 # config6 specifies a custom handler class to be loaded
1367 # but has bad arguments
1368 config6 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001369 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001370 'formatters': {
1371 'form1' : {
1372 'format' : '%(levelname)s ++ %(message)s',
1373 },
1374 },
1375 'handlers' : {
1376 'hand1' : {
1377 'class' : __name__ + '.CustomHandler',
1378 'formatter' : 'form1',
1379 'level' : 'NOTSET',
1380 'stream' : 'ext://sys.stdout',
1381 '9' : 'invalid parameter name',
1382 },
1383 },
1384 'loggers' : {
1385 'compiler.parser' : {
1386 'level' : 'DEBUG',
1387 'handlers' : ['hand1'],
1388 },
1389 },
1390 'root' : {
1391 'level' : 'WARNING',
1392 },
1393 }
1394
1395 #config 7 does not define compiler.parser but defines compiler.lexer
1396 #so compiler.parser should be disabled after applying it
1397 config7 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001398 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001399 'formatters': {
1400 'form1' : {
1401 'format' : '%(levelname)s ++ %(message)s',
1402 },
1403 },
1404 'handlers' : {
1405 'hand1' : {
1406 'class' : 'logging.StreamHandler',
1407 'formatter' : 'form1',
1408 'level' : 'NOTSET',
1409 'stream' : 'ext://sys.stdout',
1410 },
1411 },
1412 'loggers' : {
1413 'compiler.lexer' : {
1414 'level' : 'DEBUG',
1415 'handlers' : ['hand1'],
1416 },
1417 },
1418 'root' : {
1419 'level' : 'WARNING',
1420 },
1421 }
1422
1423 config8 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001424 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001425 'disable_existing_loggers' : False,
1426 'formatters': {
1427 'form1' : {
1428 'format' : '%(levelname)s ++ %(message)s',
1429 },
1430 },
1431 'handlers' : {
1432 'hand1' : {
1433 'class' : 'logging.StreamHandler',
1434 'formatter' : 'form1',
1435 'level' : 'NOTSET',
1436 'stream' : 'ext://sys.stdout',
1437 },
1438 },
1439 'loggers' : {
1440 'compiler' : {
1441 'level' : 'DEBUG',
1442 'handlers' : ['hand1'],
1443 },
1444 'compiler.lexer' : {
1445 },
1446 },
1447 'root' : {
1448 'level' : 'WARNING',
1449 },
1450 }
1451
1452 config9 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001453 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001454 'formatters': {
1455 'form1' : {
1456 'format' : '%(levelname)s ++ %(message)s',
1457 },
1458 },
1459 'handlers' : {
1460 'hand1' : {
1461 'class' : 'logging.StreamHandler',
1462 'formatter' : 'form1',
1463 'level' : 'WARNING',
1464 'stream' : 'ext://sys.stdout',
1465 },
1466 },
1467 'loggers' : {
1468 'compiler.parser' : {
1469 'level' : 'WARNING',
1470 'handlers' : ['hand1'],
1471 },
1472 },
1473 'root' : {
1474 'level' : 'NOTSET',
1475 },
1476 }
1477
1478 config9a = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001479 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001480 'incremental' : True,
1481 'handlers' : {
1482 'hand1' : {
1483 'level' : 'WARNING',
1484 },
1485 },
1486 'loggers' : {
1487 'compiler.parser' : {
1488 'level' : 'INFO',
1489 },
1490 },
1491 }
1492
1493 config9b = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001494 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001495 'incremental' : True,
1496 'handlers' : {
1497 'hand1' : {
1498 'level' : 'INFO',
1499 },
1500 },
1501 'loggers' : {
1502 'compiler.parser' : {
1503 'level' : 'INFO',
1504 },
1505 },
1506 }
1507
1508 #As config1 but with a filter added
1509 config10 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001510 'version': 1,
Vinay Sajip28c382f2010-02-04 18:48:53 +00001511 'formatters': {
1512 'form1' : {
1513 'format' : '%(levelname)s ++ %(message)s',
1514 },
1515 },
1516 'filters' : {
1517 'filt1' : {
1518 'name' : 'compiler.parser',
1519 },
1520 },
1521 'handlers' : {
1522 'hand1' : {
1523 'class' : 'logging.StreamHandler',
1524 'formatter' : 'form1',
1525 'level' : 'NOTSET',
1526 'stream' : 'ext://sys.stdout',
1527 'filters' : ['filt1'],
1528 },
1529 },
1530 'loggers' : {
1531 'compiler.parser' : {
1532 'level' : 'DEBUG',
1533 'filters' : ['filt1'],
1534 },
1535 },
1536 'root' : {
1537 'level' : 'WARNING',
1538 'handlers' : ['hand1'],
1539 },
1540 }
1541
Vinay Sajipf7610b22010-02-04 21:40:56 +00001542 #As config1 but using cfg:// references
1543 config11 = {
Vinay Sajipd45a2782010-03-06 15:12:08 +00001544 'version': 1,
1545 'true_formatters': {
1546 'form1' : {
1547 'format' : '%(levelname)s ++ %(message)s',
1548 },
1549 },
1550 'handler_configs': {
1551 'hand1' : {
1552 'class' : 'logging.StreamHandler',
1553 'formatter' : 'form1',
1554 'level' : 'NOTSET',
1555 'stream' : 'ext://sys.stdout',
1556 },
1557 },
1558 'formatters' : 'cfg://true_formatters',
1559 'handlers' : {
1560 'hand1' : 'cfg://handler_configs[hand1]',
1561 },
1562 'loggers' : {
1563 'compiler.parser' : {
1564 'level' : 'DEBUG',
1565 'handlers' : ['hand1'],
1566 },
1567 },
1568 'root' : {
1569 'level' : 'WARNING',
1570 },
1571 }
1572
1573 #As config11 but missing the version key
1574 config12 = {
1575 'true_formatters': {
1576 'form1' : {
1577 'format' : '%(levelname)s ++ %(message)s',
1578 },
1579 },
1580 'handler_configs': {
1581 'hand1' : {
1582 'class' : 'logging.StreamHandler',
1583 'formatter' : 'form1',
1584 'level' : 'NOTSET',
1585 'stream' : 'ext://sys.stdout',
1586 },
1587 },
1588 'formatters' : 'cfg://true_formatters',
1589 'handlers' : {
1590 'hand1' : 'cfg://handler_configs[hand1]',
1591 },
1592 'loggers' : {
1593 'compiler.parser' : {
1594 'level' : 'DEBUG',
1595 'handlers' : ['hand1'],
1596 },
1597 },
1598 'root' : {
1599 'level' : 'WARNING',
1600 },
1601 }
1602
1603 #As config11 but using an unsupported version
1604 config13 = {
1605 'version': 2,
Vinay Sajipf7610b22010-02-04 21:40:56 +00001606 'true_formatters': {
1607 'form1' : {
1608 'format' : '%(levelname)s ++ %(message)s',
1609 },
1610 },
1611 'handler_configs': {
1612 'hand1' : {
1613 'class' : 'logging.StreamHandler',
1614 'formatter' : 'form1',
1615 'level' : 'NOTSET',
1616 'stream' : 'ext://sys.stdout',
1617 },
1618 },
1619 'formatters' : 'cfg://true_formatters',
1620 'handlers' : {
1621 'hand1' : 'cfg://handler_configs[hand1]',
1622 },
1623 'loggers' : {
1624 'compiler.parser' : {
1625 'level' : 'DEBUG',
1626 'handlers' : ['hand1'],
1627 },
1628 },
1629 'root' : {
1630 'level' : 'WARNING',
1631 },
1632 }
1633
Vinay Sajip8651a512013-03-22 15:19:24 +00001634 out_of_order = {
1635 "version": 1,
1636 "formatters": {
1637 "mySimpleFormatter": {
1638 "format": "%(asctime)s (%(name)s) %(levelname)s: %(message)s"
1639 }
1640 },
1641 "handlers": {
1642 "fileGlobal": {
1643 "class": "logging.StreamHandler",
1644 "level": "DEBUG",
1645 "formatter": "mySimpleFormatter"
1646 },
1647 "bufferGlobal": {
1648 "class": "logging.handlers.MemoryHandler",
1649 "capacity": 5,
1650 "formatter": "mySimpleFormatter",
1651 "target": "fileGlobal",
1652 "level": "DEBUG"
1653 }
1654 },
1655 "loggers": {
1656 "mymodule": {
1657 "level": "DEBUG",
1658 "handlers": ["bufferGlobal"],
1659 "propagate": "true"
1660 }
1661 }
1662 }
1663
Vinay Sajip28c382f2010-02-04 18:48:53 +00001664 def apply_config(self, conf):
1665 logging.config.dictConfig(conf)
1666
1667 def test_config0_ok(self):
1668 # A simple config which overrides the default settings.
1669 with captured_stdout() as output:
1670 self.apply_config(self.config0)
1671 logger = logging.getLogger()
1672 # Won't output anything
1673 logger.info(self.next_message())
1674 # Outputs a message
1675 logger.error(self.next_message())
1676 self.assert_log_lines([
1677 ('ERROR', '2'),
1678 ], stream=output)
1679 # Original logger output is empty.
1680 self.assert_log_lines([])
1681
1682 def test_config1_ok(self, config=config1):
1683 # A config defining a sub-parser as well.
1684 with captured_stdout() as output:
1685 self.apply_config(config)
1686 logger = logging.getLogger("compiler.parser")
1687 # Both will output a message
1688 logger.info(self.next_message())
1689 logger.error(self.next_message())
1690 self.assert_log_lines([
1691 ('INFO', '1'),
1692 ('ERROR', '2'),
1693 ], stream=output)
1694 # Original logger output is empty.
1695 self.assert_log_lines([])
1696
1697 def test_config2_failure(self):
1698 # A simple config which overrides the default settings.
1699 self.assertRaises(StandardError, self.apply_config, self.config2)
1700
1701 def test_config2a_failure(self):
1702 # A simple config which overrides the default settings.
1703 self.assertRaises(StandardError, self.apply_config, self.config2a)
1704
1705 def test_config2b_failure(self):
1706 # A simple config which overrides the default settings.
1707 self.assertRaises(StandardError, self.apply_config, self.config2b)
1708
1709 def test_config3_failure(self):
1710 # A simple config which overrides the default settings.
1711 self.assertRaises(StandardError, self.apply_config, self.config3)
1712
1713 def test_config4_ok(self):
1714 # A config specifying a custom formatter class.
1715 with captured_stdout() as output:
1716 self.apply_config(self.config4)
1717 #logger = logging.getLogger()
1718 try:
1719 raise RuntimeError()
1720 except RuntimeError:
1721 logging.exception("just testing")
1722 sys.stdout.seek(0)
Ezio Melotti2623a372010-11-21 13:34:58 +00001723 self.assertEqual(output.getvalue(),
Vinay Sajip28c382f2010-02-04 18:48:53 +00001724 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1725 # Original logger output is empty
1726 self.assert_log_lines([])
1727
1728 def test_config4a_ok(self):
1729 # A config specifying a custom formatter class.
1730 with captured_stdout() as output:
1731 self.apply_config(self.config4a)
1732 #logger = logging.getLogger()
1733 try:
1734 raise RuntimeError()
1735 except RuntimeError:
1736 logging.exception("just testing")
1737 sys.stdout.seek(0)
Ezio Melotti2623a372010-11-21 13:34:58 +00001738 self.assertEqual(output.getvalue(),
Vinay Sajip28c382f2010-02-04 18:48:53 +00001739 "ERROR:root:just testing\nGot a [RuntimeError]\n")
1740 # Original logger output is empty
1741 self.assert_log_lines([])
1742
1743 def test_config5_ok(self):
1744 self.test_config1_ok(config=self.config5)
1745
1746 def test_config6_failure(self):
1747 self.assertRaises(StandardError, self.apply_config, self.config6)
1748
1749 def test_config7_ok(self):
1750 with captured_stdout() as output:
1751 self.apply_config(self.config1)
1752 logger = logging.getLogger("compiler.parser")
1753 # Both will output a message
1754 logger.info(self.next_message())
1755 logger.error(self.next_message())
1756 self.assert_log_lines([
1757 ('INFO', '1'),
1758 ('ERROR', '2'),
1759 ], stream=output)
1760 # Original logger output is empty.
1761 self.assert_log_lines([])
1762 with captured_stdout() as output:
1763 self.apply_config(self.config7)
1764 logger = logging.getLogger("compiler.parser")
1765 self.assertTrue(logger.disabled)
1766 logger = logging.getLogger("compiler.lexer")
1767 # Both will output a message
1768 logger.info(self.next_message())
1769 logger.error(self.next_message())
1770 self.assert_log_lines([
1771 ('INFO', '3'),
1772 ('ERROR', '4'),
1773 ], stream=output)
1774 # Original logger output is empty.
1775 self.assert_log_lines([])
1776
1777 #Same as test_config_7_ok but don't disable old loggers.
1778 def test_config_8_ok(self):
1779 with captured_stdout() as output:
1780 self.apply_config(self.config1)
1781 logger = logging.getLogger("compiler.parser")
1782 # Both will output a message
1783 logger.info(self.next_message())
1784 logger.error(self.next_message())
1785 self.assert_log_lines([
1786 ('INFO', '1'),
1787 ('ERROR', '2'),
1788 ], stream=output)
1789 # Original logger output is empty.
1790 self.assert_log_lines([])
1791 with captured_stdout() as output:
1792 self.apply_config(self.config8)
1793 logger = logging.getLogger("compiler.parser")
1794 self.assertFalse(logger.disabled)
1795 # Both will output a message
1796 logger.info(self.next_message())
1797 logger.error(self.next_message())
1798 logger = logging.getLogger("compiler.lexer")
1799 # Both will output a message
1800 logger.info(self.next_message())
1801 logger.error(self.next_message())
1802 self.assert_log_lines([
1803 ('INFO', '3'),
1804 ('ERROR', '4'),
1805 ('INFO', '5'),
1806 ('ERROR', '6'),
1807 ], stream=output)
1808 # Original logger output is empty.
1809 self.assert_log_lines([])
1810
1811 def test_config_9_ok(self):
1812 with captured_stdout() as output:
1813 self.apply_config(self.config9)
1814 logger = logging.getLogger("compiler.parser")
1815 #Nothing will be output since both handler and logger are set to WARNING
1816 logger.info(self.next_message())
1817 self.assert_log_lines([], stream=output)
1818 self.apply_config(self.config9a)
1819 #Nothing will be output since both handler is still set to WARNING
1820 logger.info(self.next_message())
1821 self.assert_log_lines([], stream=output)
1822 self.apply_config(self.config9b)
1823 #Message should now be output
1824 logger.info(self.next_message())
1825 self.assert_log_lines([
1826 ('INFO', '3'),
1827 ], stream=output)
1828
1829 def test_config_10_ok(self):
1830 with captured_stdout() as output:
1831 self.apply_config(self.config10)
1832 logger = logging.getLogger("compiler.parser")
1833 logger.warning(self.next_message())
1834 logger = logging.getLogger('compiler')
1835 #Not output, because filtered
1836 logger.warning(self.next_message())
1837 logger = logging.getLogger('compiler.lexer')
1838 #Not output, because filtered
1839 logger.warning(self.next_message())
1840 logger = logging.getLogger("compiler.parser.codegen")
1841 #Output, as not filtered
1842 logger.error(self.next_message())
1843 self.assert_log_lines([
1844 ('WARNING', '1'),
1845 ('ERROR', '4'),
1846 ], stream=output)
1847
Vinay Sajipf7610b22010-02-04 21:40:56 +00001848 def test_config11_ok(self):
1849 self.test_config1_ok(self.config11)
1850
Vinay Sajipd45a2782010-03-06 15:12:08 +00001851 def test_config12_failure(self):
1852 self.assertRaises(StandardError, self.apply_config, self.config12)
1853
1854 def test_config13_failure(self):
1855 self.assertRaises(StandardError, self.apply_config, self.config13)
1856
Victor Stinner6a102812010-04-27 23:55:59 +00001857 @unittest.skipUnless(threading, 'listen() needs threading to work')
Vinay Sajip28c382f2010-02-04 18:48:53 +00001858 def setup_via_listener(self, text):
Vinay Sajip27a13702010-05-03 15:11:53 +00001859 # Ask for a randomly assigned port (by using port 0)
1860 t = logging.config.listen(0)
Vinay Sajip28c382f2010-02-04 18:48:53 +00001861 t.start()
Benjamin Peterson239f1382010-02-06 22:08:15 +00001862 t.ready.wait()
Vinay Sajip27a13702010-05-03 15:11:53 +00001863 # Now get the port allocated
1864 port = t.port
Vinay Sajip9a164ac2010-02-08 16:05:50 +00001865 t.ready.clear()
Vinay Sajip3dd734f2010-02-05 14:52:05 +00001866 try:
1867 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Vinay Sajip23739262010-02-05 23:43:11 +00001868 sock.settimeout(2.0)
Vinay Sajip3dd734f2010-02-05 14:52:05 +00001869 sock.connect(('localhost', port))
Vinay Sajip28c382f2010-02-04 18:48:53 +00001870
Vinay Sajip3dd734f2010-02-05 14:52:05 +00001871 slen = struct.pack('>L', len(text))
1872 s = slen + text
1873 sentsofar = 0
1874 left = len(s)
1875 while left > 0:
1876 sent = sock.send(s[sentsofar:])
1877 sentsofar += sent
1878 left -= sent
1879 sock.close()
1880 finally:
Vinay Sajip9a164ac2010-02-08 16:05:50 +00001881 t.ready.wait(2.0)
Vinay Sajip3dd734f2010-02-05 14:52:05 +00001882 logging.config.stopListening()
Vinay Sajip23739262010-02-05 23:43:11 +00001883 t.join(2.0)
Vinay Sajip28c382f2010-02-04 18:48:53 +00001884
Vinay Sajip23739262010-02-05 23:43:11 +00001885 def test_listen_config_10_ok(self):
Vinay Sajip28c382f2010-02-04 18:48:53 +00001886 with captured_stdout() as output:
1887 self.setup_via_listener(json.dumps(self.config10))
1888 logger = logging.getLogger("compiler.parser")
1889 logger.warning(self.next_message())
1890 logger = logging.getLogger('compiler')
1891 #Not output, because filtered
1892 logger.warning(self.next_message())
1893 logger = logging.getLogger('compiler.lexer')
1894 #Not output, because filtered
1895 logger.warning(self.next_message())
1896 logger = logging.getLogger("compiler.parser.codegen")
1897 #Output, as not filtered
1898 logger.error(self.next_message())
1899 self.assert_log_lines([
1900 ('WARNING', '1'),
1901 ('ERROR', '4'),
1902 ], stream=output)
1903
Vinay Sajip23739262010-02-05 23:43:11 +00001904 def test_listen_config_1_ok(self):
Vinay Sajip28c382f2010-02-04 18:48:53 +00001905 with captured_stdout() as output:
1906 self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1))
1907 logger = logging.getLogger("compiler.parser")
1908 # Both will output a message
1909 logger.info(self.next_message())
1910 logger.error(self.next_message())
1911 self.assert_log_lines([
1912 ('INFO', '1'),
1913 ('ERROR', '2'),
1914 ], stream=output)
1915 # Original logger output is empty.
1916 self.assert_log_lines([])
1917
Vinay Sajip8651a512013-03-22 15:19:24 +00001918 def test_out_of_order(self):
1919 self.apply_config(self.out_of_order)
1920 handler = logging.getLogger('mymodule').handlers[0]
1921 self.assertIsInstance(handler.target, logging.Handler)
Vinay Sajip28c382f2010-02-04 18:48:53 +00001922
Vinay Sajip657514a2010-02-07 01:37:08 +00001923class ManagerTest(BaseTest):
1924 def test_manager_loggerclass(self):
1925 logged = []
1926
1927 class MyLogger(logging.Logger):
1928 def _log(self, level, msg, args, exc_info=None, extra=None):
1929 logged.append(msg)
1930
1931 man = logging.Manager(None)
1932 self.assertRaises(TypeError, man.setLoggerClass, int)
1933 man.setLoggerClass(MyLogger)
1934 logger = man.getLogger('test')
Vinay Sajip657514a2010-02-07 01:37:08 +00001935 logger.warning('should appear in logged')
1936 logging.warning('should not appear in logged')
1937
1938 self.assertEqual(logged, ['should appear in logged'])
1939
1940
Vinay Sajip804899b2010-03-22 15:29:01 +00001941class ChildLoggerTest(BaseTest):
1942 def test_child_loggers(self):
1943 r = logging.getLogger()
1944 l1 = logging.getLogger('abc')
1945 l2 = logging.getLogger('def.ghi')
1946 c1 = r.getChild('xyz')
1947 c2 = r.getChild('uvw.xyz')
1948 self.assertTrue(c1 is logging.getLogger('xyz'))
1949 self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
1950 c1 = l1.getChild('def')
1951 c2 = c1.getChild('ghi')
1952 c3 = l1.getChild('def.ghi')
1953 self.assertTrue(c1 is logging.getLogger('abc.def'))
1954 self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
1955 self.assertTrue(c2 is c3)
1956
1957
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001958class HandlerTest(BaseTest):
1959
Vinay Sajipc3ea4082012-05-31 12:35:13 +01001960 @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001961 @unittest.skipUnless(threading, 'Threading required for this test.')
1962 def test_race(self):
1963 # Issue #14632 refers.
1964 def remove_loop(fname, tries):
1965 for _ in range(tries):
1966 try:
1967 os.unlink(fname)
1968 except OSError:
1969 pass
1970 time.sleep(0.004 * random.randint(0, 4))
1971
Vinay Sajip00086bb2012-04-25 10:45:27 +01001972 del_count = 500
1973 log_count = 500
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001974
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001975 for delay in (False, True):
Vinay Sajip00086bb2012-04-25 10:45:27 +01001976 fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
1977 os.close(fd)
1978 remover = threading.Thread(target=remove_loop, args=(fn, del_count))
1979 remover.daemon = True
1980 remover.start()
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001981 h = logging.handlers.WatchedFileHandler(fn, delay=delay)
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001982 f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
1983 h.setFormatter(f)
Vinay Sajip00086bb2012-04-25 10:45:27 +01001984 try:
1985 for _ in range(log_count):
1986 time.sleep(0.005)
1987 r = logging.makeLogRecord({'msg': 'testing' })
1988 h.handle(r)
1989 finally:
Vinay Sajip00086bb2012-04-25 10:45:27 +01001990 remover.join()
Vinay Sajip7b577502012-05-19 16:50:07 +01001991 try:
1992 h.close()
1993 except ValueError:
1994 pass
Vinay Sajip00086bb2012-04-25 10:45:27 +01001995 if os.path.exists(fn):
1996 os.unlink(fn)
Vinay Sajip885f6fd2012-04-24 23:15:10 +01001997
1998
Brett Cannon56c4deb2008-03-03 00:38:58 +00001999# Set the locale to the platform-dependent default. I have no idea
2000# why the test does this, but in any case we save the current locale
2001# first and restore it at the end.
2002@run_with_locale('LC_ALL', '')
Tim Peters36f7e932003-07-23 00:05:07 +00002003def test_main():
Brett Cannon56c4deb2008-03-03 00:38:58 +00002004 run_unittest(BuiltinLevelsTest, BasicFilterTest,
Vinay Sajip657514a2010-02-07 01:37:08 +00002005 CustomLevelsAndFiltersTest, MemoryHandlerTest,
2006 ConfigFileTest, SocketHandlerTest, MemoryTest,
Vinay Sajip804899b2010-03-22 15:29:01 +00002007 EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
Vinay Sajip885f6fd2012-04-24 23:15:10 +01002008 ChildLoggerTest, HandlerTest)
Jeremy Hylton096d9862003-07-18 03:19:20 +00002009
Brett Cannon56c4deb2008-03-03 00:38:58 +00002010if __name__ == "__main__":
Neal Norwitzb4a2df02003-01-02 14:56:39 +00002011 test_main()