You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
logging.config.dictConfig shuts down socket for existing SysLogHandlers #87362
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.
This was I believe fixed for 3.11 and later in the fix for #88457 by #26490, but I'm not sure it's worth backporting the whole thing to 3.10 (it seemed messy to do it at the time).
Out of curiosity, what is messy about backporting this?
In figuring out that this was the problem, I touched logging.py quite a bit. I don't see any reason why the changes in #26490 couldn't be backported, at least not at the code level... Naturally, my perspective here is limited to my one application and not the entire CPython codebase and its millions of dependent projects, so if that's where the mess is then I understand. Again, just curious 😄
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 SysLogHandler with one small modification and it works fine so far. The only change in my subclass from what's in the PR is to the emit method:
The methods createSocket, close, and __init__ are verbatim copies of the PR and everything else is inherited from SysLogHandler. This has at least allowed it to work in iPython (which uses dictConfig and kills the socket on start-up) with 3.8.
can you please explain your solution for Python 3.8 version. I have situation where I can't upgrade to Python 3.11.
Question:
(1) Do I need to copy FixedSysLogHandler and place it to logging.py only?
(2) If possible, can you share entire logging.py file to understand properly ?
I did not modify logging.py (other than for print-debugging while tracking down the problem).
Instead, in a utilities module in my app, I subclassed SysLogHandler and used that subclass as a drop-in replacement. As I said above, most of it is copied (almost) verbatim from Pull Request #26490, specifically the methods named above from the original SysLogHandler class definition that starts at handlers.py:709 in the PR.
YMMV. This worked with the SysLogHandler as defined for Python 3.8; it may or may not work with other versions in the same way and I can't offer any support for it if it doesn't work for you.
# Assume this file is 'app/utils/logging.py'fromlogging.handlersimportSysLogHandlerasOgSysLogHandlerclassSysLogHandler(OgSysLogHandler):
def__init__(
self,
address=("localhost", 514),
facility=OgSysLogHandler.LOG_USER,
socktype=None,
):
logging.Handler.__init__(self)
self.address=addressself.facility=facilityself.socktype=socktypeself.socket=Noneself.createSocket()
defclose(self):
self.acquire()
try:
sock=self.socketifsock:
self.socket=Nonesock.close()
logging.Handler.close(self)
finally:
self.release()
defcreateSocket(self):
address=self.addresssocktype=self.socktypeifisinstance(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)
exceptOSError:
passelse:
self.unixsocket=FalseifsocktypeisNone:
socktype=socket.SOCK_DGRAMhost, port=addressress=socket.getaddrinfo(host, port, 0, socktype)
ifnotress:
raiseOSError("getaddrinfo returns an empty list")
forresinress:
af, socktype, proto, _, sa=reserr=sock=Nonetry:
sock=socket.socket(af, socktype, proto)
ifsocktype==socket.SOCK_STREAM:
sock.connect(sa)
breakexceptOSErrorasexc:
err=excifsockisnotNone:
sock.close()
iferrisnotNone:
raiseerrself.socket=sockself.socktype=socktypedefemit(self, record):
ifnotself.socket:
self.createSocket()
super().emit(record)
Then, anywhere in your app where you currently have from logging.handlers import SysLogHandler, just change that to from app.utils.logging import SysLogHandler (or whatever you make the module path on your machine). You shouldn't have to change any other code that's already trying to use SysLogHandler.
Activity
flyte commentedon Feb 10, 2021
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 ---
Reproduce the error with the following code:
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.
iritkatriel commentedon Jan 17, 2022
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.
sblondon commentedon Jan 22, 2022
I can reproduce the error on Debian/testing with:
vsajip commentedon Aug 26, 2022
This was I believe fixed for 3.11 and later in the fix for #88457 by #26490, but I'm not sure it's worth backporting the whole thing to 3.10 (it seemed messy to do it at the time).
MajorDallas commentedon Sep 27, 2022
Out of curiosity, what is messy about backporting this?
In figuring out that this was the problem, I touched
logging.pyquite a bit. I don't see any reason why the changes in #26490 couldn't be backported, at least not at the code level... Naturally, my perspective here is limited to my one application and not the entire CPython codebase and its millions of dependent projects, so if that's where the mess is then I understand. Again, just curious 😄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
SysLogHandlerwith one small modification and it works fine so far. The only change in my subclass from what's in the PR is to theemitmethod:The methods
createSocket,close, and__init__are verbatim copies of the PR and everything else is inherited fromSysLogHandler. This has at least allowed it to work in iPython (which uses dictConfig and kills the socket on start-up) with 3.8.sahilsangani98 commentedon Nov 29, 2022
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:
(1) Do I need to copy
FixedSysLogHandlerand place it to logging.py only?(2) If possible, can you share entire logging.py file to understand properly ?
Thank you!
MajorDallas commentedon Nov 30, 2022
@sahilsangani98
I did not modify
logging.py(other than forprint-debugging while tracking down the problem).Instead, in a utilities module in my app, I subclassed
SysLogHandlerand used that subclass as a drop-in replacement. As I said above, most of it is copied (almost) verbatim from Pull Request #26490, specifically the methods named above from the originalSysLogHandlerclass definition that starts at handlers.py:709 in the PR.YMMV. This worked with the
SysLogHandleras defined for Python 3.8; it may or may not work with other versions in the same way and I can't offer any support for it if it doesn't work for you.Then, anywhere in your app where you currently have
from logging.handlers import SysLogHandler, just change that tofrom app.utils.logging import SysLogHandler(or whatever you make the module path on your machine). You shouldn't have to change any other code that's already trying to useSysLogHandler.sahilsangani98 commentedon Nov 30, 2022
Thank you! @MajorDallas