I'm using systemd to start a program on boot and keep it running in the background.
I wrote a simple script for systemd to call and the script will print several lines of logs which I'd like to see in the terminal.
So I set StandardOutput=journal+console in the service configuration but I wasn't able to see the outputs neither in the terminal nor the journal.
frederick@Frederick-PC:~$ sudo systemctl start my_program.service
frederick@Frederick-PC:~$ journalctl _SYSTEMD_UNIT=my_program.service
No journal files were found.
-- No entries --And these are my service configuration and the script.
/etc/systemd/system/my_program.service
[Unit]
Description=Start my_program client after system is booted
[Service]
Type=forking
ExecStart=/usr/bin/my_program.sh start
ExecStop=/usr/bin/my_program.sh stop
PIDFile=/run/my_program.pid
WorkingDirectory=/home/frederick/Applications/my_program-go/
StandardOutput=journal+console
[Install]
WantedBy=multi-user.target/usr/bin/my_program.sh
#!/bin/sh
start() { if [ -f /run/my_program.pid ]; then kill -0 $(cat /run/my_program.pid) > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "my_program has been already started" exit 1 fi fi echo -n "Starting my_program... " nohup /home/frederick/Applications/my_program-go/my_program-local -c /home/frederick/Applications/my_program-go/config.json >> /home/frederick/Applications/my_program-go/my_program.log 2>&1 & if [ $? -gt 0 ]; then echo "failed" rm /run/my_program.pid > /dev/null 2>&1 else echo $! | tee /run/my_program.pid fi
}
stop() { if [ -f /run/my_program.pid ]; then echo -n "Stopping my_program... " msg=$(kill $(cat /run/my_program.pid) 2>&1) if [ $? -gt 0 ]; then echo "failed" echo $msg else rm /run/my_program.pid > /dev/null 2>&1 echo "succeeded" fi else echo "my_program not started" fi
}
restart() { stop start
}
case $1 in start|stop|restart) "$1" ;; *) echo "No such operation" exit 1 ;;
esacHow can I see those lines printed by echo in the script? Please help, thanks.
1 Answer
I wrote a simple script for systemd to call …
… which was the source of the problem. Your "simple script" overrode where the standard output and standard error were sent. And that entirely unnecessarily. All of the redirection, PID file writing, nohup-ing, and forking is entirely unnecessary for something that is already daemonized and already has its PID known by the service manager. You don't need any part of that script at all. Instead, write your service unit like this:
[Unit] Description=Start my_program client after system is booted [Service] Type=simple ExecStart=/home/frederick/Applications/my_program-go/my_program-local -c /home/frederick/Applications/my_program-go/config.json WorkingDirectory=/home/frederick/Applications/my_program-go/ StandardOutput=journal+console [Install] WantedBy=multi-user.target
Invoke whatever options are necessary to stop your program from forking, unless it actually definitely implements the forking readiness protocol. Very few programs actually do. Your "simple script" certainly didn't, as it exited the parent process long before the dæmon had initialized and was ready.
Further reading
- Jonathan de Boyne Pollard (2015). The systemd house of horror. Frequently Given Answers.
- Systemd kills service immediately after start
- Yocto linux service script problem
- The
systemd.execman page (and alsosystemd.serviceandsystemd.unit). The man page says: Unit configuration files for services, sockets, mount points, and swap devices share a subset of configuration options which define the execution environment of spawned processes. This man page lists the configuration options shared by these four unit types.