为什么 sshtunnel 模块将未知行打印到标准输出?

Why is an unknown line being printed to stdout by sshtunnel module?

如果我运行这个代码:

import sshtunnel

try:
    with sshtunnel.open_tunnel("hello", ssh_username="user",
                               ssh_password="PASSWORD",
                               remote_bind_address=("1.2.3.4", 23)) as server:
        pass
except:
    pass

我明白了:

2016-04-06 10:47:53,006 | ERROR   | Could not resolve IP address for hello, aborting!

我忽略了异常,但由于某种原因出现了一些随机行。为什么?这只是某个图书馆某处的一些随机打印语句吗?这很常见吗?似乎图书馆不应该直接在屏幕上打印任何东西。我如何抑制这条线?

PS。旨在简单地复制错误的代码 - 显然对异常使用包罗万象而不对它们采取任何措施是不好的

您拥有 "Hello" 的部分最好包含您要连接的 SSH 服务器的 IP 地址。您提到的随机行是解释它的 ERROR 语句。

尽管该程序没有任何标准输出语句,但错误行来自库 sshtunnel

库中的语句块使用带有此特定错误消息的 raise(exeption) 语句。 raise 函数用于填充可由 except 语句捕获的消息。

这看起来像一个日志语句,具体来说 logging.error()

它会出现在屏幕上,因为您还没有设置将它发送到其他地方的日志处理程序。有关详细信息,请参阅 https://docs.python.org/2/library/logging.html

它将转到标准错误输出(在终端 window 上看起来与常规输出相同。)如果您的代码是 Web 服务的一部分,它将转到 Web 服务器的错误日志.

您传递给 open_tunnel 的第一个非关键字参数应该是目标服务器(字符串或 (ip, port) 元组(参见函数的 docstring)。

最终,这会导致 ssh_host 在您给出的示例中被设置为 "hello",并在 this except block 中记录一条错误消息。

"some random line is showing up for some reason." - 这是一条直接的错误消息...远程服务器找不到名为 "hello" 的主机。至于为什么会看到它,如果您自己不传递记录器,sshtunnel 会为错误消息创建一个控制台记录器。恕我直言,这是一件奇怪的事情。 open_tunnel 接受两个关键字参数:logger 是标准的 python 记录器,debug_level 是要记录的级别。有关设置记录器的详细信息,请参阅 python logging

TL;DR

添加threaded=False


你好,我遇到了完全相同的错误

并在隧道关闭(释放)后出现:

2018-01-16 10:52:58,685| INFO    | Shutting down tunnel ('0.0.0.0', 33553)
2018-01-16 10:52:58,764| INFO    | Tunnel: 0.0.0.0:33553 <> sql_database_resolved_on_remote:1433 released
2018-01-16 10:52:58,767| ERROR   | Could not establish connection from ('127.0.0.1', 33553) to remote side of the tunnel
2018-01-16 10:52:58,889| DEBUG   | Transport is closed

这有点正常,但为什么会这样?

"Solution-ish"

添加threaded=False.

with ... as tunnel: 上下文中使用 open_tunnel()SSHTunnelForwarder 进行了测试:

import time
import socket
from sshtunnel import SSHTunnelForwarder, open_tunnel

def test_tunnel(tunnel):
    # Wait for tunnel to be established ?
    #tunnel.check_tunnels()
    #time.sleep(0.5)
    #print tunnel.tunnel_is_up
    s = socket.socket()
    s.settimeout(2)
    for i in range(0, 10):
        """
        I create a new socket each time otherwise I get
        the error 106 (errno.EISCONN):
        'Transport endpoint is already connected'
        """
        s = socket.socket()
        s.settimeout(2)
        state = s.connect_ex(('localhost', tunnel.local_bind_port))
        s.close()
        okoko = "OK" if state == 0 else "NO"
        print "%s (%s)" % (okoko, state)

with open_tunnel(
    'server_i_can_ssh_with_mykey',
    ssh_username='myuser',
    ssh_pkey='/home/myuser/.ssh/id_rsa',
    ssh_private_key_password=None, #no pwd on my key
    remote_bind_address=('sql_database_resolved_on_remote', 1433), #e.g.
    debug_level=10, # remove this if you test with SSHTunnelForwarder
    threaded=False,
) as tunnel:
    test_tunnel(tunnel)

hth