Я пишу класс-оболочку для использования с менеджером рабочего процесса. Я хотел бы зарегистрировать вывод из приложения (дочерний процесс, выполняемый через subprocess.Popen
) определенным образом:
stdout
ребенка должны перейти в файл журнала и stdout
родителя,
stderr
ребенка должен перейти в другой лог-файл, но также stdout
родителя.
т.е. все выходные данные дочернего элемента должны быть объединены в stdout
(как в случае subprocess.Popen(..., stderr=subprocess.STDOUT)
, поэтому я могу зарезервировать stderr
для сообщений журнала от самой оболочки. С другой стороны, дочерние потоки должны идти в разные файлы, чтобы отдельная проверка.
Я пытался использовать вспомогательный класс "Tee", чтобы связать два потока (stdout
и файл журнала) вместе, чтобы Tee.write
записывал в оба потока. Однако, это не может быть передано Popen
, потому что «подпроцесс» использует функции уровня ОС для записи (см. Здесь: http://bugs.python.org/issue1631).
Проблема с моим текущим решением (фрагмент кода ниже, адаптированный в основном из здесь ) заключается в том, что выходные данные stdout
могут отображаться не в правильном порядке.
Как я могу преодолеть это? Или я должен использовать совершенно другой подход?
(Если я придерживаюсь приведенного ниже кода, как выбрать значение для количества байтов в os.read
?)
import subprocess, select, sys, os
call = ... # set this
process = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
logs = {process.stdout: open("out.log", "w"), process.stderr: open("err.log", "w")}
done = {process.stdout: False, process.stderr: False}
while (process.poll() is None) or (not all(done.values())):
ready = select.select([process.stdout, process.stderr], [], [])[0]
for stream in ready:
data = os.read(stream.fileno(), 1)
if data:
sys.stdout.write(data)
logs[stream].write(data)
else:
done[stream] = True
logs[process.stdout].close()
logs[process.stderr].close()
Кстати, это решение с использованием "fcntl" у меня не сработало. И я пока не мог понять, как адаптировать это решение к моему делу, поэтому я не пробовал.