From echo to syslog: Smarter logging for your scripts

… or: how to use the logger
command to send messages into the system log.
If you are monitoring or troubleshooting a Linux system, then one of the most important things to check is the logfiles.
Running services like Postfix or Apache write them, tiny tools like sudo
write logs - and even the system itself, the kernel, tells you what it’s doing and what didn’t go so smoothly.
What if your cronjobs or scripts could do the same? You could simply use your known toolbox - grep
, less
, tail
, and friends - to see what’s going on, or use the more modern journalctl
.
Here’s the thing: you can easily write your own logs from the command line (and therefore from cronjobs or scripts) and inject your own messages into those central log repositories.
And if you know a few basic concepts, you can even filter your messages into certain files or “sections” of your system log.
But first: why not just append your messages to your own log file?
You could, of course, log messages yourself by just appending them to a file:
echo "my message" >> my-logfile
That works - but it misses some smart benefits you get when you log messages the way I’ll show you next:
- Automatic timestamping and tagging
Messages written via the syslog protocol (RFC 5424 / 3164) - that’s what we’ll use - include timestamps, hostnames, and tags automatically. - Centralized handling
Your messages become part of the system’s managed logs, so they rotate, compress, and get archived together with the rest. - Remote logging integration
Syslog already supports forwarding logs to a central host. So if your system’srsyslog
orsyslog-ng
is configured for remote forwarding, your messages will follow automatically.
Once you use the existing log infrastructure, your messages show up in the same places as the rest of the system - viewable with grep
, less
, or journalctl
.
So, how can you tap into that same system yourself? Let’s look at the command that makes this easy.
Say hello to logger
The essential tool for writing to the local log system is logger
.
To log a simple test message, just append it as a parameter:
logger "test message"
Instantly you’ll find this message somewhere within /var/log/*
. On my Ubuntu system, it shows up in /var/log/syslog
:
grep "test message" /var/log/syslog
2025-10-17T09:55:17.645712+00:00 demo robert: test message
And if your system runs systemd (who doesn’t these days), you can see the same message via journalctl
:
[robert@demo ~]$ journalctl | grep "test message"
Oct 17 09:55:17 demo robert[2451]: test message
Anyone who has write access to /dev/log
(or “/run/systemd/journal/dev-log”, where “/dev/log” usually points to) can inject messages this way - and typically, that means everyone.
Side note: To be more technically accurate - while any user appears to have write access to “/dev/log” (or the socket it links to), the log system only accepts messages if they come from root or a local user with a UID ≥ 1000. In practice, that means that any “normal” local user can write to the system log.
Need to log the output from a command or tool? Just pipe it to logger
:
# write the output of "w" to logger
w | logger
# write the output of top to logger
top -b -n1 | logger
Mark your messages for easier discovery later
If you want to recognize or filter your messages later, it’s helpful to mark them.
You can do this in two ways: by adding a tag, or by setting a facility and a level.
Set a tag
Every message that flows through the syslog system has a tag associated with it.
logger
uses, by default, the name of the user who sent the message. You can see this as the string robert:
within the test message:
[robert@demo ~]$ grep "test message" /var/log/syslog
2025-10-17T09:55:17.645712+00:00 demo robert: test message
^^^^^^^
To set your own tag - so you can later grep
your messages out of the chaos - use the parameter -t
followed by a tag name of your choice:
[robert@demo ~]$ logger -t BACKUP "test message 2"
[robert@demo ~]$ grep "test message 2" /var/log/syslog
2025-10-17T10:03:20.941254+00:00 demo BACKUP: test message 2
From now on, you can find all your tagged messages easily:
grep "BACKUP:" /var/log/syslog
And of course,journalctl
can also filter messages by their tag:
[robert@demo ~]$ journalctl -t BACKUP
Oct 17 10:03:20 demo BACKUP[3380]: test message 2
Side note: Notice how
journalctl
shows the number “3380” next to the tag? That’s the process ID (PID) of the “logger” command that sent the message.
Set a facility and level
Sometimes you want to mark your message as belonging to a certain category (facility) or priority (level). This could be great if you want your message to finally appear in a specific predefined log file - for example /var/log/mail.err
for email-related errors.
If you wanna to this, you need to know that with syslog, both the facility and the level must be chosen from a predefined set of values:
Facilities:
auth
, authpriv
, cron
, daemon
, ftp
, kern
(kernel messages, not usable from userspace),
lpr
, mail
, news
, syslog
, user
, uucp
, and local0
–local7
.
Priorities (levels), sorted by importance:
debug
, info
, notice
, warning
, err
, crit
, alert
, emerg
.
To use them with logger
, specify both together - connected with a dot - using the -p
option.
example: send an error message regarding the mail system:
logger -p mail.err "email doesn't work"
On my Ubuntu system with a default rsyslog
configuration, this message goes straight into /var/log/mail.err
:
[robert@demo ~]$ grep "email doesn't work" /var/log/mail.err
2025-10-17T10:15:53.702791+00:00 demo robert: email doesn't work
And of course, you can filter these messages in the journal too:
[robert@demo ~]$ journalctl --facility=mail --priority=err
Oct 17 10:15:53 demo robert[3972]: email doesn't work
Use it in cron or from your scripts
Now let’s use this in the real world.
Here’s a cronjob that logs the output of w
(who’s logged in and from where) every full hour:
0 * * * * nobody w | logger -t STATUS
Or, imagine you use rsync
in a script to create a backup of important data.
Then logger
can be the perfect add-on to log the success or failure of every run:
#!/bin/bash
if rsync -a /data /backup; then
logger -t BACKUP -p local0.info "Backup completed successfully"
else
logger -t BACKUP -p local0.err "Backup failed!"
fi
From now on, every script you write can talk to the same logging system as your kernel - clean, timestamped, and easy to search.