这两天,客户的机器上面的fail2ban一直启动失败,启动的时候显示connection refused。把能打开的loglevel都打开,依然只是显示同样的错误,没有更详细的显示。调试到一半时间,客户等不及了,同事便建议重启试试,我思考了一会,虽然重启大概率无法解决这个问题,不过依然可以试试。于是我同意重启,令人惊奇的是,重启后恢复正常。

第二天下午,同事在IM里喊“... that fail2ban issue happened again...”,于是我再继续昨日未完成的调试,调试的首要目的只是找到这个打印错误地方。搜索代码发现是个捕捉exception的地方,但是fail2ban把堆栈信息都丢弃了。我添加了traceback.print_exc来打印堆栈,结果发现是fail2ban连接syslog的unix domain socket失败,它会根据系统的类型来寻找对应的文件路径。在linux下,它会连接到/dev/log来输出日志,但是由于syslog没有启动,所以/dev/log并不存在。后续就是研究为什么syslog为什么crash了,不过和这个问题无关了。

这里有几个想到的问题:

  1. 如何在没有堆栈的情况下有效输出日志?比如不显示connection refused,而是syslog socket connection refused?
    在try catch这个架构里感觉很难做到,exception在返回上层函数的时候,丢失了中间的信息,比如这里,socket的exception没有被logger处理,所以原样返回到fail2ban,fail2ban也不知道这个exception从哪里来的,所以也只能原样显示。
    因此这条log只能显示socket连接失败,并不能找到是哪个功能连接socket。
    如果然exception往上传递的时候携带更多信息呢,比如在logger里catch并且增加一条message到exception,这个感觉有点像golang的error设计,返回error的时候进行二次包装,给它更多信息。但是python可以在try catch中直接打印堆栈信息,有堆栈就基本能知道是哪里有错误了。
    所以exception发生的时候不应该只print一条消息,增加堆栈消息也是很有用的。
  2. 为什么linux默认的syslog的socket是/dev/log,如果是有log设备那么很正常,由内核监听,但是这个是syslog创建的,用户态程序却在devfs监听,感觉有点不合理,如果syslog想要接收devfs挂载之前的日志呢?而且devfs通常可以mount多次,里面的socket文件却不能直接复制。

标签: none

评论已关闭