diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 5d981054601..79d3a03a969 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -46,6 +46,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di - Fix default paths for redis 4.0.1 logs on macOS {pull}5173[5173] - Fix Filebeat not starting if command line and modules configs are used together. {issue}5376[5376] +- Add support for adding string tags {pull}5395{5395} *Heartbeat* diff --git a/filebeat/tests/files/logs/json_tag.log b/filebeat/tests/files/logs/json_tag.log new file mode 100644 index 00000000000..c74dea53d81 --- /dev/null +++ b/filebeat/tests/files/logs/json_tag.log @@ -0,0 +1 @@ +{"http_user_agent": "ELB-HealthChecker/1.0", "tags": ["tag1", "tag2"]} diff --git a/filebeat/tests/system/test_json.py b/filebeat/tests/system/test_json.py index 70a4a554064..0e2f58b3a05 100644 --- a/filebeat/tests/system/test_json.py +++ b/filebeat/tests/system/test_json.py @@ -130,6 +130,29 @@ def test_simple_json_overwrite(self): assert output["source"] == "hello" assert output["message"] == "test source" + def test_json_add_tags(self): + self.render_config_template( + path=os.path.abspath(self.working_dir) + "/log/*", + json=dict( + keys_under_root=True, + ), + agent_tags=["tag3", "tag4"] + ) + os.mkdir(self.working_dir + "/log/") + self.copy_files(["logs/json_tag.log"], + source_dir="../files", + target_dir="log") + + proc = self.start_beat() + self.wait_until( + lambda: self.output_has(lines=1), + max_timeout=10) + + proc.check_kill_and_wait() + + output = self.read_output()[0] + assert sorted(output["tags"]) == ["tag1", "tag2", "tag3", "tag4"] + def test_config_no_msg_key_filtering(self): """ Should raise an error if line filtering and JSON are defined, diff --git a/libbeat/common/mapstr.go b/libbeat/common/mapstr.go index 3bf851266e7..31164bf6f96 100644 --- a/libbeat/common/mapstr.go +++ b/libbeat/common/mapstr.go @@ -247,19 +247,23 @@ func AddTags(ms MapStr, tags []string) error { if ms == nil || len(tags) == 0 { return nil } - - tagsIfc, ok := ms[TagsKey] - if !ok { + eventTags, exists := ms[TagsKey] + if !exists { ms[TagsKey] = tags return nil } - existingTags, ok := tagsIfc.([]string) - if !ok { - return errors.Errorf("expected string array by type is %T", tagsIfc) + switch arr := eventTags.(type) { + case []string: + ms[TagsKey] = append(arr, tags...) + case []interface{}: + for _, tag := range tags { + arr = append(arr, tag) + } + ms[TagsKey] = arr + default: + return errors.Errorf("expected string array by type is %T", eventTags) } - - ms[TagsKey] = append(existingTags, tags...) return nil } diff --git a/libbeat/common/mapstr_test.go b/libbeat/common/mapstr_test.go index 633032a8f8f..cbac6c647c2 100644 --- a/libbeat/common/mapstr_test.go +++ b/libbeat/common/mapstr_test.go @@ -390,7 +390,7 @@ func TestAddTag(t *testing.T) { "tags": []string{"json"}, }, }, - // Existing tags, appends + // Existing tags is a []string, appends { Event: MapStr{ "tags": []string{"json"}, @@ -400,7 +400,17 @@ func TestAddTag(t *testing.T) { "tags": []string{"json", "docker"}, }, }, - // Existing tags is not a []string + // Existing tags is a []interface{}, appends + { + Event: MapStr{ + "tags": []interface{}{"json"}, + }, + Tags: []string{"docker"}, + Output: MapStr{ + "tags": []interface{}{"json", "docker"}, + }, + }, + // Existing tags is not a []string or []interface{} { Event: MapStr{ "tags": "not a slice",