Я настроил команду подпроцесса в менеджере контекста, которая направляет stdout и stderr в отдельные файлы через мой собственный регистратор.Это вариант ответа, приведенного здесь: https://stackoverflow.com/a/4838875/4844311
Мой код выглядит следующим образом:
import logging
import subprocess
with StreamLogger(logging.DEBUG, my_out_logger) as out:
with StreamLogger(logging.ERROR, my_err_logger) as err:
p = subprocess.Popen(cmd, shell=False, stdout=out, stderr=err)
p.communicate()
p.wait()
, где my_out_logger
и my_err_logger
- это записи объектов с дескрипторами, которые регистрируются вфайлы и т. д.
Код StreamLogger аналогичен коду, указанному по ссылке выше:
import io
import os
import threading
import select
import time
class StreamLogger(io.IOBase):
def __init__(self, level, logger):
self.logger = logger
self.level = level
self.pipe = os.pipe()
self.thread = threading.Thread(target=self._flusher)
self.thread.start()
def _flusher(self):
self._run = True
buf = b''
while self._run:
for fh in select.select([self.pipe[0]], [], [], 0)[0]:
buf += os.read(fh, 1024)
while b'\n' in buf:
data, buf = buf.split(b'\n', 1)
self.write(data.decode())
time.sleep(0.01)
self._run = None
def write(self, data):
return self.logger.log(self.level, data)
def fileno(self):
return self.pipe[1]
def close(self):
if self._run:
self._run = False
while self._run is not None:
time.sleep(0.01)
os.close(self.pipe[0])
os.close(self.pipe[1])
Единственное существенное отличие между моим кодом и кодом, предоставленным ответом по ссылке вышев том, что мой код отправляет сообщение регистрации в регистратор, который перенаправляет в соответствии с его дескрипторами, а не напрямую, как в коде по ссылке.
Этот код в большинстве случаев работает нормально.
Но я заметил, что очень часто появляется усеченный выходной файл журнала.Похоже, что выходной файл, записываемый FileHandler
в my_out_logger
, закрывается до того, как все содержимое стандартного вывода было записано.
Я не уверен, почему это происходит или где исправить код.Сейчас я только что добавил оператор time.sleep(0.3)
между p.communicate()
и p.wait()
, и это уменьшило частоту усеченных файлов, но это выглядит как уродливое решение.
Я бы лучше понял, что происходит не таки исправить это правильно.Я приветствую любые предложения или идеи.