diff --git a/model/error.go b/model/error.go index bd0a1d30432..c16f8db3b3f 100644 --- a/model/error.go +++ b/model/error.go @@ -51,9 +51,9 @@ const ( type Error struct { ID *string - TransactionID *string - TraceID *string - ParentID *string + TransactionID string + TraceID string + ParentID string Timestamp time.Time Metadata Metadata @@ -122,16 +122,18 @@ func (e *Error) Transform(ctx context.Context, tctx *transform.Context) []beat.E // sampled and type is nil if an error happens outside a transaction or an (old) agent is not sending sampled info // agents must send semantically correct data - if e.TransactionSampled != nil || e.TransactionType != nil || (e.TransactionID != nil && *e.TransactionID != "") { + if e.TransactionSampled != nil || e.TransactionType != nil || e.TransactionID != "" { transaction := common.MapStr{} - utility.Set(transaction, "id", e.TransactionID) + if e.TransactionID != "" { + transaction["id"] = e.TransactionID + } utility.Set(transaction, "type", e.TransactionType) utility.Set(transaction, "sampled", e.TransactionSampled) utility.Set(fields, "transaction", transaction) } - utility.AddId(fields, "parent", e.ParentID) - utility.AddId(fields, "trace", e.TraceID) + utility.AddID(fields, "parent", e.ParentID) + utility.AddID(fields, "trace", e.TraceID) utility.Set(fields, "timestamp", utility.TimeAsMicros(e.Timestamp)) return []beat.Event{ diff --git a/model/error_test.go b/model/error_test.go index f907bdc976c..9ef038935f6 100644 --- a/model/error_test.go +++ b/model/error_test.go @@ -217,7 +217,7 @@ func TestEventFields(t *testing.T) { Culprit: &culprit, Exception: &exception, Log: &log, - TransactionID: &trID, + TransactionID: trID, // Service name and version are required for sourcemapping. Metadata: Metadata{ @@ -354,7 +354,7 @@ func TestEvents(t *testing.T) { Message: &exMsg, Stacktrace: Stacktrace{&StacktraceFrame{Filename: tests.StringPtr("myFile")}}, }, - TransactionID: &trID, + TransactionID: trID, TransactionSampled: &sampledTrue, Labels: &labels, Page: &Page{Url: &url, Referer: &referer}, diff --git a/model/modeldecoder/error.go b/model/modeldecoder/error.go index 17e3ca6b420..a65366493c4 100644 --- a/model/modeldecoder/error.go +++ b/model/modeldecoder/error.go @@ -77,12 +77,12 @@ func decodeError(input Input, schema *jsonschema.Schema) (*m.Error, error) { Custom: ctx.Custom, Experimental: ctx.Experimental, Timestamp: decoder.TimeEpochMicro(raw, "timestamp"), - TransactionID: decoder.StringPtr(raw, fieldName("transaction_id")), - ParentID: decoder.StringPtr(raw, fieldName("parent_id")), - TraceID: decoder.StringPtr(raw, fieldName("trace_id")), TransactionSampled: decoder.BoolPtr(raw, fieldName("sampled"), fieldName("transaction")), TransactionType: decoder.StringPtr(raw, fieldName("type"), fieldName("transaction")), } + decodeString(raw, fieldName("parent_id"), &e.ParentID) + decodeString(raw, fieldName("trace_id"), &e.TraceID) + decodeString(raw, fieldName("transaction_id"), &e.TransactionID) ex := decoder.MapStr(raw, fieldName("exception")) e.Exception = decodeException(&decoder, input.Config.HasShortFieldNames)(ex) diff --git a/model/modeldecoder/error_test.go b/model/modeldecoder/error_test.go index 53c3363a8cf..243b8640f06 100644 --- a/model/modeldecoder/error_test.go +++ b/model/modeldecoder/error_test.go @@ -217,11 +217,11 @@ func TestErrorEventDecode(t *testing.T) { }, }, ID: &id, - TransactionID: &transactionID, + TransactionID: transactionID, TransactionSampled: &transactionSampled, TransactionType: &transactionType, - ParentID: &parentID, - TraceID: &traceID, + ParentID: parentID, + TraceID: traceID, Culprit: &culprit, }, }, diff --git a/model/modeldecoder/span.go b/model/modeldecoder/span.go index 5750b2f91e5..f5688d9ec14 100644 --- a/model/modeldecoder/span.go +++ b/model/modeldecoder/span.go @@ -37,14 +37,15 @@ var ( rumV3SpanSchema = validation.CreateSchema(schema.RUMV3Schema, "span") ) -// decodeRUMV3Span decodes a v3 RUM span. -func decodeRUMV3Span(input Input) (*model.Span, error) { +// decodeRUMV3Span decodes a v3 RUM span, and optional parent index. +// If parent index wasn't specified, then the value will be negative. +func decodeRUMV3Span(input Input) (_ *model.Span, parentIndex int, _ error) { return decodeSpan(input, rumV3SpanSchema) } // DecodeSpan decodes a span. func DecodeSpan(input Input, batch *model.Batch) error { - span, err := decodeSpan(input, spanSchema) + span, _, err := decodeSpan(input, spanSchema) if err != nil { return err } @@ -52,10 +53,10 @@ func DecodeSpan(input Input, batch *model.Batch) error { return nil } -func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { +func decodeSpan(input Input, schema *jsonschema.Schema) (_ *model.Span, parentIndex int, _ error) { raw, err := validation.ValidateObject(input.Raw, schema) if err != nil { - return nil, errors.Wrap(err, "failed to validate span") + return nil, -1, errors.Wrap(err, "failed to validate span") } fieldName := field.Mapper(input.Config.HasShortFieldNames) @@ -68,16 +69,14 @@ func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { Sync: decoder.BoolPtr(raw, fieldName("sync")), Timestamp: decoder.TimeEpochMicro(raw, fieldName("timestamp")), ID: decoder.String(raw, fieldName("id")), - ParentID: decoder.StringPtr(raw, "parent_id"), ChildIDs: decoder.StringArr(raw, "child_ids"), - // ParentIdx comes from RUM V3 payloads only, and used to populate ParentID - ParentIdx: decoder.IntPtr(raw, fieldName("parent_idx")), - TraceID: decoder.StringPtr(raw, "trace_id"), - TransactionID: decoder.StringPtr(raw, "transaction_id"), - Type: decoder.String(raw, fieldName("type")), - Subtype: decoder.StringPtr(raw, fieldName("subtype")), - Action: decoder.StringPtr(raw, fieldName("action")), + Type: decoder.String(raw, fieldName("type")), + Subtype: decoder.StringPtr(raw, fieldName("subtype")), + Action: decoder.StringPtr(raw, fieldName("action")), } + decodeString(raw, fieldName("parent_id"), &event.ParentID) + decodeString(raw, fieldName("trace_id"), &event.TraceID) + decodeString(raw, fieldName("transaction_id"), &event.TransactionID) ctx := decoder.MapStr(raw, fieldName("context")) if ctx != nil { @@ -87,19 +86,19 @@ func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { db, err := decodeDB(ctx, decoder.Err) if err != nil { - return nil, err + return nil, -1, err } event.DB = db http, err := decodeSpanHTTP(ctx, input.Config.HasShortFieldNames, decoder.Err) if err != nil { - return nil, err + return nil, -1, err } event.HTTP = http dest, destService, err := decodeDestination(ctx, input.Config.HasShortFieldNames, decoder.Err) if err != nil { - return nil, err + return nil, -1, err } event.Destination = dest event.DestinationService = destService @@ -111,7 +110,7 @@ func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { } if event.Message, err = decodeMessage(ctx, decoder.Err); err != nil { - return nil, err + return nil, -1, err } if input.Config.Experimental { @@ -124,7 +123,7 @@ func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { var stacktr *m.Stacktrace stacktr, decoder.Err = decodeStacktrace(raw[fieldName("stacktrace")], input.Config.HasShortFieldNames, decoder.Err) if decoder.Err != nil { - return nil, decoder.Err + return nil, -1, decoder.Err } if stacktr != nil { event.Stacktrace = *stacktr @@ -152,7 +151,13 @@ func decodeSpan(input Input, schema *jsonschema.Schema) (*model.Span, error) { event.Timestamp = timestamp } - return &event, nil + // parent_idx comes from RUM V3 payloads only. It is used only during + // decoding to populate ParentID. We initialise to -1 to indicate lack + // of parent index. + parentIndex = -1 + decodeInt(raw, fieldName("parent_idx"), &parentIndex) + + return &event, parentIndex, nil } func decodeDB(input interface{}, err error) (*model.DB, error) { diff --git a/model/modeldecoder/span_test.go b/model/modeldecoder/span_test.go index 420990dde2d..9a9ed39adfd 100644 --- a/model/modeldecoder/span_test.go +++ b/model/modeldecoder/span_test.go @@ -98,9 +98,9 @@ func TestDecodeSpan(t *testing.T) { Action: &action2, Duration: duration, Timestamp: spanTime, - ParentID: &parentID, + ParentID: parentID, ID: id, - TraceID: &traceID, + TraceID: traceID, }, }, "no timestamp specified, request time + start used": { @@ -113,9 +113,9 @@ func TestDecodeSpan(t *testing.T) { Name: name, Type: "db", Duration: duration, - ParentID: &parentID, + ParentID: parentID, ID: id, - TraceID: &traceID, + TraceID: traceID, Start: &start, Timestamp: requestTime.Add(time.Duration(start * float64(time.Millisecond))), }, @@ -135,10 +135,10 @@ func TestDecodeSpan(t *testing.T) { Start: &start, Duration: duration, Timestamp: spanTime, - ParentID: &parentID, + ParentID: parentID, ID: id, - TraceID: &traceID, - TransactionID: &transactionID, + TraceID: traceID, + TransactionID: transactionID, }, }, "event experimental=true, no experimental payload": { @@ -156,10 +156,10 @@ func TestDecodeSpan(t *testing.T) { Start: &start, Duration: duration, Timestamp: spanTime, - ParentID: &parentID, + ParentID: parentID, ID: id, - TraceID: &traceID, - TransactionID: &transactionID, + TraceID: traceID, + TransactionID: transactionID, }, cfg: Config{Experimental: true}, }, @@ -178,10 +178,10 @@ func TestDecodeSpan(t *testing.T) { Start: &start, Duration: duration, Timestamp: spanTime, - ParentID: &parentID, + ParentID: parentID, ID: id, - TraceID: &traceID, - TransactionID: &transactionID, + TraceID: traceID, + TransactionID: transactionID, Experimental: 123, }, cfg: Config{Experimental: true}, @@ -206,9 +206,9 @@ func TestDecodeSpan(t *testing.T) { }, Labels: common.MapStr{"a": "tag", "tag_key": 17}, ID: id, - TraceID: &traceID, - ParentID: &parentID, - TransactionID: &transactionID, + TraceID: traceID, + ParentID: parentID, + TransactionID: transactionID, HTTP: &m.HTTP{Method: &method, StatusCode: &statusCode, URL: &url}, DB: &m.DB{ Instance: &instance, diff --git a/model/modeldecoder/transaction.go b/model/modeldecoder/transaction.go index 59a7e9130ce..bbd5c296587 100644 --- a/model/modeldecoder/transaction.go +++ b/model/modeldecoder/transaction.go @@ -95,7 +95,7 @@ func decodeRUMV3Spans(raw map[string]interface{}, input Input, tr *model.Transac rawSpans := decoder.InterfaceArr(raw, fieldName("span")) var spans = make([]*model.Span, len(rawSpans)) for idx, rawSpan := range rawSpans { - span, err := decodeRUMV3Span(Input{ + span, parentIndex, err := decodeRUMV3Span(Input{ Raw: rawSpan, RequestTime: input.RequestTime, Metadata: input.Metadata, @@ -104,12 +104,12 @@ func decodeRUMV3Spans(raw map[string]interface{}, input Input, tr *model.Transac if err != nil { return spans, err } - span.TransactionID = &tr.ID - span.TraceID = &tr.TraceID - if span.ParentIdx == nil { - span.ParentID = &tr.ID - } else if *span.ParentIdx < idx { - span.ParentID = &spans[*span.ParentIdx].ID + span.TransactionID = tr.ID + span.TraceID = tr.TraceID + if parentIndex >= 0 && parentIndex < idx { + span.ParentID = spans[parentIndex].ID + } else { + span.ParentID = tr.ID } spans[idx] = span } @@ -158,12 +158,12 @@ func decodeTransaction(input Input, schema *jsonschema.Schema) (*model.Transacti SpanCount: model.SpanCount{ Dropped: decoder.IntPtr(raw, fieldName("dropped"), fieldName("span_count")), Started: decoder.IntPtr(raw, fieldName("started"), fieldName("span_count"))}, - ParentID: decoder.StringPtr(raw, fieldName("parent_id")), - TraceID: decoder.String(raw, fieldName("trace_id")), + TraceID: decoder.String(raw, fieldName("trace_id")), } if decoder.Err != nil { return nil, decoder.Err } + decodeString(raw, fieldName("parent_id"), &e.ParentID) if e.Timestamp.IsZero() { e.Timestamp = input.RequestTime } diff --git a/model/modeldecoder/transaction_test.go b/model/modeldecoder/transaction_test.go index 41525df43f5..c96b15f3709 100644 --- a/model/modeldecoder/transaction_test.go +++ b/model/modeldecoder/transaction_test.go @@ -333,7 +333,7 @@ func TestTransactionEventDecode(t *testing.T) { Type: trType, Name: &name, Result: &result, - ParentID: &parentID, + ParentID: parentID, TraceID: traceID, Duration: duration, Timestamp: timestampParsed, diff --git a/model/span.go b/model/span.go index 4fadc5a9cec..7d8d56c3cbb 100644 --- a/model/span.go +++ b/model/span.go @@ -45,11 +45,10 @@ var ( type Span struct { Metadata Metadata ID string - TransactionID *string - ParentID *string + TransactionID string + ParentID string ChildIDs []string - ParentIdx *int - TraceID *string + TraceID string Timestamp time.Time @@ -191,12 +190,12 @@ func (e *Span) Transform(ctx context.Context, tctx *transform.Context) []beat.Ev utility.DeepUpdate(fields, "agent", e.Service.AgentFields()) // merges with metadata labels, overrides conflicting keys utility.DeepUpdate(fields, "labels", e.Labels) - utility.AddId(fields, "parent", e.ParentID) + utility.AddID(fields, "parent", e.ParentID) if e.ChildIDs != nil { utility.Set(fields, "child", common.MapStr{"id": e.ChildIDs}) } - utility.AddId(fields, "trace", e.TraceID) - utility.AddId(fields, "transaction", e.TransactionID) + utility.AddID(fields, "trace", e.TraceID) + utility.AddID(fields, "transaction", e.TransactionID) utility.Set(fields, "experimental", e.Experimental) utility.Set(fields, "destination", e.Destination.fields()) utility.Set(fields, "timestamp", utility.TimeAsMicros(e.Timestamp)) diff --git a/model/span_test.go b/model/span_test.go index cdc3d9f2ce8..6950b5ddc0f 100644 --- a/model/span_test.go +++ b/model/span_test.go @@ -73,8 +73,8 @@ func TestSpanTransform(t *testing.T) { Span: Span{ Metadata: metadata, ID: hexID, - TraceID: &traceID, - ParentID: &parentID, + TraceID: traceID, + ParentID: parentID, Name: "myspan", Type: "myspantype", Subtype: &subtype, diff --git a/model/transaction.go b/model/transaction.go index 8439da677ab..4e38e8cfa08 100644 --- a/model/transaction.go +++ b/model/transaction.go @@ -44,7 +44,7 @@ type Transaction struct { Metadata Metadata ID string - ParentID *string + ParentID string TraceID string Timestamp time.Time @@ -120,8 +120,8 @@ func (e *Transaction) Transform(ctx context.Context, tctx *transform.Context) [] utility.Set(fields, "source", fields["client"]) // then merge event specific information - utility.AddId(fields, "parent", e.ParentID) - utility.AddId(fields, "trace", &e.TraceID) + utility.AddID(fields, "parent", e.ParentID) + utility.AddID(fields, "trace", e.TraceID) utility.Set(fields, "timestamp", utility.TimeAsMicros(e.Timestamp)) // merges with metadata labels, overrides conflicting keys utility.DeepUpdate(fields, "labels", e.Labels.Fields()) diff --git a/processor/otel/consumer.go b/processor/otel/consumer.go index 47e67da09fd..c234f12fd05 100644 --- a/processor/otel/consumer.go +++ b/processor/otel/consumer.go @@ -111,7 +111,7 @@ func (c *Consumer) convert(td consumerdata.TraceData) *model.Batch { transaction := model.Transaction{ Metadata: md, ID: spanID, - ParentID: &parentID, + ParentID: parentID, TraceID: traceID, Timestamp: startTime, Duration: duration, @@ -128,8 +128,8 @@ func (c *Consumer) convert(td consumerdata.TraceData) *model.Batch { span := model.Span{ Metadata: md, ID: spanID, - ParentID: &parentID, - TraceID: &traceID, + ParentID: parentID, + TraceID: traceID, Timestamp: startTime, Duration: duration, Name: name, @@ -479,9 +479,9 @@ func parseErrors(logger *logp.Logger, source string, otelSpan *tracepb.Span) []* func addTransactionCtxToErr(transaction model.Transaction, err *model.Error) { err.Metadata = transaction.Metadata - err.TransactionID = &transaction.ID - err.TraceID = &transaction.TraceID - err.ParentID = &transaction.ID + err.TransactionID = transaction.ID + err.TraceID = transaction.TraceID + err.ParentID = transaction.ID err.HTTP = transaction.HTTP err.URL = transaction.URL err.TransactionType = &transaction.Type @@ -491,7 +491,7 @@ func addSpanCtxToErr(span model.Span, hostname string, err *model.Error) { err.Metadata = span.Metadata err.TransactionID = span.TransactionID err.TraceID = span.TraceID - err.ParentID = &span.ID + err.ParentID = span.ID if span.HTTP != nil { err.HTTP = &model.Http{} if span.HTTP.StatusCode != nil { diff --git a/utility/map_str_enhancer.go b/utility/map_str_enhancer.go index 2cea3ad8e55..19983d26a0d 100644 --- a/utility/map_str_enhancer.go +++ b/utility/map_str_enhancer.go @@ -209,8 +209,8 @@ func Prune(m common.MapStr) common.MapStr { return m } -func AddId(fields common.MapStr, key string, id *string) { - if id != nil && *id != "" { - fields[key] = common.MapStr{"id": *id} +func AddID(fields common.MapStr, key, id string) { + if id != "" { + fields[key] = common.MapStr{"id": id} } } diff --git a/x-pack/apm-server/aggregation/txmetrics/aggregator.go b/x-pack/apm-server/aggregation/txmetrics/aggregator.go index a50109b9bc3..069558d9fbf 100644 --- a/x-pack/apm-server/aggregation/txmetrics/aggregator.go +++ b/x-pack/apm-server/aggregation/txmetrics/aggregator.go @@ -327,7 +327,7 @@ func makeTransactionAggregationKey(tx *model.Transaction) transactionAggregation return "" } return transactionAggregationKey{ - traceRoot: tx.ParentID == nil, + traceRoot: tx.ParentID == "", transactionName: deref(tx.Name), transactionResult: deref(tx.Result), transactionType: tx.Type,