Handle TCP socket failure in `logging.handlers.SysLogHandler.emit`
還沒有人認領這個 Issue。
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 35.9k
- PR 合併指標
- PR 指標待擷取
描述
Bug report
Bug description:
Client loggers on TCP using a socket stream can timeout. A TCP logger server could issue disconnect to TCP client due to timeout caused usually by no activity after some elapsed time. TCP servers typically have to control how many TCP listeners are active in memory to prevent TCP flooding. They do it by monitoring TCP activity timeouts and by removing open TCP sockets from memory and by sending a FIN to client to disconnect socket in remote TCP table as well.
Going back to the Python apps that use "import logging" to send events to specifically to TCP handlers, an app relying on TCP logger would not recover successfully if socket was closed by server's TCP FIN packet; thus app's syslog message/event would no longer be forwarded to TCP log collector. The bug exists because there is no verification of TCP socket stream existence in logging.handlers.SysLogHandler.emit.
If socket was torned down by Kernel it doesn't exist and socket Exception is generated and a new socket stream of type socket.SOCK_STREAM should be created and message resent to remote TCP collector on 2nd attempt. The reason why the bug exists is because the current logger handler does not support explicit try:except auto-remediation handling for socket types socket.SOCK_STREAM (TCP sockets) in logging.handlers.SysLogHandler.emit. The proposed update below addresses that gap by providing recovery support for TCP sockets that were closed by Kernel ensuring data logging continuity for Python apps without restarting the application..
Notice that there isn't a recovery block in the original code for socket type socket.SOCK_STREAM in logging.handlers.
I added the code in bold to show how the socket would be created for a Python app using TCP-based client logging as a handler. I have confirmed this bug exist with our TCP syslog infrastructure and confirmed corrected by the following code in bold. You could duplicate yourself by adding a TCP handler to any IP using import logging and then wait have the TCP server disconnect the socket sending FIN to client and the TCP client will fail to create a new socket on new event through logger. An error should appear when trying to self.socket.send(msg) when a TCP socket doesn't exist and there is no try/except to recover from that in original code.
Please approve this bug and I'll issue a pull request with the bolded code below to fix it.
From logging.handlers.SysLogHandler.emit:
if not self.socket:
self.createSocket()
if self.unixsocket:
try:
self.socket.send(msg)
except OSError:
self.socket.close()
self._connect_unixsocket(self.address)
self.socket.send(msg)
+# UDP socket type
elif self.socktype == socket.SOCK_DGRAM:
self.socket.sendto(msg, self.address)
+# TCP socket type
+# This block doesn't exist in original handlers.py code for TCP
+elif self.socktype == socket.SOCK_STREAM:
+ try:
+ self.socket.sendall(msg)
+ # create new TCP socket stream, if TCP socket broken or disconnected
+ except OSError:
+ self.socket = socket.socket(socket.AF_INET, self.socktype)
+ self.socket.connect(self.address)
+ # retry sending msg after making new TCP AF_INET socket
+ self.socket.sendall(msg)
else:
self.socket.sendall(msg)
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-123238
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
先從 handlers.py 中的 logging.handlers.SysLogHandler.emit 開始,並在進行變更前檢閱相關的 PR gh-123238。驗證 issue 中所描述的 TCP socket 失敗路徑,包括在發生 OSError 後重新連線並重試傳送訊息;當該行為已受到涵蓋且現有的 logging handler 行為維持不變時,即表示完成。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- python
- 領域
- backend
- Issue 類型
- 缺陷
- 難度
- 3/5
- 預估耗時
- 1-2 天
- 活躍度
- 停滯
- 描述清晰度
- 描述清楚
- 新手友好度
- 35/100