#### RULES ####
# Ensure message is a properly formatted UTF-8 sequence
action(type="mmutf8fix" mode="utf-8")

# Parse any CEE JSON messages
action(type="mmjsonparse")

{% if not rsyslog_forwarding or rsyslog_aggregator %}
# Now that we have parsed out any CEE JSON data in log messages, we have a CEE
# JSON tree with at least a "msg" field.  We proceed with normalizing the data
# to remove redundant pieces of information, and cleanup known bad data.

# The mmjsonparse action above has made sure the $!msg is always populated
# with $msg if initially unpopulated.
if (strlen($!msg) > 0) then {
    set $.msg = $!msg;
} else {
    if ($inputname == "impstats") then {
        set $.msg = "pstats";
    } else {
        set $.msg = $msg;
    }
}
if (strlen($!MESSAGE) > 0) and ($!MESSAGE != $.msg) then {
    # Use the systemd message value when present.
    set $.msg = $!MESSAGE;
}
# Always pull msg out of the message properties so that it does not show up
# again under the CEE property in ElasticSearch.
unset $!msg;
unset $!MESSAGE;

if ($!_HOSTNAME == $hostname) then {
    unset $!_HOSTNAME;
}

if (strlen($!tags) > 0) then {
    set $.tags = $!tags;
}

# Always pull tags out of the message properties so that it does not show up
# again under the CEE property in ElasticSearch.
unset $!tags;

# We'll attempt to normalize the PID value we have from the default rsyslog
# properties with collected systemd properties below.
set $.pid = $procid;

set $.hostname = $hostname;
set $.level = $syslogseverity-text;
set $.rsyslog!appname = $app-name;
set $.rsyslog!programname = $programname;

# Copy browbeat json over then delete it from the json namespace
if (strlen($!browbeat_json) > 0) then {
    set $.browbeat_json = $!browbeat_json;
    unset $!browbeat_json;
}

# Logs are fed into imfile as pure text strings with no level info
# other than the default for that filestream, this parses the messages
# to look for log level info that it can apply
if ($.msg contains 'error') then {
    set $.level = 'error';
}
if ($.msg contains 'ERROR') then {
    set $.level = 'error';
}
if ($.msg contains 'warn') then {
    set $.level = 'notice';
}
if ($.msg contains 'WARN') then {
    set $.level = 'notice';
}
if ($.msg contains 'debug') then {
    set $.level = 'debug';
}
if ($.msg contains 'DEBUG') then {
    set $.level = 'debug';
}

# Now drop app-name if it is the same as programname, don't need to index
# both, and if either or both are still blank, just drop them entirely.
if ($app-name == $programname) then {
    unset $.rsyslog!appname;
}
if (strlen($.rsyslog!appname) == 0) then {
    unset $.rsyslog!appname;
}
if (strlen($.rsyslog!programname) == 0) then {
    unset $.rsyslog!programname;
}

# The facility is an rsyslog specific property defined to have a fixed set of
# values.
set $.rsyslog!facility = $syslogfacility-text;
# The following four properties are pulled from the RFC 5424 message, when
# available. If we don't have those kinds of messages, then the values are
# "-", and in the case of app-name, it will have the same value as
# programname.
set $.rsyslog!protocol-version = $protocol-version;
if (strlen($structured-data) > 0) and ($structured-data != "-") then {
    set $.rsyslog!structured-data = $structured-data;
}
if (strlen($msgid) > 0) and ($msgid != "-") then {
    set $.rsyslog!msgid = $msgid;
}
# The following four properities are derived by this instance of rsyslog (the
# last instance to touch the message before being indexed into ElasticSearch),
# and not sent across the wire.
set $.rsyslog!fromhost-ip = $fromhost-ip;
if ($fromhost != $hostname) and ($fromhost != $fromhost-ip) then {
    # We only report fromhost if it is different from hostname, and only if it
    # tells us something more that fromhost-ip.
    set $.rsyslog!fromhost = $fromhost;
}
template(name="timegeneratedrfc3339" type="string" string="%timegenerated:::date-rfc3339%")
set $.rsyslog!timegenerated = exec_template("timegeneratedrfc3339");
set $.rsyslog!inputname = $inputname;

if strlen($!_MACHINE_ID) > 0 then {
    # Pull out the systemd "user" and "trusted" journal fields.
    # See http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html

    # Pull out the systemd "user" journal fields...
    set $.systemd!t!MACHINE_ID = $!_MACHINE_ID;
    unset $!_MACHINE_ID;
    if strlen($!CODE_FILE) > 0 then {
        set $.systemd!u!CODE_FILE = $!CODE_FILE;
    }
    unset $!CODE_FILE;
    if strlen($!CODE_FUNCTION) > 0 then {
        set $.systemd!u!CODE_FUNCTION = $!CODE_FUNCTION;
    }
    unset $!CODE_FUNCTION;
    if strlen($!CODE_LINE) > 0 then {
        set $.systemd!u!CODE_LINE = $!CODE_LINE;
    }
    unset $!CODE_LINE;
    if strlen($!ERRNO) > 0 then {
        set $.systemd!u!ERRNO = $!ERRNO;
    }
    unset $!ERRNO;
    if strlen($!MESSAGE_ID) > 0 then {
        set $.systemd!u!MESSAGE_ID = $!MESSAGE_ID;
    }
    unset $!MESSAGE_ID;
    if strlen($!RESULT) > 0 then {
        set $.systemd!u!RESULT = $!RESULT;
    }
    unset $!RESULT;
    if strlen($!UNIT) > 0 then {
        set $.systemd!u!UNIT = $!UNIT;
    }
    unset $!UNIT;
    # NOTE We deal with $!MESSAGE separately above
    #set $.systemd!u!MESSAGE = $!MESSAGE;
    # NOTE WELL: we do not pull out MESSAGE, PRIORITY, SYSLOG_FACILITY,
    # SYSLOG_IDENTIFIER, or SYSLOG_PID, as imjournal either on the remote host
    # or on our local host has already done that for us using the values
    # appropriately for traditional rsyslog message properties.
    #unset $!MESSAGE;
    #set $.systemd!u!PRIORITY = $!PRIORITY;
    unset $!PRIORITY;
    #set $.systemd!u!SYSLOG_FACILITY = $!SYSLOG_FACILITY;
    unset $!SYSLOG_FACILITY;
    #set $.systemd!u!SYSLOG_IDENTIFIER = $!SYSLOG_IDENTIFIER;
    unset $!SYSLOG_IDENTIFIER;
    #set $.systemd!u!SYSLOG_PID = $!SYSLOG_PID;
    unset $!SYSLOG_PID;

    # Pull out the systemd "trusted" journal fields...
    if strlen($!_AUDIT_LOGINUID) > 0 then {
        set $.systemd!t!AUDIT_LOGINUID = $!_AUDIT_LOGINUID;
    }
    unset $!_AUDIT_LOGINUID;
    if strlen($!_AUDIT_SESSION) > 0 then {
        set $.systemd!t!AUDIT_SESSION = $!_AUDIT_SESSION;
    }
    unset $!_AUDIT_SESSION;
    if strlen($!_BOOT_ID) > 0 then {
        set $.systemd!t!BOOT_ID = $!_BOOT_ID;
    }
    unset $!_BOOT_ID;
    if strlen($!_CAP_EFFECTIVE) > 0 then {
        set $.systemd!t!CAP_EFFECTIVE = $!_CAP_EFFECTIVE;
    }
    unset $!_CAP_EFFECTIVE;
    if strlen($!_CMDLINE) > 0 then {
        set $.systemd!t!CMDLINE = $!_CMDLINE;
    }
    unset $!_CMDLINE;
    unset $!cmd;
    if strlen($!_COMM) > 0 then {
        set $.systemd!t!COMM = $!_COMM;
    }
    unset $!_COMM;
    unset $!appname;
    if strlen($!_EXE) > 0 then {
        set $.systemd!t!EXE = $!_EXE;
    }
    unset $!_EXE;
    unset $!exe;
    if strlen($!_GID) > 0 then {
        set $.systemd!t!GID = $!_GID;
    }
    unset $!_GID;
    unset $!gid;
    if strlen($!_HOSTNAME) > 0 then {
        set $.systemd!t!HOSTNAME = $!_HOSTNAME;
    }
    unset $!_HOSTNAME;
    if strlen($!pid) > 0 then {
        # The imjournal normalized _PID to pid in its message properties.
        set $.lclpid = $!pid;
    } else {
        if strlen($!_PID) > 0 then {
            set $.lclpid = $!_PID;
        } else {
            set $.lclpid = "-";
        }
    }
    unset $!_PID;
    unset $!pid;
    if strlen($.lclpid) > 0 then {
        if ($.pid == "-") and ($.lclpid != "-") then {
            # We don't have a PID, so use the one we found in the systemd data.
            set $.pid = $.lclpid;
        } else {
            if ($.pid != $.lclpid) then {
                # We have a PID, but the systemd's PID is different, so be
                # sure to save it.
                set $.systemd!t!PID = $.lclpid;
            }
        }
    }
    if strlen($!_SELINUX_CONTEXT) > 0 then {
        set $.systemd!t!SELINUX_CONTEXT = $!_SELINUX_CONTEXT;
    }
    unset $!_SELINUX_CONTEXT;
    if strlen($!_SOURCE_REALTIME_TIMESTAMP) > 0 then {
        set $.systemd!t!SOURCE_REALTIME_TIMESTAMP = $!_SOURCE_REALTIME_TIMESTAMP;
    }
    unset $!_SOURCE_REALTIME_TIMESTAMP;
    if strlen($!_SYSTEMD_CGROUP) > 0 then {
        set $.systemd!t!SYSTEMD_CGROUP = $!_SYSTEMD_CGROUP;
    }
    unset $!_SYSTEMD_CGROUP;
    if strlen($!_SYSTEMD_OWNER_UID) > 0 then {
        set $.systemd!t!SYSTEMD_OWNER_UID = $!_SYSTEMD_OWNER_UID;
    }
    unset $!_SYSTEMD_OWNER_UID;
    if strlen($!_SYSTEMD_SESSION) > 0 then {
        set $.systemd!t!SYSTEMD_SESSION = $!_SYSTEMD_SESSION;
    }
    unset $!_SYSTEMD_SESSION;
    if strlen($!_SYSTEMD_SLICE) > 0 then {
        set $.systemd!t!SYSTEMD_SLICE = $!_SYSTEMD_SLICE;
    }
    unset $!_SYSTEMD_SLICE;
    if strlen($!_SYSTEMD_UNIT) > 0 then {
        set $.systemd!t!SYSTEMD_UNIT = $!_SYSTEMD_UNIT;
    }
    unset $!_SYSTEMD_UNIT;
    if strlen($!_SYSTEMD_USER_UNIT) > 0 then {
        set $.systemd!t!SYSTEMD_USER_UNIT = $!_SYSTEMD_USER_UNIT;
    }
    unset $!_SYSTEMD_USER_UNIT;
    if strlen($!_TRANSPORT) > 0 then {
        set $.systemd!t!TRANSPORT = $!_TRANSPORT;
    }
    unset $!_TRANSPORT;
    if strlen($!_UID) > 0 then {
        set $.systemd!t!UID = $!_UID;
    }
    unset $!_UID;
    unset $!uid;

    # Pull out the systemd "kernel" journal fields...
    if strlen($!_KERNEL_DEVICE) > 0 then {
       set $.systemd!k!KERNEL_DEVICE = $!_KERNEL_DEVICE;
    }
    unset $!_KERNEL_DEVICE;
    if strlen($!_KERNEL_SUBSYSTEM) > 0 then {
       set $.systemd!k!KERNEL_SUBSYSTEM = $!_KERNEL_SUBSYSTEM;
    }
    unset $!_KERNEL_SUBSYSTEM;
    if strlen($!_UDEV_SYSNAME) > 0 then {
       set $.systemd!k!UDEV_SYSNAME = $!_UDEV_SYSNAME;
    }
    unset $!_UDEV_SYSNAME;
    if strlen($!_UDEV_DEVNODE) > 0 then {
       set $.systemd!k!UDEV_DEVNODE = $!_UDEV_DEVNODE;
    }
    unset $!_UDEV_DEVNODE;
    if strlen($!_UDEV_DEVLINK) > 0 then {
       set $.systemd!k!UDEV_DEVLINK = $!_UDEV_DEVLINK;
    }
    unset $!_UDEV_DEVLINK;
} else {
    # Because of how we have defined the template above, where the template
    # encodes the field name directly, we need to have an empty object for
    # $.systemd so that at least an empty set of braces ("{}") is emitted.
    # Without that, we don't have a valid JSON document to index.
    #
    # So to get that empty object whether or not we actually have systemd
    # data to normalize we need to create an object hierarchy and then remove
    # the leaf property.
    set $.systemd!foo = "bar";
    unset $.systemd!foo;
}
{% else %}
set $!browbeat_json = $.browbeat_json;
{% endif %}
