# fluent-plugin-viaq_data_model - a ViaQ data model filter plugin for [Fluentd](http://fluentd.org) [![Travis CI](https://secure.travis-ci.org/ViaQ/fluent-plugin-viaq_data_model.png)](http://travis-ci.org/#!/ViaQ/fluent-plugin-viaq_data_model) ## Introduction This plugin formats Fluentd records in the proper [ViaQ data model](https://github.com/ViaQ/elasticsearch-templates). It does the following: * Removes empty fields * fields with a value of `nil` * string fields with a value of `''` or the empty string * hash valued fields with a value of `{}` * hash valued fields which contain only empty fields as described above * FixNum, Boolean and other field values are not removed - type must respond to `:empty?` to be considered empty * Moves "undefined" values to a top level field called `undefined` The ViaQ data model wants all top level fields defined and described. These can conflict with the fields defined by ViaQ. You can "move" these fields to be under a hash valued top level field called `undefined` so as not to conflict with the "well known" ViaQ top level fields. You can optionally keep some fields as top level fields while moving others to the `undefined` container. * Rename a time field to `@timestamp` You cannot set the `@timestamp` field in a Fluentd `record_transformer` filter. The plugin allows you to use some other field e.g. `time` and have that "moved" to a top level field called `@timestamp`. * Converts systemd and json-file logs to ViaQ data model format Doing this conversion in a `record_transformer` with embedded ruby code is very resource intensive. The ViaQ plugin can convert common input formats such as Kubernetes `json-file`, `/var/log/messages`, and systemd `journald` into their corresponding ViaQ `_default_`, `systemd`, `kubernetes`, and `pipeline_metadata` namespaced fields. The `pipeline_metadata` will be added to all records, regardless of tag. Use the `pipeline_type` parameter to specify which part of the pipeline this is, `collector` or `normalizer`. The ViaQ data model conversion will only be applied to matching `tag`s specified in a `formatter` section. * Creates Elasticsearch index names or prefixes You can create either a full Elasticsearch index name for the record (to be used with the `fluent-plugin-elasticsearch` `target_index_key` parameter), or create an index name prefix (missing the date/timestamp part of the index name - to be used with `logstash_prefix_key`). In order to use this, create an `elasticsearch_index_name` section, and specify the `tag` to match, and the `name_type` type of index name to create. By default, a prefix name will be stored in the `viaq_index_prefix` field in the record, and a full name will be stored in the `viaq_index_name` field. Configure `elasticsearch_index_name_field` or `elasticsearch_index_prefix_field` to use a different field name. ## Configuration NOTE: All fields are Optional - no required fields. See `filter-viaq_data_model.conf` for an example filter configuration. * `default_keep_fields` - comma delimited string - default: `''` * This is the default list of fields to keep as top level fields in the record * `default_keep_fields message,@timestamp,ident` - do not move these fields into the `undefined` field * `extra_keep_fields` - comma delimited string - default: `''` * This is an extra list of fields to keep in addition to `default_keep_fields` - mostly useful as a way to hard code the `default_keep_fields` list for configuration management purposes, but at the same time allow customization in certain cases * `extra_keep_fields myspecialfield1,myspecialfield2` * `keep_empty_fields` - comma delimited string - default `''` * Always keep these top level fields, even if they are empty * `keep_empty_fields message` - keep the `message` field, even if empty * `use_undefined` - boolean - default `false` * If `true`, move fields not specified in `default_keep_fields` and `extra_keep_fields` to the `undefined` top level field. If you use `use_undefined` you should specify the fields you want to keep out of `undefined` by using `default_keep_fields` and/or `extra_keep_fields` * `undefined_name` - string - default `"undefined"` * Name of undefined top level field to use if `use_undefined true` is set * `undefined_name myfields` - keep undefined fields under field `myfields` * `rename_time` - boolean - default `true` * Rename the time field e.g. when you need to set `@timestamp` in the record * NOTE: This will overwrite the `dest_time_name` if already set * `rename_time_if_missing` - boolean - default `false` * Rename the time field only if it is not present. For example, if some records already have the `@timestamp` field and you do not want to overwrite them, use `rename_time_if_missing true` * `src_time_name` - string - default `time` * Use this field to get the value of the time field in the resulting record. This field will be removed from the record. * NOTE: This field must be present in the `default_keep_fields` or `extra_keep_fields` if `use_undefined true` * `dest_time_name` - string - default `@timestamp` * This is the name of the top level field to hold the time value. The value is taken from the value of the `src_time_name` field. * `formatter` - a formatter for a well known common data model source * `type` - one of the well known sources * `sys_journal` - a record read from the systemd journal * `k8s_journal` - a Kubernetes container record read from the systemd journal - should have `CONTAINER_NAME`, `CONTAINER_ID_FULL` * `sys_var_log` - a record read from `/var/log/messages` * `k8s_json_file` - a record read from a `/var/log/containers/*.log` JSON formatted container log file * `tag` - the Fluentd tag pattern to match for these records * `remove_keys` - comma delimited list of keys to remove from the record * `pipeline_type` - which part of the pipeline is this? `collector` or `normalizer` - the default is `collector` * `elasticsearch_index_name` - how to construct Elasticsearch index names or prefixes for given tags * `tag` - the Fluentd tag pattern to match for these records * `name_type` - the well known type of index name or prefix to create - `operations_full, project_full, operations_prefix, project_prefix` - The `operations_*` types will create a name like `.operations`, and the `project_*` types will create a name like `project.record['kubernetes']['namespace_name'].record['kubernetes']['namespace_id']`. When using the `full` types, a delimiter `.` followed by the date in `YYYY.MM.DD` format will be added to the string to make a full index name. When using the `prefix` types, it is assumed that the `fluent-plugin-elaticsearch` is used with the `logstash_prefix_key` to create the full index name. * `elasticsearch_index_name_field` - name of the field in the record which stores the index name - you should remove this field in the elasticsearch output plugin using the `remove_keys` config parameter - default is `viaq_idnex_name` * `elasticsearch_index_prefix_field` - name of the field in the record which stores the index prefix - you should remove this field in the elasticsearch output plugin using the `remove_keys` config parameter - default is `viaq_idnex_prefix` **NOTE** The `formatter` blocks are matched in the given order in the file. This means, don't use `tag "**"` as the first formatter or none of your others will be matched or evaulated. **NOTE** The `elasticsearch_index_name` processing is done *last*, *after* the formatting, removal of empty fields, `@timestamp` creation, etc., so use e.g. `record['systemd']['t']['GID']` instead of `record['_GID']` **NOTE** The `elasticsearch_index_name` blocks are matched in the given order in the file. This means, don't use `tag "**"` as the first formatter or none of your others will be matched or evaulated. ## Example If the input record looks like this: { "a": "b", "c": "d", "e": '', "f": { "g": '', "h": {} }, "i": { "j": 0, "k": False, "l": '' }, "time": "2017-02-13 15:30:10.259106596-07:00" } The resulting record, using the defaults, would look like this: { "a": "b", "c": "d", "i": { "j": 0, "k": False, }, "@timestamp": "2017-02-13 15:30:10.259106596-07:00" } ## Formatter example Given a record like the following with a tag of `journal.system` __REALTIME_TIMESTAMP=1502228121310282 __MONOTONIC_TIMESTAMP=722903835100 _BOOT_ID=d85e8a9d524c4a419bcfb6598db78524 _TRANSPORT=syslog PRIORITY=6 SYSLOG_FACILITY=3 SYSLOG_IDENTIFIER=dnsmasq-dhcp SYSLOG_PID=2289 _PID=2289 _UID=99 _GID=40 _COMM=dnsmasq _EXE=/usr/sbin/dnsmasq _CMDLINE=/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper _CAP_EFFECTIVE=3400 _SYSTEMD_CGROUP=/system.slice/libvirtd.service MESSASGE=my message Using a configuration like this: tag "journal.system**" type sys_journal remove_keys log,stream,MESSAGE,_SOURCE_REALTIME_TIMESTAMP,__REALTIME_TIMESTAMP,CONTAINER_ID,CONTAINER_ID_FULL,CONTAINER_NAME,PRIORITY,_BOOT_ID,_CAP_EFFECTIVE,_CMDLINE,_COMM,_EXE,_GID,_HOSTNAME,_MACHINE_ID,_PID,_SELINUX_CONTEXT,_SYSTEMD_CGROUP,_SYSTEMD_SLICE,_SYSTEMD_UNIT,_TRANSPORT,_UID,_AUDIT_LOGINUID,_AUDIT_SESSION,_SYSTEMD_OWNER_UID,_SYSTEMD_SESSION,_SYSTEMD_USER_UNIT,CODE_FILE,CODE_FUNCTION,CODE_LINE,ERRNO,MESSAGE_ID,RESULT,UNIT,_KERNEL_DEVICE,_KERNEL_SUBSYSTEM,_UDEV_SYSNAME,_UDEV_DEVNODE,_UDEV_DEVLINK,SYSLOG_FACILITY,SYSLOG_IDENTIFIER,SYSLOG_PID The resulting record will look like this: { "systemd": { "t": { "BOOT_ID":"d85e8a9d524c4a419bcfb6598db78524", "GID":40, ... }, "u": { "SYSLOG_FACILITY":3, "SYSLOG_IDENTIFIER":"dnsmasq-dhcp", ... }, "message":"my message", ... } ## Elasticsearch index name example Given a configuration like this: tag "journal.system** system.var.log** **_default_** **_openshift_** **_openshift-infra_** mux.ops" name_type operations_full tag "**" name_type project_full elasticsearch_index_field viaq_index_name A record with tag `journal.system` like this: { "@timestamp":"2017-07-27T17:27:46.216527+00:00" } will end up looking like this: { "@timestamp":"2017-07-27T17:27:46.216527+00:00", "viaq_index_name":".operations.2017.07.07" } A record with tag `kubernetes.journal.container` like this: { "@timestamp":"2017-07-27T17:27:46.216527+00:00", "kubernetes":{"namespace_name":"myproject","namespace_id":"000000"} } will end up looking like this: { "@timestamp":"2017-07-27T17:27:46.216527+00:00", "kubernetes":{"namespace_name":"myproject","namespace_id":"000000"} "viaq_index_name":"project.myproject.000000.2017.07.07" } ## Installation gem install fluent-plugin-viaq_data_model ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Test it (`GEM_HOME=vendor bundle install; GEM_HOME=vendor bundle exec rake test`) 5. Push to the branch (`git push origin my-new-feature`) 6. Create new Pull Request