Python的日志logging工作在Windows上,但不是Mac OS

# 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()) 

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

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

有想法该怎么解决这个吗?

从你的问题中可以清楚地看到,创建记录器名称,日志文件名和记录到文件中没有问题,所以我将简化这个部分以保持我的代码简洁。

第一件事:对我来说你的解决方案似乎是正确的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文件, short_logbook.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。 无论如何,这些差异与你的问题无关。