CuriousY A world with wonder

关于Python标准库logging

| Comment
  1. logging这个类有点特别,它会在初始化时生成一个全局的对象用来存储所有logger对象,而后每次import logging,可以通过getlogger来获取特定的logger对象,从而打印出相应的log。所以它类似一个树状的结构,logging.INFO()其实就是root.INFO(),是直接用根节点来打log(根节点是在import logging时就会初始化);

  2. logging的子节点如果没有setLevel的话,默认level为0,意思是一个无效的level,会通过如下方法来搜索其父节点,直到找到有效的level位置;

    def getEffectiveLevel(self):
        """
        Get the effective level for this logger.
    
        Loop through this logger and its parents in the logger hierarchy,
        looking for a non-zero logging level. Return the first one found.
        """
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET
    
  3. logging的官方流程图: img

  4. logging默认的root节点的level是WARNING:

    root = RootLogger(WARNING)
    
  5. 执行某个logger.info()时,默认会call这个logger以及它所有父节点的handler,如果不想call其父节点的handler,则需要把logger.propagate设为False。这部分源代码如下:

    def callHandlers(self, record):
        """
        Pass a record to all relevant handlers.
    
        Loop through all handlers for this logger and its parents in the
        logger hierarchy. If no handler was found, output a one-off error
        message to sys.stderr. Stop searching up the hierarchy whenever a
        logger with the "propagate" attribute set to zero is found - that
        will be the last logger whose handlers are called.
        """
        c = self
        found = 0
        while c:
            for hdlr in c.handlers:
                found = found + 1
                if record.levelno >= hdlr.level:
                    hdlr.handle(record)
            if not c.propagate:
                c = None    #break out
            else:
                c = c.parent
        if (found == 0) and raiseExceptions and not self.manager.emittedNoHandlerWarning:
            sys.stderr.write("No handlers could be found for logger"
                             " \"%s\"\n" % self.name)
            self.manager.emittedNoHandlerWarning = 1
    
  6. 使用logging打印出exception的stack trace:

    try:
        # do something here
    except Exception, e:
        logging.error(e, exc_info=True)
    

关于ssh connection time out

| Comment

先直接说结论:client端和server端都能设置time out的相关设置,具体最后断开取决于谁要看哪边设置的时间更短。比如说client端设置的time out时间大于server端所设置的话,那就由server端说了算,即最后主动断开连接的是server端;如果client端设置的时间较短,那主动断开连接的就是client端了。

server端设置

(linux平台)server端的关于ssh的设置文件为/etc/ssh/sshd_config,其中主要影响time out设置的是如下三个参数(参数下面是对参数的官方说明):

TCPKeepAlive

Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, this means that connections will die if the route is down temporarily, and some people find it annoying. On the other hand, if TCP keepalives are not sent, sessions may hang indefinitely on the server, leaving “ghost” users and consuming server resources.

The default is “yes” (to send TCP keepalive messages), and the server will notice if the network goes down or the client host crashes. This avoids infinitely hanging sessions.

To disable TCP keepalive messages, the value should be set to “no”.

This option was formerly called KeepAlive.

ClientAliveCountMax

Sets the number of client alive messages (see below) which may be sent without sshd(8) receiving any messages back from the client. If this threshold is reached while client alive messages are being sent, sshd will disconnect the client, terminating the session. It is important to note that the use of client alive messages is very different from TCPKeepAlive (below). The client alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by TCPKeepAlive is spoofable. The client alive mechanism is valueable when the client or server depend on knowing when a connection has become inactive.

The default value is 3. If ClientAliveInterval (see below) is set to 15, and ClientAliveCountMax is left at the default, unresponsive SSH clients will be disconnected after approximately 45 seconds. This option applies to protocol version 2 only.

ClientAliveInterval

Sets a timeout interval in seconds after which if no data has been received from the client, sshd(8) will send a message through the encrypted channel to request a response from the client. The default is 0, indicating that these messages will not be sent to the client. This option applies to protocol version 2 only.

从官方的解释来看,默认设置下server端是不会主动断开连接的(ClientAliveInterval为0)。

如果改为如下:

ClientAliveInterval 600
ClientAliveCountMax 3

则连续30min没有通信后(准确地说是server每个10分钟发送一条消息,连续3次发送消息都没有回应)会timeout(600s * 3)。

client端设置

在client端也是能设置的,这里只研究了python的paramiko库的设置方法,就是在SSHClient.connect()时,设置其中的timeout参数,默认timeout=None其实是3600s,即一个小时。

在不修改server端设置的情况下,如何保证ssh connection不会timeout?

一个可以想到的方法是每隔一段时间发送一条消息到server端,告诉server自己还活着。

  • 对应于paramiko,可以如下设置:

    transport = SSHClient.get_transport()
    transport.set_keepalive(30) # send message every 30 seconds
    
  • 对应于linux平台下的ssh connection,可以在/etc/ssh/ssh_config中设置ServerAliveInterval变量(默认为0应该就是不会发送消息,设置后每隔指定的时间(s)会发送一条消息到server端)。

| Page 25 of 25 | Last