How can I output logs to a file from the content of a service with systemd
Well, I have a service configured with systemctl. This is the config file:
[Unit]
Description=The description of the service (:
After=network.target
[Service]
ExecStartPre=/bin/echo 'Starting Service' >> /var/log/node/myapp.log
ExecStart=/root/.nvm/versions/node/v5.0.0/bin/node ./bin/www
ExecStopPost=/bin/echo 'Stopping Service' >> /var/log/node/myapp.log
Restart=always
#StandardOutput=/var/log/node/myapp.log
#StandardError=/var/log/node/myapp.log
SyslogIdentifier=myapp
Environment=NODE_ENV=production
WorkingDirectory=/home/user/node-apps/theapp
[Install]
WantedBy=multi-user.target
What I need?:
1) The ExecStartPre
and ExecStopPost
could write the message 'starting service'
or 'stopping service'
to the file /var/log/node/myapp.log
. With the above configuration, doesn't work, it only outputs 'Starting Service' >> /var/log/node/myapp.log
and 'Stopping Service' >> /var/log/node/myapp.log
to journalctl
. (I checked with journalctl -u myapp
)
2) I need that instead of the all logs of the app, outputs to the journalctl
, could output to a file. Ex: /var/log/node/myapp.log
. I mean, if in my app, I have a console.log()
, this could be there.
With upstart, I can do it in this way:
script
exec start-stop-daemon --start --make-pidfile --pidfile /var/run/upstart-yourapp.pid --chdir /var/www/yourapp/--chuid user:usergroup --exec /usr/bin/node index.js >> /var/log/yourapp.upstart.log 2>&1
end script
pre-start script
# Date format same as (new Date()).toISOString() for consistency
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/yourapp.upstart.log
end script
post-stop script
rm /var/run/upstart-ghost.pid
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/yourapp.upstart.log
end script
But, it is possible to do it with systemctl?
I encountered a similar issue. As explained here, it turns out that you can't redirect output directly within ExecStartPre
, ExecStart
, or ExecStopPost
commands - systemd will interpret the >
or >>
as arguments. The solution is to execute your command using sh -c
.
There's also one other issue I ran into when trying to use the date
command in my systemd script: %m
is a special code referring to the machine ID of the current host. So in order to have it output the month you need to escape the percent sign by using two percent signs (%%
). Putting it all together, the systemd version of the above pre and post-scripts is:
# Date format same as (new Date()).toISOString() for consistency
ExecStartPre = /bin/sh -c 'echo "[`date -u +%Y-%%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/yourapp.upstart.log'
ExecStopPost = /bin/sh -c 'rm /var/run/upstart-ghost.pid; echo "[`date -u +%Y-%%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/yourapp.upstart.log'