running some services and want to be notified if anything goes wrong? let’s get started.
this will require sendmail
to be installed and working on your system.
keep in mind
if you’re working on a windows based system to use this on a unix based system, your line endings will be fucky. use a tool like notepad++ to change them over.
these notifications work quite well with something like auto restart services.
- identify your executable’s service file by running
sudo systemctl status myApp
. theloaded
line will tell you where to locate it. - open your executable’s service file in your editor of choice.
- in the
[Unit]
block, add this:OnFailure=crashmailserv@%n.service
- in a new text file, input this:
[Unit]
Description=status email for %i to user
[Service]
Type=oneshot
ExecStart=/etc/script/crashmail you@domain.tld %i
User=monitor
Group=systemd-journal - save that text file as
crashmailserv@.service
and put it in/etc/systemd/system
- in a new text file, input this:
#!/bin/bash
/usr/sbin/sendmail -t <<ERRMAIL
To: $1
From: servmon <monitor@$HOSTNAME>
Subject: "$2" has crashed, and won't resurrect
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8
$(journalctl -u "$2" -e -n 20)
ERRMAIL - save this as
crashmail
in/etc/script
- run the following commands:
sudo useradd -g systemd-journal -G sudo monitor
sudo chmod +x /etc/script/crashmail
sudo systemctl daemon-reload
what did we just do?
i’ll take you through it bit by bit.
- using systemctl’s
OnFailure
functionality, requested that systemctl start a defined service when the subject service displays a failure status. - created a new service (
crashmailserv@.service
) which runs once and then exits (Type=oneshot
), and in doing so runs a defined executable (/etc/script/crashmail
) as a defined user and under a defined group - created a new executable (
crashmail
) which runs in a shell and usessendmail
to send an email containing information about the subject service - added a user called
monitor
under whom these services and commands will be executed - added the
executable
permission to our crashmail applet (without it, nothing would be able to execute it like a script) - reloaded
systemctl
‘s loaded unit files and reference information to make it pull in the modifications we just made
what’s all this %n, %i and $1 stuff?
in short, they are dynamic variables which are used to represent aspects of the subjects at hand.
the %n in the OnFailure
line tells systemctl to replace that %n with the name of the current subject service, let’s say mysql
, so we end up with systemctl start crashmailserv@mysql.service.service
the %i in our crashmailserv@.service
tells systemctl to replace that %i with the name of the invoking service, in this case mysql.service
as mysql has theoretically reached a failure status.ExecStart
in our crash service file tells systemctl what to do when the service starts, so now we’ve replaced our variables, we get ExecStart=/etc/script/crashmail you@domain.tld mysql.service
and now we’re on to our crashmail, which tells sendmail
to send an email.
in a shell script like this, $1 and $2 refer to the first and second argument, respectively, to be passed with the command. now as we’ve discovered above, these are your email address, and the subject service.
so, replacing our variables again:To: you@domain.tld
From: servmon <monitor@$HOSTNAME>
Subject: "mysql.service" has crashed, and won't resurrect
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8
$(journalctl -u "mysql.service" -e -n 20)journalctl
calls the system log journal, -u "mysql.service"
filters it by only mysql’s entries, -e
jumps directly to the end of the journal (ie the most current entries) and -n 20
makes the command output only the last 20 lines.
all of this together, when a failure is reported in a subject service, asks systemctl
to start a oneshot service, which starts an executable which asks sendmail
to send an email informing you the subject service has crashed, and gives you the last 20 lines which might help you work out why it’s crashed.