Skip to content

Commit 087570a

Browse files
tirkarthivsajip
authored andcommitted
bpo-33978: Close existing handlers before logging (re-)configuration. (GH-8008)
1 parent c6cd164 commit 087570a

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
@@ -73,8 +73,8 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True):
7373
# critical section
7474
logging._acquireLock()
7575
try:
76-
logging._handlers.clear()
77-
del logging._handlerList[:]
76+
_clearExistingHandlers()
77+
7878
# Handlers add themselves to logging._handlers
7979
handlers = _install_handlers(cp, formatters)
8080
_install_loggers(cp, handlers, disable_existing_loggers)
@@ -265,6 +265,14 @@ def _install_loggers(cp, handlers, disable_existing):
265265
# logger.disabled = 1
266266
_handle_existing_loggers(existing, child_loggers, disable_existing)
267267

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

270278

@@ -524,8 +532,7 @@ def configure(self):
524532
else:
525533
disable_existing = config.pop('disable_existing_loggers', True)
526534

527-
logging._handlers.clear()
528-
del logging._handlerList[:]
535+
_clearExistingHandlers()
529536

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

Lib/test/test_logging.py

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

10901090
"""Reading logging config from a .ini-style config file."""
10911091

1092+
check_no_resource_warning = support.check_no_resource_warning
10921093
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
10931094

10941095
# config0 is a standard configuration.
@@ -1297,6 +1298,27 @@ class ConfigFileTest(BaseTest):
12971298
datefmt=
12981299
"""
12991300

1301+
# config 8, check for resource warning
1302+
config8 = r"""
1303+
[loggers]
1304+
keys=root
1305+
1306+
[handlers]
1307+
keys=file
1308+
1309+
[formatters]
1310+
keys=
1311+
1312+
[logger_root]
1313+
level=DEBUG
1314+
handlers=file
1315+
1316+
[handler_file]
1317+
class=FileHandler
1318+
level=DEBUG
1319+
args=("{tempfile}",)
1320+
"""
1321+
13001322
disable_test = """
13011323
[loggers]
13021324
keys=root
@@ -1442,6 +1464,29 @@ def test_config7_ok(self):
14421464
# Original logger output is empty.
14431465
self.assert_log_lines([])
14441466

1467+
def test_config8_ok(self):
1468+
1469+
def cleanup(h1, fn):
1470+
h1.close()
1471+
os.remove(fn)
1472+
1473+
with self.check_no_resource_warning():
1474+
fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
1475+
os.close(fd)
1476+
1477+
# Replace single backslash with double backslash in windows
1478+
# to avoid unicode error during string formatting
1479+
if os.name == "nt":
1480+
fn = fn.replace("\\", "\\\\")
1481+
1482+
config8 = self.config8.format(tempfile=fn)
1483+
1484+
self.apply_config(config8)
1485+
self.apply_config(config8)
1486+
1487+
handler = logging.root.handlers[0]
1488+
self.addCleanup(cleanup, handler, fn)
1489+
14451490
def test_logger_disabling(self):
14461491
self.apply_config(self.disable_test)
14471492
logger = logging.getLogger('some_pristine_logger')
@@ -2022,6 +2067,7 @@ class ConfigDictTest(BaseTest):
20222067

20232068
"""Reading logging config from a dictionary."""
20242069

2070+
check_no_resource_warning = support.check_no_resource_warning
20252071
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
20262072

20272073
# config0 is a standard configuration.
@@ -2896,6 +2942,35 @@ def test_config14_ok(self):
28962942
logging.warning('Exclamation')
28972943
self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
28982944

2945+
def test_config15_ok(self):
2946+
2947+
def cleanup(h1, fn):
2948+
h1.close()
2949+
os.remove(fn)
2950+
2951+
with self.check_no_resource_warning():
2952+
fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
2953+
os.close(fd)
2954+
2955+
config = {
2956+
"version": 1,
2957+
"handlers": {
2958+
"file": {
2959+
"class": "logging.FileHandler",
2960+
"filename": fn
2961+
}
2962+
},
2963+
"root": {
2964+
"handlers": ["file"]
2965+
}
2966+
}
2967+
2968+
self.apply_config(config)
2969+
self.apply_config(config)
2970+
2971+
handler = logging.root.handlers[0]
2972+
self.addCleanup(cleanup, handler, fn)
2973+
28992974
def setup_via_listener(self, text, verify=None):
29002975
text = text.encode("utf-8")
29012976
# Ask for a randomly assigned port (by using port 0)
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)