runner runs a program, capturing its output (from both standard output and standard error) and printing it to standard output only if the program fails.
The output can also be printed if the program produces, or does not produce, a specific string (see -print-if-match and -print-if-not-match). As of Runner 2.0.0, output can always be printed regardless of program exit status, with the -always-print option.
If the program failed, or its output would otherwise be printed, runner can also:
- email the program's output, if provided with an SMTP server and credentials
- send a notification via ntfy
- send a notification to a Discord webhook
- send a notification to a Slack webhook
Output is optionally written to a log directory, regardless of program exit status.
If runner is run as root or with CAP_SETUID and CAP_SETGID, the target program can be run as a different user.
On Linux 5.6+, if run with CAP_SYS_PTRACE, runner can redirect its output to file descriptors of your choice belonging to a different process. This is useful in some containerization situations. To use this feature, the container must be run with --cap-add CAP_SYS_PTRACE.
The core runner logic (capturing and discarding program output) is useful when running a program via cron, when you only want to see its output, typically via email, in case of failure or when specific outputs occur.
runner 2+ is useful in various containerization applications, even as a container entrypoint. It can run a target program in the container, retry it if need be, capture its output, and then send the output via email, ntfy, Discord, or Slack. Email, ntfy, Discord, and Slack outputs can be configured by the image's end user via environment variables, requiring no build-time customization. Regardless of these output delivery options, it can always log the program's result to a file as well.
It can even run the target program as a non-root user, and if runner is not the container's entrypoint, you can set environment variables like the following to redirect output to the root process's stdout/stderr:
RUNNER_OUTFD_PID=1
RUNNER_OUTFD_STDOUT=1
RUNNER_OUTFD_STDERR=2Install my Debian repository if you haven't already:
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://dist.cdzombak.net/deb.key | sudo gpg --dearmor -o /etc/apt/keyrings/dist-cdzombak-net.gpg
sudo chmod 0644 /etc/apt/keyrings/dist-cdzombak-net.gpg
echo -e "deb [signed-by=/etc/apt/keyrings/dist-cdzombak-net.gpg] https://dist.cdzombak.net/deb/oss any oss\n" | sudo tee -a /etc/apt/sources.list.d/dist-cdzombak-net.list > /dev/null
sudo apt-get updateThen install runner via apt-get:
sudo apt-get install runnerbrew install cdzombak/oss/runnerPre-built binaries for Linux and macOS on various architectures are downloadable from each GitHub Release. Debian packages for each release are available as well.
Requirements: Go >= 1.15.
make build will build runner for your current OS/architecture. Copy the resulting binary from ./out/runner to wherever makes sense for your deployment, and adjust its owner as necessary:
git clone https://github.com/cdzombak/runner.git
cd runner
make build
cp out/runner $INSTALL_DIR
sudo chown root:root $INSTALL_DIR/runner
sudo chmod 755 $INSTALL_DIR/runnerIf you plan to use the RUNNER_OUTFD_PID and RUNNER_OUTFD_STD[OUT|ERR] variables, run setcap 'CAP_SYS_PTRACE=ep' /path/to/runner on the runner binary.
[ENV VARS] runner [OPTIONS] -- /path/to/myprogram --myprogram-args
-always-print: Always print the program's output, sidestepping exit code and-print-if[-not]-matchchecks.-healthy-exit value: "Healthy" or "success" exit codes. May be specified multiple times to provide more than one success exit code. (default:0)-hide-env: Hide the process's environment, which is normally printed & logged as part of the output.-job-name string: Job name used in failure notifications and log file name. (default: program name, without path)-log-dir string: The directory to write run logs to.- Can also be set by the
RUNNER_LOG_DIRenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-print-if-match value: Print/mail output if the given (case-sensitive) string appears in the program's output, even if it was a healthy exit. May be specified multiple times.-print-if-not-match value: Print/mail output if the given (case-sensitive) string does not appear in the program's output, even if it was a healthy exit. May be specified multiple times.-print-stderr: Print output to stderr instead of stdout (if this flag is not given, output is printed to stdout).-retries int: If the command fails, retry it this many times. (default:0)-retry-delay int: If the command fails, wait this many seconds before retrying. (default:0)timeout int: Maximum number of seconds for the program's execution. If retries are allowed, each try may take this long. The timeout given does not include retry delay. (default:0, meaning "no timeout")-version: Print version and exit.-work-dir string: Set the working directory for the program.
RUNNER_CENSOR_ENV(environment variable only): Colon-separated list of environment variables whose values will be censored in output.RUNNER_SMTP_PASSandRUNNER_NTFY_ACCESS_TOKENare always censored.RUNNER_HIDE_ENV(environment variable only): Colon-separated list of environment variables which will be entirely omitted from output.
-gid int: Run the program as the given GID. Ignored on Windows. (If provided, runner must be run asrootor withCAP_SETGID.)-uid int: Run the program as the given UID. Ignored on Windows. (If provided, runner must be run asrootor withCAP_SETUID.)-user string: Run the program as the given user. Ignored on Windows. (If provided, runner must be run asrootor withCAP_SETUIDandCAP_SETGID.)
-mail-from string: The email address to use as theFrom:address in failure emails. (default:runner@hostname)- Can also be set by the
RUNNER_MAIL_FROMenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-mail-tab-char string: Replace tab characters in emailed output by this string.- Can also be set by the
RUNNER_MAIL_TAB_CHARenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-mailto string: Send an email to the given address if the program fails or its output would otherwise be printed per-healthy-exit/-print-if-[not]-match/-always-print.- Can also be set by the
RUNNER_MAILTOenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-smtp-host string: SMTP server hostname.- Can also be set by the
RUNNER_SMTP_HOSTenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-smtp-pass string: Password for SMTP authentication.- Can also be set by the
RUNNER_SMTP_PASSenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-smtp-port int: SMTP server port.- Can also be set by the
RUNNER_SMTP_PORTenvironment variable; this flag overrides the environment variable. (default: 25)
- Can also be set by the
-smtp-user string: Username for SMTP authentication.- Can also be set by the
RUNNER_SMTP_USERenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-ntfy-access-token string: If set, use this access token for ntfy.- Can also be set by the
RUNNER_NTFY_ACCESS_TOKENenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-ntfy-email string: If set, tell ntfy to send an email to this address.- Can also be set by the
RUNNER_NTFY_EMAILenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-ntfy-priority int: Priority for the notification sent to ntfy. Must be between 1-5, inclusive.- Can also be set by the
RUNNER_NTFY_PRIORITYenvironment variable; this flag overrides the environment variable. (default 3)
- Can also be set by the
-ntfy-server string: Send a notification to the given ntfy server if the program fails or its output would otherwise be printed per -healthy-exit/-print-if-[not]-match/-always-print.- Can also be set by the
RUNNER_NTFY_SERVERenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-ntfy-tags string: Comma-separated list of ntfy tags to send.- Can also be set by the
RUNNER_NTFY_TAGSenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-ntfy-topic string: The ntfy topic to send to.- Can also be set by the
RUNNER_NTFY_TOPICenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-discord-webhook string: If set, post to this Discord webhook if the program fails or its output would otherwise be printed per -healthy-exit/-print-if-[not]-match/-always-print.- Can also be set by the
RUNNER_DISCORD_WEBHOOKenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-slack-webhook string: If set, post to this Slack webhook if the program fails or its output would otherwise be printed per -healthy-exit/-print-if-[not]-match/-always-print.- Can also be set by the
RUNNER_SLACK_WEBHOOKenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-slack-username string: If set, use this username for the Slack message.- Can also be set by the
RUNNER_SLACK_USERNAMEenvironment variable; this flag overrides the environment variable.
- Can also be set by the
-slack-icon-emoji string: If set, use this emoji for the Slack message. Examples::floppy_disk:,:octocat:.- Can also be set by the
RUNNER_SLACK_ICON_EMOJIenvironment variable; this flag overrides the environment variable.
- Can also be set by the
Success notification options (for e.g. Uptime Kuma Push monitors)
-success-notify string: If set,GETthis URL if the program succeeds.- Can also be set by the
RUNNER_SUCCESS_NOTIFYenvironment variable; this flag overrides the environment variable.
- Can also be set by the
This heartbeat-style notification is useful if you want to have Uptime Kuma or a similar tool alert you if your program stops succeeding.
[myhostname] Success running exampledatejob
Command: /bin/date
Exit code: 0
Working directory: /home/ubuntu
Duration: 3.794033ms
Start time: 2020-05-27 09:17:59 -0400
End time: 2020-05-27 09:17:59 -0400
--- Program output follows: ---
Wed May 27 09:17:59 EDT 2020
I store my personal logs in $HOME/log/runner. Accomplish this by setting the RUNNER_LOG_DIR environment variable at the top of your crontab:
RUNNER_LOG_DIR=/home/myusername/log/runnerrunner will create this folder for you if it doesn’t already exist.
Schedule a cleanup job to run daily via cron:
RUNNER_LOG_DIR="/home/myusername/log/runner"
# ...
0 0 * * * /usr/bin/find "$RUNNER_LOG_DIR" -mtime +30 -name "*.log" -delete
This will remove logs older than 30 days.
LGPLv3; see LICENSE in this repository.
Runner uses or includes code from open-source libraries:
- AnthonyHewins/gotfy (Apache 2 License)
- oraoto/go-pidfd (MIT License)
