bb44cd830c
This implements rsyslog -> elasticsearch logging as well as rsyslog forwarder -> rsyslog aggregator -> elasticsearch logging using the common logging template as a base and adding in dynamic detection of containerized services and log path detection. Services can be moved into and out of containers and add or remove log files and the log detector script will create a template that reflects these changes dynamically. Logging inherits cloud name and elasticsearch info from the existing group_vars variables, so this should be no additional work to setup beyond setting logging_backend: rsyslog and either running the install playbook or the rsyslog-logging playbook. Finally additional variables can be passed into the deployment with -e or just being in the ansible namespace, this way things like a unique build ID can be templated into the logs automatically. I've added support for browbeat_uuid, dlrn_hash, and rhos_puddle others should be trivial to add. There are also additional tunables to configure if logging instaces should be standalone (viable for small clouds) or rely on a server side aggregator service (more efficient for large deployments). Disk backed mode is another tunable that will create a variable disk load that may be undesierable in some deployments, but if collecting every last log is important it can be turned on creating a one or two layer queueing structure in case of Elasticsearch downtime or overload depending on if the aggregation server is in use. If you want to see examples from both containerized and non container clouds check out elk.browbeatproject.org's logstash index. Change-Id: I3e6652223a08ab8a716a40b7a0e21b7fcea6c000
315 lines
10 KiB
Django/Jinja
315 lines
10 KiB
Django/Jinja
#### 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 %}
|