如何将Systemd服务的输出重定向到文件


171

我正在尝试将systemd服务的输出重定向到文件,但它似乎不起作用:

[Unit]
Description=customprocess
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server
StandardOutput=/var/log1.log
StandardError=/var/log2.log
Restart=always

[Install]
WantedBy=multi-user.target

请更正我的方法。

Answers:


232

我认为有一种解决问题的更优雅的方法:将stdout / stderr发送给具有标识符的syslog,并指示syslog管理器按程序名称拆分其输出。

在systemd服务单元文件中使用以下属性:

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<your program identifier> # without any quote

然后,假设您的发行版正在使用rsyslog管理syslog,请在/etc/rsyslog.d/<new_file>.conf其中创建一个包含以下内容的文件:

if $programname == '<your program identifier>' then /path/to/log/file.log
& stop

现在,使日志文件可通过syslog写入:

# ls -alth /var/log/syslog 
-rw-r----- 1 syslog adm 439K Mar  5 19:35 /var/log/syslog
# chown syslog:adm /path/to/log/file.log

重新启动rsyslog(sudo systemctl restart rsyslog)享受!您的程序stdout / stderr仍可通过journalctl(sudo journalctl -u <your program identifier>)获得,但它们也将在您选择的文件中提供。

资料来源:archive.org


8
在Ubuntu 16.04上不适合我。journalctl -u仍然有效,但是没有任何内容发送到指定文件。
邓肯·卡尔弗特

1
这在Debian上很有效,但是它抱怨它~已被弃用,stop应该改为使用。另请注意,第二行可以缩短为& stop两者紧挨在一起。
jlh

47
对于systemd 236或更高版本,您还可以使用StandardOutput = file:/ some / path github.com/systemd/systemd/pull/7198
leezu

5
我通过将/etc/rsyslog.d/<newfile>.conf内容更改为来完成此工作: :programname, isequal, "<your program identifier>" /var/log/somelog.log 这是有关rsyslog过滤器的文档:rsyslog.com/doc/v8-stable/configuration/filters.html 这是有关以下属性的文档programnamersyslog.com/doc/master/configuration/properties .html
mbil

1
在使用该配置之前,我一直遇到问题,直到我发现该rsyslog用户拥有自己的用户syslog并且必须具有对日志位置的写权限。因此请相应地使用chown。希望这对某人有帮助。
Imaskar

73

如果您的发行版较新systemdsystemd版本236或更高),则可以将StandardOutput或的值设置StandardErrorfile:YOUR_ABSPATH_FILENAME


很长的故事:

在较新的版本中,systemd有一个相对较新的选项(github请求来自2016 ish,增强功能已合并/关闭2017 ish),您可以在其中设置StandardOutputStandardErrorfile:YOUR_ABSPATH_FILENAME。该file:path选项记录在最新的systemd.exec手册页中

此新功能是相对较新的功能,因此不适用于较旧的发行版,如centos-7(或之前的任何centos)。


10
在2018-03-20中无法在ubuntu 1604中工作。在Ubuntu 1604的systemd版本仅229
青铜人

谢谢,你说的很清楚。我只是不敢相信ubuntu 1604中的systemd不能仅通过config将输出重定向到文件。我必须使用sh方法来解决此问题。
青铜人

@bronzeman的功能请求直到2017年才关闭,而Ubuntu 16.04于2016年问世。在给定的主要Ubuntu版本(例如16.04、16.10、17.04等)中,Ubuntu在其核心系统软件包中保持ABI兼容性。因此,除非systemd(或Linux内核,glibc或其他任何东西)保持与首次发布Ubuntu版本时相同的ABI,否则他们不会升级systemd。
villapx

1
FWIW:我进行了一些搜索,但是此功能似乎没有日志轮换的规定,例如重新打开日志文件的功能,其中一个必须使用copytruncatein的类似符号logrotate
antak

48

您可能会收到此错误:

Failed to parse output specifier, ignoring: /var/log1.log

systemd.exec(5)手册页:

StandardOutput=

控制已执行进程的文件描述符1(STDOUT)连接到的位置。注意到之一inheritnullttyjournalsyslogkmsgjournal+consolesyslog+consolekmsg+consolesocket

systemd.exec(5)手册页介绍了相关记录其他选项。另请参见systemd.service(5)systemd.unit(5)手册页。

或者,您可以尝试以下操作(全部在一行上):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 

7
在这些选项中,建议登录到systemd日志。您可以使用来仅在日记中查看过程日志journalctl -u your-unit-name
Mark Stosberg '16

6
要指定文件,还有另一个更清洁的选项,如文档所示:The fd option connects the output stream to a single file descriptor provided by a socket unit. A custom named file descriptor can be specified as part of this option, after a ":" (e.g. "fd:foobar").
orion

5
极好的答案,它解决了我的问题。我只想扩展,因为当前如果服务重新启动会覆盖旧日志,则必须将以下部分替换2>&1 > /var/log.log为:2>&1 >> /var/log.log。谢谢您
南瓜种子

10
坦白说,在ExecStart中使用命令字符串调用Shell听起来像是“错误方式”。
David Tonhofer

1
“ / bin / sh”是一个很好的解决方法,但是必须使用“ exec”,否则该服务将无法正确重启,因为SIGTERM不会传递给子进程。参见veithen.io/2014/11/16/sigterm-propagation.html
丰富

33

我建议在systemd 文件本身中添加stdoutstderr文件service

引用:https : //www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

如您所配置,它不应该喜欢:

StandardOutput=/home/user/log1.log
StandardError=/home/user/log2.log

它应该是:

StandardOutput=file:/home/user/log1.log
StandardError=file:/home/user/log2.log

当您不想一次又一次地重新启动服务时,此方法有效

这将创建一个新文件,并且不会追加到现有文件中。

使用代替:

StandardOutput=append:/home/user/log1.log
StandardError=append:/home/user/log2.log

注意:请确保您已经创建目录。我猜它不支持创建目录。


5
此答案重复,但细节较少
Gert van den Berg

9
我认为,这使其更直接\更易于理解。
Rajat jain '19

1
对我而言,该file:路由在服务的首次加载时起作用,但在随后的重新启动时,它不再写入文件。我append:从文档中尝试过,但这根本没有用。
rb-

3
请注意,文档清楚地表明file:每次都写入文件的开头,并且不会截断……进一步,这append:似乎是一个新添加(即,在man systemd.execUbuntu 18.04 的页面中不存在)。
科尔

19

如果由于某种原因不能使用rsyslog,则可以这样做: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"


bash的-e选项有什么作用?

3

假设日志已经放在stdout / stderr中,并且已经有systemd单元的日志/var/log/syslog

journalctl -u unitxxx.service

Jun 30 13:51:46 host unitxxx[1437]: time="2018-06-30T11:51:46Z" level=info msg="127.0.0.1
Jun 30 15:02:15 host unitxxx[1437]: time="2018-06-30T13:02:15Z" level=info msg="127.0.0.1
Jun 30 15:33:02 host unitxxx[1437]: time="2018-06-30T13:33:02Z" level=info msg="127.0.0.1
Jun 30 15:56:31 host unitxxx[1437]: time="2018-06-30T13:56:31Z" level=info msg="127.0.0.1

Config rsyslog(系统日志记录服务)

# Create directory for log file
mkdir /var/log/unitxxx

# Then add config file /etc/rsyslog.d/unitxxx.conf

if $programname == 'unitxxx' then /var/log/unitxxx/unitxxx.log
& stop

重启rsyslog

systemctl restart rsyslog.service

1

我们正在使用带有systemd的Spring Boot应用程序Centos7。我正在如下运行Java。并将StandardOutput设置为file对我不起作用。

ExecStart=/bin/java -jar xxx.jar  -Xmx512-Xms32M

以下解决方法解决方案在不设置StandardOutput的情况下工作。通过sh如下运行java。


ExecStart=/bin/sh -c 'exec /bin/java -jar xxx.jar -Xmx512M -Xms32M >> /data/logs/xxx.log 2>&1'

在此处输入图片说明


-1用于以错误的顺序定义jvm参数。-Xmx512M必须在-jar之前定义。您的经验也值得期待。Systemd不使用Shell调用服务
Sami Korhonen

1
@SamiKorhonen,我在测试此功能后添加了我的评论。甚至我在想-Xmx512M的命令对您来说都是一个笑柄。添加盲注之前,请先进行测试。
Santhosh Hirekerur,

0

简短答案:

StandardOutput=file:/var/log1.log
StandardError=file:/var/log2.log

如果您不想每次运行该服务时都清除文件,请使用append代替:

StandardOutput=append:/var/log1.log
StandardError=append:/var/log2.log

2
此答案重复,但细节较少
rustyx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.