From Gentoo Linux Wiki
As it is stated in the Gentoo Security Guide, syslog-ng provides some of the same features as syslog and metalog with a small difference. It can filter messages based on level and content (like metalog), provide remote logging like syslog, handle logs from syslogd (even streams from Solaris), write to a TTY, execute programs, and it can act as a logging server. Basically it is the best of both loggers combined with advanced configuration.
Quick Start
First, you have to emerge syslog-ng and add it to the default runlevel. If you want to start syslog-ng just now, execute the init script. Also, it is recomended to unmerge any system logger you have previously installed as loggers often use /dev/log (see this thread):
# emerge -av syslog-ng
# rc-update add syslog-ng default
# /etc/init.d/syslog-ng start
Also, you may want logrotate to rotate your logs
# emerge -av logrotate
For a quick start, here there is a classic configuration file slightly modified from Gentoo Security Guide.
File: /etc/syslog-ng/syslog-ng.conf |
|
You will see your defined log files in /var/log. In the following sections we will explain this configuration file in order to understand how syslog-ng works.
Sources
Syslog-ng receives log messages from a source. To define a source you should follow the following syntax:
source <identifier> { source-driver(params); source-driver(params); ... };
You can look at the identifiers and source-drivers in the manuals. This will follow the manual to explain the configuration file above.
The unix-stream() source-driver opens the given AF_UNIX socket and starts listening on it for messages. The internal() source-driver gets messages generated by syslog-ng.
Therefore,
source src { unix-stream("/dev/log"); internal(); };
Means: src gets messages from /dev/log socket and syslog-ng.
The kernel sends log messages to /proc/kmsg and the file() driver reads log messages from files. Therefore:
source kernsrc { file("/proc/kmsg"); };
Means: kernsrc gets messages from file /proc/kmsg
In the default configuration file after emerging syslog-ng, the source is defined as:
source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };
Reading messages by pipe("/proc/kmsg") gives a better performance but because it opens its argument in read-write mode can be a security hazard as the syslog-ng admin guide states in section 7.1.6:
Pipe is very similar to the file() driver, but there are a few
differences, for example pipe() opens its argument in read-write
mode, therefore it is not recommended to be used on special files
like /proc/kmsg." (You can follow this discussion in this post.)
Destinations
syslog-ng sends log messages to files. The syntax is very similar to sources:
destination <identifier> {destination-driver(params); destination-driver(params); ... };
You will be normally logging to a file, but you could log to a different destination-driver: pipe, unix socket, TCP-UDP ports, terminals or to specific programs. Therefore:
destination authlog { file("/var/log/auth.log"); };
Means sent authlog messages to /var/log/auth.log
usertty() sends messages to the terminal of the specified user, if the user is logged in. Then:
destination console { usertty("root"); };
Sends console messages to root's terminal if it is logged in.
pipe() sends messages to a pipe /dev/xconsole. Then:
destination xconsole { pipe("/dev/xconsole"); };
Sends xconsole messages to the pipe /dev/xconsole. This needs some more configuration, so you could look at the sub-section xconsole below.
udb() sends on the network
destination remote_server { udp("10.0.0.2" port(514)); };
this will send your log data out to a another server
xconsole
ATTENTION: this part is not yet finished.
You can look and contribute at this thread discussing the topic,
and have a look at this explanation.
syslog-ng can send messages to the pipe /dev/xconsole. You should create it with mkfifo, giving the appropriate access and owner permissions:
# mkfifo /dev/xconsole
# chmod 644 /dev/xconsole
# chown root.tty /dev/xconsole
Afterwards, you need a program to read the messages sent to /dev/xconsole. xconsole is a console that monitors system messages with X. Frist step is to emerge xconsole:
emerge -av xconsole
And tell xconsole to read /dev/xconsole
# xconsole -file /dev/xconsole
You can modify the text window space editing /usr/share/X11/app-defaults/XConsole:
*text.width: 900
*text.height: 100
And the geometry:
xconsole -file /dev/xconsole -geometry +67+640
Creating Filters for Messages
Syntax for the filter statement:
filter <identifier> { expression; };
Functions can be used in the expression, such as the fuction facility() which selects messages based on the facility codes (look at the sub-section below for a list of facility codes). Therefore, the filter
filter f_auth { facility(auth); };
filters those messages coming from authorisation, like:
May 11 23:42:31 mimosinnet su(pam_unix)[18569]: session opened for user root by (uid=1000)
Expression can use the boolean operators and, or, not, so the filter:
filter f_debug { not facility(auth, authpriv, news, mail); };
selects those messages not coming from authorisation, network news or mail.
The funciont level() selects messages based on its priority level, therefore:
filter f_info { level(info); };
selects informational levels.
Functions and boolean operators can be combined in more complex expressions like:
filter f_messages { level(info..warn)
and not facility(auth, authpriv, mail, news); };
that filters messages with a priority level from informational to warning not coming from atuh, authpriv, mail and news facilities.
Messages can also be selected by matching a regular expression in the message with the function match(regexp). For example:
filter f_failed { match("failed"); };
Facilities and log-levels
The linux kernel has a few facilities you can use for logging. Each facility has a log-level; where debug is the most verbose, and panic only shows serious errors. You can find the facilities, log levels and priority names in /usr/include/sys/syslog.h:
File: /usr/include/sys/syslog.h |
|
Log Paths
syslog-ng connects sources, filters and destinations with log statements. The syntax is:
log {source(s1); source(s2); ...
filter(f1); filter(f2); ...
destination(d1); destination(d2); ...
flags(flag1[, flag2...]); };
For example:
log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };
Sends messages from 'src' source to 'mailinfo' destination filtered by 'f_info' filter.
Tips and Tricks
After understanding the logic behind syslog-ng, many possible and complex configuration are possible. Here there are some examples.
[edit] Move log to another file
in order to move some log from messages to another file:
#sshd configuration
destination ssh { file("/var/log/ssh.log"); };
filter f_ssh { program("sshd"); };
log { source(src); filter(f_ssh); destination(ssh); };
Configuring as a loghost
Configuring your system to be a loghost is quite simple.
Drop the following into your configuration, and create the needed directory.
File: /etc/syslog-ng/syslog-ng.conf |
|
With this simple configuration, log filenames will be based on the FQDN of the remote host, and located in; /var/log/remote/
After creating the remote directory, reload your syslog-ng.configuration.
Use pipe("/proc/kmsg") or file("/proc/kmsg")
In the default configuration file after emerging syslog-ng, the source is defined as:
source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };
It is not clear if we should use pipe("/proc/kmsg") or file("/proc/kmsg")- As the syslog-ng admin guide states in section 7.1.6:
Pipe is very similar to the file() driver, but there are a few
differences, for example pipe() opens its argument in read-write
mode, therefore it is not recommended to be used on special files
like /proc/kmsg."
(You can follow this discussion in this post.
Improve Performance
syslog performance can be improved in different ways:
Avoid redundant processing and disk space with flag(final)
A single log message can be sent to different log files several times. For example, in the initial configuration file, we have the following definitions:
destination cron { file("/var/log/cron.log"); };
destination messages { file("/var/log/messages"); };
filter f_cron { facility(cron); };
filter f_messages { level(info..warn)
and not facility(auth, authpriv, mail, news); };
log { source(src); filter(f_cron); destination(cron); };
log { source(src); filter(f_messages); destination(messages); };
The same message from the 'cron' facility will end up in both the cron.log and messages file. To change this behavior we can use the final flag, ending up further processing with the message. Therefore, in this example, if we want messages from the 'cron' facility not ending up in the messages file, we should change the cron's log sentence by:
log { source(src); filter(f_cron); destination(cron); flags(final); };
Postgresql Destination
Some of this information was obtained from http://www.kdough.net/docs/syslog_postgresql/.
Please note that this is a work in progress. For one, psql never gets killed when you restart syslog-ng. I just got this going today, so I haven't had a chance to look into it. For another, there are security implications.
Also, I'm still debating with myself whether there's really value in putting syslog logs into an RDBM.
[edit] syslog-ng-pgsql-pipe.sh
The following file can reside in /usr/local/sbin/syslog-ng-pgsql-pipe.sh
#!/bin/bash
#
# File: syslog-ng-pgsql-pipe.sh
#
# Take input from a FIFO and run execute it as a query for
# a PostgreSQL database.
#
# IMPORTANT NOTE: This could potentially be a huge security hole.
# You should change permissions on the FIFO accordingly.
#
ERROR_CODE=0
if [ -e /var/run/syslog-ng.pgsql.pipe ]; then
while [ -e /var/run/syslog-ng.pgsql.pipe ] && [ "$ERROR_CODE" -ne "143" ]
do
psql -q -h localhost -U syslog syslog < /var/run/syslog-ng.pgsql.pipe
/usr/local/bin/syslog-ng-parse.awk < /var/run/syslog-ng.pgsql.pipe
done
else
mkfifo /var/run/syslog-ng.pgsql.pipe
fi
syslog-ng.conf
#
# SQL logging support
#
destination d_pgsql {
pipe("/var/run/syslog-ng.pgsql.pipe"
template("INSERT INTO logs (host, facility, priority, level, tag, date,
time, program, msg) VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG',
'$YEAR-$MONTH-$DAY', '$HOUR:$MIN:$SEC', '$PROGRAM', '$MSG' );\n"
)
template-escape(yes)
);
};
# make a filter if you like
# filter postfix {program ("postfix");};
log { source(src); destination(d_pgsql); };
syslog-ng (init.d)
I still can't figure out how to make the psql process die, during a stop or a restart of syslog-ng. pidof returns nothing, when run inside the syslog-ng init script. And using --make-pidfile of start-stop-daemon is almost useless, because it only kills the shell script that start psql, not psql itself.
start()
+ start-stop-daemon --start --background --quiet --exec /usr/local/sbin/syslog-ng-pgsql-pipe.sh
+ echo `pidof psql` > /var/run/syslog-ng-pgsql-pipe.pid
start-stop-daemon --start --quiet --exec /usr/sbin/syslog-ng ${SYSLOG_NG_OPTS}
[edit] stop()
start-stop-daemon --stop --quiet --pidfile /var/run/syslog-ng.pid
+ start-stop-daemon --stop --quiet --pidfile /var/run/syslog-ng-pgsql-pipe.pid
PostgreSQL
In order for this to work, you're going to need a TRUST rule in pg_hba.conf, or a password, for the syslog user. There's obviously security implications for this, if you're using a TRUST rule. Although INSERTS into syslog will be possible, reads/modifications of existing log entries will not be. If you use a password, you may be able to restrict the init script to root access only. I'm not sure if that will work though. I'll have to try it. :) Alternatively, you can use the ~/.pgpass file to supply the credentials. See the reference, http://www.postgresql.org/docs/current/interactive/libpq-pgpass.html
~/.pgpass
hostname:port:database:username:password
su - postgres
createdb syslog
psql -h localhost -U postgres syslog
CREATE USER syslog WITH PASSWORD 'syslogXXXXXXX';
CREATE TABLE logs (
host varchar(32) default NULL,
facility varchar(10) default NULL,
priority varchar(10) default NULL,
level varchar(10) default NULL,
tag varchar(10) default NULL,
date date default NULL,
time time default NULL,
program varchar(15) default NULL,
msg text,
seq serial,
PRIMARY KEY (seq)
);
GRANT INSERT ON logs TO syslog; # security so people can't update the logs