Jupyter notebook不会将日志打印到输出单元格

21

我目前正在使用 Jupyter 笔记本,并希望强制它将 Python 日志打印到输出单元格。

我正在使用旧版笔记本,可能是在旧版本的 Jupyter 笔记本中运行。

我的日志设置如下:

import logging
logging.basicConfig(format='%(levelname)s : %(message)s', level=logging.INFO)
logging.root.level = 20

但是当我接着调用:

logging.info("hello world")

它不会在输出单元格中打印任何内容。它只会在我启动 Jupyter 笔记本的控制台中打印出东西。

我正在使用 python 2.7.10,并且在我的虚拟环境中安装了以下软件包:

appnope==0.1.0
backports-abc==0.4
backports.ssl-match-hostname==3.5.0.1
certifi==2016.2.28
decorator==4.0.9
functools32==3.2.3.post2
gnureadline==6.3.3
ipykernel==4.3.1
ipython==4.1.2
ipython-genutils==0.1.0
ipywidgets==4.1.1
Jinja2==2.8
jsonschema==2.5.1
jupyter==1.0.0
jupyter-client==4.2.2
jupyter-console==4.1.1
jupyter-core==4.1.0
MarkupSafe==0.23
mistune==0.7.2
nbconvert==4.1.0
nbformat==4.0.1
notebook==4.1.0
path.py==8.1.2
pexpect==4.0.1
pickleshare==0.6
ptyprocess==0.5.1
Pygments==2.1.3
pyzmq==15.2.0
qtconsole==4.2.0
simplegeneric==0.8.1
singledispatch==3.4.0.3
six==1.10.0
terminado==0.6
tornado==4.3
traitlets==4.1.0
wheel==0.24.0

记录单元格中的打印输出是否已更改?有没有什么方法可以强制 Jupyter 将日志写入输出单元格?


@MikeMüller 4.0.1 版本是哪个包的?ipython 吗? - ziky90
1
是的,IPython 和 Jupyter 1.0.0 在 Python 3.5 上。 - Mike Müller
谢谢,我已经尝试安装ipython 4.0.1,但问题仍然存在。 - ziky90
1
检查 sys.stderr 是什么。应该是 <ipykernel.iostream.OutStream at ....> - Mike Müller
1
在我的情况下,sys.stderr<ipykernel.iostream.OutStream at 0x1079e9e10>,看起来是正确的。 - ziky90
显示剩余3条评论
6个回答

12
之前的答案似乎已经不再适用了。最完整的答案已经不再适用,因为没有默认处理程序,因此修改零号处理程序将无法使用。此外,在笔记本中运行时操纵根记录器似乎存在潜在风险。
要使“foo”记录器将其输出放入单元格中,请执行以下操作:
logger = logging.getLogger("foo")
logger.addHandler(logging.StreamHandler(stream=sys.stdout))

因此,您需要自己添加处理程序,并将其输出定向到指定的位置。


谢谢。这是唯一对我有效的解决方案。在我的情况下,更奇怪的是,如果我创建一个新的Jupyter笔记本,并且与无法工作的那个具有完全相同的配置以及完全相同的记录器和日志配置,则记录器实际上是有效的。但是,在我的旧笔记本中,我确实需要它打印。 - alelom

7

希望jupyter的开发者们能够修复这个问题。但是,我找到了一个临时的解决方法供您使用。似乎新版本的jupyter notebook不会在notebook中显示stderr,而是将其发送到终端。但是,它们仍然会打印stdout。您可以将根记录器的处理程序设置为stdout:

import logging
import sys

# Get root logger (all other loggers will be derived from this logger's
# properties)
logger = logging.getLogger()
logger.warning("I will output to terminal")  # No output in notebook, goes to terminal

# assuming only a single handler has been setup (seems 
# to be default in notebook), set that handler to go to stdout.
logger.handlers[0].stream = sys.stdout

logger.warning("FOO")  # Prints: WARNING:root:FOO

# Other loggers derive from the root logger, so you can also do:
logger2 = logging.getLogger("logger2")
logger2.warning("BAR")  # Prints: WARNING:logger2:BAR

如果您将此放置在笔记本的顶部,此更改应该传播到您导入的模块中初始化的任何记录器,因为通常记录器将继承根记录器的设置。

2
以上代码对我无效(Python 3.6.8)。我的记录器没有任何处理程序附加到它上面,因此尝试设置第零个流只会导致数组引用错误。 - Robert P. Goldman
现在它不会保存到文件了。 - MehmedB

3

这里提出的所有解决方法都对我没用,但下面这个方法有效,希望能帮到其他人。

使用 python 3.4.3、jupyter-client==4.1.1 和 jupyter-core==4.0.6。

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

logger.info("hello")

信息:主要:你好


0

我找到了一个旧的 python 2.7.10 虚拟环境,在其中 jupyter 可以按预期工作。

appnope==0.1.0
backports.ssl-match-hostname==3.4.0.2
boto==2.38.0
bz2file==0.98
certifi==2015.9.6.2
decorator==4.0.4
functools32==3.2.3.post2
gensim==0.12.2
gnureadline==6.3.3
httpretty==0.8.6
ipykernel==4.1.1
ipython==4.0.0
ipython-genutils==0.1.0
ipywidgets==4.1.1
Jinja2==2.8
jsonschema==2.5.1
jupyter==1.0.0
jupyter-client==4.1.1
jupyter-console==4.0.3
jupyter-core==4.0.6
MarkupSafe==0.23
mistune==0.7.1
nbconvert==4.1.0
nbformat==4.0.1
notebook==4.0.6
numpy==1.10.1
path.py==8.1.2
Pattern==2.6
pexpect==4.0.1
pickleshare==0.5
ptyprocess==0.5
Pygments==2.0.2
pyzmq==14.7.0
qtconsole==4.1.0
requests==2.8.1
scipy==0.16.0
simplegeneric==0.8.1
six==1.10.0
smart-open==1.3.0
terminado==0.5
tornado==4.2.1
traitlets==4.0.0
wheel==0.24.0

有些软件包与 jupyter 问题无关,问题可能在一些相关软件包的版本上。我将进一步调查确切的位置。

编辑:

最后我发现问题出在软件包:ipykernel==4.3.1 或自 ipykernel==4.3.0 以来,使用 ipykernel==4.1.1ipykernel==4.2.2 可以正常工作。

问题已在 github 上向 jupyter 和 ipykernel 报告:https://github.com/ipython/ipykernel/issues/111


0

指定流的解决方案效果很好。如果使用dictConfig进行配置,另一种选项是将流作为参数添加。

import logging
import logging.config

logging.config.dictConfig({
    "version": 1,
    "disable_existing_loggers": True,
    "formatters": {
        "default": {
            "format": "{levelname} {asctime} | {message}",
            "style": "{",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "default",
            "stream": sys.stdout,
        }
    },
    "root": {
        "level": "DEBUG",
        "handlers": ["console"],
    },
})

0
对我来说,只需要在logging.basicConfig中设置stream参数就足够了。
import logger
import sys
logging.basicConfig(
    level=logging.DEBUG, 
    format="(%asctime)s | %(message)s", 
    stream=sys.stdout
)

之后,基本的日志输出被正确地定向到单元格下方。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接