Some of our most active users chose syslog-ng because of its detailed and accurate documentation (https://syslog-ng.github.io/). Later I received complaints that it is too detailed, and we need a tutorial: https://peter.czanik.hu/posts/syslog-ng-tutorial-toc/. This time, I was asked for something even shorter. Here you are!
Before you begin
If you want to configure syslog-ng, you have to install it first. There are way too many ways to install syslog-ng, but I cannot include that many details here. Possibilities range from installing syslog-ng from a package included in your Linux distribution, through installing it from a 3rd party repository, like ours, to building syslog-ng from source. In either case, you end up with syslog-ng installed in your environment and a default syslog-ng configuration.
Configuring syslog-ng
The default configuration usually collects local log messages in one or more text files. It is perfect for standalone workstations, but the main strength of syslog-ng is central log collection. Here we will learn about the main building blocks of a syslog-ng configuration and building a minimal syslog-ng configuration to collect log messages centrally.
Minimal configuration
@version:4.8 source s_sys { system(); internal(); }; destination d_mesg { file("/var/log/messages"); }; log { source(s_sys); destination(d_mesg); };
This is the shortest config I can think of. Of course, shorter identifiers and file names could make it even shorter, just as removing any white space. There is also an alternative syntax to make it shorter, however that is confusing for new users, and sometimes even to seasoned professionals.
So, what do you see in this configuration? It starts with declaring the version number. This ensures that you get appropriate warnings if you use an old config with a new syslog-ng.
Next, you will see three configuration blocks. Each one states the kind of building block first, like source, destination or log, all of which, except for log, have unique names. The other configurations are optional. By tradition, each name starts with a letter referring to the type of the block. This is not mandatory, and many Linux distros have a different naming scheme.
Each source and destination might include multiple drivers. The system() source collects platform-specific local logs. The internal() source collects syslog-ng’s own logs. The file() destination writes logs to a file.
The log statement (or log path) is a bit special: it connects the various building blocks together. In this case, it makes sure that logs from the s_sys source are written to the d_mesg destination.
As you can see, the formatting of the configuration is pretty much flexible. One line, multiple lines, white space, no white space, it is up to you. Formatting can make the config easier to read, but syslog-ng does not need it.
Adding a filter and more
I extended the previous configuration a bit. The changes are marked with bold:
@version:4.8 @include "scl.conf" source s_sys { system(); internal(); }; # this is a comment destination d_mesg { file("/var/log/messages.${MONTH}.${DAY}"); }; filter f_default { level(info..emerg) and not (facility(mail)); }; log { source(s_sys); filter(f_default); destination(d_mesg); };
You can include other configuration files. “scl.conf” is a special one, as this name stands for the syslog-ng configuration library, which includes many useful configuration snippets. For example, parsers for Apache access logs or an Elasticsearch destination.
You can use comments to explain more complex parts of your configuration.
You can use macros in file names. In this example, instead of a single log file, a new one is created each day, and named after the current month and day. If you do additional message parsing, you could also use values parsed from log messages: for example, user names.
You can use blank lines to separate building blocks. Unfortunately, I could not mark them with bold :-)
I also added a filter, which means that I defined the filter, and included in the log path. I also defined a filter and included it in the log path. There is no need to add new lines to the configuration, therefore I placed the filter in the same line as the reference to the destination.
Adding a network source and a few more destinations
This configuration adds a network source and a few destinations to show that you can use a configuration block multiple times in your configuration.
@version:4.8 @include "scl.conf" source s_sys { system(); internal(); }; # this is a comment destination d_mesg { file("/var/log/messages.${MONTH}.${DAY}"); }; filter f_default { level(info..emerg) and not (facility(mail)); }; log { source(s_sys); filter(f_default); destination(d_mesg); }; # source for RFC5424 logs source s_syslog { syslog(port(601)); }; # destination for network logs destination d_fromnet { file("/var/log/fromnet"); file("/var/log/fromnet.json" template("$(format-json --scope rfc5424 --scope dot-nv-pairs --rekey .* --shift 1 --scope nv-pairs)\n") ); }; # Elasticsearch destination destination d_elasticsearch { elasticsearch-http( index("syslog-ng") type("") user("elastic") password("Do2oFMbINS3hzfmR8uIV") url("https://172.16.167.182:9200/_bulk") template("$(format-json --scope rfc5424 --scope dot-nv-pairs --rekey .* --shift 1 --scope nv-pairs --exclude DATE @timestamp=${ISODATE})") tls(peer-verify(no)) ); }; # all logs to Elasticsearch log { source(s_sys); source(s_syslog); destination(d_elasticsearch); }; # network logs to files log { source(s_sys); destination(d_fromnet); };
Here, I added a source and two more destinations, and, of course, also connected them in two log statements:
-
s_syslog collects RFC5424-compliant log messages at port 601 over non-encrypted TCP connections.
-
d_fromnet writes log messages to two different files. The first one is a regular syslog-formatted destination. The second one writes logs with a JSON template function, with all name-value pairs parsed from log messages included.
-
d_elasticsearch stores log data to an Elasticsearch database. It uses the JSON template function for message formatting, and it formats dates to be accepted by Elasticsearch.
-
The first log statement sends both local and network source log messages to the Elasticsearch destination. Here you can see that various building blocks can be used multiple times. Logs from s_src are written in a file, and also sent to the Elasticsearch destination.
-
The second log statement stores logs from the network source into files.
What is next?
Of course, while this blog is enough to understand the basic concepts of syslog-ng configuration, it did not cover all possibilities. There are parsers and other configuration elements, you can make things conditional with an if statement within a log path, and you can define sources and others within a log statement in-line, just to mention a few.
-
Links to the blogs and videos of the syslog-ng tutorial: https://peter.czanik.hu/posts/syslog-ng-tutorial-toc/
-
Syslog-ng documentation: https://syslog-ng.github.io/
-
How to build a syslog-ng configuration with parsers and conditional parts: https://www.syslog-ng.com/community/b/blog/posts/developing-a-syslog-ng-configuration
-
If you have questions or comments related to syslog-ng, do not hesitate to contact us. You can reach us by email or even chat with us. For a list of possibilities, check our GitHub page under the “Community” section at https://github.com/syslog-ng/syslog-ng. On Twitter, I am available as @PCzanik, on Mastodon as @Pczanik@fosstodon.org.