
在使用python的 logging 模块配合 logging.handlers.sysloghandler 将日志发送到远程syslog服务器时,如果远程服务器出现故障、网络中断或响应缓慢,日志发送操作可能会无限期地阻塞应用程序。这通常在使用面向连接的协议(如tcp,即 socktype=socket.sock_stream)时尤为明显,因为套接字尝试建立连接或发送数据时会等待服务器响应,若无响应则会一直阻塞,直到操作系统层面的tcp超时(可能长达数分钟)或连接被重置。
原始代码示例中,SysLogHandler 的初始化并未提供设置连接或发送超时的参数,导致在远程Syslog服务器无响应时,splunk_logger.emergency(msg) 等日志发送调用会长时间挂起,影响应用的可用性。
logging.handlers.SysLogHandler 内部通过 createSocket 方法来创建和初始化用于与Syslog服务器通信的套接字。这个方法在处理器首次尝试发送日志时被调用。虽然 SysLogHandler 没有直接暴露设置超时的方法,但我们可以通过继承 SysLogHandler 类并重写其 createSocket 方法,在套接字创建之后立即对其进行配置,例如设置超时。
具体步骤如下:
以下是实现自定义 SysLogHandler 并集成到现有日志发送逻辑中的示例代码。此代码兼容Python 2.7及更高版本。
立即学习“Python免费学习笔记(深入)”;
import logging
import logging.handlers
import socket
import sys
import time
# 假设的Syslog服务器地址和端口
# 在实际部署中,请替换为您的远程Syslog服务器地址
SyslogServer = '127.0.0.1' # 示例:指向本地回环地址
SyslogPort = 514 # TCP Syslog默认端口,如果使用UDP通常是514或5140
# 全局日志器字典,用于缓存已配置的日志器
loggers = {}
class SysLogHandlerCustomTimeout(logging.handlers.SysLogHandler):
"""
自定义SysLogHandler,用于在套接字连接和发送时设置超时。
"""
def __init__(self, address, socktype=socket.SOCK_STREAM, timeout_seconds=10):
# 使用Python 2.7/3 兼容的super() 调用父类构造函数
super(SysLogHandlerCustomTimeout, self).__init__(address, socktype=socktype)
self.timeout_seconds = timeout_seconds
def createSocket(self):
"""
重写createSocket方法,在创建套接字后设置超时。
此方法在处理器首次尝试发送日志时被调用。
"""
# 调用父类的createSocket方法来创建套接字
# Python 2.7/3 兼容的super() 调用
super(SysLogHandlerCustomTimeout, self).createSocket()
# 检查套接字是否成功创建,并设置超时
if self.socket:
self.socket.settimeout(self.timeout_seconds)
else:
# 理论上父类的createSocket不会返回None,但作为防御性编程可保留
raise IOError("Failed to create socket for SysLogHandler.")
def writeSyslog (mtype, msg):
"""
发送消息/日志到Syslog服务器。
此函数整合了自定义超时处理器和日志器缓存逻辑。
"""
try:
global loggers
logger_name = 'SplunkLogger' # 定义日志器名称
# 检查日志器是否已存在于缓存中
if loggers.get(logger_name):
splunk_logger = loggers.get(logger_name)
else:
# 如果日志器不存在,则创建并配置它
# 使用自定义的SysLogHandlerCustomTimeout
handler = SysLogHandlerCustomTimeout(
address = (SyslogServer, SyslogPort),
socktype = socket.SOCK_STREAM, # 示例:使用TCP协议
timeout_seconds = 5 # 设置5秒的连接和发送超时
)
# 设置日志格式
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
# 获取或创建名为'SplunkLogger'的日志器
splunk_logger = logging.getLogger(logger_name)
# 避免重复添加handler,确保只添加一次
if not splunk_logger.handlers:
splunk_logger.addHandler(handler)
# 将配置好的日志器存入缓存
loggers[logger_name] = splunk_logger
# 根据消息类型发送日志
if "emerg" in mtype:
splunk_logger.emergency(msg)
elif "alert" in mtype:
splunk_logger.alert(msg)
elif "crit" in mtype:
splunk_logger.critical(msg)
elif "err" in mtype:
splunk_logger.error(msg)
elif "warn" in mtype:
splunk_logger.warning(msg)
elif "notice" in mtype:
splunk_logger.notice(msg)
elif "info" in mtype:
splunk_logger.info(msg)
else:
splunk_logger.debug(msg)
except socket.timeout:
# 捕获套接字超时异常
sys.stdout.write(f"\t\tSyslog sending timed out to {SyslogServer}:{SyslogPort}\n")
except Exception as e:
# 捕获其他可能的网络或I/O异常
sys.stdout.write(f"\t\tSyslog failed sending to {SyslogServer}:{SyslogPort} with error: {e}\n")
# 示例用法
if __name__ == "__main__":
print(f"尝试向 {SyslogServer}:{SyslogPort} 发送日志...")
# 假设远程Syslog服务器未运行,或网络不通
# 在这种情况下,日志发送操作将在5秒后因超时而失败
writeSyslog("info", "这是一条测试信息,期望在超时后失败。")
time.sleep(1) # 稍作等待,模拟发送多条日志
writeSyslog("error", "另一条错误信息。")
print("日志发送尝试完成。请检查控制台输出以确认超时行为。")
# 如果有实际的Syslog服务器运行在指定地址和端口,可以测试成功发送
# SyslogServer = 'your_actual_syslog_server_ip'
# SyslogPort = 514
# writeSyslog("info", "这是一条成功发送的测试信息。")通过继承 `
以上就是Python日志发送:为SysLogHandler添加连接超时机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号