
在python应用程序中,当使用logging.handlers.sysloghandler将日志发送到远程syslog服务器时,如果目标服务器因网络故障、宕机或端口未开放而无响应,默认的sysloghandler行为可能导致日志发送操作无限期地阻塞。这意味着应用程序会长时间等待网络连接建立或数据发送完成,从而影响程序的响应性甚至导致整个应用挂起。尤其是在关键业务场景下,这种阻塞是不可接受的。
logging.handlers.SysLogHandler内部通过createSocket方法来创建和配置用于与Syslog服务器通信的底层网络套接字。这个方法在处理器初始化或首次需要发送日志时被调用。通过继承SysLogHandler并重写createSocket方法,我们可以在套接字创建后,立即为其设置一个超时时间。这样,任何后续的网络操作(如连接尝试或数据发送)都将在指定时间内完成,如果超时,则会抛出socket.timeout异常,而不是无限期等待。
为了实现这一目标,我们需要创建一个自定义的SysLogHandler子类,并在其中重写createSocket方法。以下是具体的实现步骤和Python 2.7兼容的示例代码:
import logging
import logging.handlers
import socket
import sys
import time
# 假设的Syslog服务器地址和端口
# 在实际应用中,这些应从配置文件或环境变量中获取
SyslogServer = '127.0.0.1' # 替换为你的远程Syslog服务器IP
SyslogPort = 514 # 默认TCP Syslog端口
# 全局logger字典,用于缓存logger实例,避免重复创建和添加handler
loggers = {}
class SysLogHandlerCustomTimeout(logging.handlers.SysLogHandler):
"""
一个自定义的SysLogHandler,支持设置连接和发送超时。
此实现兼容Python 2.7。
"""
def createSocket(self):
"""
重写createSocket方法,在创建套接字后设置超时。
"""
# 调用父类的createSocket方法来创建套接字
# 对于Python 2.7,直接调用父类方法并传入self是常见的做法
logging.handlers.SysLogHandler.createSocket(self)
# 设置套接字超时时间为10秒
# 这个超时适用于连接建立和数据发送操作
self.socket.settimeout(10)
# print("Socket timeout set to 10 seconds.") # 调试信息
def writeSyslog (mtype, msg):
"""
发送消息/日志到Syslog服务器,并带有超时机制。
"""
try:
global loggers
logger_name = 'SplunkLogger' # 假设Logger名称
# 获取或创建logger实例
if logger_name in loggers:
splunk_logger = loggers[logger_name]
else:
# 使用我们自定义的带超时功能的Handler
handler = SysLogHandlerCustomTimeout(address=(SyslogServer, SyslogPort), socktype=socket.SOCK_STREAM)
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
splunk_logger = logging.getLogger(logger_name)
# 确保logger只添加一次handler,避免重复日志输出
if not splunk_logger.handlers:
splunk_logger.addHandler(handler)
# 设置logger的级别,确保所有消息都能被处理
splunk_logger.setLevel(logging.DEBUG)
loggers[logger_name] = splunk_logger
# 根据消息类型发送日志
# 注意:logging模块的标准级别是DEBUG, INFO, WARNING, ERROR, CRITICAL
# 原始问题中的"emerg", "alert", "notice"等是Syslog级别,这里映射到logging标准级别
if "emerg" in mtype or "alert" in mtype or "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 or "info" in mtype:
splunk_logger.info(msg)
else: # 默认处理为debug级别
splunk_logger.debug(msg)
except socket.timeout:
# 捕获套接字超时异常
sys.stdout.write("\t\tSyslog connection or send timed out while sending to %s:%d\n" % (SyslogServer, SyslogPort))
except socket.error as e:
# 捕获其他套接字相关的错误,如连接拒绝、网络不可达等
sys.stdout.write("\t\tSyslog socket error (%s) while sending to %s:%d\n" % (e, SyslogServer, SyslogPort))
except Exception as e:
# 捕获其他所有未预料的异常
sys.stdout.write("\t\tSyslog failed sending to %s:%d due to unexpected error: %s\n" % (SyslogServer, SyslogPort, e))
# 示例用法
if __name__ == "__main__":
print("--- 启动日志发送测试 ---")
print("请确保Syslog服务器 %s:%d 可达,或不可达以测试超时。" % (SyslogServer, SyslogPort))
# 示例1:尝试发送一条日志
print("\n[测试用例 1] 发送一条 'info' 级别的日志...")
writeSyslog("info", "这是一条测试信息,如果服务器无响应,期望在10秒内超时。")
time.sleep(1) # 稍微等待,确保异步日志处理有时间执行
# 示例2:发送一条 'warning' 级别的日志
print("\n[测试用例 2] 发送一条 'warn' 级别的日志...")
writeSyslog("warn", "这是一条警告信息,用于测试日志级别映射。")
time.sleep(1)
# 示例3:发送一条 'critical' 级别的日志
print("\n[测试用例 3] 发送一条 'crit' 级别的日志...")
writeSyslog("crit", "这是一条严重错误信息。")
time.sleep(1)
print("\n--- 日志发送测试完成 ---")
print("请检查控制台输出以确认超时或错误处理是否按预期工作。")
# 如果SyslogServer不可达,你将看到"Syslog connection or send timed out..."的输出通过继承logging.handlers.SysLogHandler并重写其createSocket方法来设置套接字超时,是解决Python日志发送到远程Syslog服务器时可能阻塞问题的有效且专业的方案。这种方法不仅提高了应用程序的健壮性和容错性,确保了在网络异常情况下的稳定运行,同时也提供了清晰的错误处理机制。在构建任何依赖外部服务的应用程序时,考虑并实现这种超时机制是至关重要的最佳实践。
以上就是Python SysLogHandler:实现日志发送超时机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号