This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Modifying messages using rewrite rules

The AxoSyslog application can rewrite parts of the messages using rewrite rules. Rewrite rules are global objects similar to parsers and filters and can be used in log paths. The AxoSyslog application has two methods to rewrite parts of the log messages: substituting (setting) a part of the message to a fix value, and a general search-and-replace mode.

  • Substitution completely replaces a specific part of the message that is referenced using a built-in or user-defined macro.

  • General rewriting searches for a string in the entire message (or only a part of the message specified by a macro) and replaces it with another string. Optionally, this replacement string can be a template that contains macros.

Rewriting messages is often used in conjunction with message parsing parser: Parse and segment structured messages.

Rewrite rules are similar to filters: they must be defined in the syslog-ng.conf configuration file and used in the log statement. You can also define the rewrite rule inline in the log path.

1 - Replacing message parts

To replace a part of the log message, you have to:

  • define a string or regular expression to find the text to replace

  • define a string to replace the original text (macros can be used as well)

  • select the field of the message that the rewrite rule should process

Substitution rules can operate on any soft macros, for example, MESSAGE, PROGRAM, or any user-defined macros created using parsers. You can also rewrite the structured-data fields of messages complying to the RFC5424 (IETF-syslog) message format.

Substitution rules use the following syntax:

Declaration:

   rewrite <name_of_the_rule> {
        subst(
            "<string or regular expression to find>",
            "<replacement string>", value(<field name>), flags()
        );
    };

The type() and flags() options are optional. The type() specifies the type of regular expression to use, while the flags() are the flags of the regular expressions. For details on regular expressions, see Regular expressions.

A single substitution rule can include multiple substitutions that are applied sequentially to the message. Note that rewriting rules must be included in the log statement to have any effect.

Example: Using substitution rules

The following example replaces the IP in the text of the message with the string IP-Address.

   rewrite r_rewrite_subst{
        subst("IP", "IP-Address", value("MESSAGE"));
    };

To replace every occurrence, use:

   rewrite r_rewrite_subst{
        subst("IP", "IP-Address", value("MESSAGE"), flags("global"));
    };

Multiple substitution rules are applied sequentially. The following rules replace the first occurrence of the string IP with the string IP-Addresses.

   rewrite r_rewrite_subst{
        subst("IP", "IP-Address", value("MESSAGE"));
        subst("Address", "Addresses", value("MESSAGE"));
    };

Example: Anonymizing IP addresses

The following example replaces every IPv4 address in the MESSAGE part with its SHA-1 hash:

   rewrite pseudonymize_ip_addresses_in_message {subst ("((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))", "$(sha1 $0)", value("MESSAGE"));};

2 - Setting message fields to specific values

To set a field of the message to a specific value, you have to:

  • define the string to include in the message, and
  • select the field where it should be included.
  • You can set the type of the field. Where you can use of templates in set() and groupset(), you can use type-casting, and the type information is properly promoted. For details, see Specifying data types in value-pairs.

You can set the value of available macros, for example, HOST, MESSAGE, PROGRAM, or any user-defined macros created using parsers (for details, see parser: Parse and segment structured messages and db-parser: Process message content with a pattern database (patterndb)). Note that the rewrite operation completely replaces any previous value of that field.

Use the following syntax:

Declaration:

   rewrite <name_of_the_rule> {
        set("<string to include>", value(<field name>));
    };

Example: Setting message fields to a particular value

The following example sets the HOST field of the message to myhost.

   rewrite r_rewrite_set{
        set("myhost", value("HOST"));
    };

The following example appends the “suffix” string to the MESSAGE field:

   rewrite r_rewrite_set{
        set("$MESSAGE suffix", value("MESSAGE"));
    };

For details on rewriting SDATA fields, see Creating custom SDATA fields.

You can also use the following options in rewrite rules that use the set() operator.

   rewrite <name_of_the_rule> {
        set("<string to include>", value(<field name>), on-error("fallback-to-string");
    };

3 - Setting severity with the set-severity() rewrite function

It is possible to configure the severity field with the set-severity() rewrite function. When configured, the set-severity() rewrite function will only rewrite the $SEVERITY field in the message to the first parameter value specified in the function.

Declaration

   rewrite <name_of_the_rule> {
        set-severity("severity string or number");
    };

Parameters

The set-severity() rewrite function has a single, mandatory parameter that can be defined as follows:

   `set-severity( "parameter1" );`

Accepted values

The set-severity() rewrite function accepts numeric values, named values, and aliases. Aliases are available in AxoSyslog version 4.6 and later.

Numerical CodeNamed ValueAlias
0emergSYSLOG_SEVERITY_CODE(0)
0emergencySYSLOG_SEVERITY_CODE(0)
0panicSYSLOG_SEVERITY_CODE(0)
1alertSYSLOG_SEVERITY_CODE(1)
2critSYSLOG_SEVERITY_CODE(2)
2criticalSYSLOG_SEVERITY_CODE(2)
2fatalSYSLOG_SEVERITY_CODE(2)
3errSYSLOG_SEVERITY_CODE(3)
3errorSYSLOG_SEVERITY_CODE(3)
4warningSYSLOG_SEVERITY_CODE(4)
4warnSYSLOG_SEVERITY_CODE(4)
5noticeSYSLOG_SEVERITY_CODE(5)
6infoSYSLOG_SEVERITY_CODE(6)
6logSYSLOG_SEVERITY_CODE(6)
7debugSYSLOG_SEVERITY_CODE(7)

Example usage for the set-severity() rewrite function

The following examples can be used in production for the set-severity() rewrite function.

Example using string:

   rewrite {
        set-severity("info");
    };

Example using numeric string:

   rewrite {
        set-severity("6");
    };

Example using template:

   rewrite {
        set-severity("${.json.severity}");
    };

4 - Setting the facility field with the set-facility() rewrite function

It is possible to set the facility field with the set-facility() rewrite function. When set, the set-facility() rewrite function will only rewrite the $PRIORITY field in the message to the first parameter value specified in the function.

Declaration

   log {
                    source { system(); };
                        if (program("postfix")) {
                          rewrite { set-facility("mail"); };
                        };
                        destination { file("/var/log/mail.log"); };
                        flags(flow-control);
                    };

Parameters

The set-facility() rewrite function has a single, mandatory parameter that can be defined as follows:

   `set-facility( "parameter1" );`

Accepted values

The set-facility() rewrite function accepts the following values:

  • numeric strings: [0-7]
  • named values: emerg, emergency, panic, alert, crit, critical, err, error, warning, warn, notice, info, informational, debug

Example usage for the set-facility() rewrite function

The following example can be used in production for the set-facility() rewrite function.

   rewrite {
    set-facility("info");
    set-facility("6");
    set-facility("${.json.severity}");};

5 - Setting the priority of a message with the set-pri() rewrite function

You can set the PRI value of a BSD or IETF syslog message with the set-pri() rewrite function by specifying a template string. This is useful, for example, if incoming messages do not have a PRI value specified by default, but a PRI value is required for filtering purposes.

When configured, the set-pri() function will only rewrite the PRI value of the message field.

Declaration

   rewrite <rule-name> {
        set-pri("template-string");
    };

Parameters

The set-pri() rewrite function expects a template string as its only parameter, for example:

  • set-pri(“42”);

  • set-pri("$.json.priority");

Accepted values

The template string specified for the set-pri() rewrite function must expand to a natural number in the interval of 0–1023, inclusive. This means that if you, for example, extract the value from a syslog <PRI> header (such as <42>), then you need to remove the opening and closing brackets (< >) in the specified template string.

Example: Temporarily raising the priority of an application

In the following example, the set-pri() rewrite function is used to temporarily raise the priority of the application myprogram:

   log {
      source { system(); };
      if (program("myprogram")){
      rewrite { set-pri("92"); };
      };
      destination { file("/var/log/mail.log"); };
      flags(flow-control);
    }

Example: Changing the priority of an application log message in JSON format

In the following example, an application sends log messages in the following JSON format:

   {
    "time": "2003-10-11T22:14:15.003Z",
    "host": "mymachine",
    "priority": "165",
    "message": "An application event log entry."
    }

You can parse these logs with the JSON parser function:

   {
    parser p_json {
    json-parser (prefix(".json."));
    }

As the application message contains a valid priority field, you can use the set-pri() rewrite function to modify the priority of the message:

   set-pri("$.json.priority");

6 - Setting match variables with the set-matches() rewrite rule

Match macros ($1, $2, ... $255) are temporary variables. You can use them for general purposes when operating with list-like items. For example, the match() filter stores capture group results in match variables when the store-matches flag is set, or the JSON parser produces match variables if the parsed JSON data is an array.

It is possible to set match variables in a single operation with the set-matches() rewrite function. set-matches() uses AxoSyslog list expressions to set $1, $2, ... $255, so it can be considered as a conversion function between AxoSyslog lists and match variables.

Declaration

   rewrite <name_of_the_rule> {
        set-matches("<list-expression or list-based template function>");
    };

Example usage for the set-matches() rewrite function

In the following two examples, $1, $2, and $3 will be set to foo, bar, and baz, respectively.

Example using string:

   rewrite {
        set-matches("foo,bar,baz");
    };

Example using a list template function:

   rewrite {
        set-matches("$(explode ':' 'foo:bar:baz')");
    };

7 - Unsetting message fields

You can unset macros or fields of the message, including any user-defined macros created using parsers (for details, see parser: Parse and segment structured messages and db-parser: Process message content with a pattern database (patterndb)). Note that the unset operation completely deletes any previous value of the field that you apply it on.

Use the following syntax:

Declaration:

   rewrite <name_of_the_rule> {
        unset(value("<field-name>"));
    };

Example: Unsetting a message field

The following example unsets the HOST field of the message.

   rewrite r_rewrite_unset{
        unset(value("HOST"));
    };

To unset a group of fields, you can use the groupunset() rewrite rule.

Declaration:

   rewrite <name_of_the_rule> {
        groupunset(values("<expression-for-field-names>"));
    };

Example: Unsetting a group of fields

The following rule clears all SDATA fields:

   rewrite r_rewrite_unset_SDATA{
        groupunset(values(".SDATA.*"));
    };

8 - Renaming message fields

If you want to change the name of a field of a message, you can use rename() rewrite rules. This can be also achieved via using set() and unset() but those require extra conditions and two operation instead of one.

The rename() rewrite rule uses positional arguments and they are both required. It supports condition rewrite. For more information, see Conditional rewrites.

Declaration

   rewrite r_rewrite_rename {
        rename("<string1>" "<string2>");
    };

Example usage for the rename() rewrite function

The following example renames the .app.name into .container if the .app.name exists. Otherwise, it does nothing.

   rewrite r_rewrite_rename {
        rename(".app.name" ".container");
    };

9 - Creating custom SDATA fields

If you use RFC5424-formatted (IETF-syslog) messages, you can also create custom fields in the SDATA part of the message (For details on the SDATA message part, see The STRUCTURED-DATA message part). According to RFC5424, the name of the field (its SD-ID) must not contain the @ character for reserved SD-IDs. Custom SDATA fields must be in the following format: .SDATA.group-name@<private enterprise number>.field-name, for example, [email protected]. (18372.4 is the private enterprise number of Axoflow, the developer of AxoSyslog.)

Example: Rewriting custom SDATA fields

The following example sets the sequence ID field of the RFC5424-formatted (IETF-syslog) messages to a fixed value. This field is a predefined SDATA field with a reserved SD-ID, therefore its name does not contain the @ character.

   rewrite r_sd {
        set("55555" value(".SDATA.meta.sequenceId"));
    };

It is also possible to set the value of a field that does not exist yet, and create a new, custom name-value pair that is associated with the message. The following example creates the [email protected] field and sets its value to yes. If you use the ${[email protected]} macro in a template or SQL table, its value will be yes for every message that was processed with this rewrite rule, and empty for every other message.

The next example creates a new SDATA field-group and field called custom and sourceip, respectively:

   rewrite r_rewrite_set {
        set("${SOURCEIP}" value("[email protected]"));
    };

If you use the ${[email protected]} macro in a template or SQL table, its value will be that of the SOURCEIP macro (as seen on the machine where the SDATA field was created) for every message that was processed with this rewrite rule, and empty for every other message.

You can verify whether or not the format is correct by looking at the actual network traffic. The SDATA field-group will be called [email protected], and sourceip will become a field within that group. If you decide to set up several fields, they will be listed in consecutive order within the field-group’s SDATA block.

10 - Setting multiple message fields to specific values

The groupset() rewrite rule allows you to modify the value of multiple message fields at once, for example, to change the value of sensitive fields extracted using patterndb, or received in a JSON format. (If you want to modify the names of message fields, see map-value-pairs: Rename value-pairs to normalize logs.)

  • The first parameter is the new value of the modified fields. This can be a simple string, a macro, or a template (which can include template functions as well).
  • The second parameter (values()) specifies the fields to modify. You can explicitly list the macros or fields (a space-separated list with the values enclosed in double-quotes), or use wildcards and glob expressions to select multiple fields.
  • Note that groupset() does not create new fields, it only modifies existing fields.
  • You can refer to the old value of the field using the $_ macro. This is resolved to the value of the current field, and is available only in groupset() rules.
  • You can set the type of the field. Where you can use of templates in set() and groupset(), you can use type-casting, and the type information is properly promoted. For details, see Specifying data types in value-pairs.

Declaration:

   rewrite <name_of_the_rule> {
        groupset("<new-value-of-the-fields>", values("<field-name-or-glob>" ["<another-field-name-or-glob>"]));
    };

Example: Using groupset rewrite rules

The following examples show how to change the values of multiple fields at the same time.

  • Change the value of the HOST field to myhost.

        groupset ("myhost" values("HOST"))
    
  • Change the value of the HOST and FULLHOST fields to myhost.

        groupset ("myhost" values("HOST" "FULLHOST"))
    
  • Change the value of the HOST, FULLHOST and fields to lowercase.

        groupset ("$(lowercase "$_")" values("HOST" "FULLHOST"))
    
  • Change the value of each field and macro that begins with .USER to nobody.

        groupset ("nobody" values(".USER.*"))
    
  • Change the value of each field and macro that begins with .USER to its SHA-1 hash (truncated to 6 characters).

        groupset ("$(sha1 --length 6 $_)" values(".USER.*"))
    

11 - map-value-pairs: Rename value-pairs to normalize logs

The map-value-pairs() parser allows you to map existing name-value pairs to a different set of name-value pairs. You can rename them in bulk, making it easy to use for log normalization tasks (for example, when you parse information from different log messages, and want to convert them into a uniform naming scheme). You can use the normal value-pairs expressions, similarly to value-pairs based destinations. Using map-value-pairs() retains type data if available.

Available in AxoSyslog version 3.10 and later.

Declaration:

   parser parser_name {
        map-value-pairs(
            <list-of-value-pairs-options>
        );
    };

Example: Map name-value pairs

The following example creates a new name-value pair called username, adds the hashed value of the .apache.username to this new name-value pair, then adds the webserver prefix to the name of every name-value pair of the message that starts with .apache

   parser p_remap_name_values {
        map-value-pairs(
            pair("username", "'($sha1 $.apache.username)")
            key('.apache.*' rekey(add-prefix("webserver")))
        );
    };

12 - Conditional rewrites

Starting with 3.2, it is possible to apply a rewrite rule to a message only if certain conditions are met. The condition() option effectively embeds a filter expression into the rewrite rule: the message is modified only if the message passes the filter. If the condition is not met, the message is passed to the next element of the log path (that is, the element following the rewrite rule in the log statement, for example, the destination). Any filter expression normally used in filters can be used as a rewrite condition. Existing filter statements can be referenced using the filter() function within the condition. For details on filters, see Filters.

Using conditional rewrite

The following procedure summarizes how conditional rewrite rules (rewrite rules that have the condition() parameter set) work. The following configuration snippet is used to illustrate the procedure:

   rewrite r_rewrite_set{
        set(
            "myhost",
            value("HOST")
            condition(program("myapplication"))
        );
    };
    log {
        source(s1);
        rewrite(r_rewrite_set);
        destination(d1);
    };

To configure condtional rewrite

  1. The log path receives a message from the source (s1).

  2. The rewrite rule (r_rewrite_set) evaluates the condition. If the message matches the condition (the PROGRAM field of the message is “myapplication”), AxoSyslog rewrites the log message (sets the value of the HOST field to “myhost”), otherwise it is not modified.

  3. The next element of the log path processes the message (d1).

Example: Using conditional rewriting

The following example sets the HOST field of the message to myhost only if the message was sent by the myapplication program.

   rewrite r_rewrite_set{set("myhost", value("HOST") condition(program("myapplication")));};

The following example is identical to the previous one, except that the condition references an existing filter template.

   filter f_rewritefilter {program("myapplication");};
    rewrite r_rewrite_set{set("myhost", value("HOST") condition(filter(f_rewritefilter)));};

13 - Adding and deleting tags

To add or delete a tag, you can use rewrite rules. To add a tag, use the following syntax:

   rewrite <name_of_the_rule> {
        set-tag("<tag-to-add>");
    };

To delete a tag, use the following syntax:

   rewrite <name_of_the_rule> {
        clear-tag("<tag-to-delete>");
    };

Templates (macros, template functions) can be used when specifying tags, for example, set-tag("dyn::$HOST");.

14 - Rewrite the timezone of a message

Starting with version 3.24 of the AxoSyslog application, you can manipulate the timezone information of messages using rewrite rules. You can:

By default, these operations modify the date-related macros of the message that correspond to the date the message was sent (that is, the S_ macros). You can modify the dates when AxoSyslog has received the messages (that is, the R_ macros), but this is rarely needed. To do so, include the time-stamp(recvd) option in the operation, for example:

   rewrite { fix-time-zone("EST5EDT" time-stamp(recvd)); };

fix-time-zone()

Use the fix-time-zone() operation to correct the timezone of a message if it was parsed incorrectly for some reason, or if the client did not include any timezone information in the message. You can specify the new timezone as the name of a timezone, or as a template string. For example, use the following rewrite rule to set the timezone to EST5EDT:

   rewrite { fix-time-zone("EST5EDT"); };

If you have lots of clients that do not send timezone information in the log messages, you can create a database file that stores the timezone of the clients, and feed this data to AxoSyslog using the add-contextual-data() feature. For details, see Adding metadata from an external file.

guess-time-zone()

Use the guess-time-zone() operation attempts to set the timezone of the message automatically, using heuristics on the timestamps. Normally the AxoSyslog application performs this operation automatically when it parses the incoming message. Using this operation in a rewrite rule can be useful if you cannot parse the incoming message for some reason (and use the flags(no-parse) option in your source, but you want to set the timezone automatically later (for example, after you have preprocessed the message).

Using this operation is identical to using the flags(guess-timezone) flag in the source.

set-time-zone()

Use the set-time-zone() operation to set the timezone of the message to a specific value, that is to convert an existing timezone to a different one. This operation is identical to setting the time-zone() option in a destination or as a global option, but can be applied selectively to the messages using conditions.

15 - Anonymizing credit card numbers

Log messages of banking and e-commerce applications might include credit card numbers (Primary Account Number or PAN). According to privacy best practices and the requirements of the Payment Card Industry Data Security Standards (PCI-DSS), PAN must be rendered unreadable. The AxoSyslog application uses a regular expression to detect credit card numbers, and provides two ways to accomplish this: you can either mask the credit card numbers, or replace them with a hash. To mask the credit card numbers, use the credit-card-mask() or the credit-card-hash() rewrite rules in a log path.

Declaration:

   @include "scl/rewrite/cc-mask.conf"
    
    rewrite {
        credit-card-mask(value("<message-field-to-process>"));
    };

By default, these rewrite rules process the MESSAGE part of the log message.

credit-card-hash()

Synopsis:credit-card-hash(value(""))

Description: Process the specified message field (by default, ${MESSAGE}), and replace any credit card numbers (Primary Account Number or PAN) with a 16-character-long hash. This hash is generated by calculating the SHA-1 hash of the credit card number, selecting the first 64 bits of this hash, and representing this 64 bits in 16 characters.

credit-card-mask()

Synopsis:credit-card-mask(value(""))

Description: Process the specified message field (by default, ${MESSAGE}), and replace the 7-12th character of any credit card numbers (Primary Account Number or PAN) with asterisks (\*). For example, AxoSyslog replaces the number 5542043004559005 with 554204\*\*\*\*\*\*9005.