2014-10-28 3 views
2

로그 파일을 꼬집어 쓰려고합니다. 작동합니다. 그러나 나는 또한 출력을 분석하고 오류 등을 기록 할 수 있어야합니다. Paramiko-expect github 페이지에서 기본 예제를 사용하고 있으며이를 수행하는 방법을 알 수 없습니다. 이것은 그것의 지점으로 작동Paramiko Expect - Tailing

import traceback 
import paramiko 
from paramikoe import SSHClientInteraction 

def main(): 

    # Set login credentials and the server prompt 
    hostname = 'server' 
    username = 'username' 
    password = 'xxxxxxxx' 
    port = 22 

    # Use SSH client to login 
    try: 

     # Create a new SSH client object 
     client = paramiko.SSHClient() 

     # Set SSH key parameters to auto accept unknown hosts 
     client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 

     # Connect to the host 
     client.connect(hostname, port, username, password) 

     # Create a client interaction class which will interact with the host 
     interact = SSHClientInteraction(client, timeout=10, display=False) 

     # Send the tail command 
     interact.send('tail -f /var/log/log') 

     # Now let the class tail the file for us 
     interact.tail(line_prefix=hostname+': ') 




    except KeyboardInterrupt: 
     print 'Ctrl+C interruption detected, stopping tail' 
    except Exception: 
     traceback.print_exc() 
    finally: 
     try: 
      client.close() 
     except: 
      pass 

if __name__ == '__main__': 
    main() 

은 로그가에서 실행되는 콘솔에 시간을 살고 인쇄,하지만 난 방식 paramiko에서 나는 OUPUT을 반복 할 수있는 방법을 알아낼 수 없습니다 기대 가치를 찾으십니까?

도움 말?

https://github.com/fgimian/paramiko-expect

이것은 또한 이벤트의 기록 백업을 위해 로컬 파일에 로그의 출력을 밀어 수있는 도움이 될 것이다.

업데이트 : 그래서이 정보가 표시되는 방식은 sys.stdout입니다. 인터럽트 방식으로 출력을 끌어내는 방법이나이 방식을 여전히 작동 할 수있는 다른 유형의 출력으로 수정하는 방법에 익숙하지 않습니다. 나는 많은 성공없이이 모듈의 제작자에게 이메일을 보내려고 노력했다.

이 모듈은 매우 강력한 도구입니다. 실제로 출력을 모니터링 할 수 있다면 모듈을 매우 훌륭한 도구로 만들 수 있습니다. 도와주세요! Paramiko이-기대의

출력 섹션 : 꼬리 기능 :

 # Read the output one byte at a time so we can detect \n correctly 
     buffer = self.channel.recv(1) 

     # If we have an empty buffer, then the SSH session has been closed 
     if len(buffer) == 0: 
      break 

     # Strip all ugly \r (Ctrl-M making) characters from the current 
     # read 
     buffer = buffer.replace('\r', '') 

     # Add the currently read buffer to the current line output 
     current_line += buffer 

     # Display the last read line in realtime when we reach a \n 
     # character 
     if current_line.endswith('\n'): 
      if line_counter and line_prefix: 
       sys.stdout.write(line_prefix) 
      if line_counter: 
       sys.stdout.write(current_line) 
       sys.stdout.flush() 
      line_counter += 1 
      current_line = '' 

Paramiko가 기대 모듈 :

# 
# Paramiko Expect 
# 
# Written by Fotis Gimian 
# http://github.com/fgimian 
# 
# This library works with a Paramiko SSH channel to provide native SSH 
# expect-like handling for servers. The library may be used to interact 
# with commands like 'configure' or Cisco IOS devices or with interactive 
# Unix scripts or commands. 
# 
# You must have Paramiko installed in order to use this library. 
# 
import sys 
import re 
import socket 
# Windows does not have termios 
try: 
    import termios 
    import tty 
    has_termios = True 
except ImportError: 
    import threading 
    has_termios = False 

import select 


class SSHClientInteraction: 
    """This class allows an expect-like interface to Paramiko which allows 
    coders to interact with applications and the shell of the connected 
    device. 
    """ 

    def __init__(self, client, timeout=60, newline='\r', buffer_size=1024, 
       display=False): 
     """The constructor for our SSHClientInteraction class. 

     Arguments: 
     client -- A Paramiko SSHClient object 

     Keyword arguments: 
     timeout -- THe connection timeout in seconds 
     newline -- The newline character to send after each command 
     buffer_size -- The amount of data (in bytes) that will be read at a 
         time after a command is run 
     display -- Whether or not the output should be displayed in real-time 
        as it is being performed (especially useful when debugging) 

     """ 
     self.channel = client.invoke_shell() 
     self.newline = newline 
     self.buffer_size = buffer_size 
     self.display = display 
     self.timeout = timeout 
     self.current_output = '' 
     self.current_output_clean = '' 
     self.current_send_string = '' 
     self.last_match = '' 

    def __del__(self): 
     """The destructor for our SSHClientInteraction class.""" 
     self.close() 

    def close(self): 
     """Attempts to close the channel for clean completion.""" 
     try: 
      self.channel.close() 
     except: 
      pass 

    def expect(self, re_strings=''): 
     """This function takes in a regular expression (or regular expressions) 
     that represent the last line of output from the server. The function 
     waits for one or more of the terms to be matched. The regexes are 
     matched using expression \n<regex>$ so you'll need to provide an 
     easygoing regex such as '.*server.*' if you wish to have a fuzzy match. 

     Keyword arguments: 
     re_strings -- Either a regex string or list of regex strings that 
         we should expect. If this is not specified, then 
         EOF is expected (i.e. the shell is completely closed 
         after the exit command is issued) 

     Returns: 
     - EOF: Returns -1 
     - Regex String: When matched, returns 0 
     - List of Regex Strings: Returns the index of the matched string as 
           an integer 
     """ 

     # Set the channel timeout 
     self.channel.settimeout(self.timeout) 

     # Create an empty output buffer 
     self.current_output = '' 

     # This function needs all regular expressions to be in the form of a 
     # list, so if the user provided a string, let's convert it to a 1 
     # item list. 
     if len(re_strings) != 0 and isinstance(re_strings, str): 
      re_strings = [re_strings] 

     # Loop until one of the expressions is matched or loop forever if 
     # nothing is expected (usually used for exit) 
     while (
      len(re_strings) == 0 or 
      not [re_string 
       for re_string in re_strings 
       if re.match('.*\n' + re_string + '$', 
          self.current_output, re.DOTALL)] 
     ): 

      # Read some of the output 
      buffer = self.channel.recv(self.buffer_size) 

      # If we have an empty buffer, then the SSH session has been closed 
      if len(buffer) == 0: 
       break 

      # Strip all ugly \r (Ctrl-M making) characters from the current 
      # read 
      buffer = buffer.replace('\r', '') 

      # Display the current buffer in realtime if requested to do so 
      # (good for debugging purposes) 
      if self.display: 
       sys.stdout.write(buffer) 
       sys.stdout.flush() 

      # Add the currently read buffer to the output 
      self.current_output += buffer 

     # Grab the first pattern that was matched 
     if len(re_strings) != 0: 
      found_pattern = [(re_index, re_string) 
          for re_index, re_string in enumerate(re_strings) 
          if re.match('.*\n' + re_string + '$', 
             self.current_output, re.DOTALL)] 

     self.current_output_clean = self.current_output 

     # Clean the output up by removing the sent command 
     if len(self.current_send_string) != 0: 
      self.current_output_clean = (
       self.current_output_clean.replace(
        self.current_send_string + '\n', '')) 

     # Reset the current send string to ensure that multiple expect calls 
     # don't result in bad output cleaning 
     self.current_send_string = '' 

     # Clean the output up by removing the expect output from the end if 
     # requested and save the details of the matched pattern 
     if len(re_strings) != 0: 
      self.current_output_clean = (
       re.sub(found_pattern[0][1] + '$', '', 
         self.current_output_clean)) 
      self.last_match = found_pattern[0][1] 
      return found_pattern[0][0] 
     else: 
      # We would socket timeout before getting here, but for good 
      # measure, let's send back a -1 
      return -1 

    def send(self, send_string): 
     """Saves and sends the send string provided""" 
     self.current_send_string = send_string 
     self.channel.send(send_string + self.newline) 

    def tail(self, line_prefix=None): 
     """This function takes control of an SSH channel and displays line 
     by line of output as \n is recieved. This function is specifically 
     made for tail-like commands. 

     Keyword arguments: 
     line_prefix -- Text to append to the left of each line of output. 
         This is especially useful if you are using my 
         MultiSSH class to run tail commands over multiple 
         servers. 

     """ 

     # Set the channel timeout to the maximum integer the server allows, 
     # setting this to None breaks the KeyboardInterrupt exception and 
     # won't allow us to Ctrl+C out of teh script 
     self.channel.settimeout(sys.maxint) 

     # Create an empty line buffer and a line counter 
     current_line = '' 
     line_counter = 0 

     # Loop forever, Ctrl+C (KeyboardInterrupt) is used to break the tail 
     while True: 

      # Read the output one byte at a time so we can detect \n correctly 
      buffer = self.channel.recv(1) 

      # If we have an empty buffer, then the SSH session has been closed 
      if len(buffer) == 0: 
       break 

      # Strip all ugly \r (Ctrl-M making) characters from the current 
      # read 
      buffer = buffer.replace('\r', '') 

      # Add the currently read buffer to the current line output 
      current_line += buffer 

      # Display the last read line in realtime when we reach a \n 
      # character 
      if current_line.endswith('\n'): 
       if line_counter and line_prefix: 
        sys.stdout.write(line_prefix) 
       if line_counter: 
        sys.stdout.write(current_line) 
        sys.stdout.flush() 
       line_counter += 1 
       current_line = '' 

    def take_control(self): 
     """This function is a better documented and touched up version of the 
     posix_shell function found in the interactive.py demo script that 
     ships with Paramiko""" 

     if has_termios: 
      # Get attributes of the shell you were in before going to the 
      # new one 
      original_tty = termios.tcgetattr(sys.stdin) 
      try: 
       tty.setraw(sys.stdin.fileno()) 
       tty.setcbreak(sys.stdin.fileno()) 

       # We must set the timeout to 0 so that we can bypass times when 
       # there is no available text to receive 
       self.channel.settimeout(0) 

       # Loop forever until the user exits (i.e. read buffer is empty) 
       while True: 
        select_read, select_write, select_exception = (
         select.select([self.channel, sys.stdin], [], [])) 
        # Read any output from the terminal and print it to the 
        # screen. With timeout set to 0, we just can ignore times 
        # when there's nothing to receive. 
        if self.channel in select_read: 
         try: 
          buffer = self.channel.recv(self.buffer_size) 
          if len(buffer) == 0: 
           break 
          sys.stdout.write(buffer) 
          sys.stdout.flush() 
         except socket.timeout: 
          pass 
        # Send any keyboard input to the terminal one byte at a 
        # time 
        if sys.stdin in select_read: 
         buffer = sys.stdin.read(1) 
         if len(buffer) == 0: 
          break 
         self.channel.send(buffer) 
      finally: 
       # Restore the attributes of the shell you were in 
       termios.tcsetattr(sys.stdin, termios.TCSADRAIN, original_tty) 
     else: 
      def writeall(sock): 
       while True: 
        buffer = sock.recv(self.buffer_size) 
        if len(buffer) == 0: 
         break 
        sys.stdout.write(buffer) 
        sys.stdout.flush() 

      writer = threading.Thread(target=writeall, args=(self.channel,)) 
      writer.start() 

      try: 
       while True: 
        buffer = sys.stdin.read(1) 
        if len(buffer) == 0: 
         break 
        self.channel.send(buffer) 
      # User has hit Ctrl+Z or F6 
      except EOFError: 
       pass 
+0

왜 그냥'로컬 호스트에'는/var/log/log'을 scp'ing 여기를 분석 반복 : 여기

은 예입니다? 'diffutils'를 사용하여 새로운 파트를 찾을 수 있습니다. –

답변

1

그래서이 질문은 3 개 가지 다른 웹 사이트에 거의 24 시간 동안 최대되었습니다 하나의 진정한 대답은 이것과 관련이 없습니다. 나는 충격을 받았다. 하위 프로세스로 스크립트를 실행 한 다음 출력을 stdout으로 파이핑했습니다. 작동했습니다 :

import subprocess 
proc = subprocess.Popen(['python','tail_try.py'],stdout=subprocess.PIPE) 
for line in iter(proc.stdout.readline, ''): 
     print line 

인쇄 된 모든 줄의 출력을 제어 할 수 있습니다. proc.stdout.readline.

정말 간단한 대답입니다.

2

저는 paramiko-expect의 저자입니다.

내 모듈의 0.2에서 새로운 기능을 구현했습니다. 꼬리 메서드에 대한 콜백을 지정하여 원하는대로 현재 줄을 처리 할 수 ​​있습니다. 출력을 grep하거나 표시하기 전에 더 처리 할 수 ​​있습니다. 콜백 함수는 현재 줄을 조작 한 후에 sys.stdout.write로 보낼 문자열을 반환합니다.

import traceback 
import paramiko 
from paramikoe import SSHClientInteraction 


def process_tail(line_prefix, current_line): 
    if current_line.startswith('hello'): 
     return current_line 
    else: 
     return '' 


def main(): 

    # Set login credentials and the server prompt 
    hostname = 'localhost' 
    username = 'fots' 
    password = 'password123' 
    port = 22 

    # Use SSH client to login 
    try: 

     # Create a new SSH client object 
     client = paramiko.SSHClient() 

     # Set SSH key parameters to auto accept unknown hosts 
     client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 

     # Connect to the host 
     client.connect(hostname, port, username, password) 

     # Create a client interaction class which will interact with the host 
     interact = SSHClientInteraction(client, timeout=10, display=False) 

     # Send the tail command 
     interact.send('tail -f /home/fots/something.log') 

     # Now let the class tail the file for us 
     interact.tail(line_prefix=hostname+': ', callback=process_tail) 

    except KeyboardInterrupt: 
     print 'Ctrl+C interruption detected, stopping tail' 
    except Exception: 
     traceback.print_exc() 
    finally: 
     try: 
      client.close() 
     except: 
      pass 

if __name__ == '__main__': 
    main() 
+0

니스! 프로그래밍 방식으로 꼬리를 멈추는 적절한 방법은 무엇입니까? 콜백에서 예외를 발생 시키시겠습니까? – monkut

+0

@monkut 좋은 질문입니다. 당분간, tail 함수에서 while 루프를 인터럽트하기위한 예외를 발생시키는 유일한 방법이있을 것이다.그러나 그렇게하면 연결을 종료해야합니다. 나는 조금 더 우아하게 구현할 수 있다고 생각하지만, 예외를 발생시키지 않으면 작동하지 않는 https://github.com/fgimian/paramiko-expect/issues에서 문제를 만들 수 있습니다. 잘 충분하다 :) –

+0

추신 : 필자는 paramiko expect를 쓸 때 꼬리 기능에 대한 꽤 특별한 사용 사례를 가졌고 모든 것이 stdout에 쓰여지는 것을 끝낸다. 그러나 사람들이 하나 이상의 원격 서버에서 파일의 출력을 실시간으로 처리 할 수 ​​있도록 문제를 피하는 방법을보고 싶다면 문제를 제기하십시오. 정말 훌륭한 아이디어라고 생각합니다. 처음에는 모듈을 작성할 때 제가하고 있었던 것이 아닙니다. –