by Balázs Scheidler | Jul 31, 2023 | background
I haven’t recently posted here, and the reason for that is that I have started Axoflow, a new startup in the observability space that took a lot of energy to get off the ground. We’ve closed our initial round of funding, which makes this a perfect time to introduce what we are set out to do.
Most of the innovation on how logs are processed and managed happen under the umbrella of “observability” these days: logs becoming one pillar of the logs/metrics/traces triumvirate, a combination often called telemetry data.
What I found is that mainstream observability focuses very much on the operational aspects of running applications and less so on the security element. Also, I find that in a lot of cases, enterprises tend to have separate teams for security (reporting to the CISO/CIO) and observability (reporting to the development organization/CTO).
At Axoflow, we know both sides of these coins: I am very much part of the “security camp”: syslog-ng being the #1 solution to feed the enterprise SIEM (Splunk and the like). The background of my co-founders is the observability space, having created logging operator (at Banzai Cloud and Cisco) and having run global, web-scale applications (at Ustream and IBM).
Based on our combined expertise, we are building a product that helps enterprises run their combined logging/observability pipelines.
Enterprises have invested millions of their security budget into deploying or running their log management infrastructures that feed their SIEM. They are also investing millions into deploying observability products to help running their applications. Yet, these systems are often separate. Their operation often manual and error prone.
This is where Axoflow is set out to help. We are building a management plane that greatly simplifies the operation of these telemetry pipelines (or shows where they are leaking) and also allows the separation between security and observability to be torn down.
You could ask how this relates to syslog-ng and this blog: even though Axoflow is a vendor agnostic management plane for telemetry pipelines, the data plane carrying the actual data is crucial as well. That’s where syslog-ng plays a role: we consider syslog-ng to be our open source, reference data plane that we use to show-case our management functionality. syslog-ng is also a great stepping stone to plug Axoflow in: Axoflow is a simple add-on to your existing pipeline and you immediately get the benefits, without the risks involved in changing a critical, functional system in a major way.
by Balázs Scheidler | Jan 24, 2023 | howto, technology
Log volumes are growing 25% year over year, which means they are doubling every three years. Considering that SIEMs and other log processing tools are licensed based on volume, tools and mechanisms to make log storage and processing more efficient are very much sought for.
A typical solution to this problem is the use of a dedicated log management layer, or as it is called these days: a dedicated observability pipeline. Regardless of how you name the solution in place, there are two separate gains of using these systems:
- you can make data more valuable by fixing up data problems or enriching data,
- you get to choose where the data gets stored (in the SIEM or elsewhere), thus potentially decreasing the volume of data sent to the SIEM.
As you look at the data ingested into the SIEM, you will recognize that not all of that data is displayed in dashboards or used for detecting threats. Nevertheless, organizations still collect and store this data as best practice, because a forensics investigation could potentially use this data, should an incident be discovered later.
While I believe that all data can be made valuable with enough effort, let me zoom in on the volume question.
Simple log deduplication
With something like syslog-ng, you can obviously route specific applications or severity levels somewhere else (like a set of files or an S3 bucket), simply by using filters. In addition to routing non-essential data to a separate log archive, you can also reduce redundancy between messages and combine groups of multi-line logs into single events. Or, you can transform a huge XML-based event into a neater, smaller structure.
Even with all of this in place, you may still get runaway applications sending messages in a tight loop in huge quantities, repeating the same message over and over. The original syslogd had support for suppressing such repeated messages, and syslog-ng has even improved this feature. Here’s a sample message and its suppression that follows it, as produced by syslog-ng:
Jan 23 19:23:10 bzorp sshd[3561]: Failed password for admin from 10.110.2.151 port 9807 ssh2
Jan 23 19:23:20 bzorp sshd: Last message 'Failed password for ' repeated 2 times, suppressed by syslog-ng on bzorp
syslog-ng improves the original syslogd functionality by keeping the $HOST / $PROGRAM values intact to make it easier to correlate the repetitions and the original message.
Let me point out that suppression like this does decrease the volume, but at the same time it also loses information. With the example above, you are losing the timestamp of the two subsequent login failure attempts, which might prove useful in a forensics investigation or when training an AI model that uses failed logins as an input.
This kind of suppression is also pretty limited: sometimes the message is not completely the same: events may differ in ways that are not material to your analytics tools, while the representation as a log message would be different. In these cases, the above suppression would not work.
Flexible streaming log deduplication
syslog-ng is a Swiss Army Knife for logs, so obviously there is a more flexible solution in its arsenal: syslog-ng can perform something I call “streaming correlation” using its grouping-by() parser (available since version 3.8.1 from 2016). A grouping-by() parser is very similar to the “GROUP BY” construct in SQL databases, but instead of tables of data, you can apply it to a stream of events. This is usually used to transform a series of events into a combined one, but this can also be used to deduplicate the log stream while ignoring unimportant changes to the message, as discussed in this GitHub thread.
Here is an example with an iptables message parsed by our iptables-parser() which has ${PROTO}, ${SRC}, ${DST} and ${DPT} fields extracted by the time it gets into this processing element:
parser p_dedup {
grouping-by(
key("${.iptables.PROTO}/${.iptables.SRC}/${.iptables.DST}/${.iptables.DPT}")
aggregate(
value("MESSAGE" "${MESSAGE} REPEAT=$(- $(context-length) 1)")
)
timeout(10)
inject-mode(aggregate-only));
};
This configuration instructs syslog-ng to follow the log stream and “group” all messages that have the same key within a 10 second window. The key contains only proto/srcip/dstip/dstport values and omits srcport which can be considered unimportant when looking at a sequence of connections.
Once the 10 second elapses, syslog-ng reports a single event with the $MESSAGE part changed, so that it includes the number of messages that were considered the same. Do note that you can construct the “aggregate” message quite flexibly. You can
- change any existing name-value pairs or even add new ones.
- have repetitions in a dedicated field so it does not change $MESSAGE itself.
- do aggregations for various fields across the group (using the $(sum) or $(average) template functions for example)
Using grouping-by() while collecting data is a lot more performant that storing the entire data set and then doing the same query from the database. It reduces the amount of data to be ingested and the CPU time required to come up with the same aggregation at search time.
One caveat is that you should probably store the raw data stream into a separate archive and only perform these kind of reductions en-route to your SIEM/analytics/dashboarding system, so that you can access to the unchanged, raw data for forensics investigations or the training of AI models.
In case you would like to play with streaming deduplication and syslog-ng, here’s a complete syslog-ng configuration that I’ve prepared while writing this blog post. If you send an iptables message to TCP port 2000, it would perform deduplication with a 10 second window.
@version: 4.0
@include "scl.conf"
parser p_dedup {
grouping-by(
key("${.iptables.PROTO}/${.iptables.SRC}/${.iptables.DST}/${.iptables.DPT}")
aggregate(
value("MESSAGE" "${MESSAGE} REPEAT=$(- $(context-length) 1)")
)
timeout(10)
inject-mode(aggregate-only));
};
log {
source { tcp(port(2000)); };
parser { iptables-parser(); };
parser(p_dedup);
destination { file("deduplicated.log"); };
}
Just start syslog-ng with the config above in the foreground (-d tells syslog-ng to run in debug mode, which you can omit):
$ /usr/sbin/syslog-ng -F -d -f <path/to/config/file
Then post a message to port 2000 using netcat (repeat this potentially a number of times):
$ echo '<5> https: IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=63370 DF PROTO=TCP SPT=46006 DPT=443 WINDOW=65495 RES=0x00 SYN URGP=0' | nc -q0 localhost 2000
And you will get this output in deduplicated.log for 6 repetitions of the same message:
Jan 24 10:22:07 localhost https: IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=63370 DF PROTO=TCP SPT=46006 DPT=443 WINDOW=65495 RES=0x00 SYN URGP=0 REPEAT=6
by Balázs Scheidler | Jan 16, 2023 | background, technology
It’s been a while since I personally acted as the release manager for a syslog-ng release, the last such release was 3.3.1 back in October 2011. v3.3 was an important milestone, as that was the version that introduced threaded mode and came with a completely revamped core architecture to scale up properly on computers that had multiple CPUs or cores. I released syslog-ng 4.0.1 a couple of weeks ago which brings with it the support for runtime typing, which is a significant conceptual improvement.
Apart from typing, which I have discussed at length already, the release sports important additions and improvements in syslog-ng’s support for Python, which I would like to zoom into a bit in this post.
In case you are not aware, syslog-ng has allowed you to write source and destination drivers, parsers and template functions in Python for a while now. See this post on writing a source in general and this one for writing an HTTP source.
There was one caveat in using Python though: while it was easy to extend an existing configuration and relatively easy to deploy these in a specific environment, syslog-ng lacked the infrastructure to merge such components into syslog-ng itself and expose this functionality as if it was implemented natively. For instance, to use the Python based HTTP source described in the blog post I mentioned above, you needed to write something like this to use the Python based http source:
source s_http {
python(
class("httpsource_v2.HTTPSource")
options("port", "8081")
);
};
As you can see, this syntax is pretty foreign, at least if you compare this to a native driver that would look like this:
source s_http {
http(port(8081));
};
A lot simpler, right? Apart from configuration syntax, there was another shortcoming though: Python code usually relies on 3rd party libraries, usually distributed using PyPI and installed using pip. Up to 4.0.0, one needed to take care about these dependencies manually. The http source example above needs you to install the “python3-twisted” package using dnf/apt-get or pip manually and only then would you be able to use it.
These short-comings are all addressed in the 4.0.0 release, so that:
- 3rd party libraries are automatically managed once you install syslog-ng.
- you can use native configuration syntax,
- we can ship Python code as a part of syslog-ng,
Let’s break these down one-by-one.
Managing 3rd party Python dependencies
From now on, syslog-ng automatically creates and populates a Python virtualenv to host such 3rd party dependencies. This virtualenv is located in ${localstatedir}/venv, which expands to /var/lib/syslog-ng/venv normally. The virtualenv is created by a script named syslog-ng-update-virtualenv, which is automatically run at package installation time.
The list of packages that syslog-ng will install into this virtualenv is described by /usr/lib/syslog-ng/python/requirements.txt.
If you want to make further libraries available (for instance because your local configuration needs it), you can simply use pip to install them:
$ /var/lib/syslog-ng/python-venv/bin/pip install <pypi package>
syslog-ng will automatically activate this virtualenv at startup, no need to explicitly activate it before launching syslog-ng.
Using this mechanism, system installed Python packages will not interfere with packages that you need because of a syslog-ng related functionality.
Native configuration syntax for Python based plugins using blocks.
There are two ways of hiding the implementation complexities of a Python based component, in your configuration file:
- using blocks to wrap the python() low level syntax, described just below
- using Python based config generators, described in the next section
Blocks have been around for a while, they basically allow you to take a relatively complex configuration snippet and turn it into a more abstract component that can easily be reused. For instance, to allow using this syntax:
source s_http {
http(port(8081));
};
and turn it into a python() based source driver, you just need the following block:
block source http(port(8081)) {
python(class("httpsource_v2.HTTPSource")
options("port", "`port`") );
}
The content of the block will be substituted into the configuration, whenever the name of the block is encountered. Parameters in the form of param(value) will be substituted using backticks.
In simple cases, using blocks provides just enough flexibility to hide an implementation detail (e.g. that we used Python as the implementation language) and also hides redundant configuration code.
Blocks are very similar to macros as used in other languages. This term was unfortunately already taken in the syslog-ng context, that’s why it has been named differently.
Blocks are defined in syslog-ng include files, these include files you can store as an “scl” subdirectory of the Python module.
Native configuration syntax for Python based plugins using configuration generators.
Sometimes, blocks are insufficient to properly wrap our desired functionality. Sometimes you need conditionals, in other cases you want to use a more complex mechanism or a template language to generate part of the configuration. That you can do using configuration generators.
Configuration generators have also been around for a while, but until now they were only available using external shell scripts (using the confgen module), or restricted to be used from C, syslog-ng’s base language. The changes in 4.0 allow you to write generators in Python.
Here’s an example:
@version: 4.0
python {
from syslogng import register_config_generator
def generate_foobar(args):
print(args)
return "tcp(port(2000))"
#
# this registers a plugin in the "source" context named "foobar"
# which would invoke the generate_foobar() function when a foobar() source
# reference is encountered.
#
register_config_generator("source", "foobar", generate_foobar)
};
log {
# we are actually calling the generate_foobar() function in this
# source, passing all parameters as values in the "args" dictionary
source { foobar(this(is) a(value)); };
destination { file("logfile"); };
};
syslog-ng will automatically invoke your generate_foobar() function whenever it finds a “foobar” source driver and then takes the return value for that function and substitutes back to where it was found. Parameters are passed around in the args parameter.
Shipping Python code with syslog-ng
Until now, Python was more of an “extended” configuration language, but with the features described above, it can actually become a language to write native-looking and native-behaving plugins for syslog-ng, therefore it becomes important for us to ship these.
To submit a Python implemented functionality to syslog-ng, just open a PR that places the new Python code into the modules/python-modules/syslogng/modules subdirectory. This will get installed as a part of our syslog-ng-python package. If you have 3rd party dependencies, just include them in the setup.py and requirements.txt files.
If you need an example how to use the new Python based facilities, just look at the implementation of our kubernetes() source.
by Balázs Scheidler | Sep 16, 2022 | background
The other day I was reading a blog post on handling syslog at scale back on cribl.io’s blog. As you can imagine, syslog-ng has been used to solve syslog related challenges for a while now (24 years to be exact) and with that expertise I wanted to point out a few things in relation to that blog post. This might even become a series.
The blog post linked above, gives some advice how to scale syslog, in the section titled: Scaling Syslog the Right Way. Read the blog post for more details, but here’s my summary:
- place the receiver (e.g. Cribl Stream) right next to your log sources (e.g. in the same data center)
- scale out the receiver over many nodes so it becomes a cluster
- make sure to deploy a load balancer in front
What this means in practice is that you will need a sizeable infrastructure to consume the logs of a syslog producing device. Since my assumption is that all data centers have such appliances, you will need to deploy this infrastructure in each of your data centres (to be close to the sources).
While I can see that load balancing clusters to process log data are important in some scenarios, I don’t think this use case should be one of them. A single node, potentially in a failover High Availability setup should suffice.
There’s a choice between scaling out vs scaling up a workload. Cribl recommends scaling it out. My take is that it should be possible to scale it up before scaling it out.
syslog-ng has a bag of tricks to make it fast even on a single node, thereby reducing hardware costs and operational complexities and the need for a load balancer.
- it is implemented in C (compared to Cribl’s choice of TypeScript, fluentd and logstash are Ruby IIRC)
- it avoids/minimizes copying of data while processing them, its log routing implementation uses copy-on-write semantics for cases where multiple paths potentially change the message in parallel paths
- it avoids/minimizes memory allocations, in the simplest case it allocates 1 block of memory for 1 message
- it uses an efficient asynchronous architecture, using epoll and one thread per CPU core
- it uses a message representation where fields (aka: name-value pairs or properties) are stored in a packed block of memory, that is efficient to look up & serialize.
- it uses internal queueing mechanisms that avoids lock contention and allows back-pressure to be applied selectively
- it offers alternatives to regular expressions, as regexps are pretty slow to evaluate at volume
syslog-ng offers a domain specific language to route and manipulate messages, Cribl uses JavaScript.
I understand that this is an apples to oranges comparison. Cribl seems to have good UX. syslog-ng has good performance.
This is on my ~2018 laptop (Intel(R) Core(TM) i5-7440HQ CPU @ 2.80GHz, 4 cores), with a single destination writing all messages to disk, with syslog parsing enabled.
# single threaded sender
$ loggen -S -r 10000000 -s 300 –active-connections=1 -I 20 -P localhost 2000
average rate = 305506.81 msg/sec, count=6111711, time=20.0052, (average) msg size=304, bandwidth=90697.33 kB/sec
# sending on 10 threads
$ loggen -S -r 10000000 -s 300 –active-connections=10 -I 20 -P localhost 2000
average rate = 561537.95 msg/sec, count=11533347, time=20.5389, (average) msg size=304, bandwidth=166706.58 kB/sec
syslog-ng config:
@version: 3.38
log {
source { tcp(port(2000) log-iw-size(10000) log-fetch-limit(1000) flags(syslog-protocol)) ; };
destination { file("/install/foobar" log-fifo-size(10000)); };
};
by Balázs Scheidler | Aug 26, 2022 | technology
syslog-ng 4 is right around the corner and the work on the topics I listed in this blog post are nearing completion. Instead of a pile of breaking changes, we choose to improve syslog-ng in an evolutionary manner: providing fine grained compatibility with older versions along the way, so that syslog-ng 4 remains a drop-in replacement for any earlier release in the past 15 years.
What evolution in this context means in practice is that features/changes are merged into 3.x releases as we are ready with them, but they are all hidden behind a feature flag: they all come disabled by default and to enable them, one needs to use `@version: 4.0` at the top of one’s configuration file. This process is detailed in Peter Czanik’s blog post with a couple of real-world examples.
The first set of changes went into 3.36.1 released in March, some more followed in 3.37.1 (and a related blog post) released in June and 3.38.1 is any day now with most changes accumulated already on the “master” branch (nightly snapshots).
Hopefully, this is going to be the last 3.x release before 4.x is cut, but this also depends on feedback and issues that we might encounter in this cycle.
This release was focused primarily to get 4.0 ready and as such it concentrated pretty much on finishing up the typing feature. If you have already read the linked blog post, you might already be aware that we intend to associate runtime type information to any name-value pair that we encounter, so that we can 1) allow type aware comparisons in routing decisions, 2) reproduce the original types when sending a log message to consumers. I also expect this to be an important feature as we implement more features in our long term objectives (observability, app awareness, user friendliness).
Problems that type aware comparisons attempt to solve
Probably the most important change in 3.38.1 is the introduction of type aware comparisons. Traditionally syslog-ng had two kinds of comparison operators, just like shell scripts with the “test” builtin command.
- one to compare strings (eq, ne, gt, lt)
- one to compare numbers (==, !=, >, <)
Here’s an example:
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.response}" >= "500") {
file("/logs/apache-errors");
};
};
This example shows how to route HTTP 500 and above requests to a separate file. If you look at the if {} statement, you can see that we compared the HTTP response code to 500 and tried to capture anything that is higher than 500. But there’s a potential trap in here. ${.apache.response} is a string that contains a number. “500” in syslog-ng 3.x is also a string.
How this comparison is performed depends on the operator that we use: numeric (<, >, ==, !=) or string (lt, gt, eq, ne) focused.
If you look at the example again, you can see that we used the “numeric” operators, which means that the configuration above correctly performs the comparison, converts both “${.apache.response}” and “500” to numbers and compares them numerically.
But then, let’s see this example:
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.httpversion}" == "1.0") {
file("/logs/http-10-logs");
};
};
Again, we are trying to compare a name-value pair against a literal string, this time checking for equality, and albeit version numbers are not strictly numeric, they are in this specific case. Also, using “==” as an operator as before.
But this example will do something that is pretty unexpected:
- we used the numeric operators in the example, so syslog-ng would convert both “${.apache.httpversion}” and “1.0” to numbers
- but the numeric operators only support INTEGERS, floating point numbers are not supported (actually syslog-ng uses the function atoi(3) for this conversion)
- atoi() actually picks up the numbers before the “.” in the version number and converts that to an integer, this means “1.0” becomes 1 and “1.1” becomes 1 too!
- so the comparison above would evaluate to TRUE to any value that starts with a 1 and then a non-digit character.
- this means that all HTTP versions starting from 1.0 up to 1.9 end up in our file that we designated as one to hold 1.0 only traffic.
Not really the expected behaviour. But it becomes worse.
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.request}" == "/wp-admin/login.php") {
file("/logs/wordpress-logins");
};
};
This time, we are trying to filter our data based on a string comparison, and we erroneously used the numeric operator. This is what happens:
- Neither “${.apache.request}” nor “/wp-admin/login.php” is numeric, they don’t even have digits in front of them
- Both values are converted to 0.
- Zero equals to zero, so the filter expression above is always TRUE.
There are other similar cases, the ugliest one when comparing a name-value pair to an empty string with numeric operators. Results are completely unexpected.
Type aware comparisons come to the rescue
I saw numerous cases where someone got the operator incorrect when trying to compare/match something in syslog-ng. I felt that the issue has never been a user error, rather we made a poor job of providing a user friendly syntax and thus we pushed too much responsibility on those attempting to make use of these features.
But solving these kind of design mistakes is never easy. Some of our users have figured this out already. We don’t want to break their configuration, right? But we want to make this easier, more intuitive for new users or new use-cases.
The solution we implemented was to make the numeric operators (==, !=, <, >) do the right thing. Based on the types of its arguments, it can in most cases infer what would be the right thing to do. So let’s help them there. We took some inspiration from JavaScript (which operates in a similar string-heavy environment) and implemented more intuitive rules for our – previously numeric only – comparisons.
Let’s see our previous examples:
@version: 4.0
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.response}" >= 500) {
file("/logs/apache-errors");
};
};
If you compare this to my previous example, I have removed the quotes from around “500”. In syslog-ng 3.x, the quotes were mandatory. In 4.x, they are not. If you are not using quotes, the literal 500 becomes a numeric literal. And comparing a string to a number would compare those as numeric (e.g. just like JavaScript). We could even improve the Apache parser to make ${.apache.response} a number as it parses its input, but to do the right thing, it is enough that one side of the comparison is numeric.
Next example:
@version: 4.0
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.httpversion}" == "1.0") {
file("/logs/http-10-logs");
};
};
I haven’t changed anything in this example, both “${.apache.httpversion}” and “1.0” are strings and they are compared as strings. So this time, only HTTP/1.0 would be routed to our logfile. 1.1 or even 1.9 would be filtered out, as expected. We could use floating point based comparisons if we wanted to by removing the quotes (just like in the previous example) or by using explicit type-casting:
if ("${.apache.httpversion}" == 1.0)
OR
if (double("${.apache.httpversion}") == "1.0")
Type casting can be applied anywhere where we used template strings before to apply a type to the result of the template expansion.
And here’s the third example:
@version: 4.0
log {
source { file("/var/log/apache2/access.log"); };
parser { apache-accesslog-parser(); };
if ("${.apache.request}" == "/wp-admin/login.php") {
file("/logs/wordpress-logins");
};
};
Again, no changes necessary. Both sides are strings, we are comparing as strings. No need to use the “eq” operator. Just one set of operators and sometimes explicit type-casts will cover all use-cases. For compatibility reasons, the old “string” operators (eq, ne, lt, gt) remain to be available, but I hope we can forget those eventually.
Other typing related changes
This section briefly lists the various components that we needed to adapt to typing. These changes happened since 3.36.1 was released but not explicitly announced in those versions. Let me know if you are interested in any of these topics in more detail, probably there are a couple of blog posts worth of content here:
- type aware comparisons in filter expressions: as detailed above, the previously numeric operators become type aware and the exact comparison performed will be based on types associated with the values that we compare.
- json-parser() and $(format-json): JSON support is massively improved with the introduction of types. For one: type information is retained across input parsing->transformation->output formatting. JSON lists (arrays) are now supported and are converted to syslog-ng lists so they can be manipulated using the $(list-*) template functions. There are other important improvements in how we support JSON.
- set(), groupset(): in any case where we allow the use of templates, support for type-casting was added and the type information is properly promoted.
- db-parser() type support: db-parser() gets support for type casts, <value> assignments within db-parser() rules can associate types with values using the type-casting syntax, e.g. <value name=”foobar”>int32($PID)</value>. The “int32” is a type-cast that associates $foobar with an integer type. db-parser()’s internal parsers (e.g. @NUMBER@) will also associated type information with a name-value pair automatically.
- add-contextual-data() type support: any new name-value pair that is populated using add-contextual-data() will propagate type information, similarly to db-parser().
- map-value-pairs() type support: propagate type information
- SQL type support: the sql() driver gained support for types, so that columns with specific types will be stored as those types.
- template type support: templates can now be casted explicitly to a specific type, but they also propagate type information from macros/template functions and values in the template string
- value-pairs type support: value-pairs form the backbone of specifying a set of name-value pairs and associated transformations to generate JSON or a key-value pair format. It also gained support for types, the existing type-hinting feature that was already part of value-pairs was adapted and expanded to other parts of syslog-ng.
- on-disk serialized formats (e.g. disk buffer/logstore): we remain compatible with messages serialized with an earlier version of syslog-ng, and the format we choose remains compatible for “downgrades” as well. E.g. even if a new version of syslog-ng serialized a message, the old syslog-ng and associated tools will be able to read it (sans type information of course)
Recent Comments