0

I am trying to control a continuously running license server on a workstation using systemd. The service itself is started by a shell script, which is essentially

Usage: ./rlm_control.sh {start|stop|restart|status}

From this I created a systemd service file:

[Unit]
Description=RLM License Server
After=network.target

[Service]
Type=forking
ExecStart=/path/to/rlm_control.sh start
ExecStop=/path/to/rlm_control.sh stop
ExecReload=/path/to/rlm_control.sh restart
User=chris
Restart=on-failure

[Install]
WantedBy=multi-user.target

The problem is that this control script actually forks off another process with its own logs rlm. The logs of rlm_control.sh are found by journald, but the logs of rlm are not.

Is it possible to tell journald somehow to essentially append the output of tail -f /path/to/rlm.log to the journal of this service?

EDIT: I noticed this was asked before [0], but that solution seems to suggest appending the logs using a command, not adjusting the service file to read from another log file as well.

[0] Forward logs from file to journald

  • 1
    This is an example of the difference between open and closed source softwares. The right thing to do is to eliminate the Poor Man's Dæmon Supervisor, written badly in shell script, and run the actual dæmon directly under proper service management.There have been plenty of cases on this WWW site where people have done that, inspecting the scripts concerned and creating service units for other people. Your software, however, is closed source. The rest of us do not get to see what is in that shell script. You are locked into only getting this stuff from the vendor, not from here. – JdeBP Mar 20 at 12:05
2

The problem here is what was already said in the comments: You have not created a systemd unit but rather a "systemd process spawner". And since you are talking about adequating your service and not concatenating a file to your logs, you have to solve some problems before getting your software logs to Journal:

  • A true systemd unit would have something like ExecStart=/path/to/license_software_bin -d parameter1 -f parameter2 -c -whatever and not invoke a script that with Type=forking call fork() and kill the parent process that started the daemon
  • Configure PIDFile=/run/path/to/pidfile.pid to make the process identification better. Quoting systemd.service manpages:

PIDFile=

Takes a path referring to the PID file of the service. Usage of this option is recommended for services where Type= is set to forking. The path specified typically points to a file below /run/. If a relative path is specified it is hence prefixed with /run/. The service manager will read the PID of the main process of the service from this file after start-up of the service. The service manager will not write to the file configured here, although it will remove the file after the service has shut down if it still exists. The PID file does not need to be owned by a privileged user, but if it is owned by an unprivileged user additional safety restrictions are enforced: the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the PID file must refer to a process already belonging to the service.

and:

If set to forking, it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication channels are set up. The child continues to run as the main service process, and the service manager will consider the unit started when the parent process exits. This is the behavior of traditional UNIX services. If this setting is used, it is recommended to also use the PIDFile= option, so that systemd can reliably identify the main process of the service. systemd will proceed with starting follow-up units as soon as the parent process exits.

Take look at the design simplicity of the httpd.service systemd unit of CentOS 7: ExecStart= calls directly the binary so no PIDFile= is needed, stop is made by killing the process and giving it some time with SIGCONT in conjunction with TimeoutStopSec and reload uses the httpd -k graceful, something specific of Apache itself.

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • Thanks for the thorough response. I have access to the script being invoked by my service unit (rlm_control.sh), so if I understand you correctly, I should compose a systemd service unit that replaces the script and calls rlm directly using the options defined in the shell script. – cbcoutinho Mar 20 at 15:30
  • That's right. I think calling the binary directly is the best approach when creating systemd units withouth having to rely on PID File tweaks :) – user34720 Mar 20 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.