0

0

Python日志发送:为SysLogHandler添加连接超时机制

花韻仙語

花韻仙語

发布时间:2025-10-06 13:16:12

|

558人浏览过

|

来源于php中文网

原创

Python日志发送:为SysLogHandler添加连接超时机制

本文将介绍如何解决Python logging.handlers.SysLogHandler在发送日志到远程Syslog服务器时可能发生的无限期阻塞问题。通过自定义SysLogHandler并重写其createSocket方法,我们可以为底层套接字设置连接和发送超时,从而确保在服务器无响应时日志发送操作能够及时放弃,提升应用的健壮性。

1. 问题背景:SysLogHandler的阻塞行为

在使用python的 logging 模块配合 logging.handlers.sysloghandler 将日志发送到远程syslog服务器时,如果远程服务器出现故障、网络中断或响应缓慢,日志发送操作可能会无限期地阻塞应用程序。这通常在使用面向连接的协议(如tcp,即 socktype=socket.sock_stream)时尤为明显,因为套接字尝试建立连接或发送数据时会等待服务器响应,若无响应则会一直阻塞,直到操作系统层面的tcp超时(可能长达数分钟)或连接被重置。

原始代码示例中,SysLogHandler 的初始化并未提供设置连接或发送超时的参数,导致在远程Syslog服务器无响应时,splunk_logger.emergency(msg) 等日志发送调用会长时间挂起,影响应用的可用性。

2. 解决方案:自定义SysLogHandler并重写createSocket方法

logging.handlers.SysLogHandler 内部通过 createSocket 方法来创建和初始化用于与Syslog服务器通信的套接字。这个方法在处理器首次尝试发送日志时被调用。虽然 SysLogHandler 没有直接暴露设置超时的方法,但我们可以通过继承 SysLogHandler 类并重写其 createSocket 方法,在套接字创建之后立即对其进行配置,例如设置超时。

具体步骤如下:

  1. 继承 logging.handlers.SysLogHandler: 创建一个新的类,例如 SysLogHandlerCustomTimeout。
  2. 重写 __init__ 方法(可选但推荐): 允许在初始化时传入超时时间。
  3. 重写 createSocket 方法:
    • 首先调用父类的 createSocket 方法来完成套接字的默认创建和初始化。
    • 然后,通过访问 self.socket 属性获取到已创建的套接字对象。
    • 使用 self.socket.settimeout(timeout_value) 方法为该套接字设置连接和发送超时。

3. 实现细节与示例代码

以下是实现自定义 SysLogHandler 并集成到现有日志发送逻辑中的示例代码。此代码兼容Python 2.7及更高版本。

笔头写作
笔头写作

AI为论文写作赋能,协助你从0到1。

下载

立即学习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", "这是一条成功发送的测试信息。")

4. 注意事项

  • 超时值选择: timeout_seconds 的值应根据实际的网络环境和Syslog服务器的预期响应时间来合理设置。过短的超时可能导致在网络暂时拥堵时正常请求失败,而过长的超时则会降低超时机制的有效性。
  • TCP与UDP:
    • 本教程主要针对 socktype=socket.SOCK_STREAM (TCP) 协议,因为TCP是面向连接的,其连接建立和数据发送过程可能阻塞。
    • 如果使用 socktype=socket.SOCK_DGRAM (UDP) 协议,UDP是无连接的,sendto 操作通常是立即返回的,不会阻塞等待远程服务器响应。因此,为UDP套接字设置发送超时通常没有实际意义,但连接超时(如果存在)可能仍有用。
  • Python版本兼容性: 示例代码中的 super(Class, self).__init__(...) 和 super(Class, self).createSocket() 语法在Python 2.7和Python 3中均兼容,确保了广泛适用性。
  • 异常处理: 捕获 socket.timeout 异常是关键,它允许应用程序在超时发生时执行特定的错误处理逻辑,例如记录错误、通知管理员或尝试重试。除了 socket.timeout,也应考虑捕获其他可能的 socket.error 或 IOError。
  • 日志器管理: 确保日志器和处理器被正确初始化和管理,避免重复添加处理器。在示例代码中,通过 loggers 字典缓存日志器,并检查 splunk_logger.handlers 来避免多次添加同一个处理器。

5. 总结

通过继承 `

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

297

2023.10.25

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

469

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

13

2025.12.06

tcp和udp的区别
tcp和udp的区别

TCP和UDP的区别,在连接性、可靠性、速度和效率、数据报大小以及适用场景等方面。本专题为大家提供tcp和udp的区别的相关的文章、下载、课程内容,供大家免费下载体验。

121

2023.07.25

udp是什么协议
udp是什么协议

UDP是OSI参考模型中一种无连接的传输层协议。本专题为大家带来udp是什么协议的相关文章,免费提供给大家。

293

2023.08.08

tcp和udp有什么区别
tcp和udp有什么区别

tcp和udp的区别有:1、udp是无连接的,tcp是面向连接的;2、udp是不可靠传输,tcp是可靠传输;3、udp是面向报文传输,tcp是面向字节流传输。想了解更多tcp相关的内容,可阅读本专题下面的相关文章。

384

2024.11.14

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

2

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

446

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号