diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index ef7c8514f3e..65b12c29903 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -115,6 +115,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - Include network information by default on add_host_metadata and add_observer_metadata. {issue}15347[15347] {pull}16077[16077] - Add `aws_ec2` provider for autodiscover. {issue}12518[12518] {pull}14823[14823] - Add support for multiple password in redis output. {issue}16058[16058] {pull}16206[16206] +- Add support for Histogram type in fields.yml {pull}16570[16570] *Auditbeat* diff --git a/libbeat/mapping/field.go b/libbeat/mapping/field.go index 66cde47e834..66a580dac5e 100644 --- a/libbeat/mapping/field.go +++ b/libbeat/mapping/field.go @@ -134,7 +134,7 @@ func (f *Field) validateType() error { return geoPointType.validate(f.Format) case "date_range": return dateRangeType.validate(f.Format) - case "boolean", "binary", "ip", "alias", "array": + case "boolean", "binary", "ip", "alias", "array", "histogram": if f.Format != "" { return fmt.Errorf("no format expected for field %s, found: %s", f.Name, f.Format) } diff --git a/libbeat/template/processor.go b/libbeat/template/processor.go index 48593ad4317..7ce0d01cde2 100644 --- a/libbeat/template/processor.go +++ b/libbeat/template/processor.go @@ -80,6 +80,8 @@ func (p *Processor) Process(fields mapping.Fields, state *fieldState, output com indexMapping = p.array(&field) case "alias": indexMapping = p.alias(&field) + case "histogram": + indexMapping = p.histogram(&field) case "group": indexMapping = common.MapStr{} if field.Dynamic.Value != nil { @@ -287,6 +289,18 @@ func (p *Processor) alias(f *mapping.Field) common.MapStr { return properties } +func (p *Processor) histogram(f *mapping.Field) common.MapStr { + // Histograms were introduced in Elasticsearch 7.6, ignore if unsupported + if p.EsVersion.LessThan(common.MustNewVersion("7.6.0")) { + return nil + } + + properties := getDefaultProperties(f) + properties["type"] = "histogram" + + return properties +} + func (p *Processor) object(f *mapping.Field) common.MapStr { matchType := func(onlyType string, mt string) string { if mt != "" { @@ -324,6 +338,9 @@ func (p *Processor) object(f *mapping.Field) common.MapStr { case "byte", "double", "float", "long", "short", "boolean": dynProperties["type"] = otp.ObjectType addDynamicTemplate(f, dynProperties, matchType(otp.ObjectType, otp.ObjectTypeMappingType)) + case "histogram": + dynProperties["type"] = otp.ObjectType + addDynamicTemplate(f, dynProperties, matchType("*", otp.ObjectTypeMappingType)) } } diff --git a/libbeat/template/processor_test.go b/libbeat/template/processor_test.go index dd316957e24..61f29c24a66 100644 --- a/libbeat/template/processor_test.go +++ b/libbeat/template/processor_test.go @@ -34,6 +34,7 @@ func TestProcessor(t *testing.T) { pEsVersion2 := &Processor{EsVersion: *common.MustNewVersion("2.0.0")} pEsVersion64 := &Processor{EsVersion: *common.MustNewVersion("6.4.0")} pEsVersion63 := &Processor{EsVersion: *common.MustNewVersion("6.3.6")} + pEsVersion76 := &Processor{EsVersion: *common.MustNewVersion("7.6.0")} tests := []struct { output common.MapStr @@ -300,6 +301,14 @@ func TestProcessor(t *testing.T) { output: migrationP.alias(&mapping.Field{Type: "alias", AliasPath: "a.f", MigrationAlias: true}), expected: common.MapStr{"path": "a.f", "type": "alias"}, }, + { + output: p.histogram(&mapping.Field{Type: "histogram"}), + expected: nil, + }, + { + output: pEsVersion76.histogram(&mapping.Field{Type: "histogram"}), + expected: common.MapStr{"type": "histogram"}, + }, } for _, test := range tests {