summaryrefslogtreecommitdiffstats
path: root/Lib/logging
diff options
context:
space:
mode:
authorDale Collison <92315623+dcollison@users.noreply.github.com>2023-09-27 16:26:41 (GMT)
committerGitHub <noreply@github.com>2023-09-27 16:26:41 (GMT)
commit74723e11109a320e628898817ab449b3dad9ee96 (patch)
tree4d50d43744e116f339b4fd752f8928d022feca23 /Lib/logging
parentcc54bcf17b5b5f7681f52baf3acef75b995fa1fd (diff)
downloadcpython-74723e11109a320e628898817ab449b3dad9ee96.zip
cpython-74723e11109a320e628898817ab449b3dad9ee96.tar.gz
cpython-74723e11109a320e628898817ab449b3dad9ee96.tar.bz2
gh-109461: Update logging module lock to use context manager (#109462)
Co-authored-by: Victor Stinner <vstinner@python.org>
Diffstat (limited to 'Lib/logging')
-rw-r--r--Lib/logging/__init__.py136
-rw-r--r--Lib/logging/config.py30
-rw-r--r--Lib/logging/handlers.py30
3 files changed, 60 insertions, 136 deletions
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 2d228e5..eb7e020 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -159,12 +159,9 @@ def addLevelName(level, levelName):
This is used when converting levels to text during message formatting.
"""
- _acquireLock()
- try: #unlikely to cause an exception, but you never know...
+ with _lock:
_levelToName[level] = levelName
_nameToLevel[levelName] = level
- finally:
- _releaseLock()
if hasattr(sys, "_getframe"):
currentframe = lambda: sys._getframe(1)
@@ -231,25 +228,27 @@ def _checkLevel(level):
#
_lock = threading.RLock()
-def _acquireLock():
+def _prepareFork():
"""
- Acquire the module-level lock for serializing access to shared data.
+ Prepare to fork a new child process by acquiring the module-level lock.
- This should be released with _releaseLock().
+ This should be used in conjunction with _afterFork().
"""
- if _lock:
- try:
- _lock.acquire()
- except BaseException:
- _lock.release()
- raise
+ # Wrap the lock acquisition in a try-except to prevent the lock from being
+ # abandoned in the event of an asynchronous exception. See gh-106238.
+ try:
+ _lock.acquire()
+ except BaseException:
+ _lock.release()
+ raise
-def _releaseLock():
+def _afterFork():
"""
- Release the module-level lock acquired by calling _acquireLock().
+ After a new child process has been forked, release the module-level lock.
+
+ This should be used in conjunction with _prepareFork().
"""
- if _lock:
- _lock.release()
+ _lock.release()
# Prevent a held logging lock from blocking a child from logging.
@@ -264,23 +263,20 @@ else:
_at_fork_reinit_lock_weakset = weakref.WeakSet()
def _register_at_fork_reinit_lock(instance):
- _acquireLock()
- try:
+ with _lock:
_at_fork_reinit_lock_weakset.add(instance)
- finally:
- _releaseLock()
def _after_at_fork_child_reinit_locks():
for handler in _at_fork_reinit_lock_weakset:
handler._at_fork_reinit()
- # _acquireLock() was called in the parent before forking.
+ # _prepareFork() was called in the parent before forking.
# The lock is reinitialized to unlocked state.
_lock._at_fork_reinit()
- os.register_at_fork(before=_acquireLock,
+ os.register_at_fork(before=_prepareFork,
after_in_child=_after_at_fork_child_reinit_locks,
- after_in_parent=_releaseLock)
+ after_in_parent=_afterFork)
#---------------------------------------------------------------------------
@@ -883,25 +879,20 @@ def _removeHandlerRef(wr):
# set to None. It can also be called from another thread. So we need to
# pre-emptively grab the necessary globals and check if they're None,
# to prevent race conditions and failures during interpreter shutdown.
- acquire, release, handlers = _acquireLock, _releaseLock, _handlerList
- if acquire and release and handlers:
- acquire()
- try:
- handlers.remove(wr)
- except ValueError:
- pass
- finally:
- release()
+ handlers, lock = _handlerList, _lock
+ if lock and handlers:
+ with lock:
+ try:
+ handlers.remove(wr)
+ except ValueError:
+ pass
def _addHandlerRef(handler):
"""
Add a handler to the internal cleanup list using a weak reference.
"""
- _acquireLock()
- try:
+ with _lock:
_handlerList.append(weakref.ref(handler, _removeHandlerRef))
- finally:
- _releaseLock()
def getHandlerByName(name):
@@ -946,15 +937,12 @@ class Handler(Filterer):
return self._name
def set_name(self, name):
- _acquireLock()
- try:
+ with _lock:
if self._name in _handlers:
del _handlers[self._name]
self._name = name
if name:
_handlers[name] = self
- finally:
- _releaseLock()
name = property(get_name, set_name)
@@ -1026,11 +1014,8 @@ class Handler(Filterer):
if isinstance(rv, LogRecord):
record = rv
if rv:
- self.acquire()
- try:
+ with self.lock:
self.emit(record)
- finally:
- self.release()
return rv
def setFormatter(self, fmt):
@@ -1058,13 +1043,10 @@ class Handler(Filterer):
methods.
"""
#get the module data lock, as we're updating a shared structure.
- _acquireLock()
- try: #unlikely to raise an exception, but you never know...
+ with _lock:
self._closed = True
if self._name and self._name in _handlers:
del _handlers[self._name]
- finally:
- _releaseLock()
def handleError(self, record):
"""
@@ -1141,12 +1123,9 @@ class StreamHandler(Handler):
"""
Flushes the stream.
"""
- self.acquire()
- try:
+ with self.lock:
if self.stream and hasattr(self.stream, "flush"):
self.stream.flush()
- finally:
- self.release()
def emit(self, record):
"""
@@ -1182,12 +1161,9 @@ class StreamHandler(Handler):
result = None
else:
result = self.stream
- self.acquire()
- try:
+ with self.lock:
self.flush()
self.stream = stream
- finally:
- self.release()
return result
def __repr__(self):
@@ -1237,8 +1213,7 @@ class FileHandler(StreamHandler):
"""
Closes the stream.
"""
- self.acquire()
- try:
+ with self.lock:
try:
if self.stream:
try:
@@ -1254,8 +1229,6 @@ class FileHandler(StreamHandler):
# Also see Issue #42378: we also rely on
# self._closed being set to True there
StreamHandler.close(self)
- finally:
- self.release()
def _open(self):
"""
@@ -1391,8 +1364,7 @@ class Manager(object):
rv = None
if not isinstance(name, str):
raise TypeError('A logger name must be a string')
- _acquireLock()
- try:
+ with _lock:
if name in self.loggerDict:
rv = self.loggerDict[name]
if isinstance(rv, PlaceHolder):
@@ -1407,8 +1379,6 @@ class Manager(object):
rv.manager = self
self.loggerDict[name] = rv
self._fixupParents(rv)
- finally:
- _releaseLock()
return rv
def setLoggerClass(self, klass):
@@ -1471,12 +1441,11 @@ class Manager(object):
Called when level changes are made
"""
- _acquireLock()
- for logger in self.loggerDict.values():
- if isinstance(logger, Logger):
- logger._cache.clear()
- self.root._cache.clear()
- _releaseLock()
+ with _lock:
+ for logger in self.loggerDict.values():
+ if isinstance(logger, Logger):
+ logger._cache.clear()
+ self.root._cache.clear()
#---------------------------------------------------------------------------
# Logger classes and functions
@@ -1701,23 +1670,17 @@ class Logger(Filterer):
"""
Add the specified handler to this logger.
"""
- _acquireLock()
- try:
+ with _lock:
if not (hdlr in self.handlers):
self.handlers.append(hdlr)
- finally:
- _releaseLock()
def removeHandler(self, hdlr):
"""
Remove the specified handler from this logger.
"""
- _acquireLock()
- try:
+ with _lock:
if hdlr in self.handlers:
self.handlers.remove(hdlr)
- finally:
- _releaseLock()
def hasHandlers(self):
"""
@@ -1795,16 +1758,13 @@ class Logger(Filterer):
try:
return self._cache[level]
except KeyError:
- _acquireLock()
- try:
+ with _lock:
if self.manager.disable >= level:
is_enabled = self._cache[level] = False
else:
is_enabled = self._cache[level] = (
level >= self.getEffectiveLevel()
)
- finally:
- _releaseLock()
return is_enabled
def getChild(self, suffix):
@@ -1834,16 +1794,13 @@ class Logger(Filterer):
return 1 + logger.name.count('.')
d = self.manager.loggerDict
- _acquireLock()
- try:
+ with _lock:
# exclude PlaceHolders - the last check is to ensure that lower-level
# descendants aren't returned - if there are placeholders, a logger's
# parent field might point to a grandparent or ancestor thereof.
return set(item for item in d.values()
if isinstance(item, Logger) and item.parent is self and
_hierlevel(item) == 1 + _hierlevel(item.parent))
- finally:
- _releaseLock()
def __repr__(self):
level = getLevelName(self.getEffectiveLevel())
@@ -2102,8 +2059,7 @@ def basicConfig(**kwargs):
"""
# Add thread safety in case someone mistakenly calls
# basicConfig() from multiple threads
- _acquireLock()
- try:
+ with _lock:
force = kwargs.pop('force', False)
encoding = kwargs.pop('encoding', None)
errors = kwargs.pop('errors', 'backslashreplace')
@@ -2152,8 +2108,6 @@ def basicConfig(**kwargs):
if kwargs:
keys = ', '.join(kwargs.keys())
raise ValueError('Unrecognised argument(s): %s' % keys)
- finally:
- _releaseLock()
#---------------------------------------------------------------------------
# Utility functions at module level.
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 41283f4..951bba7 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -83,15 +83,12 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non
formatters = _create_formatters(cp)
# critical section
- logging._acquireLock()
- try:
+ with logging._lock:
_clearExistingHandlers()
# Handlers add themselves to logging._handlers
handlers = _install_handlers(cp, formatters)
_install_loggers(cp, handlers, disable_existing_loggers)
- finally:
- logging._releaseLock()
def _resolve(name):
@@ -516,8 +513,7 @@ class DictConfigurator(BaseConfigurator):
raise ValueError("Unsupported version: %s" % config['version'])
incremental = config.pop('incremental', False)
EMPTY_DICT = {}
- logging._acquireLock()
- try:
+ with logging._lock:
if incremental:
handlers = config.get('handlers', EMPTY_DICT)
for name in handlers:
@@ -661,8 +657,6 @@ class DictConfigurator(BaseConfigurator):
except Exception as e:
raise ValueError('Unable to configure root '
'logger') from e
- finally:
- logging._releaseLock()
def configure_formatter(self, config):
"""Configure a formatter from a dictionary."""
@@ -988,9 +982,8 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None):
def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
handler=None, ready=None, verify=None):
ThreadingTCPServer.__init__(self, (host, port), handler)
- logging._acquireLock()
- self.abort = 0
- logging._releaseLock()
+ with logging._lock:
+ self.abort = 0
self.timeout = 1
self.ready = ready
self.verify = verify
@@ -1004,9 +997,8 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None):
self.timeout)
if rd:
self.handle_request()
- logging._acquireLock()
- abort = self.abort
- logging._releaseLock()
+ with logging._lock:
+ abort = self.abort
self.server_close()
class Server(threading.Thread):
@@ -1027,9 +1019,8 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None):
self.port = server.server_address[1]
self.ready.set()
global _listener
- logging._acquireLock()
- _listener = server
- logging._releaseLock()
+ with logging._lock:
+ _listener = server
server.serve_until_stopped()
return Server(ConfigSocketReceiver, ConfigStreamHandler, port, verify)
@@ -1039,10 +1030,7 @@ def stopListening():
Stop the listening server which was created with a call to listen().
"""
global _listener
- logging._acquireLock()
- try:
+ with logging._lock:
if _listener:
_listener.abort = 1
_listener = None
- finally:
- logging._releaseLock()
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 671cc95..e75da9b 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -683,15 +683,12 @@ class SocketHandler(logging.Handler):
"""
Closes the socket.
"""
- self.acquire()
- try:
+ with self.lock:
sock = self.sock
if sock:
self.sock = None
sock.close()
logging.Handler.close(self)
- finally:
- self.release()
class DatagramHandler(SocketHandler):
"""
@@ -953,15 +950,12 @@ class SysLogHandler(logging.Handler):
"""
Closes the socket.
"""
- self.acquire()
- try:
+ with self.lock:
sock = self.socket
if sock:
self.socket = None
sock.close()
logging.Handler.close(self)
- finally:
- self.release()
def mapPriority(self, levelName):
"""
@@ -1333,11 +1327,8 @@ class BufferingHandler(logging.Handler):
This version just zaps the buffer to empty.
"""
- self.acquire()
- try:
+ with self.lock:
self.buffer.clear()
- finally:
- self.release()
def close(self):
"""
@@ -1387,11 +1378,8 @@ class MemoryHandler(BufferingHandler):
"""
Set the target handler for this handler.
"""
- self.acquire()
- try:
+ with self.lock:
self.target = target
- finally:
- self.release()
def flush(self):
"""
@@ -1401,14 +1389,11 @@ class MemoryHandler(BufferingHandler):
The record buffer is only cleared if a target has been set.
"""
- self.acquire()
- try:
+ with self.lock:
if self.target:
for record in self.buffer:
self.target.handle(record)
self.buffer.clear()
- finally:
- self.release()
def close(self):
"""
@@ -1419,12 +1404,9 @@ class MemoryHandler(BufferingHandler):
if self.flushOnClose:
self.flush()
finally:
- self.acquire()
- try:
+ with self.lock:
self.target = None
BufferingHandler.close(self)
- finally:
- self.release()
class QueueHandler(logging.Handler):