如何通过Python logging记录Paramiko exec_command的stdin/stdout/stderr?
解决Paramiko exec_command日志记录时的"File not open for reading"错误
我刚帮你排查了这个问题,核心原因其实很简单:你代码里对stdin调用了readlines(),但Paramiko的stdin是只写流,根本不能用来读取内容,这直接触发了那个IO错误。
咱们一步步来解决:
错误原因拆解
Paramiko通过exec_command返回的三个对象里:
stdin:是ChannelStdinFile类型,专门用来给远程命令输入数据(比如输入密码、交互指令),它的打开模式是只写,所以任何读取操作(比如read()、readlines())都会抛出"File not open for reading"错误。stdout和stderr:才是可读的输出流,用来获取远程命令的正常输出和错误信息。
修复后的代码
我给你调整了client_exe函数,修正了stdin的处理,同时优化了输出读取的逻辑(避免缓冲区死锁,确保读取完整):
def client_exe(hostname, command, username, password): logger = getLogger("EXEC", "log.log") ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh_client.connect(hostname=hostname, username=username, password=password) stdin, stdout, stderr = ssh_client.exec_command(command, get_pty=True) # stdin是写入流,无法读取,这里标注说明 stdin_info = "Write-only stream (no input sent to remote command)" # 先获取命令退出状态,确保所有输出都已写入缓冲区 exit_status = stdout.channel.recv_exit_status() # 读取完整的输出和错误信息 stdout_content = stdout.readlines() stderr_content = stderr.readlines() logger.info( "Remote Machine: {} \n" "\tCommand: {} \n" "\tSTDIN: {} \n" "\tSTDOUT: {} \n" "\tErrors: {} \n" "\tExit Status: {}".format( hostname, command, stdin_info, stdout_content, stderr_content, exit_status ) ) finally: # 确保SSH客户端始终关闭,避免资源泄漏 ssh_client.close()
额外优化说明
- stdin的写入场景:如果你的业务需要给远程命令输入内容(比如执行
sudo时输入密码),可以这样操作stdin,但依然不能读取它:
# 示例:给远程命令输入密码 stdin.write("your_sudo_password\n") stdin.flush() # 确保数据发送到远程端
- 避免日志重复输出:你的
getLogger函数每次调用都会重复添加Handler,会导致同一条日志多次输出,我给你加个判断优化一下:
def getLogger(name, logname): logger = logging.getLogger(name) # 避免重复添加Handler if logger.handlers: return logger fmt = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", datefmt='%m/%d/%Y %I:%M:%S %p') fileHandler = logging.FileHandler(logname, mode="a") fileHandler.setFormatter(fmt) streamHandler = logging.StreamHandler() streamHandler.setFormatter(fmt) logger.setLevel(logging.DEBUG) logger.addHandler(fileHandler) logger.addHandler(streamHandler) return logger
这样修改后,你的日志记录就能正常工作,不会再触发那个IO错误了。
内容的提问来源于stack exchange,提问作者johnnyb
相关产品推荐
相关产品推荐

