diff --git a/input/otlp/metadata.go b/input/otlp/metadata.go index 1fa767b4..f39c8c5a 100644 --- a/input/otlp/metadata.go +++ b/input/otlp/metadata.go @@ -289,6 +289,9 @@ func translateResourceMetadata(resource pcommon.Resource, out *modelpb.APMEvent) // devices. APM server should drop this field. case "telemetry.sdk.elastic_export_timestamp": // Do nothing. + case "telemetry.distro.name": + case "telemetry.distro.version": + //distro version & name are handled below and should not end up as labels // data_stream.* case attributeDataStreamDataset: @@ -375,10 +378,10 @@ func translateResourceMetadata(resource pcommon.Resource, out *modelpb.APMEvent) // service.name is a required field. out.Service.Name = "unknown" } + if out.Agent == nil { + out.Agent = modelpb.AgentFromVTPool() + } if out.GetAgent().GetName() == "" { - if out.Agent == nil { - out.Agent = modelpb.AgentFromVTPool() - } // agent.name is a required field. out.Agent.Name = "otlp" } @@ -386,12 +389,31 @@ func translateResourceMetadata(resource pcommon.Resource, out *modelpb.APMEvent) // agent.version is a required field. out.Agent.Version = "unknown" } - if out.GetService().GetLanguage().GetName() != "" { - if out.Agent == nil { - out.Agent = modelpb.AgentFromVTPool() + + distroName, distroNameSet := resource.Attributes().Get("telemetry.distro.name") + distroVersion, distroVersionSet := resource.Attributes().Get("telemetry.distro.version") + + if distroNameSet && distroName.Str() != "" { + agentLang := "unknown" + if out.GetService().GetLanguage().GetName() != "" { + agentLang = out.GetService().GetLanguage().GetName() + } + + out.Agent.Name = fmt.Sprintf("%s/%s/%s", out.Agent.Name, agentLang, distroName.Str()) + + //we intentionally do not want to fallback to the Otel SDK version if we have a distro name, this would only cause confusion + out.Agent.Version = "unknown" + if distroVersionSet && distroVersion.Str() != "" { + out.Agent.Version = distroVersion.Str() } - out.Agent.Name = fmt.Sprintf("%s/%s", out.Agent.Name, out.Service.Language.Name) } else { + //distro is not set, use just the language as suffix if present + if out.GetService().GetLanguage().GetName() != "" { + out.Agent.Name = fmt.Sprintf("%s/%s", out.Agent.Name, out.GetService().GetLanguage().GetName()) + } + } + + if out.GetService().GetLanguage().GetName() == "" { if out.Service == nil { out.Service = modelpb.ServiceFromVTPool() } diff --git a/input/otlp/metadata_test.go b/input/otlp/metadata_test.go index 52b16aca..9ba2c76c 100644 --- a/input/otlp/metadata_test.go +++ b/input/otlp/metadata_test.go @@ -75,6 +75,52 @@ func TestResourceConventions(t *testing.T) { }, }, }, + "agent_distro": { + attrs: map[string]interface{}{ + "telemetry.sdk.name": "sdk_name", + "telemetry.sdk.version": "sdk_version", + "telemetry.sdk.language": "language_name", + "telemetry.distro.name": "distro_name", + "telemetry.distro.version": "distro_version", + }, + expected: &modelpb.APMEvent{ + Agent: &modelpb.Agent{Name: "sdk_name/language_name/distro_name", Version: "distro_version"}, + Service: &modelpb.Service{ + Name: "unknown", + Language: &modelpb.Language{Name: "language_name"}, + }, + }, + }, + "agent_distro_no_language": { + attrs: map[string]interface{}{ + "telemetry.sdk.name": "sdk_name", + "telemetry.sdk.version": "sdk_version", + "telemetry.distro.name": "distro_name", + "telemetry.distro.version": "distro_version", + }, + expected: &modelpb.APMEvent{ + Agent: &modelpb.Agent{Name: "sdk_name/unknown/distro_name", Version: "distro_version"}, + Service: &modelpb.Service{ + Name: "unknown", + Language: &modelpb.Language{Name: "unknown"}, + }, + }, + }, + "agent_distro_no_version": { + attrs: map[string]interface{}{ + "telemetry.sdk.name": "sdk_name", + "telemetry.sdk.version": "sdk_version", + "telemetry.sdk.language": "language_name", + "telemetry.distro.name": "distro_name", + }, + expected: &modelpb.APMEvent{ + Agent: &modelpb.Agent{Name: "sdk_name/language_name/distro_name", Version: "unknown"}, + Service: &modelpb.Service{ + Name: "unknown", + Language: &modelpb.Language{Name: "language_name"}, + }, + }, + }, "runtime": { attrs: map[string]interface{}{ "process.runtime.name": "runtime_name",