receiver/elasticapmreceiver/internal/mappers/intakeV2ToDerivedFields.go (116 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file contains mappings where we move intakeV2 fields into Attributes and Resource attributes on OTel events
// These fields are not covered by SemConv and are specific to Elastic
package mappers // import "github.com/elastic/opentelemetry-collector-components/receiver/elasticapmreceiver/internal/mappers"
import (
"fmt"
"strings"
"github.com/elastic/apm-data/model/modelpb"
"github.com/elastic/opentelemetry-lib/elasticattr"
"go.opentelemetry.io/collector/pdata/pcommon"
)
// Sets fields that are NOT part of OTel for transactions. These fields are derived by the Enrichment lib in case of OTLP input
func SetDerivedFieldsForTransaction(event *modelpb.APMEvent, attributes pcommon.Map) {
attributes.PutStr(elasticattr.ProcessorEvent, "transaction")
attributes.PutStr(elasticattr.TransactionID, event.Transaction.Id)
attributes.PutStr(elasticattr.TransactionName, event.Transaction.Name)
attributes.PutBool(elasticattr.TransactionSampled, event.Transaction.Sampled)
// from whatever reason Transaction.Root is always false. That seems to be a derived field already - I don't see that fields directly on IntakeV2 - there is only ParentId
attributes.PutBool(elasticattr.TransactionRoot, event.ParentId == "")
attributes.PutStr(elasticattr.TransactionType, event.Transaction.Type)
attributes.PutStr(elasticattr.TransactionResult, event.Transaction.Result)
attributes.PutInt(elasticattr.TransactionDurationUs, int64(event.Event.Duration/1_000))
}
// Sets fields that are NOT part of OTel for spans. These fields are derived by the Enrichment lib in case of OTLP input
func SetDerivedFieldsForSpan(event *modelpb.APMEvent, attributes pcommon.Map) {
attributes.PutStr(elasticattr.ProcessorEvent, "span")
attributes.PutInt(elasticattr.SpanDurationUs, int64(event.Event.Duration/1_000))
attributes.PutStr("span.id", event.Span.Id)
attributes.PutStr(elasticattr.SpanName, event.Span.Name)
attributes.PutStr(elasticattr.SpanType, event.Span.Type)
attributes.PutStr(elasticattr.SpanSubtype, event.Span.Subtype)
attributes.PutStr("span.action", event.Span.Action)
if event.Span.Sync != nil {
attributes.PutBool("span.sync", *event.Span.Sync)
}
if event.Span.DestinationService != nil {
attributes.PutStr(elasticattr.ServiceTargetName, event.Span.DestinationService.Name)
attributes.PutStr(elasticattr.ServiceTargetType, event.Span.DestinationService.Type)
attributes.PutStr(elasticattr.SpanDestinationServiceResource, event.Span.DestinationService.Resource)
}
}
// Sets resource fields that are NOT part of OTel. These fields are derived by the Enrichment lib in case of OTLP input
func SetDerivedResourceAttributes(event *modelpb.APMEvent, attributes pcommon.Map) {
attributes.PutStr(elasticattr.AgentName, event.Agent.Name)
attributes.PutStr(elasticattr.AgentVersion, event.Agent.Version)
if event.Service != nil && event.Service.Language != nil {
if event.Service.Language.Name != "" {
attributes.PutStr("service.language.name", event.Service.Language.Name)
}
if event.Service.Language.Version != "" {
attributes.PutStr("service.language.version", event.Service.Language.Version)
}
}
}
// Shared across spans and transactions
func SetDerivedFieldsCommon(event *modelpb.APMEvent, attributes pcommon.Map) {
attributes.PutInt(elasticattr.TimestampUs, int64(event.Timestamp/1_000))
if strings.EqualFold(event.Event.Outcome, "success") {
attributes.PutStr(elasticattr.EventOutcome, "success")
} else if strings.EqualFold(event.Event.Outcome, "failure") {
attributes.PutStr(elasticattr.EventOutcome, "failure")
} else {
attributes.PutStr(elasticattr.EventOutcome, "unknown")
}
}
// Sets fields that are NOT part of OTel for errors. These fields are derived by the Enrichment lib in case of OTLP input
func SetDerivedFieldsForError(event *modelpb.APMEvent, attributes pcommon.Map) {
attributes.PutStr(elasticattr.ProcessorEvent, "error")
if event.Error == nil {
return
}
if event.Error.Id != "" {
attributes.PutStr(elasticattr.ErrorID, event.Error.Id)
}
if event.Transaction != nil && event.Transaction.Id != "" {
attributes.PutStr(elasticattr.TransactionID, event.Transaction.Id)
}
if event.ParentId != "" {
attributes.PutStr(elasticattr.ParentID, event.ParentId)
}
if event.Error.Type != "" {
attributes.PutStr("error.type", event.Error.Type)
}
if event.Error.Message != "" {
attributes.PutStr("message", event.Error.Message)
}
attributes.PutStr(elasticattr.ErrorGroupingKey, event.Error.GroupingKey)
attributes.PutInt(elasticattr.TimestampUs, int64(event.Timestamp/1_000))
if event.Error.Culprit != "" {
attributes.PutStr("error.culprit", event.Error.Culprit)
}
if event.Error.Exception != nil {
if event.Error.Exception.Type != "" {
attributes.PutStr("exception.type", event.Error.Exception.Type)
}
if event.Error.Exception.Message != "" {
attributes.PutStr("exception.message", event.Error.Exception.Message)
}
if event.Error.Exception.Stacktrace != nil {
str := ""
for _, frame := range event.Error.Exception.Stacktrace {
f := frame.GetFunction()
l := frame.GetLineno()
if f != "" {
str += fmt.Sprintf("%s:%d %s \n", frame.GetFilename(), l, f)
} else {
c := frame.GetClassname()
if c != "" && l != 0 {
str += fmt.Sprintf("%s:%d \n", c, l)
}
}
}
attributes.PutStr("exception.stacktrace", str)
}
if event.Error.Exception.Module != "" {
attributes.PutStr("error.exception.module", event.Error.Exception.Module)
}
if event.Error.Exception.Handled != nil {
attributes.PutBool("error.exception.handled", *event.Error.Exception.Handled)
}
if event.Error.Exception.Code != "" {
attributes.PutStr("error.exception.code", event.Error.Exception.Code)
}
}
}