Algernon@BalaBit

Guarding Your Business

HOWTO: Write a simple template function for syslog-ng

Saturday, January 29, 2011 @ 06:01 PM Author: Gergely Nagy

A week or two ago, on a hungarian forum someone wanted to implement a log rotation scheme within syslog-ng, using no external programs, in such a way that his logs would get rotated every three days. While that’s easy to accomplish using the overwrite_if_older() setting, I figured one can do better, and not only rotate logs every three days, but store each day in a separate file aswell. That too, is possible already, but the solution is not pretty. So I sat down, estimating that I could present a solution within an hour – and boy, was I suprised!

It turns out, one needs a lot less than that to implement a simple template function, and for that reason, I’m going to show you how!

To see what template functions are, I’d refer my dear readers to our excellent documentation on this topic. Now, what I will implement here today, is a $(modN) function, which takes two numbers as arguments, divides the first with the second, and returns the remainder. We can use this to place the logs for each day into a different config, yet, still rotate every three days:

destination d_file {
  file("/var/log/messages-$(modN ${WEEK_DAY} 3).log");
};

We’ll take the current week day, divide by three, and use the remainder as part of our filename. This guarantees that each consecutive day’s will end up in a different file, yet, we’ll use no more than three files.

To begin, lets have a look at the simplest template function available in syslog-ng: echo, in modules/basicfuncs/basicfuncs.c :

static void tf_echo(LogMessage *msg, gint argc,
                    GString *argv[], GString *result);

As we can see, it takes four arguments: the current log message, msg, the number of arguments passed to the function, argc, a list of GStrings – the arguments themselves -, argv, and finally, a GString to store the result in, result. Pretty straightforward so far, huh? Conveniently, syslog-ng does all the parsing for us, and we only need to care about what we want to do: grab two ints, and return a remainder.

However, syslog-ng passes GStrings to us, so we’ll have to do some extra work, and convert them to integers. Luckily, that isn’t particularly hard, either, since the standard C library provides atol(). So how would our function look?

static void tf_modN(LogMessage *msg, gint argc,
                    GString *argv[], GString *result)
{
  gulong i1, i2;
  if (argc != 2)
    return;
  i1 = atol(argv[0]->str);
  i2 = atol(argv[1]->str);
  g_string_append_printf (result, "%lu", i1 % i2);
}

One thing to note here, that might not be obvious for people new to syslog-ng: the function does not simply return a value, because that would make it very hard to allow more complex template functions (such as $(if)), instead, a template function has to append its result to the result GString it received as a parameter.

And that’s about it! What is left still, is to hook this into syslog-ng, tell it that this is, indeed, a template function. Luckily, we also have a helper macro or two to help with that. First of all, we’ll have to declare that this is a simple template function. Simple, because well… it is! One can do more complex template functions, but that will be the topic of another HOWTO. For now, we’re doing simple things:

TEMPLATE_FUNCTION_SIMPLE(tf_modN);

Now that it’s registered as a simple template function, we need to tell syslog-ng about it. Scrolling down to the end of modules/basicfuncs/basicfuncs.c, we find a variable named builtin_tmpl_func_plugins, which is a list of function name – template function pairs. This is where we need to add our tf_modN, to register it as the $(modN) template function:

TEMPLATE_FUNCTION_PLUGIN(tf_modN, "modN"),

With this done, we can save the file, recompile syslog-ng and start using our template function. It’s that simple! We didn’t even need to read any documentation, as the example we found was so self-explanatory.

A slightly more advanced version of the above function can be found in my git repo, on the howto/tf/modN branch: that version has a little more error handling, but other than that, it’s pretty much the same thing. The code can, of course, be viewed online here.

One Response to “HOWTO: Write a simple template function for syslog-ng”

  1. [...] A blog, how to get started with coding [...]


Leave a Reply