How to redirect output of systemd service to a file
I’m voting to close this question because From the tag: systemd questions should be for programming questions using systemd or its libraries. Questions about configuring the daemon (including writing unit files) are better directed to Unix & Linux: unix.stackexchange.com. Please delete this.
I would agree with Rob if the question was new, but it’s been around for 7 years and has several highly upvoted answers; it’s too late to delete it now imo.
10 Answers 10
I think there’s a more elegant way to solve the problem: send the stdout/stderr to syslog with an identifier and instruct your syslog manager to split its output by program name.
Use the following properties in your systemd service unit file:
StandardOutput=syslog StandardError=syslog SyslogIdentifier= # without any quote
Then, assuming your distribution is using rsyslog to manage syslogs, create a file in /etc/rsyslog.d/.conf with the following content:
if $programname == '' then /path/to/log/file.log & stop
Now make the log file writable by 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
Restart rsyslog ( sudo systemctl restart rsyslog ) and enjoy! Your program stdout/stderr will still be available through journalctl ( sudo journalctl -u ) but they will also be available in your file of choice.
Not working for me on Ubuntu 16.04. journalctl -u still works but nothing gets sent to the specified file.
This works great on Debian stretch, however it complains that ~ is deprecated and stop should be used instead. Also note that the second line can be shortened to & stop if the two come after each other.
With systemd 236 or newer you can also write directly to a file using StandardOutput=file:/some/path github.com/systemd/systemd/pull/7198
I got this working by changing /etc/rsyslog.d/
I had problem using this configuration until I found that rsyslog has its own user syslog and it has to have write access to the logs location. So use chown accordingly. Hope this helps somebody.
If you have a newer distro with a newer systemd ( systemd version 236 or newer), you can set the values of StandardOutput or StandardError to file:YOUR_ABSPATH_FILENAME .
In newer versions of systemd there is a relatively new option (the github request is from 2016 ish and the enhancement is merged/closed 2017 ish) where you can set the values of StandardOutput or StandardError to file:YOUR_ABSPATH_FILENAME . The file:path option is documented in the most recent systemd.exec man page.
This new feature is relatively new and so is not available for older distros like centos-7 (or any centos before that).
Thanks, you said very clear. I just can not believe the systemd in ubuntu 1604 can not redirect output to a file just by config.I have to use the sh way to solve this problem.
@bronzeman the feature request wasn’t closed until 2017, while Ubuntu 16.04 came out in 2016. In a given major release of Ubuntu (e.g. 16.04, 16.10, 17.04, etc.), Ubuntu maintains ABI compatibility in its core system packages. So they won’t upgrade systemd (or the Linux kernel, or glibc, or anything) unless it maintains the same ABI as when the Ubuntu version was first released.
FWIW: I’ve searched a bit but this feature doesn’t appear to have provisions for log rotation, such as function to reopen the log file, with one having to use the likes of copytruncate in logrotate .
I would suggest adding stdout and stderr file in systemd service file itself.
As you have configured it should not like:
StandardOutput=/home/user/log1.log StandardError=/home/user/log2.log
StandardOutput=file:/home/user/log1.log StandardError=file:/home/user/log2.log
This works when you don’t want to restart the service again and again.
This will create a new file and does not append to the existing file.
StandardOutput=append:/home/user/log1.log StandardError=append:/home/user/log2.log
NOTE: Make sure you create the directory already. I guess it does not support to create a directory. This feature was introduced in systemd 240, but backported to earlier versions on e.g. RHEL8.
For me the file: route works on the first load of the service, but on subsequent restarts it no longer writes to the file. I tried append: from the docs and that didn’t work at all.
Note that the docs make clear that file: writes to the start of the file every time, and does not truncate. further, append: seems to be a new addition (i.e. not present in the man systemd.exec page on Ubuntu 18.04).
append: has been introduced in systemd version 240. To work around file: placing new log output at the beginning of the target file, something like this may help: ExecStartPre=/bin/bash -c ‘mv /var/log/my/logs.log /var/log/my/$$(date +%%T)-logs.log’ . Keeps a clean log and emulates log rotation effect in a way
For anybody curious, Ubuntu 20.04 currently has systemd version 245, while Ubuntu 18.04 has 237. So unfortunately you have to have 20.04 to use append: .
You possibly get this error:
Failed to parse output specifier, ignoring: /var/log1.log
From the systemd.exec(5) man page:
StandardOutput=
Controls where file descriptor 1 (STDOUT) of the executed processes is connected to. Takes one of inherit , null , tty , journal , syslog , kmsg , journal+console , syslog+console , kmsg+console or socket .
The systemd.exec(5) man page explains other options related to logging. See also the systemd.service(5) and systemd.unit(5) man pages.
Or maybe you can try things like this (all on one line):
ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log'
Among the options, logging into the systemd journal is recommend. You view just the logs for your process in the journal by using journalctl -u your-unit-name .
To specify a file, there’s another cleaner option, as indicated by the documentation: 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»).
Awsome answer, it’s solved my problem. I just want to extend, because currently if the service restart overwrite the old logs, have to replace this part: 2>&1 > /var/log.log to this: 2>&1 >> /var/log.log . Thank you
«/bin/sh» is a great workaround, but you MUST use «exec», otherwise the service will not restart properly as SIGTERM will not get passed to the child process. See veithen.io/2014/11/16/sigterm-propagation.html
If for a some reason can’t use rsyslog, this will do: ExecStart=/bin/bash -ce «exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1»
The only solution that worked in my case for not losing the log file at every service restart as append is not available in my current systemd version unfortunately.
@Lamp, I doubt you still need this but I was also curious about the -e option in bash. I found this: stackoverflow.com/a/41760745/5033594
StandardOutput=file:/var/log1.log StandardError=file:/var/log2.log
If you don’t want the files to be cleared every time the service is run, use append instead:
StandardOutput=append:/var/log1.log StandardError=append:/var/log2.log
Super helpful. I used this technique to restore logging to /var/log/tomcatX/catalina.out for Ubuntu 18.04 and 20.04.
Wrong about «file». Read the docs about what that does. It’s «truncate» mode that actually does: . cleared every time the service is run Also, there is no reason to specify StandardError as you do here, since default behavior is for the error stream to inherit the stream set up by StandardOutput.
It does log trancating based on size automatically with this. Is there a way to change that? I don’t seem to see anyone talking about that.
We are using Centos7, spring boot application with systemd. I was running java as below. and setting StandardOutput to file was not working for me.
ExecStart=/bin/java -jar xxx.jar -Xmx512-Xms32M
Below workaround solution working without setting StandardOutput. running java through sh as below.
ExecStart=/bin/sh -c 'exec /bin/java -jar xxx.jar -Xmx512M -Xms32M >> /data/logs/xxx.log 2>&1'
-1 for defining jvm parameters in wrong order. -Xmx512M must be defined before -jar . Also what you experience is expected. Systemd does not invoke services using shell
@SamiKorhonen, I added my comments after testing this is working. Even I was thinking about order of -Xmx512M is smilar to you. Please test before adding blind comments.
Assume logs are already put to stdout/stderr, and have systemd unit’s log in /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 mt24">)" data-controller="se-share-sheet" data-se-share-sheet-title="Share a link to this answer" data-se-share-sheet-subtitle="" data-se-share-sheet-post-type="answer" data-se-share-sheet-social="facebook twitter devto" data-se-share-sheet-location="2" data-se-share-sheet-license-url="https%3a%2f%2fcreativecommons.org%2flicenses%2fby-sa%2f4.0%2f" data-se-share-sheet-license-name="CC BY-SA 4.0" data-s-popover-placement="bottom-start">Share)" title="">Improve this answeranswered Jun 30, 2018 at 16:21 Hieu HuynhHieu Huynh9859 silver badges17 bronze badges