python - 为什么 print() 和 logger 对象以意外的顺序流式传输到控制台输出?

标签 python logging python-logging

我尝试在使用两个记录器对象之前和之后使用打印函数,将输出流式传输到控制台。 问题是我得到的输出非常困惑,不符合预期的顺序。

我尝试将 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 对象以用 loggerC.info() 替换 print() :

...
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

第二种情况使用 loggerC.info() 而不是 print(),这是预期的输出:

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

最佳答案

您的问题可能是 standard streams 的问题。默认情况下,print 使用std::outlogger.info 使用std::err。两个流are bound to your terminal但它们可能有不同的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

因为 printlogger.info 每当将其刷新到终端时都会以正确的顺序提供相同的流,因此结果是正确的。

您还可以保留different streams并强制 std::out 流为 flushed explicitly :

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的定义是thread-safeprint 不是。如果您要使用线程创建模块,只需使用logger来跟踪执行情况。

关于python - 为什么 print() 和 logger 对象以意外的顺序流式传输到控制台输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55546757/

相关文章:

python - 在项目本地安装 Python 依赖

php - 寻找一个 PHP 类来解析 access.log 文件

.net - 自定义异常类型是 'self logging' - 这很糟糕吗?

python - pip 安装 ortools : No matching distribution - Alpine

python - VIM/Python 无法向 VIM 返回值

python - 在同一轴上绘制多个标签

python - 如何将自定义日志级别添加到 Python 的日志记录工具

java - Logback native VS 通过 SLF4J 的 Logback

python - "()"在 python 日志配置中做什么

python - 登录 Python/Django 未按预期工作