如何通过Python记录到journald(systemd)?

40
我希望logging.info()日志记录输出到journald (systemd)。

到目前为止,我只找到了读取journald的Python模块(不是我想要的),或者像这样工作的模块:journal.send('Hello world')

4个回答

50

python-systemd库提供了一个JournalHandler,可以与日志框架一起使用。

从文档中得知:

import logging
from systemd.journal import JournalHandler

log = logging.getLogger('demo')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)
log.info("sent to journal")

1
你能帮忙看一下这个吗:http://stackoverflow.com/questions/40748156/python3-journal-logging-does-not-show-log-level? - user180574
1
从systemd.journal导入JournalHandler出现错误,改为: 从systemd导入journal import logginglogging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() logger.addHandler(journal.JournaldLogHandler()) - alireza
1
有没有办法设置“单位”?这是一个非常严重的限制。 - Federico
3
@Federico 我找不到设置单位的方法,但是你可以使用 JournalHandler(SYSLOG_IDENTIFIER=<id>) 进行操作,然后 <id> 会被用作相应日志条目中的单位/ID字段(如果您不设置这个,则默认使用文件名;请参阅源代码)。但是,这并不会创建一个 <id> 单位,所以 journalctl -u <id> 不会产生任何输出。但是,您可以使用 journalctl SYSLOG_IDENTIFIER=<id> 来过滤 <id> 消息。 - ntc2
1
请注意,令人困惑的是,pypi上的软件包名称实际上是systemd-python而不是python-systemd。 - Eskander Bejaoui
JournalHandler已更名为JournaldLogHandler,就像其他答案中所述。 - Romain

15

一种替代官方软件包的选择是systemd软件包,它适用于Python 3.6。其源代码也可在github上找到。

该实现是官方库的镜像,有些微小的更改:

import logging
from systemd import journal

log = logging.getLogger('demo')
log.addHandler(journal.JournaldLogHandler())
log.setLevel(logging.INFO)
log.info("sent to journal")

或者使用更加简短的方法:

from systemd import journal

journal.write("Hello Lennart")

@Rob,我不确定你的系统出了什么问题,但这绝对是有效的。我创建了一个简单的示例Vagrantfile,它将启动一个带有Python 3.5的系统,安装systemd包,并执行示例:https://gist.github.com/schlueter/ce1f2e32ef350bfa21e1b8b8605711b6。 - bschlueter
官方软件包广泛可用且建议使用。 - Federico
@Federico 我并没有表达是否使用它的观点,这只是我遇到的一个选项。 - bschlueter
@bschlueter澄清:这是systemd推荐的。 - Federico
在我的系统上,journal.write() 不存在,但 journal.send("Hello Lennart") 可以工作! - carloslockward
显示剩余3条评论

5
这是一个没有第三方模块的解决方案。 它适用于我,并且消息会出现在journald中。
import logging
import sys

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

# this is just to make the output look nice
formatter = logging.Formatter(fmt="%(asctime)s %(name)s.%(levelname)s: %(message)s", datefmt="%Y.%m.%d %H:%M:%S")

# this logs to stdout and I think it is flushed immediately
handler = logging.StreamHandler(stream=sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.info('test')

我的消息也会在 journald 中显示,默认情况下是使用 sys.stderr 流。 - Dominik
我喜欢简单明了的解决方案 :)) - Nacho R
无法确认,无论是使用stderr还是stdout。 - ataraxis
3
这段代码与journald无关。你可能忘记提到你将脚本作为systemd服务运行,在这种情况下,systemd会收集程序的stdout和stderr,并将其传递给journald,因此你甚至可以使用print,它最终仍将进入journald。 - Osman-pasha
是的,那是正确的。这取决于代码运行的上下文环境。 - Joe

-1
这是一种不需要第三方模块的替代解决方案。
import subprocess

data = "sent to journal"
echoCmd = ["echo", data]
sysdCat = ["systemd-cat", "-p", "info"]

echoResult = subprocess.Popen(echoCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sysdCatResult = subprocess.Popen(sysdCat, stdin=echoResult.stdout)
sysdCatResult.communicate()
```

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