Я создал класс по запросу, который можно запустить для сбора любых новых данных, записанных в файл из start_recording
звони, пока stop_recording
которые закрывают соединение и извлекают собранные данные.
Он используется в тестовых примерах для получения соответствующих журналов во время выполнения определенной операции, чтобы проверить ее успешность.
В настоящее время я использую этот класс для тестов на удаленной машине, но был бы рад услышать любые идеи по улучшению, правильности и т. Д.
import time
import paramiko
import select
from virtual_machine import utils
from multiprocessing import Queue
import multiprocess
class background():
def __init__(self, config_file):
self.q = Queue(1000)
#this methods implemented elsewhere and read a config file into dictionary
self.config = utils.get_params(config_file)
@staticmethod
def linesplit(socket):
buffer_string = socket.recv(4048).decode('utf-8')
done = False
while not done:
if 'n' in buffer_string:
(line, buffer_string) = buffer_string.split('n', 1)
yield line + "n"
else:
more = socket.recv(4048)
if not more:
done = True
else:
buffer_string = buffer_string + more.decode('utf-8')
if buffer_string:
yield buffer_string
def do_tail(self, log_file):
data = ""
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
from os.path import expanduser
home = expanduser("~")
client.connect(self.config["ip"],self.config["username"],self.config["password"])
grep_pattern = "grep_filter"
remote_command = 'tail -0 -f {} '.format(log_file)
print(remote_command)
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command(remote_command)
while 1:
try:
rl, _, _ = select.select([channel], [], [], 0.0)
if len(rl) > 0:
print("ready to read")
for line in background.linesplit(channel):
self.q.put_nowait(line)
except (KeyboardInterrupt, SystemExit):
print('got ctrl+c')
break
client.close()
return data
def start_recording(self, log_file):
q = Queue(100)
self.p = multiprocess.Process(target=self.do_tail, args=(log_file,), daemon=True)
self.p.start()
def stop_recording(self):
self.p.terminate()
data = ""
while not self.q.empty():
data += self.q.get()
return data
#example
if __name__ == '__main__':
x = background("config.conf")
x.start_recording("/tmp/logfile.log")
# doing some operation
data = x.stop_recording()
print(data)
1 ответ
Ваш linesplit
немного повторяет код; Вы могли бы сформулировать это как
while True:
buffer_bytes = socket.recv(4096)
if len(buffer_bytes) == 0:
break
buffer_string = buffer_bytes.decode('utf-8')
*lines, buffer_string = buffer_string.split('n')
yield from lines
'tail -0 -f {} '.format(log_file)
может быть просто 'tail -0 -f ' + log_file
.
background
должно быть Background
.
Подумайте о добавлении подсказок типа PEP484.
rl, _, _ = select ...
возможно
rl, *_ = select ...
Код между paramiko.SSHClient()
и client.close()
не имеет закрытой гарантийной защиты. Есть разные варианты, в том числе try
/finally
или сделать ваш текущий класс (или выделенный класс, специфичный для хвоста) диспетчером контекста.
Спасибо за ваши комментарии. Кстати, я столкнулся с тем, что запись журнала отставала, а где это произошло, интересная часть уже закончилась. Интересно, есть ли какая-то системная блокировка, которая может заблокировать
start_recording
от возврата, пока подпроцесс не достигнетready to read
линия. Вы можете что-нибудь порекомендовать? Благодарность !— Зохар81