如何从 Raspbian 上的 systemd 服务正确重定向 stdout/stderr?

How do I properly redirect stdout/stderr from a systemd service on Raspbian?

我使用 systemd 在 Raspbian (Jessie) 上设置了一项服务,使其在启动后启动。守护程序配置如下所示:

[Unit]
After=multi-user.target

[Service]
Type=idle
User=root
ExecStart=/bin/sh -c "exec /home/pi/sources/mydaemon.py >> /home/pi/mydaemon.log 2>&1"

[Install]
WantedBy=multi-user.target

重定向 >> 无效。我已经尝试了 StandardOutputStandardError 可用的大部分选项,但它们永远不会最终将我的脚本输出打印到 /var/log/daemon.log 并且 journalctl -u mydaemon.service 仅显示有关服务的消息正在启动和停止。

目前我没有对脚本中的文件描述符做任何有趣的事情。我只希望我的 print()logging.info() 语句出现在我可以阅读的地方。有什么想法吗?

(需要说明的是,守护进程确实必须 运行 作为 root。这可能与我的打印问题有关吗?)

通常你只是直接 运行 一个服务(确保它的可执行文件有一个 shebang 行):

 ExecStart=/home/pi/sources/mydaemon.py

并使用 StandardOutput= 的默认重定向到 systemd 日志,因此您可以使用 journalctl -u mydaemon.service 阅读日志。

Systemd 很好地为您控制日志的文件增长和文件轮换。

您的服务 运行 与 root 无关。

如果您没有看到上述任何日志输出,还请检查整个日志以查找附近可能归因于您的服务的日志:

 journalctl

这是必要的,因为存在一个已知问题,即脚本存在之前的最后几行日志记录可能不归因于该脚本。这对于在退出前仅 运行s 几分之一秒的脚本尤其明显。

我需要 运行 python 使用 -u 参数来确保消息没有被缓冲。

使用这些行,打印行会立即添加到日志中:

StandardOutput=journal+console
ExecStart=/home/pengman/scripts/mqtt_monitor/venv/bin/python -u home/pengman/scripts/mqtt_monitor/src/mqtt_monitor.py

(我在 virtualenv 中 运行ning,但这不重要)

@mark-stosberg 接受的答案是正确的。我想稍微扩展他的答案,但评论太短了。

systemd-journald.service 手册页在 STREAM LOGGING 部分提到了这一点:

The systemd service manager invokes all service processes with standard output and standard error connected to the journal by default. This behaviour may be altered via the StandardOutput=/StandardError= unit file settings, see systemd.exec(5) for details.

所以在@eric 的原始单元文件中,为了得到 /home/pi/mydaemon.log 的输出,你可以在单元文件中这样做

ExecStart=/usr/bin/python -u /home/pi/sources/mydaemon.py
StandardOutput=file:/home/pi/mydaemon.log
StandardError=inherit

记下 StandardError 的值。这来自 systemd.exec(5) 联机帮助页,它意味着将 stderr 挂接到与 stdout 相同的句柄,很像 2>&1 在 shell 语法中。

此外,如果您希望日志立即更新,您必须告诉 Python 不要缓冲输出(使用它的 -u 开关)。这也是我更改 ExecStart= 的原因。流式传输 python 输出时 (whether in systemd or from the shell) the output is buffered by default 并且在缓冲区刷新或进程结束之前不会更新文件。


更新 20190411 - Raspbian 的早期版本的 systemd 不接受 StandardOutputfile:/ 目标(感谢@nak 指出这一点),所以我的回答没有关于 Raspbian(我在 openSUSE Tumbleweed 中测试过)对于 OP 问题并没有真正起作用。 详细介绍了使用旧版 systemd 执行此操作的替代方法。

我遇到了同样的问题。
使用 StandardOutput=journal+console 解决。