in input/otlp/traces.go [227:571]
func TranslateTransaction(
attributes pcommon.Map,
spanStatus ptrace.Status,
library pcommon.InstrumentationScope,
event *modelpb.APMEvent,
) {
isJaeger := strings.HasPrefix(event.Agent.Name, "Jaeger")
var (
netHostName string
netHostPort int
)
var (
httpScheme string
httpURL string
httpServerName string
httpHost string
http modelpb.HTTP
httpRequest modelpb.HTTPRequest
httpResponse modelpb.HTTPResponse
urlPath string
urlQuery string
)
var isHTTP, isRPC, isMessaging bool
var messagingQueueName string
var samplerType, samplerParam pcommon.Value
attributes.Range(func(kDots string, v pcommon.Value) bool {
if isJaeger {
switch kDots {
case "sampler.type":
samplerType = v
return true
case "sampler.param":
samplerParam = v
return true
}
}
k := replaceDots(kDots)
switch v.Type() {
case pcommon.ValueTypeSlice:
switch kDots {
case "elastic.profiler_stack_trace_ids":
var vSlice = v.Slice()
event.Transaction.ProfilerStackTraceIds = slices.Grow(event.Transaction.ProfilerStackTraceIds, vSlice.Len())
for i := 0; i < vSlice.Len(); i++ {
var idVal = vSlice.At(i)
if idVal.Type() == pcommon.ValueTypeStr {
event.Transaction.ProfilerStackTraceIds = append(event.Transaction.ProfilerStackTraceIds, idVal.Str())
}
}
default:
setLabel(k, event, v)
}
case pcommon.ValueTypeInt:
switch kDots {
case semconv25.AttributeHTTPStatusCode, semconv.AttributeHTTPResponseStatusCode:
isHTTP = true
httpResponse.StatusCode = uint32(v.Int())
http.Response = &httpResponse
case semconv25.AttributeNetPeerPort, semconv.AttributeClientPort:
if event.Source == nil {
event.Source = &modelpb.Source{}
}
event.Source.Port = uint32(v.Int())
case semconv25.AttributeNetHostPort, semconv.AttributeServerPort:
netHostPort = int(v.Int())
case semconv.AttributeRPCGRPCStatusCode:
isRPC = true
event.Transaction.Result = codes.Code(v.Int()).String()
default:
setLabel(k, event, v)
}
case pcommon.ValueTypeMap:
case pcommon.ValueTypeStr:
stringval := truncate(v.Str())
switch kDots {
// http.*
case semconv25.AttributeHTTPMethod, semconv.AttributeHTTPRequestMethod:
isHTTP = true
httpRequest.Method = stringval
http.Request = &httpRequest
case semconv25.AttributeHTTPURL, semconv.AttributeURLFull, semconv25.AttributeHTTPTarget, attributeHTTPPath:
isHTTP = true
httpURL = stringval
case semconv.AttributeURLPath:
isHTTP = true
urlPath = stringval
case semconv.AttributeURLQuery:
isHTTP = true
urlQuery = stringval
case semconv12.AttributeHTTPHost: //removed after 1.12 (stable)
isHTTP = true
httpHost = stringval
case semconv25.AttributeHTTPScheme, semconv.AttributeURLScheme:
isHTTP = true
httpScheme = stringval
case semconv25.AttributeHTTPStatusCode, semconv.AttributeHTTPResponseStatusCode:
if intv, err := strconv.Atoi(stringval); err == nil {
isHTTP = true
httpResponse.StatusCode = uint32(intv)
http.Response = &httpResponse
}
case "http.protocol":
if !strings.HasPrefix(stringval, "HTTP/") {
// Unexpected, store in labels for debugging.
modelpb.Labels(event.Labels).Set(k, stringval)
break
}
stringval = strings.TrimPrefix(stringval, "HTTP/")
fallthrough
case semconv25.AttributeHTTPFlavor: //removed after 1.25 (experimental)
isHTTP = true
http.Version = stringval
case semconv12.AttributeHTTPServerName: //removed after 1.12 (stable)
isHTTP = true
httpServerName = stringval
case semconv18.AttributeHTTPClientIP: //removed after 1.18 (stable)
if ip, err := modelpb.ParseIP(stringval); err == nil {
if event.Client == nil {
event.Client = &modelpb.Client{}
}
event.Client.Ip = ip
}
case semconv25.AttributeHTTPUserAgent, semconv.AttributeUserAgentOriginal:
if event.UserAgent == nil {
event.UserAgent = &modelpb.UserAgent{}
}
event.UserAgent.Original = stringval
// net.*
case semconv12.AttributeNetPeerIP, semconv25.AttributeNetSockPeerAddr:
if event.Source == nil {
event.Source = &modelpb.Source{}
}
if ip, err := modelpb.ParseIP(stringval); err == nil {
event.Source.Ip = ip
}
case semconv25.AttributeNetPeerName, semconv.AttributeClientAddress:
if event.Source == nil {
event.Source = &modelpb.Source{}
}
event.Source.Domain = stringval
case semconv25.AttributeNetHostName, semconv.AttributeServerAddress:
netHostName = stringval
case semconv.AttributeNetworkConnectionType:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Connection == nil {
event.Network.Connection = &modelpb.NetworkConnection{}
}
event.Network.Connection.Type = stringval
case semconv.AttributeNetworkConnectionSubtype:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Connection == nil {
event.Network.Connection = &modelpb.NetworkConnection{}
}
event.Network.Connection.Subtype = stringval
case semconv.AttributeNetworkCarrierMcc:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Carrier == nil {
event.Network.Carrier = &modelpb.NetworkCarrier{}
}
event.Network.Carrier.Mcc = stringval
case semconv.AttributeNetworkCarrierMnc:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Carrier == nil {
event.Network.Carrier = &modelpb.NetworkCarrier{}
}
event.Network.Carrier.Mnc = stringval
case semconv.AttributeNetworkCarrierName:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Carrier == nil {
event.Network.Carrier = &modelpb.NetworkCarrier{}
}
event.Network.Carrier.Name = stringval
case semconv.AttributeNetworkCarrierIcc:
if event.Network == nil {
event.Network = &modelpb.Network{}
}
if event.Network.Carrier == nil {
event.Network.Carrier = &modelpb.NetworkCarrier{}
}
event.Network.Carrier.Icc = stringval
// messaging.*
//
// messaging.destination is now called messaging.destination.name in the latest semconv
// https://opentelemetry.io/docs/specs/semconv/attributes-registry/messaging
// keep both of them for the backward compatibility
case semconv16.AttributeMessagingDestination, semconv.AttributeMessagingDestinationName, "message_bus.destination":
isMessaging = true
messagingQueueName = stringval
case semconv.AttributeMessagingSystem:
isMessaging = true
modelpb.Labels(event.Labels).Set(k, stringval)
case semconv25.AttributeMessagingOperation, semconv.AttributeMessagingOperationType, semconv.AttributeMessagingOperationName:
isMessaging = true
modelpb.Labels(event.Labels).Set(k, stringval)
// rpc.*
//
// TODO(axw) add RPC fieldset to ECS? Currently we drop these
// attributes, and rely on the operation name like we do with
// Elastic APM agents.
case semconv.AttributeRPCSystem:
isRPC = true
case semconv.AttributeRPCGRPCStatusCode:
isRPC = true
case semconv.AttributeRPCService:
case semconv.AttributeRPCMethod:
// miscellaneous
case "type":
event.Transaction.Type = stringval
case "session.id":
if event.Session == nil {
event.Session = &modelpb.Session{}
}
event.Session.Id = stringval
case semconv.AttributeServiceVersion:
// NOTE support for sending service.version as a span tag
// is deprecated, and will be removed in 8.0. Instrumentation
// should set this as a resource attribute (OTel) or tracer
// tag (Jaeger).
event.Service.Version = stringval
// data_stream.*
case attributeDataStreamDataset:
if event.DataStream == nil {
event.DataStream = &modelpb.DataStream{}
}
event.DataStream.Dataset = sanitizeDataStreamDataset(stringval)
case attributeDataStreamNamespace:
if event.DataStream == nil {
event.DataStream = &modelpb.DataStream{}
}
event.DataStream.Namespace = sanitizeDataStreamNamespace(stringval)
default:
modelpb.Labels(event.Labels).Set(k, stringval)
}
default:
setLabel(k, event, v)
}
return true
})
if event.Transaction.Type == "" {
switch {
case isMessaging:
event.Transaction.Type = "messaging"
case isHTTP, isRPC:
event.Transaction.Type = "request"
default:
event.Transaction.Type = "unknown"
}
}
if isHTTP {
if http.SizeVT() != 0 {
event.Http = &http
}
// Set outcome nad result from status code.
if statusCode := httpResponse.StatusCode; statusCode > 0 {
if event.Event.Outcome == outcomeUnknown {
event.Event.Outcome = serverHTTPStatusCodeOutcome(int(statusCode))
}
if event.Transaction.Result == "" {
event.Transaction.Result = httpStatusCodeResult(int(statusCode))
}
}
httpHost := httpHost
if httpHost == "" {
httpHost = httpServerName
if httpHost == "" {
httpHost = netHostName
if httpHost == "" {
httpHost = event.GetHost().GetHostname()
}
}
if httpHost != "" && netHostPort > 0 {
httpHost = net.JoinHostPort(httpHost, strconv.Itoa(netHostPort))
}
}
// Build a relative url from the UrlPath and UrlQuery.
httpURL := httpURL
if httpURL == "" && urlPath != "" {
httpURL = urlPath
if urlQuery != "" {
httpURL += "?" + urlQuery
}
}
// Build the modelpb.URL from http{URL,Host,Scheme}.
event.Url = modelpb.ParseURL(httpURL, httpHost, httpScheme)
}
if isMessaging {
// Overwrite existing event.Transaction.Message
event.Transaction.Message = nil
if messagingQueueName != "" {
event.Transaction.Message = &modelpb.Message{}
event.Transaction.Message.QueueName = messagingQueueName
}
}
if event.Client == nil && event.Source != nil {
event.Client = &modelpb.Client{}
event.Client.Ip = event.Source.Ip
event.Client.Port = event.Source.Port
event.Client.Domain = event.Source.Domain
}
if samplerType != (pcommon.Value{}) {
// The client has reported its sampling rate, so we can use it to extrapolate span metrics.
parseSamplerAttributes(samplerType, samplerParam, event)
}
if event.Transaction.Result == "" {
event.Transaction.Result = spanStatusResult(spanStatus)
}
// if outcome and result are still not assigned, assign success
if event.Event.Outcome == outcomeUnknown {
event.Event.Outcome = outcomeSuccess
if event.Transaction.Result == "" {
event.Transaction.Result = "Success"
}
}
}