From 5f977373058333f3485462132d9b626aebaecedc Mon Sep 17 00:00:00 2001 From: Isaac Flores Date: Fri, 13 Mar 2026 13:54:45 -0700 Subject: [PATCH 1/3] [exporter/elasticsearch] Remove `host.os.type` encoding in ECS mode --- ...porter-remove-host-os-type-enrichment.yaml | 27 ++++ exporter/elasticsearchexporter/README.md | 22 --- exporter/elasticsearchexporter/model.go | 35 ----- exporter/elasticsearchexporter/model_test.go | 131 +----------------- 4 files changed, 29 insertions(+), 186 deletions(-) create mode 100644 .chloggen/es-exporter-remove-host-os-type-enrichment.yaml diff --git a/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml new file mode 100644 index 0000000000000..550a29d9d7913 --- /dev/null +++ b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog) +component: exporter/elasticsearch + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Remove `host.os.type` encoding in ECS mode." + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: "Use [processor/elasticapmprocessor](https://github.com/elastic/opentelemetry-collector-components/tree/main/processor/elasticapmprocessor) v0.36.2 or later for `host.os.type` enrichment" + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/exporter/elasticsearchexporter/README.md b/exporter/elasticsearchexporter/README.md index 1ccd1e946d131..37a41c30fcd21 100644 --- a/exporter/elasticsearchexporter/README.md +++ b/exporter/elasticsearchexporter/README.md @@ -564,28 +564,6 @@ There are ECS fields that are not mapped easily 1 to 1 but require more advanced Maintains the SemConv Value `host.name` as ECS Value `host.name` and maps it to ECS Value `host.hostname`, if this does not already exist. -#### `host.os.type` - -Maps values of `os.type` in the following manner: - -| SemConv Value | ECS Value | -|---------------|-----------| -| windows | windows | -| linux | linux | -| darwin | macos | -| aix | unix | -| hpux | unix | -| solaris | unix | - -In case `os.name` is present and falls within the specified range of values: - -| SemConv Value | ECS Value | -|---------------|-----------| -| Android | android | -| iOS | ios | - -Otherwise, it is mapped to an empty string (""). - #### `@timestamp` In case the record contains `timestamp`, this value is used. Otherwise, the `observed timestamp` is used. diff --git a/exporter/elasticsearchexporter/model.go b/exporter/elasticsearchexporter/model.go index 70bfc9dd68ae0..f1cd2c7c7df47 100644 --- a/exporter/elasticsearchexporter/model.go +++ b/exporter/elasticsearchexporter/model.go @@ -253,7 +253,6 @@ func (ecsModeEncoder) encodeLog( addDataStreamAttributes(&document, "", idx) // Handle special cases. - encodeHostOsTypeECSMode(&document, ec.resource) encodeLogTimestampECSMode(&document, record) document.AddTraceID("trace.id", record.TraceID()) document.AddSpanID("span.id", record.SpanID()) @@ -284,7 +283,6 @@ func (ecsModeEncoder) encodeSpan( encodeAttributesECSMode(&document, ec.scope.Attributes(), scopeAttrsConversionMap) // Finally, try to map span-level attributes to ECS fields. encodeAttributesECSMode(&document, span.Attributes(), spanAttrsConversionMap) - encodeHostOsTypeECSMode(&document, ec.resource) addDataStreamAttributes(&document, "", idx) document.AddTimestamp("@timestamp", span.StartTimestamp()) @@ -589,39 +587,6 @@ func encodeAttributesECSMode(document *objmodel.Document, attrs pcommon.Map, con } } -func encodeHostOsTypeECSMode(document *objmodel.Document, resource pcommon.Resource) { - // https://www.elastic.co/guide/en/ecs/current/ecs-os.html#field-os-type: - // - // "One of these following values should be used (lowercase): linux, macos, unix, windows. - // If the OS you’re dealing with is not in the list, the field should not be populated." - - var ecsHostOsType string - if semConvOsType, exists := resource.Attributes().Get(string(conventions.OSTypeKey)); exists { - switch semConvOsType.Str() { - case "windows", "linux": - ecsHostOsType = semConvOsType.Str() - case "darwin": - ecsHostOsType = "macos" - case "aix", "hpux", "solaris": - ecsHostOsType = "unix" - } - } - - if semConvOsName, exists := resource.Attributes().Get(string(conventions.OSNameKey)); exists { - switch semConvOsName.Str() { - case "Android": - ecsHostOsType = "android" - case "iOS": - ecsHostOsType = "ios" - } - } - - if ecsHostOsType == "" { - return - } - document.AddString("host.os.type", ecsHostOsType) -} - func encodeLogTimestampECSMode(document *objmodel.Document, record plog.LogRecord) { if record.Timestamp() != 0 { document.AddTimestamp("@timestamp", record.Timestamp()) diff --git a/exporter/elasticsearchexporter/model_test.go b/exporter/elasticsearchexporter/model_test.go index 495748925cf71..36640099b93c3 100644 --- a/exporter/elasticsearchexporter/model_test.go +++ b/exporter/elasticsearchexporter/model_test.go @@ -489,7 +489,7 @@ func TestEncodeLogECSModeDuplication(t *testing.T) { }) require.NoError(t, err) - want := `{"@timestamp":"2024-03-12T20:00:41.123456789Z","agent":{"name":"custom-agent","version":"1.2.3"},"container":{"image":{"tag":["v3.4.0"]}},"event":{"action":"user-password-change"},"host":{"hostname":"localhost","name":"localhost","os":{"full":"Mac OS Mojave","name":"Mac OS X","platform":"darwin","type":"macos","version":"10.14.1"}},"service":{"name":"foo.bar","version":"1.1.0"}}` + want := `{"@timestamp":"2024-03-12T20:00:41.123456789Z","agent":{"name":"custom-agent","version":"1.2.3"},"container":{"image":{"tag":["v3.4.0"]}},"event":{"action":"user-password-change"},"host":{"hostname":"localhost","name":"localhost","os":{"full":"Mac OS Mojave","name":"Mac OS X","platform":"darwin","version":"10.14.1"}},"service":{"name":"foo.bar","version":"1.1.0"}}` resourceContainerImageTags := resource.Attributes().PutEmptySlice("container.image.tags") err = resourceContainerImageTags.FromRaw([]any{"v3.4.0"}) @@ -783,8 +783,7 @@ func TestEncodeLogECSMode(t *testing.T) { "platform": "darwin", "full": "Mac OS Mojave", "name": "Mac OS X", - "version": "10.14.1", - "type": "macos" + "version": "10.14.1" } }, "process": { @@ -847,132 +846,6 @@ func TestEncodeLogECSMode(t *testing.T) { }`, buf.String()) } -func TestEncodeLogECSModeHostOSType(t *testing.T) { - tests := map[string]struct { - osType string - osName string - - expectedHostOsName string - expectedHostOsType string - expectedHostOsPlatform string - }{ - "none_set": { - expectedHostOsName: "", // should not be set - expectedHostOsType: "", // should not be set - expectedHostOsPlatform: "", // should not be set - }, - "type_windows": { - osType: "windows", - expectedHostOsName: "", // should not be set - expectedHostOsType: "windows", - expectedHostOsPlatform: "windows", - }, - "type_linux": { - osType: "linux", - expectedHostOsName: "", // should not be set - expectedHostOsType: "linux", - expectedHostOsPlatform: "linux", - }, - "type_darwin": { - osType: "darwin", - expectedHostOsName: "", // should not be set - expectedHostOsType: "macos", - expectedHostOsPlatform: "darwin", - }, - "type_aix": { - osType: "aix", - expectedHostOsName: "", // should not be set - expectedHostOsType: "unix", - expectedHostOsPlatform: "aix", - }, - "type_hpux": { - osType: "hpux", - expectedHostOsName: "", // should not be set - expectedHostOsType: "unix", - expectedHostOsPlatform: "hpux", - }, - "type_solaris": { - osType: "solaris", - expectedHostOsName: "", // should not be set - expectedHostOsType: "unix", - expectedHostOsPlatform: "solaris", - }, - "type_unknown": { - osType: "unknown", - expectedHostOsName: "", // should not be set - expectedHostOsType: "", // should not be set - expectedHostOsPlatform: "unknown", - }, - "name_android": { - osName: "Android", - expectedHostOsName: "Android", - expectedHostOsType: "android", - expectedHostOsPlatform: "", // should not be set - }, - "name_ios": { - osName: "iOS", - expectedHostOsName: "iOS", - expectedHostOsType: "ios", - expectedHostOsPlatform: "", // should not be set - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - logs := plog.NewLogs() - resource := logs.ResourceLogs().AppendEmpty().Resource() - scope := pcommon.NewInstrumentationScope() - record := plog.NewLogRecord() - - resource.Attributes().PutStr("agent.name", "custom-agent") - resource.Attributes().PutStr("agent.version", "1.2.3") - if test.osType != "" { - resource.Attributes().PutStr("os.type", test.osType) - } - if test.osName != "" { - resource.Attributes().PutStr("os.name", test.osName) - } - - timestamp := pcommon.Timestamp(1710373859123456789) - record.SetTimestamp(timestamp) - logs.MarkReadOnly() - - var buf bytes.Buffer - encoder, _ := newEncoder(MappingECS) - err := encoder.encodeLog( - encodingContext{resource: resource, scope: scope}, - record, elasticsearch.Index{}, &buf, - ) - require.NoError(t, err) - - expectedJSON := `{"@timestamp":"2024-03-13T23:50:59.123456789Z","agent":{"name":"custom-agent","version":"1.2.3"}` - if test.expectedHostOsName != "" || - test.expectedHostOsPlatform != "" || - test.expectedHostOsType != "" { - expectedJSON += `, "host":{"os":{` - - first := true - maybeAdd := func(k, v string) { - if v != "" { - if first { - first = false - } else { - expectedJSON += "," - } - expectedJSON += fmt.Sprintf("%q:%q", k, v) - } - } - maybeAdd("name", test.expectedHostOsName) - maybeAdd("type", test.expectedHostOsType) - maybeAdd("platform", test.expectedHostOsPlatform) - expectedJSON += "}}" - } - expectedJSON += "}" - require.JSONEq(t, expectedJSON, buf.String()) - }) - } -} - func TestEncodeLogECSModeTimestamps(t *testing.T) { tests := map[string]struct { timeUnixNano int64 From a9edcb3c081d74378501c5e1371ae558e24f9ead Mon Sep 17 00:00:00 2001 From: Isaac Flores Date: Fri, 13 Mar 2026 13:59:31 -0700 Subject: [PATCH 2/3] add PR to chlog --- .chloggen/es-exporter-remove-host-os-type-enrichment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml index 550a29d9d7913..f6c57b3c73e76 100644 --- a/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml +++ b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml @@ -7,10 +7,10 @@ change_type: enhancement component: exporter/elasticsearch # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: "Remove `host.os.type` encoding in ECS mode." +note: "Remove `host.os.type` encoding in ECS mode" # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. -issues: [] +issues: [46900] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document. From d91ad4f2792aaf5a19812ab78aa1cef5bd5cf8f4 Mon Sep 17 00:00:00 2001 From: Isaac Flores Date: Tue, 17 Mar 2026 15:19:23 -0700 Subject: [PATCH 3/3] update chlog to breaking change --- .chloggen/es-exporter-remove-host-os-type-enrichment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml index f6c57b3c73e76..686e3bd942ee1 100644 --- a/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml +++ b/.chloggen/es-exporter-remove-host-os-type-enrichment.yaml @@ -1,7 +1,7 @@ # Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: enhancement +change_type: breaking # The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog) component: exporter/elasticsearch