
在 python 中,logging.handlers.sysloghandler 是一个常用的日志处理器,用于将日志信息发送到远程 syslog 服务器。然而,当远程 syslog 服务器出现故障、网络中断或响应缓慢时,默认的 sysloghandler 可能会导致日志发送操作无限期地等待。这是因为其内部使用的套接字(socket)默认处于阻塞模式,如果没有设置超时,网络操作(如连接、发送)将一直等待直到完成或发生错误。在生产环境中,这种无限期阻塞可能导致应用程序性能瓶颈,甚至完全挂起,严重影响系统的稳定性和可用性。
原始代码示例中,SysLogHandler 的初始化方式并未提供直接设置超时参数的接口,因此在远程服务器无响应时,splunk_logger.emergency(msg) 等日志发送调用会一直阻塞。
Python 的 logging 模块设计得非常灵活,允许用户通过继承来扩展或修改现有处理器的行为。对于 SysLogHandler 的阻塞问题,关键在于其内部创建和管理套接字的方式。SysLogHandler 提供了一个名为 createSocket 的方法,专门负责创建并配置用于与 Syslog 服务器通信的套接字。
我们可以通过继承 SysLogHandler,并重写 createSocket 方法,在套接字创建后立即为其设置超时。这样,所有后续的网络操作(连接、发送)都将在指定的时间内完成,如果超时,则会抛出 socket.timeout 异常,从而避免无限期阻塞。
以下是实现自定义 SysLogHandler 并设置超时机制的详细步骤和示例代码:
立即学习“Python免费学习笔记(深入)”;
import logging
import logging.handlers
import socket
import sys
# 假设 SyslogServer 和 SyslogPort 已定义
SyslogServer = '127.0.0.1' # 替换为你的Syslog服务器地址
SyslogPort = 514 # 替换为你的Syslog服务器端口
# 全局字典用于存储logger实例,避免重复创建
loggers = {}
class SysLogHandlerCustomTimeout(logging.handlers.SysLogHandler):
"""
一个自定义的SysLogHandler,用于在发送日志时设置套接字超时。
"""
def createSocket(self):
"""
重写createSocket方法,在创建套接字后设置超时。
"""
# 调用父类的createSocket方法来创建原始套接字
# 注意:Python 2.7 的super()调用方式与Python 3不同
# 对于Python 2.7,应使用:super(SysLogHandlerCustomTimeout, self).createSocket()
# 对于Python 3.x,可以使用:super().createSocket()
# 考虑到原始问题指定Python 2.7,这里使用兼容2.7的写法
super(SysLogHandlerCustomTimeout, self).createSocket()
# 设置套接字超时,例如10秒
self.socket.settimeout(10)
# 可以根据实际需求调整超时时间
# 这个超时会应用于连接和发送操作
print(f"Socket created and timeout set to {self.socket.gettimeout()} seconds.")
def writeSyslog(mtype, msg):
"""
发送消息/日志到Syslog服务器。
"""
try:
global loggers
if loggers.get('SplunkLogger'):
splunk_logger = loggers.get('SplunkLogger')
else:
# 使用我们自定义的SysLogHandlerCustomTimeout
handler = SysLogHandlerCustomTimeout(address=(SyslogServer, SyslogPort), socktype=socket.SOCK_STREAM)
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
splunk_logger = logging.getLogger('SplunkLogger')
splunk_logger.addHandler(handler)
loggers['SplunkLogger'] = 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 to {SyslogServer}:{SyslogPort} timed out.\n")
except Exception as e:
# 捕获其他可能的异常
sys.stdout.write(f"\t\tSyslog failed sending to {SyslogServer}:{SyslogPort} due to: {e}\n")
# 示例用法
if __name__ == '__main__':
print("--- 尝试发送日志到正常工作的Syslog服务器(假设存在)---")
writeSyslog("info", "This is an informational message.")
writeSyslog("warn", "This is a warning message.")
print("\n--- 尝试发送日志到无响应的Syslog服务器(模拟超时)---")
# 为了模拟无响应,可以设置一个不存在的IP或关闭对应端口的服务
# 例如,将SyslogServer设置为一个无法访问的IP
# SyslogServer = '192.168.99.99'
# SyslogPort = 514
# 重新创建logger以使用新的地址,或清理loggers字典
# loggers = {} # 清空logger缓存,以便重新创建handler
# 再次调用,如果服务器无响应,将会在10秒后超时
writeSyslog("error", "This is an error message that might time out.")
writeSyslog("crit", "Critical message during server outage.")通过继承 logging.handlers.SysLogHandler 并重写其 createSocket 方法来设置底层套接字的超时,我们成功地解决了远程 Syslog 服务器无响应时日志发送操作无限期阻塞的问题。这种方法不仅提高了应用程序的健壮性和响应性,也符合 Python logging 模块的扩展设计理念。在实际应用中,合理配置超时时间和完善异常处理机制,将大大提升日志系统的可靠性。
以上就是优化 Python SysLogHandler:实现远程日志发送超时机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号