Skip to content

Commit b6c1989

Browse files
tirkarthivsajip
authored andcommitted
[3.6] bpo-33978: Close existing handlers before logging (re-)configuration. (GH-8008). (GH-8045)
(cherry picked from commit 087570a) Co-authored-by: Xtreak <tirkarthi@users.noreply.github.com>
1 parent b1707ab commit b6c1989

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

Lib/logging/config.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True):
7878
# critical section
7979
logging._acquireLock()
8080
try:
81-
logging._handlers.clear()
82-
del logging._handlerList[:]
81+
_clearExistingHandlers()
82+
8383
# Handlers add themselves to logging._handlers
8484
handlers = _install_handlers(cp, formatters)
8585
_install_loggers(cp, handlers, disable_existing_loggers)
@@ -268,6 +268,14 @@ def _install_loggers(cp, handlers, disable_existing):
268268
# logger.disabled = 1
269269
_handle_existing_loggers(existing, child_loggers, disable_existing)
270270

271+
272+
def _clearExistingHandlers():
273+
"""Clear and close existing handlers"""
274+
logging._handlers.clear()
275+
logging.shutdown(logging._handlerList[:])
276+
del logging._handlerList[:]
277+
278+
271279
IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
272280

273281

@@ -527,8 +535,7 @@ def configure(self):
527535
else:
528536
disable_existing = config.pop('disable_existing_loggers', True)
529537

530-
logging._handlers.clear()
531-
del logging._handlerList[:]
538+
_clearExistingHandlers()
532539

533540
# Do formatters first - they don't refer to anything else
534541
formatters = config.get('formatters', EMPTY_DICT)

Lib/test/test_logging.py

+75
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,7 @@ class ConfigFileTest(BaseTest):
10761076

10771077
"""Reading logging config from a .ini-style config file."""
10781078

1079+
check_no_resource_warning = support.check_no_resource_warning
10791080
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
10801081

10811082
# config0 is a standard configuration.
@@ -1284,6 +1285,27 @@ class ConfigFileTest(BaseTest):
12841285
datefmt=
12851286
"""
12861287

1288+
# config 8, check for resource warning
1289+
config8 = r"""
1290+
[loggers]
1291+
keys=root
1292+
1293+
[handlers]
1294+
keys=file
1295+
1296+
[formatters]
1297+
keys=
1298+
1299+
[logger_root]
1300+
level=DEBUG
1301+
handlers=file
1302+
1303+
[handler_file]
1304+
class=FileHandler
1305+
level=DEBUG
1306+
args=("{tempfile}",)
1307+
"""
1308+
12871309
disable_test = """
12881310
[loggers]
12891311
keys=root
@@ -1429,6 +1451,29 @@ def test_config7_ok(self):
14291451
# Original logger output is empty.
14301452
self.assert_log_lines([])
14311453

1454+
def test_config8_ok(self):
1455+
1456+
def cleanup(h1, fn):
1457+
h1.close()
1458+
os.remove(fn)
1459+
1460+
with self.check_no_resource_warning():
1461+
fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1462+
os.close(fd)
1463+
1464+
# Replace single backslash with double backslash in windows
1465+
# to avoid unicode error during string formatting
1466+
if os.name == "nt":
1467+
fn = fn.replace("\\", "\\\\")
1468+
1469+
config8 = self.config8.format(tempfile=fn)
1470+
1471+
self.apply_config(config8)
1472+
self.apply_config(config8)
1473+
1474+
handler = logging.root.handlers[0]
1475+
self.addCleanup(cleanup, handler, fn)
1476+
14321477
def test_logger_disabling(self):
14331478
self.apply_config(self.disable_test)
14341479
logger = logging.getLogger('some_pristine_logger')
@@ -1977,6 +2022,7 @@ class ConfigDictTest(BaseTest):
19772022

19782023
"""Reading logging config from a dictionary."""
19792024

2025+
check_no_resource_warning = support.check_no_resource_warning
19802026
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
19812027

19822028
# config0 is a standard configuration.
@@ -2851,6 +2897,35 @@ def test_config14_ok(self):
28512897
logging.warning('Exclamation')
28522898
self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
28532899

2900+
def test_config15_ok(self):
2901+
2902+
def cleanup(h1, fn):
2903+
h1.close()
2904+
os.remove(fn)
2905+
2906+
with self.check_no_resource_warning():
2907+
fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
2908+
os.close(fd)
2909+
2910+
config = {
2911+
"version": 1,
2912+
"handlers": {
2913+
"file": {
2914+
"class": "logging.FileHandler",
2915+
"filename": fn
2916+
}
2917+
},
2918+
"root": {
2919+
"handlers": ["file"]
2920+
}
2921+
}
2922+
2923+
self.apply_config(config)
2924+
self.apply_config(config)
2925+
2926+
handler = logging.root.handlers[0]
2927+
self.addCleanup(cleanup, handler, fn)
2928+
28542929
@unittest.skipUnless(threading, 'listen() needs threading to work')
28552930
def setup_via_listener(self, text, verify=None):
28562931
text = text.encode("utf-8")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Closed existing logging handlers before reconfiguration via fileConfig
2+
and dictConfig. Patch by Karthikeyan Singaravelan.

0 commit comments

Comments
 (0)