NAME
syslogd - receive syslog messages over UDP and write them to a CSV file
SYNOPSIS
/usr/local/etc/syslogd [--port 514] [--address 0.0.0.0] [--file /var/log/syslog/syslog.csv]
[--no-resolve] [--language en]
# Without root, on a port above 1023, logging addresses only
/usr/local/etc/syslogd --port 5514 --file /var/log/remote.csv --no-resolve
# Under taint mode: the module must be installed or named with -I
perl -T -I/usr/local/lib /usr/local/etc/syslogd --port 5514
DESCRIPTION
A small wrapper around App::Syslogd. It turns the command line into options, opens the socket and the log, prints a "listening" line, and runs until SIGTERM or SIGINT. Then it prints how many messages it recorded.
Purpose
Run a syslog server from the command line.
Arguments
The command-line options below. Options that are not given are not passed on, so the defaults of App::Syslogd apply.
--port N- UDP port (a whole number, 0 to 65535; default 514).--address A- local address to listen on (default0.0.0.0).--file F- the CSV log file (default /var/log/syslog/syslog.csv; the directory must exist, and on Debian and Ubuntu /var/log/syslog is a file, so give--filethere).--resolve/--no-resolve- write host names (the default) or addresses.--language TAG- the language of the program's messages.
Returns
The exit status: 0 after a clean stop (SIGTERM or SIGINT); 1 if the server could not start or failed while running; 2 if it was started wrongly (see "EXIT STATUS").
Side Effects
Binds a UDP socket; creates or appends to the log file (mode 0600); prints a "listening" line and, on stopping, a "shutting down" line on standard output. It never reads standard input.
Usage
/usr/local/etc/syslogd --port 5514 --file /var/log/remote.csv
API SPECIFICATION
INPUT
The program takes no HTTP input. It reads no QUERY_STRING, PATH_INFO, cookies, other HTTP_* variables or request body, and if GATEWAY_INTERFACE or REQUEST_METHOD is set (it was started by a web server) it refuses to run. Its inputs are the command line:
{
port => { type => 'integer', min => 0, max => 65535, optional => 1 },
address => { type => 'string', min => 1, optional => 1 },
file => { type => 'string', min => 1, optional => 1 },
resolve => { type => 'boolean', optional => 1 },
language => { type => 'string', min => 1, optional => 1 },
}
and the environment that App::Syslogd reads (App__Syslogd__*, LANG, LANGUAGE, LC_*).
OUTPUT
{
exit_status => { type => 'integer', min => 0, max => 2 },
stdout => { type => 'string', matches => qr/\ASyslog server listening on .+\n(?:Syslog server shutting down after recording .+\n)?\z/ },
}
FORMAL SPECIFICATION
[OPTION, VALUE, LINE]
argv? : seq STRING ; env? : NAME ⇸ VALUE
out! : seq LINE ; status! : 0 .. 2
SyslogdOk
argv?, env?, out!, status!
─────────
GATEWAY_INTERFACE ¬in; dom env? ∧ REQUEST_METHOD ¬in; dom env?
parses(argv?)
status! = 0
out! = ⟨listening(address, port), shutdown(count)⟩
SyslogdRefused
argv?, env?, out!, status!
─────────
(GATEWAY_INTERFACE ∈ dom env? ∨ REQUEST_METHOD ∈ dom env?) ∨
¬ parses(argv?) ∨ ¬ startable(argv?, env?)
out! = ⟨⟩
status! = 2 ⇔ (GATEWAY_INTERFACE ∈ dom env? ∨ REQUEST_METHOD ∈ dom env? ∨ ¬ parses(argv?))
status! = 1 ⇔ ¬ (status! = 2)
Syslogd ≙ SyslogdOk ∨ SyslogdRefused
-- Running as CGI is decided before the command line is read:
CgiFirst ≙ (GATEWAY_INTERFACE ∈ dom env? ∨ REQUEST_METHOD ∈ dom env?)
⇒ ¬ parsed ∧ ¬ bound ∧ ¬ logging
EXIT STATUS
+--------+----------------------------------------------------------------+
| Status | Meaning |
+--------+----------------------------------------------------------------+
| 0 | stopped cleanly by SIGTERM or SIGINT |
| 1 | could not start (the socket or the log could not be opened, a |
| | setting was invalid) or failed while running |
| 2 | started wrongly: a bad option (the usage message), or by a web |
| | server |
+--------+----------------------------------------------------------------+
Errors that stop Perl before the program runs (for example, App::Syslogd cannot be found) are reported by Perl itself, with Perl's own status.
SIGNALS
SIGHUP reopens the log file (for log rotation); SIGTERM and SIGINT stop the server.
ENVIRONMENT
App__Syslogd__port, App__Syslogd__file and the other App__Syslogd__* variables set options, and win over the command line (see "new" in App::Syslogd). LANG, LANGUAGE and LC_* choose the language. GATEWAY_INTERFACE or REQUEST_METHOD make the program refuse to run.
SECURITY
It refuses to run from a web server: as a CGI program a query without "=" becomes its command line (RFC 3875, "ISINDEX"), so any visitor could start a listening server writing where they chose.
It never runs another program, and passes file names straight to the system, never to a shell.
It only adds to an empty file or to one of its own logs (a file that starts with the column-names line), so even as root a mistaken or hostile
--filecannot append to, or change the permissions of, a file such as /etc/passwd.Without
-Tit loads App::Syslogd from ../lib next to itself (/usr/local/lib once installed): keep that directory writable only by root. With-Tthat path is not used, because it is built from$0; the module must then be installed or named with-I. Under-Toption values from the command line or the environment are tainted, so a--fileis refused by taint mode.Getopt::Long's "Unknown option" warning and the usage message show the option name and
$0as given; both come from whoever starts the program, so they cannot carry anyone else's text.
See also "SECURITY" in App::Syslogd.
AUTHOR
Nigel Horne, <njh at nigelhorne.com>
LICENSE AND COPYRIGHT
Copyright 2026 Nigel Horne.
This program is released under the GNU General Public License, version 2 (see the LICENSE file). If you use it, please let me know.