Почему функции print () и logger передаются на консольные выходы в неожиданном порядке? - PullRequest
1 голос
/ 06 апреля 2019

Я пытаюсь использовать функцию печати до и после использования двух объектов логгера, которые будут передавать вывод на консоль.Дело в том, что я получаю действительно грязный вывод, который не в ожидаемом порядке.

Я попытался изменить print () на logger_object.info (), и он работает хорошо, как и предполагалось.

Полный код с неожиданным выводом:

import logging

# Create logger objects and set  level
loggerA = logging.getLogger()
loggerA.setLevel(logging.DEBUG)

loggerB = logging.getLogger()
loggerB.setLevel(logging.DEBUG)

# Set log output format
log_format = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s', datefmt='%m/%d/%Y - %I:%M:%S %p')

# Create a console stream handler
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(log_format)

# Add handlers to the loggers
loggerA.addHandler(stream_handler)
loggerB.addHandler(stream_handler)


def main():
    for i in range(10):
        print('Starting loop number {}'.format(i))
        loggerA.info("loop number {}".format(i))
        loggerB.info("loop number {}".format(i))
        print('Finished loop number {}'.format(i))

if __name__ == '__main__':
    main()

Добавление объекта loggerC для замены print () на loggerC.info ():

...
loggerC = logging.getLogger()
loggerC.setLevel(logging.DEBUG)
...
def main():
    for i in range(10):
        loggerC('Starting loop number {}'.format(i))
        loggerA.info("loop number {}".format(i))
        loggerB.info("loop number {}".format(i))
        loggerC('Finished loop number {}'.format(i))
...

Первый случай с использованием print () неожиданныйвывод:

04/06/2019 - 10:10:34 AM - INFO - loggerA - loop number 1
Starting loop number 1
04/06/2019 - 10:10:34 AM - INFO - loggerB - loop number 1
04/06/2019 - 10:10:34 AM - INFO - loggerA - loop number 2
04/06/2019 - 10:10:34 AM - INFO - loggerB - loop number 2
Finished loop number 1
Starting loop number 2
Finished loop number 2
Starting loop number 3
Finished loop number 3
04/06/2019 - 10:10:34 AM - INFO - loggerA - loop number 3
04/06/2019 - 10:10:34 AM - INFO - loggerB - loop number 3

Во втором случае вместо функции print () используется loggerC.info (), что является ожидаемым выводом:

04/06/2019 - 10:12:21 AM - INFO - loggerC - Starting loop number 1
04/06/2019 - 10:12:21 AM - INFO - loggerA - loop number 1
04/06/2019 - 10:12:21 AM - INFO - loggerB - loop number 1
04/06/2019 - 10:12:21 AM - INFO - loggerC - Finished loop number 1
04/06/2019 - 10:12:21 AM - INFO - loggerC - Starting loop number 2
04/06/2019 - 10:12:21 AM - INFO - loggerA - loop number 2
04/06/2019 - 10:12:21 AM - INFO - loggerB - loop number 2
04/06/2019 - 10:12:21 AM - INFO - loggerC - Finished loop number 2
04/06/2019 - 10:12:21 AM - INFO - loggerC - Starting loop number 3
04/06/2019 - 10:12:21 AM - INFO - loggerA - loop number 3
04/06/2019 - 10:12:21 AM - INFO - loggerB - loop number 3
04/06/2019 - 10:12:21 AM - INFO - loggerC - Finished loop number 3

1 Ответ

1 голос
/ 06 апреля 2019

Вы, вероятно, проблема стандартных потоков . По умолчанию print использует std::out, а logger.info использует std::err. Оба потока связаны с вашим терминалом , но они могут иметь различные flush обновления или триггеры.

Вот почему ваши выходы смешиваются, функции записывают в разные потоки, и они выводятся по-разному на терминал, что приводит к очевидному противоречивому результату.

Изменение вашего первого кода, чтобы logger.info использовал тот же поток, что и print, решило вашу проблему:

import sys
stream_handler = logging.StreamHandler(sys.stdout)

Теперь он возвращает правильный вывод:

-- Starting loop number 0
04/06/2019 - 07:41:34 AM - INFO - root - loop number 0
04/06/2019 - 07:41:34 AM - INFO - root - loop number 0
-- Finished loop number 0
-- Starting loop number 1
04/06/2019 - 07:41:34 AM - INFO - root - loop number 1
04/06/2019 - 07:41:34 AM - INFO - root - loop number 1
-- Finished loop number 1
-- Starting loop number 2
04/06/2019 - 07:41:34 AM - INFO - root - loop number 2
04/06/2019 - 07:41:34 AM - INFO - root - loop number 2
-- Finished loop number 2
-- Starting loop number 3
04/06/2019 - 07:41:34 AM - INFO - root - loop number 3
04/06/2019 - 07:41:34 AM - INFO - root - loop number 3
-- Finished loop number 3

Поскольку и print, и logger.info подают один и тот же поток в правильном порядке всякий раз, когда он сбрасывается на ваш терминал, результат правильный.

Вы также можете сохранить различных потоков и принудительно заставить std::out поток очищаться явно :

def main():
    for i in range(10):
        print('-- Starting loop number {}'.format(i))
        # Force std::out stream (fed by print) to be flushed to the terminal
        # before logger feeds std::err and also flushes
        sys.stdout.flush() 
        loggerA.info("loop number {}".format(i))
        loggerB.info("loop number {}".format(i))
        print('-- Finished loop number {}'.format(i))
        sys.stdout.flush()

Эта вторая версия также дает ожидаемый результат.

Также помните, что logger по определению поточно-безопасен , но print нет. Если вы собираетесь создать модуль с использованием потока, для отслеживания выполнения используйте только logger.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...