func translateResourceMetadata()

in input/otlp/metadata.go [45:457]


func translateResourceMetadata(resource pcommon.Resource, out *modelpb.APMEvent) {
	var exporterVersion string
	resource.Attributes().Range(func(k string, v pcommon.Value) bool {
		switch k {
		// service.*
		case semconv.AttributeServiceName:
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			out.Service.Name = cleanServiceName(v.Str())
		case semconv.AttributeServiceVersion:
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			out.Service.Version = truncate(v.Str())
		case semconv.AttributeServiceInstanceID:
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			if out.Service.Node == nil {
				out.Service.Node = &modelpb.ServiceNode{}
			}
			out.Service.Node.Name = truncate(v.Str())

		// deployment.*
		case semconv26.AttributeDeploymentEnvironment, semconv.AttributeDeploymentEnvironmentName:
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			out.Service.Environment = truncate(v.Str())

		// telemetry.sdk.*
		case semconv.AttributeTelemetrySDKName:
			if out.Agent == nil {
				out.Agent = &modelpb.Agent{}
			}
			out.Agent.Name = truncate(v.Str())
		case semconv.AttributeTelemetrySDKVersion:
			if out.Agent == nil {
				out.Agent = &modelpb.Agent{}
			}
			out.Agent.Version = truncate(v.Str())
		case semconv.AttributeTelemetrySDKLanguage:
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			if out.Service.Language == nil {
				out.Service.Language = &modelpb.Language{}
			}
			out.Service.Language.Name = truncate(v.Str())

		// cloud.*
		case semconv.AttributeCloudProvider:
			if out.Cloud == nil {
				out.Cloud = &modelpb.Cloud{}
			}
			out.Cloud.Provider = truncate(v.Str())
		case semconv.AttributeCloudAccountID:
			if out.Cloud == nil {
				out.Cloud = &modelpb.Cloud{}
			}
			out.Cloud.AccountId = truncate(v.Str())
		case semconv.AttributeCloudRegion:
			if out.Cloud == nil {
				out.Cloud = &modelpb.Cloud{}
			}
			out.Cloud.Region = truncate(v.Str())
		case semconv.AttributeCloudAvailabilityZone:
			if out.Cloud == nil {
				out.Cloud = &modelpb.Cloud{}
			}
			out.Cloud.AvailabilityZone = truncate(v.Str())
		case semconv.AttributeCloudPlatform:
			if out.Cloud == nil {
				out.Cloud = &modelpb.Cloud{}
			}
			out.Cloud.ServiceName = truncate(v.Str())

		// container.*
		case semconv.AttributeContainerName:
			if out.Container == nil {
				out.Container = &modelpb.Container{}
			}
			out.Container.Name = truncate(v.Str())
		case semconv.AttributeContainerID:
			if out.Container == nil {
				out.Container = &modelpb.Container{}
			}
			out.Container.Id = truncate(v.Str())
		case semconv.AttributeContainerImageName:
			if out.Container == nil {
				out.Container = &modelpb.Container{}
			}
			out.Container.ImageName = truncate(v.Str())
		case "container.image.tag":
			if out.Container == nil {
				out.Container = &modelpb.Container{}
			}
			out.Container.ImageTag = truncate(v.Str())
		case "container.runtime":
			if out.Container == nil {
				out.Container = &modelpb.Container{}
			}
			out.Container.Runtime = truncate(v.Str())

		// k8s.*
		case semconv.AttributeK8SNamespaceName:
			if out.Kubernetes == nil {
				out.Kubernetes = &modelpb.Kubernetes{}
			}
			out.Kubernetes.Namespace = truncate(v.Str())
		case semconv.AttributeK8SNodeName:
			if out.Kubernetes == nil {
				out.Kubernetes = &modelpb.Kubernetes{}
			}
			out.Kubernetes.NodeName = truncate(v.Str())
		case semconv.AttributeK8SPodName:
			if out.Kubernetes == nil {
				out.Kubernetes = &modelpb.Kubernetes{}
			}
			out.Kubernetes.PodName = truncate(v.Str())
		case semconv.AttributeK8SPodUID:
			if out.Kubernetes == nil {
				out.Kubernetes = &modelpb.Kubernetes{}
			}
			out.Kubernetes.PodUid = truncate(v.Str())

		// host.*
		case semconv.AttributeHostName:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			out.Host.Hostname = truncate(v.Str())
		case semconv.AttributeHostID:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			out.Host.Id = truncate(v.Str())
		case semconv.AttributeHostType:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			out.Host.Type = truncate(v.Str())
		case "host.arch":
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			out.Host.Architecture = truncate(v.Str())
		case semconv.AttributeHostIP:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			slice := v.Slice()
			result := make([]*modelpb.IP, 0, slice.Len())
			for i := 0; i < slice.Len(); i++ {
				ip, err := modelpb.ParseIP(slice.At(i).Str())
				if err == nil {
					result = append(result, ip)
				}
			}
			out.Host.Ip = result

		// process.*
		case semconv.AttributeProcessPID:
			if out.Process == nil {
				out.Process = &modelpb.Process{}
			}
			out.Process.Pid = uint32(v.Int())
		case semconv.AttributeProcessCommandLine:
			if out.Process == nil {
				out.Process = &modelpb.Process{}
			}
			out.Process.CommandLine = truncate(v.Str())
		case semconv.AttributeProcessExecutablePath:
			if out.Process == nil {
				out.Process = &modelpb.Process{}
			}
			out.Process.Executable = truncate(v.Str())
		case "process.runtime.name":
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			if out.Service.Runtime == nil {
				out.Service.Runtime = &modelpb.Runtime{}
			}
			out.Service.Runtime.Name = truncate(v.Str())
		case "process.runtime.version":
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			if out.Service.Runtime == nil {
				out.Service.Runtime = &modelpb.Runtime{}
			}
			out.Service.Runtime.Version = truncate(v.Str())
		case semconv.AttributeProcessOwner:
			if out.User == nil {
				out.User = &modelpb.User{}
			}
			out.User.Name = truncate(v.Str())

		// os.*
		case semconv.AttributeOSType:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			if out.Host.Os == nil {
				out.Host.Os = &modelpb.OS{}
			}
			out.Host.Os.Platform = strings.ToLower(truncate(v.Str()))
		case semconv.AttributeOSDescription:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			if out.Host.Os == nil {
				out.Host.Os = &modelpb.OS{}
			}
			out.Host.Os.Full = truncate(v.Str())
		case semconv.AttributeOSName:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			if out.Host.Os == nil {
				out.Host.Os = &modelpb.OS{}
			}
			out.Host.Os.Name = truncate(v.Str())
		case semconv.AttributeOSVersion:
			if out.Host == nil {
				out.Host = &modelpb.Host{}
			}
			if out.Host.Os == nil {
				out.Host.Os = &modelpb.OS{}
			}
			out.Host.Os.Version = truncate(v.Str())

		// device.*
		case semconv.AttributeDeviceID:
			if out.Device == nil {
				out.Device = &modelpb.Device{}
			}
			out.Device.Id = truncate(v.Str())
		case semconv.AttributeDeviceModelIdentifier:
			if out.Device == nil {
				out.Device = &modelpb.Device{}
			}
			if out.Device.Model == nil {
				out.Device.Model = &modelpb.DeviceModel{}
			}
			out.Device.Model.Identifier = truncate(v.Str())
		case semconv.AttributeDeviceModelName:
			if out.Device == nil {
				out.Device = &modelpb.Device{}
			}
			if out.Device.Model == nil {
				out.Device.Model = &modelpb.DeviceModel{}
			}
			out.Device.Model.Name = truncate(v.Str())
		case "device.manufacturer":
			if out.Device == nil {
				out.Device = &modelpb.Device{}
			}
			out.Device.Manufacturer = truncate(v.Str())

		// Legacy OpenCensus attributes.
		case "opencensus.exporterversion":
			exporterVersion = v.Str()

		// timestamp attribute to deal with time skew on mobile
		// 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:
			if out.DataStream == nil {
				out.DataStream = &modelpb.DataStream{}
			}
			out.DataStream.Dataset = sanitizeDataStreamDataset(v.Str())
		case attributeDataStreamNamespace:
			if out.DataStream == nil {
				out.DataStream = &modelpb.DataStream{}
			}
			out.DataStream.Namespace = sanitizeDataStreamNamespace(v.Str())
		default:
			if out.Labels == nil {
				out.Labels = make(modelpb.Labels)
			}
			if out.NumericLabels == nil {
				out.NumericLabels = make(modelpb.NumericLabels)
			}
			setLabel(replaceDots(k), out, v)
		}
		return true
	})

	// 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."
	switch out.GetHost().GetOs().GetPlatform() {
	case "windows", "linux":
		out.Host.Os.Type = out.Host.Os.Platform
	case "darwin":
		out.Host.Os.Type = "macos"
	case "aix", "hpux", "solaris":
		out.Host.Os.Type = "unix"
	}

	switch out.GetHost().GetOs().GetName() {
	case "Android":
		out.Host.Os.Type = "android"
	case "iOS":
		out.Host.Os.Type = "ios"
	}

	if strings.HasPrefix(exporterVersion, "Jaeger") {
		// version is of format `Jaeger-<agentlanguage>-<version>`, e.g. `Jaeger-Go-2.20.0`
		const nVersionParts = 3
		versionParts := strings.SplitN(exporterVersion, "-", nVersionParts)
		if out.GetService().GetLanguage().GetName() == "" && len(versionParts) == nVersionParts {
			if out.Service == nil {
				out.Service = &modelpb.Service{}
			}
			if out.Service.Language == nil {
				out.Service.Language = &modelpb.Language{}
			}
			out.Service.Language.Name = versionParts[1]
		}
		if out.Agent == nil {
			out.Agent = &modelpb.Agent{}
		}
		if v := versionParts[len(versionParts)-1]; v != "" {
			out.Agent.Version = v
		}
		out.Agent.Name = AgentNameJaeger

		// Translate known Jaeger labels.
		if clientUUID, ok := out.Labels["client-uuid"]; ok {
			out.Agent.EphemeralId = clientUUID.Value
			delete(out.Labels, "client-uuid")
		}
		if systemIP, ok := out.Labels["ip"]; ok {
			if ip, err := modelpb.ParseIP(systemIP.Value); err == nil {
				out.Host.Ip = []*modelpb.IP{ip}
			}
			delete(out.Labels, "ip")
		}
	}

	if out.GetService().GetName() == "" {
		if out.Service == nil {
			out.Service = &modelpb.Service{}
		}
		// service.name is a required field.
		out.Service.Name = "unknown"
	}
	if out.Agent == nil {
		out.Agent = &modelpb.Agent{}
	}
	if out.GetAgent().GetName() == "" {
		// agent.name is a required field.
		out.Agent.Name = "otlp"
	}
	if out.Agent.Version == "" {
		// agent.version is a required field.
		out.Agent.Version = "unknown"
	}

	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()
		}
	} 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.Service{}
		}
		if out.Service.Language == nil {
			out.Service.Language = &modelpb.Language{}
		}
		out.Service.Language.Name = "unknown"
	}

	// Set the decoded labels as "global" -- defined at the service level.
	for k, v := range out.Labels {
		v.Global = true
		out.Labels[k] = v
	}
	for k, v := range out.NumericLabels {
		v.Global = true
		out.NumericLabels[k] = v
	}
}