diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 0b18cc32aed..c088a63d740 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -26,6 +26,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di - Split the audit.kernel and audit.file metricsets into their own modules named auditd and file_integrity, respectively. This change requires existing users to update their config. {issue}5422[5422] +- Renamed file_integrity module fields. {issue}5423[5423] {pull}5995[5995] *Filebeat* - Switch to docker prospector in sample manifests for Kubernetes deployment {pull}5963[5963] diff --git a/auditbeat/Makefile b/auditbeat/Makefile index dd535a35f25..2f1f36f2721 100644 --- a/auditbeat/Makefile +++ b/auditbeat/Makefile @@ -18,7 +18,7 @@ before-build: ${ES_BEATS}/libbeat/_meta/config.yml > \ ${PREFIX}/${BEAT_NAME}-win.yml @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os windows -concat) \ + <(go run scripts/generate_config.go -os windows -concat -ref) \ ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ ${PREFIX}/${BEAT_NAME}-win.reference.yml @@ -28,7 +28,7 @@ before-build: ${ES_BEATS}/libbeat/_meta/config.yml > \ ${PREFIX}/${BEAT_NAME}-darwin.yml @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os darwin -concat) \ + <(go run scripts/generate_config.go -os darwin -concat -ref) \ ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ ${PREFIX}/${BEAT_NAME}-darwin.reference.yml @@ -38,7 +38,7 @@ before-build: ${ES_BEATS}/libbeat/_meta/config.yml > \ ${PREFIX}/${BEAT_NAME}-linux.yml @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os linux -concat) \ + <(go run scripts/generate_config.go -os linux -concat -ref) \ ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ ${PREFIX}/${BEAT_NAME}-linux.reference.yml diff --git a/auditbeat/_meta/fields.common.yml b/auditbeat/_meta/fields.common.yml index 113f46b98d4..a2e9a264e5f 100644 --- a/auditbeat/_meta/fields.common.yml +++ b/auditbeat/_meta/fields.common.yml @@ -3,7 +3,7 @@ description: > Contains common fields available in all event types. fields: - - name: dataset.module + - name: event.module description: > The name of the module that generated the event. diff --git a/auditbeat/core/eventmod.go b/auditbeat/core/eventmod.go index fe4a166cb33..7146bd4cd76 100644 --- a/auditbeat/core/eventmod.go +++ b/auditbeat/core/eventmod.go @@ -12,5 +12,5 @@ func AddDatasetToEvent(module, metricSet string, event *mb.Event) { event.RootFields = common.MapStr{} } - event.RootFields.Put("dataset.module", module) + event.RootFields.Put("event.module", module) } diff --git a/auditbeat/docs/fields.asciidoc b/auditbeat/docs/fields.asciidoc index 31d73d47103..717a8003cf4 100644 --- a/auditbeat/docs/fields.asciidoc +++ b/auditbeat/docs/fields.asciidoc @@ -2092,7 +2092,7 @@ Contains common fields available in all event types. [float] -=== `dataset.module` +=== `event.module` The name of the module that generated the event. @@ -2144,17 +2144,31 @@ Image labels. These are the fields generated by the file_integrity module. +[float] +=== `event.action` + +type: keyword + +example: attributes_modified + +Action describes the change that triggered the event. The possible values are: attributes_modified, created, deleted, updated, moved, and config_change. + + +[float] +== file fields + +File attributes. [float] -=== `audit.file.path` +=== `file.path` type: text The path to the file. [float] -=== `audit.file.path.raw` +=== `file.path.raw` type: keyword @@ -2162,73 +2176,57 @@ The path to the file. This is an non-analyzed field that is useful for aggregati [float] -=== `audit.file.target_path` +=== `file.target_path` type: keyword The target path for symlinks. [float] -=== `audit.file.action` - -type: keyword - -example: attributes_modified - -Action describes the change that triggered the event. The possible values are: attributes_modified, created, deleted, updated, moved, and config_change. - - -[float] -=== `audit.file.type` +=== `file.type` type: keyword The file type (file, dir, or symlink). [float] -=== `audit.file.inode` +=== `file.inode` type: keyword The inode representing the file in the filesystem. [float] -=== `audit.file.uid` +=== `file.uid` type: keyword -The user ID (UID) of the file owner. +The user ID (UID) or security identifier (SID) of the file owner. + [float] -=== `audit.file.owner` +=== `file.owner` type: keyword The file owner's username. [float] -=== `audit.file.gid` +=== `file.gid` type: keyword The primary group ID (GID) of the file. [float] -=== `audit.file.group` +=== `file.group` type: keyword The primary group name of the file. [float] -=== `audit.file.sid` - -type: keyword - -The security identifier (SID) of the file owner (Windows only). - -[float] -=== `audit.file.mode` +=== `file.mode` type: keyword @@ -2237,7 +2235,7 @@ example: 416 The mode of the file in octal representation. [float] -=== `audit.file.setuid` +=== `file.setuid` type: boolean @@ -2246,7 +2244,7 @@ example: True Set if the file has the `setuid` bit set. Omitted otherwise. [float] -=== `audit.file.setgid` +=== `file.setgid` type: boolean @@ -2255,146 +2253,146 @@ example: True Set if the file has the `setgid` bit set. Omitted otherwise. [float] -=== `audit.file.size` +=== `file.size` type: long The file size in bytes (field is only added when `type` is `file`). [float] -=== `audit.file.mtime` +=== `file.mtime` type: date The last modified time of the file (time when content was modified). [float] -=== `audit.file.ctime` +=== `file.ctime` type: date The last change time of the file (time when metadata was changed). [float] -=== `audit.file.hashed` +=== `file.origin` -type: boolean +type: keyword + +An array of strings describing a possible external origin for this file. For example, the URL it was downloaded from. Only supported in macOS, via the kMDItemWhereFroms attribute. Omitted if origin information is not available. -Boolean indicating if the event includes any file hashes. [float] -=== `audit.file.blake2b_256` +== hash fields + +Hashes of the file. The keys are algorithm names and the values are the hex encoded digest values. + + + +[float] +=== `hash.blake2b_256` type: keyword BLAKE2b-256 hash of the file. [float] -=== `audit.file.blake2b_384` +=== `hash.blake2b_384` type: keyword BLAKE2b-384 hash of the file. [float] -=== `audit.file.blake2b_512` +=== `hash.blake2b_512` type: keyword BLAKE2b-512 hash of the file. [float] -=== `audit.file.md5` +=== `hash.md5` type: keyword MD5 hash of the file. [float] -=== `audit.file.sha1` +=== `hash.sha1` type: keyword SHA1 hash of the file. [float] -=== `audit.file.sha224` +=== `hash.sha224` type: keyword SHA224 hash of the file. [float] -=== `audit.file.sha256` +=== `hash.sha256` type: keyword SHA256 hash of the file. [float] -=== `audit.file.sha384` +=== `hash.sha384` type: keyword SHA384 hash of the file. [float] -=== `audit.file.sha3_224` +=== `hash.sha3_224` type: keyword SHA3_224 hash of the file. [float] -=== `audit.file.sha3_256` +=== `hash.sha3_256` type: keyword SHA3_256 hash of the file. [float] -=== `audit.file.sha3_384` +=== `hash.sha3_384` type: keyword SHA3_384 hash of the file. [float] -=== `audit.file.sha3_512` +=== `hash.sha3_512` type: keyword SHA3_512 hash of the file. [float] -=== `audit.file.sha512` +=== `hash.sha512` type: keyword SHA512 hash of the file. [float] -=== `audit.file.sha512_224` +=== `hash.sha512_224` type: keyword SHA512/224 hash of the file. [float] -=== `audit.file.sha512_256` +=== `hash.sha512_256` type: keyword SHA512/256 hash of the file. -[float] -=== `audit.file.origin` - -type: keyword - -An array of strings describing a possible external origin for this file. For example, the URL it was downloaded from. Only supported in macOS, via the kMDItemWhereFroms attribute. Omitted if origin information is not available. - - [[exported-fields-kubernetes-processor]] == Kubernetes fields diff --git a/auditbeat/module/auditd/_meta/data.json b/auditbeat/module/auditd/_meta/data.json index 6d417fe57e8..5247a50c93d 100644 --- a/auditbeat/module/auditd/_meta/data.json +++ b/auditbeat/module/auditd/_meta/data.json @@ -36,7 +36,7 @@ "hostname": "host.example.com", "name": "host.example.com" }, - "dataset": { + "event": { "module": "auditd" } } \ No newline at end of file diff --git a/auditbeat/module/file_integrity/_meta/data.json b/auditbeat/module/file_integrity/_meta/data.json index 0338c1d4f55..4d092abbf5f 100644 --- a/auditbeat/module/file_integrity/_meta/data.json +++ b/auditbeat/module/file_integrity/_meta/data.json @@ -1,30 +1,30 @@ { "@timestamp": "2017-10-12T08:05:34.853Z", - "audit": { - "file": { - "action": [ - "created" - ], - "ctime": "2017-12-13T20:58:45.240217481Z", - "gid": 1000, - "group": "vagrant", - "hashed": true, - "inode": "38496", - "mode": "0600", - "mtime": "2017-12-13T20:58:45.240217481Z", - "owner": "vagrant", - "path": "/tmp/audit-file341509799/file.data", - "sha1": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", - "size": 11, - "type": "file", - "uid": 1000 - } - }, "beat": { "hostname": "host.example.com", "name": "host.example.com" }, - "dataset": { + "event": { + "action": [ + "created", + "updated" + ], "module": "file_integrity" + }, + "file": { + "ctime": "2018-01-05T03:28:26Z", + "gid": 20, + "group": "staff", + "inode": "20164115", + "mode": "0600", + "mtime": "2018-01-05T03:28:26Z", + "owner": "akroh", + "path": "/private/var/folders/8x/rnyk6yxn6w97lddn3bs02gf00000gn/T/audit-file864778064/file.data", + "size": 11, + "type": "file", + "uid": 501 + }, + "hash": { + "sha1": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" } } \ No newline at end of file diff --git a/auditbeat/module/file_integrity/_meta/fields.yml b/auditbeat/module/file_integrity/_meta/fields.yml index f211e94852e..4bcca3dd959 100644 --- a/auditbeat/module/file_integrity/_meta/fields.yml +++ b/auditbeat/module/file_integrity/_meta/fields.yml @@ -2,157 +2,155 @@ title: File Integrity description: These are the fields generated by the file_integrity module. fields: - - name: audit + - name: event.action + type: keyword + example: attributes_modified + description: > + Action describes the change that triggered the event. The possible + values are: attributes_modified, created, deleted, updated, moved, and + config_change. + + - name: file type: group + description: File attributes. fields: - - name: file - type: group - fields: - - name: path - type: text - description: The path to the file. - multi_fields: - - name: raw - type: keyword - description: > - The path to the file. This is an non-analyzed field that is useful - for aggregations. - - - name: target_path + - name: path + type: text + description: The path to the file. + multi_fields: + - name: raw type: keyword - description: The target path for symlinks. - - - name: action - type: keyword - example: attributes_modified description: > - Action describes the change that triggered the event. The possible - values are: attributes_modified, created, deleted, updated, moved, and - config_change. - - - name: type - type: keyword - description: The file type (file, dir, or symlink). - - - name: inode - type: keyword - description: The inode representing the file in the filesystem. - - - name: uid - type: keyword - description: The user ID (UID) of the file owner. - - - name: owner - type: keyword - description: The file owner's username. - - - name: gid - type: keyword - description: The primary group ID (GID) of the file. - - - name: group - type: keyword - description: The primary group name of the file. - - - name: sid - type: keyword - description: The security identifier (SID) of the file owner (Windows only). - - - name: mode - type: keyword - example: 0640 - description: The mode of the file in octal representation. - - - name: setuid - type: boolean - example: true - description: Set if the file has the `setuid` bit set. Omitted otherwise. - - - name: setgid - type: boolean - example: true - description: Set if the file has the `setgid` bit set. Omitted otherwise. - - - name: size - type: long - description: The file size in bytes (field is only added when `type` is `file`). - - - name: mtime - type: date - description: The last modified time of the file (time when content was modified). - - - name: ctime - type: date - description: The last change time of the file (time when metadata was changed). - - - name: hashed - type: boolean - description: Boolean indicating if the event includes any file hashes. - - - name: blake2b_256 - type: keyword - description: BLAKE2b-256 hash of the file. + The path to the file. This is an non-analyzed field that is useful + for aggregations. + + - name: target_path + type: keyword + description: The target path for symlinks. + + - name: type + type: keyword + description: The file type (file, dir, or symlink). + + - name: inode + type: keyword + description: The inode representing the file in the filesystem. + + - name: uid + type: keyword + description: > + The user ID (UID) or security identifier (SID) of the file owner. + + - name: owner + type: keyword + description: The file owner's username. + + - name: gid + type: keyword + description: The primary group ID (GID) of the file. + + - name: group + type: keyword + description: The primary group name of the file. + + - name: mode + type: keyword + example: 0640 + description: The mode of the file in octal representation. + + - name: setuid + type: boolean + example: true + description: Set if the file has the `setuid` bit set. Omitted otherwise. + + - name: setgid + type: boolean + example: true + description: Set if the file has the `setgid` bit set. Omitted otherwise. + + - name: size + type: long + description: The file size in bytes (field is only added when `type` is `file`). + + - name: mtime + type: date + description: The last modified time of the file (time when content was modified). + + - name: ctime + type: date + description: The last change time of the file (time when metadata was changed). + + - name: origin + type: keyword + description: > + An array of strings describing a possible external origin for + this file. For example, the URL it was downloaded from. Only + supported in macOS, via the kMDItemWhereFroms attribute. + Omitted if origin information is not available. + + - name: hash + type: group + description: > + Hashes of the file. The keys are algorithm names and the values are + the hex encoded digest values. - - name: blake2b_384 - type: keyword - description: BLAKE2b-384 hash of the file. + fields: + - name: blake2b_256 + type: keyword + description: BLAKE2b-256 hash of the file. - - name: blake2b_512 - type: keyword - description: BLAKE2b-512 hash of the file. + - name: blake2b_384 + type: keyword + description: BLAKE2b-384 hash of the file. - - name: md5 - type: keyword - description: MD5 hash of the file. + - name: blake2b_512 + type: keyword + description: BLAKE2b-512 hash of the file. - - name: sha1 - type: keyword - description: SHA1 hash of the file. + - name: md5 + type: keyword + description: MD5 hash of the file. - - name: sha224 - type: keyword - description: SHA224 hash of the file. + - name: sha1 + type: keyword + description: SHA1 hash of the file. - - name: sha256 - type: keyword - description: SHA256 hash of the file. + - name: sha224 + type: keyword + description: SHA224 hash of the file. - - name: sha384 - type: keyword - description: SHA384 hash of the file. + - name: sha256 + type: keyword + description: SHA256 hash of the file. - - name: sha3_224 - type: keyword - description: SHA3_224 hash of the file. + - name: sha384 + type: keyword + description: SHA384 hash of the file. - - name: sha3_256 - type: keyword - description: SHA3_256 hash of the file. + - name: sha3_224 + type: keyword + description: SHA3_224 hash of the file. - - name: sha3_384 - type: keyword - description: SHA3_384 hash of the file. + - name: sha3_256 + type: keyword + description: SHA3_256 hash of the file. - - name: sha3_512 - type: keyword - description: SHA3_512 hash of the file. + - name: sha3_384 + type: keyword + description: SHA3_384 hash of the file. - - name: sha512 - type: keyword - description: SHA512 hash of the file. + - name: sha3_512 + type: keyword + description: SHA3_512 hash of the file. - - name: sha512_224 - type: keyword - description: SHA512/224 hash of the file. + - name: sha512 + type: keyword + description: SHA512 hash of the file. - - name: sha512_256 - type: keyword - description: SHA512/256 hash of the file. + - name: sha512_224 + type: keyword + description: SHA512/224 hash of the file. - - name: origin - type: keyword - description: > - An array of strings describing a possible external origin for - this file. For example, the URL it was downloaded from. Only - supported in macOS, via the kMDItemWhereFroms attribute. - Omitted if origin information is not available. + - name: sha512_256 + type: keyword + description: SHA512/256 hash of the file. diff --git a/auditbeat/module/file_integrity/event.go b/auditbeat/module/file_integrity/event.go index cdf7bf9851f..918f9ee2719 100644 --- a/auditbeat/module/file_integrity/event.go +++ b/auditbeat/module/file_integrity/event.go @@ -197,69 +197,75 @@ func NewEvent( } func buildMetricbeatEvent(e *Event, existedBefore bool) mb.Event { - m := common.MapStr{ - "path": e.Path, - "hashed": len(e.Hashes) > 0, + file := common.MapStr{ + "path": e.Path, } - - if e.Action > 0 { - m["action"] = e.Action.InOrder(existedBefore, e.Info != nil).StringArray() + out := mb.Event{ + Timestamp: e.Timestamp, + Took: e.rtt, + MetricSetFields: common.MapStr{ + "file": file, + }, } if e.TargetPath != "" { - m["target_path"] = e.TargetPath + file["target_path"] = e.TargetPath } if e.Info != nil { info := e.Info - m["inode"] = strconv.FormatUint(info.Inode, 10) - m["mtime"] = info.MTime - m["ctime"] = info.CTime + file["inode"] = strconv.FormatUint(info.Inode, 10) + file["mtime"] = info.MTime + file["ctime"] = info.CTime if e.Info.Type == FileType { - m["size"] = info.Size + file["size"] = info.Size } if info.Type != UnknownType { - m["type"] = info.Type.String() + file["type"] = info.Type.String() } if runtime.GOOS == "windows" { if info.SID != "" { - m["sid"] = info.SID + file["uid"] = info.SID } } else { - m["uid"] = info.UID - m["gid"] = info.GID - m["mode"] = fmt.Sprintf("%#04o", uint32(info.Mode)) + file["uid"] = info.UID + file["gid"] = info.GID + file["mode"] = fmt.Sprintf("%#04o", uint32(info.Mode)) } if info.Owner != "" { - m["owner"] = info.Owner + file["owner"] = info.Owner } if info.Group != "" { - m["group"] = info.Group + file["group"] = info.Group } if info.SetUID { - m["setuid"] = true + file["setuid"] = true } if info.SetGID { - m["setgid"] = true + file["setgid"] = true } if len(info.Origin) > 0 { - m["origin"] = info.Origin + file["origin"] = info.Origin } } - for hashType, digest := range e.Hashes { - m[string(hashType)] = digest + if len(e.Hashes) > 0 { + hashes := make(common.MapStr, len(e.Hashes)) + for hashType, digest := range e.Hashes { + hashes[string(hashType)] = digest + } + out.MetricSetFields.Put("hash", hashes) } - out := mb.Event{ - Timestamp: e.Timestamp, - Took: e.rtt, - MetricSetFields: m, + if e.Action > 0 { + actions := e.Action.InOrder(existedBefore, e.Info != nil).StringArray() + out.MetricSetFields.Put("event.action", actions) } + return out } diff --git a/auditbeat/module/file_integrity/event_test.go b/auditbeat/module/file_integrity/event_test.go index 4c6a2e8851c..222afc4eb0c 100644 --- a/auditbeat/module/file_integrity/event_test.go +++ b/auditbeat/module/file_integrity/event_test.go @@ -1,6 +1,7 @@ package file_integrity import ( + "bytes" "encoding/hex" "fmt" "io/ioutil" @@ -8,9 +9,9 @@ import ( "testing" "time" - "bytes" - "github.com/stretchr/testify/assert" + + "github.com/elastic/beats/libbeat/common" ) var testEventTime = time.Now().UTC() @@ -257,22 +258,54 @@ func BenchmarkHashFile(b *testing.B) { } func TestBuildEvent(t *testing.T) { + t.Run("all fields", func(t *testing.T) { + e := testEvent() + e.TargetPath = "link_target" + e.Info.Owner = "beats" + e.Info.Group = "staff" + e.Info.SetUID = true + e.Info.Origin = []string{"google.com"} + + fields := buildMetricbeatEvent(e, false).MetricSetFields + assert.Equal(t, testEventTime, e.Timestamp) + + assertHasKey(t, fields, "event.action") + + assertHasKey(t, fields, "file.path") + assertHasKey(t, fields, "file.target_path") + assertHasKey(t, fields, "file.inode") + assertHasKey(t, fields, "file.uid") + assertHasKey(t, fields, "file.gid") + assertHasKey(t, fields, "file.owner") + assertHasKey(t, fields, "file.group") + assertHasKey(t, fields, "file.size") + assertHasKey(t, fields, "file.mtime") + assertHasKey(t, fields, "file.ctime") + assertHasKey(t, fields, "file.type") + assertHasKey(t, fields, "file.mode") + assertHasKey(t, fields, "file.setuid") + assertHasKey(t, fields, "file.setgid") + assertHasKey(t, fields, "file.origin") + + assertHasKey(t, fields, "hash.sha1") + assertHasKey(t, fields, "hash.sha256") + }) t.Run("no setuid/setgid", func(t *testing.T) { e := testEvent() e.Info.SetGID = false fields := buildMetricbeatEvent(e, false).MetricSetFields - _, err := fields.GetValue("setuid") + _, err := fields.GetValue("file.setuid") assert.Error(t, err) - _, err = fields.GetValue("setgid") + _, err = fields.GetValue("file.setgid") assert.Error(t, err) }) t.Run("setgid set", func(t *testing.T) { e := testEvent() fields := buildMetricbeatEvent(e, false).MetricSetFields - _, err := fields.GetValue("setuid") + _, err := fields.GetValue("file.setuid") assert.Error(t, err) - setgid, err := fields.GetValue("setgid") + setgid, err := fields.GetValue("file.setgid") if err != nil { t.Fatal(err) } @@ -285,10 +318,10 @@ func TestBuildEvent(t *testing.T) { e.Info.SetUID = true e.Info.SetGID = false fields := buildMetricbeatEvent(e, false).MetricSetFields - _, err := fields.GetValue("setgid") + _, err := fields.GetValue("file.setgid") assert.Error(t, err) - setgid, err := fields.GetValue("setuid") + setgid, err := fields.GetValue("file.setuid") if err != nil { t.Fatal(err) } @@ -296,11 +329,11 @@ func TestBuildEvent(t *testing.T) { assert.True(t, ok) assert.True(t, flag) }) - t.Run("both set", func(t *testing.T) { + t.Run("setuid and setgid set", func(t *testing.T) { e := testEvent() e.Info.SetUID = true fields := buildMetricbeatEvent(e, false).MetricSetFields - setuid, err := fields.GetValue("setgid") + setuid, err := fields.GetValue("file.setgid") if err != nil { t.Fatal(err) } @@ -308,7 +341,7 @@ func TestBuildEvent(t *testing.T) { assert.True(t, ok) assert.True(t, flag) - setgid, err := fields.GetValue("setuid") + setgid, err := fields.GetValue("file.setuid") if err != nil { t.Fatal(err) } @@ -325,3 +358,11 @@ func mustDecodeHex(v string) []byte { } return data } + +func assertHasKey(t testing.TB, m common.MapStr, key string) { + t.Helper() + found, err := m.HasKey(key) + if err != nil || !found { + t.Errorf("key %v not found: %v", key, err) + } +} diff --git a/auditbeat/module/file_integrity/metricset.go b/auditbeat/module/file_integrity/metricset.go index eda2f10d02b..f6b636a5d7d 100644 --- a/auditbeat/module/file_integrity/metricset.go +++ b/auditbeat/module/file_integrity/metricset.go @@ -21,7 +21,7 @@ const ( bucketName = "file.v1" // Use old namespace for data until we do some field renaming for GA. - namespace = "audit.file" + namespace = "." ) func init() { diff --git a/auditbeat/module/file_integrity/metricset_test.go b/auditbeat/module/file_integrity/metricset_test.go index e335cebf426..d3c8e673fbe 100644 --- a/auditbeat/module/file_integrity/metricset_test.go +++ b/auditbeat/module/file_integrity/metricset_test.go @@ -31,7 +31,7 @@ func TestData(t *testing.T) { }() ms := mbtest.NewPushMetricSetV2(t, getConfig(dir)) - events := mbtest.RunPushMetricSetV2(10*time.Second, 1, ms) + events := mbtest.RunPushMetricSetV2(10*time.Second, 2, ms) for _, e := range events { if e.Error != nil { t.Fatalf("received error: %+v", e.Error) @@ -83,23 +83,23 @@ func TestDetectDeletedFiles(t *testing.T) { return } event := events[0].MetricSetFields - path, err := event.GetValue("path") + path, err := event.GetValue("file.path") if assert.NoError(t, err) { assert.Equal(t, dir, path) } - action, err := event.GetValue("action") + action, err := event.GetValue("event.action") if assert.NoError(t, err) { assert.Equal(t, []string{"created"}, action) } event = events[1].MetricSetFields - path, err = event.GetValue("path") + path, err = event.GetValue("file.path") if assert.NoError(t, err) { assert.Equal(t, e.Path, path) } - action, err = event.GetValue("action") + action, err = event.GetValue("event.action") if assert.NoError(t, err) { assert.Equal(t, []string{"deleted"}, action) } @@ -151,7 +151,7 @@ func TestExcludedFiles(t *testing.T) { } for _, e := range events { event := e.MetricSetFields - path, err := event.GetValue("path") + path, err := event.GetValue("file.path") if assert.NoError(t, err) { _, ok := wanted[path.(string)] assert.True(t, ok) diff --git a/metricbeat/mb/event.go b/metricbeat/mb/event.go index ff21a1178e2..34167cb1943 100644 --- a/metricbeat/mb/event.go +++ b/metricbeat/mb/event.go @@ -47,11 +47,16 @@ func (e *Event) BeatEvent(module, metricSet string, modifiers ...EventModifier) } if len(e.MetricSetFields) > 0 { - prefix := e.Namespace - if prefix == "" { - prefix = module + "." + metricSet + switch e.Namespace { + case ".": + // Add fields to root. + b.Fields.DeepUpdate(e.MetricSetFields) + case "": + b.Fields.Put(module+"."+metricSet, e.MetricSetFields) + default: + b.Fields.Put(e.Namespace, e.MetricSetFields) } - b.Fields.Put(prefix, e.MetricSetFields) + e.MetricSetFields = nil }