Python日志在Windows上运行,但不适用于Mac OS

时间:2016-03-16 20:12:03

标签: python windows macos logging

# Logging
cur_flname = os.path.splitext(os.path.basename(__file__))[0]
LOG_FILENAME = constants.log_dir + os.sep + 'Log_' + cur_flname + '.txt'
util.make_dir_if_missing(constants.log_dir)
logging.basicConfig(filename=LOG_FILENAME, level=logging.INFO, filemode='w',
                    format='%(asctime)s %(levelname)s %(module)s - %(funcName)s: %(message)s',
                    datefmt="%m-%d %H:%M")  # Logging levels are DEBUG, INFO, WARNING, ERROR, and CRITICAL
# Output to screen
logger = logging.getLogger(cur_flname)
logger.addHandler(logging.StreamHandler())

我使用上面的代码创建一个logger,我可以在我的模块中使用它来同时将消息打印到屏幕上。

在Windows上,消息会输出到文件和屏幕。但是,在Mac OS X 10.9.5上,它们只能输出到文件。我使用的是Python 2.7。

有关如何解决此问题的任何想法?

1 个答案:

答案 0 :(得分:3)

从你的问题很清楚,创建记录器名称没有问题, 日志文件名和记录到文件,因此我将简化此部分以保持我的代码简洁。

第一件事:对我来说,你的解决方案似乎正确logging.StreamHandler 默认情况下将输出发送到sys.stderr。你可能有一些代码(不是 在您的问题中显示),正在修改sys.stderr,或者您正在运行 以这种方式在OSX上的代码,没有显示输出到stderr(但是 真的输出)。

logging

的解决方案

将以下代码放入with_logging.py

import logging
import sys

logformat = "%(asctime)s %(levelname)s %(module)s - %(funcName)s: %(message)s"
datefmt = "%m-%d %H:%M"

logging.basicConfig(filename="app.log", level=logging.INFO, filemode="w",
                    format=logformat, datefmt=datefmt)

stream_handler = logging.StreamHandler(sys.stderr)
stream_handler.setFormatter(logging.Formatter(fmt=logformat, datefmt=datefmt))

logger = logging.getLogger("app")
logger.addHandler(stream_handler)

logger.info("information")
logger.warning("warning")


def fun():
    logger.info(" fun inf")
    logger.warning("fun warn")

if __name__ == "__main__":
    fun()

运行它:$ python with_logging.py,您将看到预期的日志记录(格式正确) 在日志文件app.logstderr上。

请注意,如果您在stderr上没有看到它,则会隐藏您的stderr 输出。要查看内容,请将StreamHandler流更改为sys.stdout

logbook

的解决方案

logbook是python包,提供替代日志记录方法。我在这里展示它以显示主要内容 与stdlib logging的区别:对于logbook,使用和配置对我来说似乎更简单。

先前的解决方案已重写为with_logbook.py

import logbook
import sys

logformat = ("{record.time:%m-%d %H:%M} {record.level_name} {record.module} - "
             "{record.func_name}: {record.message}")
kwargs = {"level": logbook.INFO, "format_string": logformat, "bubble": True}

logbook.StreamHandler(sys.stderr, **kwargs).push_application()
logbook.FileHandler("app.log", **kwargs).push_application()

logger = logbook.Logger("app")

logger.info("information")
logger.warning("warning")


def fun():
    logger.info(" fun inf")
    logger.warning("fun warn")

if __name__ == "__main__":
    fun()

主要区别在于,您不必将处理程序附加到记录器,您的记录器只会发出 一些日志记录。

这些记录将由处理程序处理,如果它们已经到位。一种方法 是创建一个处理程序并在其上调用push_application()。这将把 处理程序进入使用中的处理程序堆栈。

和以前一样,我们需要两个处理程序,一个用于文件,另一个用于stderr。

如果您运行此脚本$ python with_logbook.py,您将看到完全相同的结果 记录。

从模块代码中分离日志记录设置:short_logbook.py

使用stdlib logging我真的不喜欢介绍性的舞蹈来使记录器工作。我想要 只需发出一些日志记录,并希望尽可能简单地做到这一点。

以下示例是对前一个示例的修改。而不是设置 在模块的最开头登录,我是在代码运行之前完成的 - 在if __name__ == "__main__"内(你可以在任何其他方面做同样的事情 位)。

出于实际原因,我将模块和调用代码分成两个文件:

档案funmodule.py

from logbook import Logger

log = Logger(__name__)

log.info("information")
log.warning("warning")


def fun():
    log.info(" fun inf")
    log.warning("fun warn")

您可以注意到,实际上只有两行与制作相关 可用的记录。

然后,创建调用代码,放入short_logbook.py

import sys
import logbook

if __name__ == "__main__":
    logformat = ("{record.time:%m-%d %H:%M} {record.level_name} {record.module}"
                 "- {record.func_name}: {record.message}")
    kwargs = {"level": logbook.INFO, "format_string": logformat, "bubble": True}

    logbook.StreamHandler(sys.stderr, **kwargs).push_application()
    logbook.FileHandler("app.log", **kwargs).push_application()

    from funmodule import fun
    fun()

运行代码,您将看到它与以前一样工作,只有记录器名称为funmodule

请注意,我在设置日志记录后执行了from funmodule import fun。如果我做了 如果short_logbook.py文件为top,则不会显示funmodule.py中的前两个日志记录 因为它们在模块导入期间发生。

编辑:添加了另一个logging解决方案以进行公平比较

还有一个stdlib logging解决方案

尝试对logbooklogging进行公平比较我将最终logbook示例重写为 logging

funmodule_logging.py看起来像:

import logging

log = logging.getLogger(__name__)

log.info("information")
log.warning("warning")


def fun():
    log.info(" fun inf")
    log.warning("fun warn")
    log.error("no fun at all")

short_logging.py如下所示:

import sys
import logging

if __name__ == "__main__":
    logformat = "%(asctime)s %(levelname)s %(module)s - %(funcName)s: %(message)s"
    datefmt = "%m-%d %H:%M"

    logging.basicConfig(filename="app.log", level=logging.INFO, filemode="w",
                        format=logformat, datefmt=datefmt)

    stream_handler = logging.StreamHandler(sys.stderr)
    stream_handler.setFormatter(logging.Formatter(fmt=logformat, datefmt=datefmt))

    logger = logging.getLogger("funmodule_logging")
    logger.addHandler(stream_handler)

    from funmodule_logging import fun
    fun()

功能非常相似。

我仍然记录着日志。 stdlib logging不容易掌握,但它在stdlib并提供 一些很好的东西,比如logging.config.dictConfig允许通过字典配置日志记录。 logbook开始时要简单得多,但目前有点慢,缺乏 dictConfig。无论如何,这些差异与您的问题无关。