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.
Note
The order of filters, rewriting rules, and parsers in the log statement is important, as they are processed sequentially.
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.
Note
For case-insensitive searches, add the flags(ignore-case)
option. To replace every occurrence of the string, add flags(global)
option. Note that the store-matches
flag is automatically enabled in rewrite rules.
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.
Note
If the parameter value is not a valid parameter value, the function ignores it and sends a debug message, but the AxoSyslog application still sends the message.
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 Code |
Named Value |
Alias |
0 |
emerg |
SYSLOG_SEVERITY_CODE(0) |
0 |
emergency |
SYSLOG_SEVERITY_CODE(0) |
0 |
panic |
SYSLOG_SEVERITY_CODE(0) |
1 |
alert |
SYSLOG_SEVERITY_CODE(1) |
2 |
crit |
SYSLOG_SEVERITY_CODE(2) |
2 |
critical |
SYSLOG_SEVERITY_CODE(2) |
2 |
fatal |
SYSLOG_SEVERITY_CODE(2) |
3 |
err |
SYSLOG_SEVERITY_CODE(3) |
3 |
error |
SYSLOG_SEVERITY_CODE(3) |
4 |
warning |
SYSLOG_SEVERITY_CODE(4) |
4 |
warn |
SYSLOG_SEVERITY_CODE(4) |
5 |
notice |
SYSLOG_SEVERITY_CODE(5) |
6 |
info |
SYSLOG_SEVERITY_CODE(6) |
6 |
log |
SYSLOG_SEVERITY_CODE(6) |
7 |
debug |
SYSLOG_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.
Note
If the parameter value is not a valid parameter value, the function ignores it and sends a debug message, but the application still sends the message.
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.
Note
If the specified parameter value is not a valid value, the function ignores it and sends a debug message. However, the AxoSyslog application will still send the message.
Declaration
rewrite <rule-name> {
set-pri("template-string");
};
Parameters
The set-pri()
rewrite function expects a template string as its only parameter, for example:
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);
}
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.
Note
To convert match variables into a AxoSyslog list, use the
$*
macro, which can be further manipulated using
list template functions, or turned into a list in type-aware destinations.
Note
To reset match variables to be empty, use the unset-matches()
rewrite rule.
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, .SDATA.mySDATA-field-group@18372.4.mySDATA-field
. (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 .SDATA.groupID.fieldID@18372.4
field and sets its value to yes
. If you use the ${.SDATA.groupID.fieldID@18372.4}
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(".SDATA.custom@18372.4.sourceip"));
};
If you use the ${.SDATA.custom@18372.4.sourceip}
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 custom@18372.4
, 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.
Note
Using conditions in rewrite rules can simplify your AxoSyslog configuration file, as you do not need to create separate log paths to modify certain messages.
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
-
The log path receives a message from the source (s1
).
-
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.
-
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
.