-
-
Notifications
You must be signed in to change notification settings - Fork 31k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
logging.config.dictConfig shuts down socket for existing SysLogHandlers #87362
Comments
Since b6c1989 dictConfig (and presumably fileConfig) has called logging.shutdown() on the existing handlers. This causes existing SysLogHandlers' sockets to be closed, which then causes a BadFileDescriptor error when you try to use it: --- Logging error --- Traceback (most recent call last):
File "/usr/lib/python3.8/logging/handlers.py", line 940, in emit
self.socket.sendto(msg, self.address)
OSError: [Errno 9] Bad file descriptor
Call stack:
File "/home/flyte/workspaces/python/test.py", line 18, in <module>
log.warning("Breaks") Reproduce the error with the following code: import logging.config
import socket
from logging.handlers import SysLogHandler
log = logging.getLogger("logtest")
syslog_handler = SysLogHandler(("127.0.0.1", 12345), socktype=socket.SOCK_DGRAM)
log.addHandler(syslog_handler)
log.warning("Works")
logging.config.dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
}
)
log.warning("Breaks") This causes issues such as benoitc/gunicorn#2073 where gunicorn sets up a SysLogHandler, then when any app (Django does it by default) calls dictConfig() it closes the socket used by gunicorn's SysLogHandler. Assuming this also affects Python 3.9 and 3.10, but untested. |
I'm not getting this error on 3.11 on a Mac. Can you check on versions <= 3.9? Earlier versions are no longer getting bugfixes. |
I can reproduce the error on Debian/testing with:
|
Out of curiosity, what is messy about backporting this? In figuring out that this was the problem, I touched If anyone else ran into this issue, can't upgrade to 3.11 right away, and needs a workaround, I had success with copy/pasting the code out of the PR into a class definition that subclasses class FixedSysLogHandler(SysLogHandler):
...
def emit(self, record):
if not self.socket:
self.createSocket()
super().emit(record) The methods |
Hey @MajorDallas can you please explain your solution for Python 3.8 version. I have situation where I can't upgrade to Python 3.11. Question: Thank you! |
I did not modify Instead, in a utilities module in my app, I subclassed YMMV. This worked with the # Assume this file is 'app/utils/logging.py'
from logging.handlers import SysLogHandler as OgSysLogHandler
class SysLogHandler(OgSysLogHandler):
def __init__(
self,
address=("localhost", 514),
facility=OgSysLogHandler.LOG_USER,
socktype=None,
):
logging.Handler.__init__(self)
self.address = address
self.facility = facility
self.socktype = socktype
self.socket = None
self.createSocket()
def close(self):
self.acquire()
try:
sock = self.socket
if sock:
self.socket = None
sock.close()
logging.Handler.close(self)
finally:
self.release()
def createSocket(self):
address = self.address
socktype = self.socktype
if isinstance(address, str):
self.unixsocket = True
# Syslog server may be unavailable during handler initialisation.
# C's openlog() function also ignores connection errors.
# Moreover, we ignore these errors while logging, so it not worse
# to ignore it also here.
try:
self._connect_unixsocket(address)
except OSError:
pass
else:
self.unixsocket = False
if socktype is None:
socktype = socket.SOCK_DGRAM
host, port = address
ress = socket.getaddrinfo(host, port, 0, socktype)
if not ress:
raise OSError("getaddrinfo returns an empty list")
for res in ress:
af, socktype, proto, _, sa = res
err = sock = None
try:
sock = socket.socket(af, socktype, proto)
if socktype == socket.SOCK_STREAM:
sock.connect(sa)
break
except OSError as exc:
err = exc
if sock is not None:
sock.close()
if err is not None:
raise err
self.socket = sock
self.socktype = socktype
def emit(self, record):
if not self.socket:
self.createSocket()
super().emit(record) Then, anywhere in your app where you currently have |
Thank you! @MajorDallas |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: