input/elasticapm/internal/modeldecoder/rumv3/decoder.go (829 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. package rumv3 import ( "fmt" "io" "net/http" "net/textproto" "strings" "time" "github.com/elastic/apm-data/input/elasticapm/internal/decoder" "github.com/elastic/apm-data/input/elasticapm/internal/modeldecoder" "github.com/elastic/apm-data/input/elasticapm/internal/modeldecoder/modeldecoderutil" "github.com/elastic/apm-data/input/elasticapm/internal/modeldecoder/nullable" "github.com/elastic/apm-data/model/modelpb" ) // DecodeNestedMetadata decodes metadata from d, updating out. func DecodeNestedMetadata(d decoder.Decoder, out *modelpb.APMEvent) error { root := &metadataRoot{} if err := d.Decode(root); err != nil && err != io.EOF { return modeldecoder.NewDecoderErrFromJSONIter(err) } if err := root.validate(); err != nil { return modeldecoder.NewValidationErr(err) } mapToMetadataModel(&root.Metadata, out) return nil } // DecodeNestedError decodes an error from d, appending it to batch. // // DecodeNestedError should be used when the stream in the decoder contains the `error` key func DecodeNestedError(d decoder.Decoder, input *modeldecoder.Input, batch *modelpb.Batch) error { root := &errorRoot{} if err := d.Decode(root); err != nil && err != io.EOF { return modeldecoder.NewDecoderErrFromJSONIter(err) } if err := root.validate(); err != nil { return modeldecoder.NewValidationErr(err) } event := input.Base.CloneVT() mapToErrorModel(&root.Error, event) *batch = append(*batch, event) return nil } // DecodeNestedTransaction a transaction and zero or more nested spans and // metricsets, appending them to batch. // // DecodeNestedTransaction should be used when the decoder contains the `transaction` key func DecodeNestedTransaction(d decoder.Decoder, input *modeldecoder.Input, batch *modelpb.Batch) error { root := &transactionRoot{} if err := d.Decode(root); err != nil && err != io.EOF { return modeldecoder.NewDecoderErrFromJSONIter(err) } if err := root.validate(); err != nil { return modeldecoder.NewValidationErr(err) } transaction := input.Base.CloneVT() mapToTransactionModel(&root.Transaction, transaction) *batch = append(*batch, transaction) for _, m := range root.Transaction.Metricsets { event := input.Base.CloneVT() event.Transaction = &modelpb.Transaction{} event.Transaction.Name = transaction.Transaction.Name event.Transaction.Type = transaction.Transaction.Type if mapToTransactionMetricsetModel(&m, event) { *batch = append(*batch, event) } } offset := len(*batch) for _, s := range root.Transaction.Spans { event := input.Base.CloneVT() mapToSpanModel(&s, event) event.Transaction = &modelpb.Transaction{} event.Transaction.Id = transaction.Transaction.Id event.ParentId = transaction.GetTransaction().GetId() // may be overridden later event.Trace = transaction.Trace.CloneVT() *batch = append(*batch, event) } spans := (*batch)[offset:] for i, s := range root.Transaction.Spans { if s.ParentIndex.IsSet() && s.ParentIndex.Val >= 0 && s.ParentIndex.Val < len(spans) { if e := spans[s.ParentIndex.Val]; e != nil { spans[i].ParentId = e.Span.Id } } } return nil } func mapToErrorModel(from *errorEvent, event *modelpb.APMEvent) { out := modelpb.Error{} event.Error = &out // overwrite metadata with event specific information if from.Context.Service.IsSet() { if event.Service == nil { event.Service = &modelpb.Service{} } mapToServiceModel(from.Context.Service, event.Service) } if from.Context.Service.Agent.IsSet() { if event.Agent == nil { event.Agent = &modelpb.Agent{} } mapToAgentModel(from.Context.Service.Agent, event.Agent) } overwriteUserInMetadataModel(from.Context.User, event) if from.Context.Request.Headers.IsSet() { if event.UserAgent == nil { event.UserAgent = &modelpb.UserAgent{} } mapToUserAgentModel(from.Context.Request.Headers, event.UserAgent) } // map errorEvent specific data if from.Context.IsSet() { if len(from.Context.Tags) > 0 { modeldecoderutil.MergeLabels(from.Context.Tags, event) } if from.Context.Request.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } event.Http.Request = &modelpb.HTTPRequest{} mapToRequestModel(from.Context.Request, event.Http.Request) if from.Context.Request.HTTPVersion.IsSet() { event.Http.Version = from.Context.Request.HTTPVersion.Val } } if from.Context.Response.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } event.Http.Response = &modelpb.HTTPResponse{} mapToResponseModel(from.Context.Response, event.Http.Response) } if from.Context.Page.IsSet() { if from.Context.Page.URL.IsSet() { event.Url = modelpb.ParseURL(from.Context.Page.URL.Val, "", "") } if from.Context.Page.Referer.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } if event.Http.Request == nil { event.Http.Request = &modelpb.HTTPRequest{} } event.Http.Request.Referrer = from.Context.Page.Referer.Val } } if len(from.Context.Custom) > 0 { out.Custom = modeldecoderutil.ToKv(from.Context.Custom, out.Custom) } } if from.Culprit.IsSet() { out.Culprit = from.Culprit.Val } if from.Exception.IsSet() { out.Exception = &modelpb.Exception{} mapToExceptionModel(&from.Exception, out.Exception) } if from.ID.IsSet() { out.Id = from.ID.Val } if from.Log.IsSet() { log := modelpb.ErrorLog{Level: "error"} if from.Log.Level.IsSet() { log.Level = from.Log.Level.Val } loggerName := "default" if from.Log.LoggerName.IsSet() { loggerName = from.Log.LoggerName.Val } log.LoggerName = loggerName if from.Log.Message.IsSet() { log.Message = from.Log.Message.Val } if from.Log.ParamMessage.IsSet() { log.ParamMessage = from.Log.ParamMessage.Val } if len(from.Log.Stacktrace) > 0 { log.Stacktrace = modeldecoderutil.ResliceAndPopulateNil( log.Stacktrace, len(from.Log.Stacktrace), modeldecoderutil.NewType[modelpb.StacktraceFrame], ) mapToStacktraceModel(from.Log.Stacktrace, log.Stacktrace) } out.Log = &log } if from.ParentID.IsSet() { event.ParentId = from.ParentID.Val } if !from.Timestamp.Val.IsZero() { event.Timestamp = modelpb.FromTime(from.Timestamp.Val) } if from.TraceID.IsSet() { event.Trace = &modelpb.Trace{} event.Trace.Id = from.TraceID.Val } if from.Transaction.IsSet() { event.Transaction = &modelpb.Transaction{} if from.Transaction.Sampled.IsSet() { event.Transaction.Sampled = from.Transaction.Sampled.Val } if from.Transaction.Name.IsSet() { event.Transaction.Name = from.Transaction.Name.Val } if from.Transaction.Type.IsSet() { event.Transaction.Type = from.Transaction.Type.Val } if from.TransactionID.IsSet() { event.Transaction.Id = from.TransactionID.Val } } } func mapToExceptionModel(from *errorException, out *modelpb.Exception) { if len(from.Attributes) > 0 { out.Attributes = modeldecoderutil.ToKv(from.Attributes, out.Attributes) } if from.Code.IsSet() { out.Code = modeldecoderutil.ExceptionCodeString(from.Code.Val) } if len(from.Cause) > 0 { out.Cause = modeldecoderutil.ResliceAndPopulateNil( out.Cause, len(from.Cause), modeldecoderutil.NewType[modelpb.Exception], ) for i := 0; i < len(from.Cause); i++ { mapToExceptionModel(&from.Cause[i], out.Cause[i]) } } if from.Handled.IsSet() { handled := from.Handled.Val out.Handled = &handled } if from.Message.IsSet() { out.Message = from.Message.Val } if from.Module.IsSet() { out.Module = from.Module.Val } if len(from.Stacktrace) > 0 { out.Stacktrace = modeldecoderutil.ResliceAndPopulateNil( out.Stacktrace, len(from.Stacktrace), modeldecoderutil.NewType[modelpb.StacktraceFrame], ) mapToStacktraceModel(from.Stacktrace, out.Stacktrace) } if from.Type.IsSet() { out.Type = from.Type.Val } } func mapToMetadataModel(m *metadata, out *modelpb.APMEvent) { // Labels if len(m.Labels) > 0 { modeldecoderutil.GlobalLabelsFrom(m.Labels, out) } // Service if m.Service.Agent.IsSet() { if out.Agent == nil { out.Agent = &modelpb.Agent{} } if m.Service.Agent.Name.IsSet() { out.Agent.Name = m.Service.Agent.Name.Val } if m.Service.Agent.Version.IsSet() { out.Agent.Version = m.Service.Agent.Version.Val } } if m.Service.IsSet() { if out.Service == nil { out.Service = &modelpb.Service{} } if m.Service.Environment.IsSet() { out.Service.Environment = m.Service.Environment.Val } if m.Service.Framework.IsSet() { if out.Service.Framework == nil { out.Service.Framework = &modelpb.Framework{} } if m.Service.Framework.Name.IsSet() { out.Service.Framework.Name = m.Service.Framework.Name.Val } if m.Service.Framework.Version.IsSet() { out.Service.Framework.Version = m.Service.Framework.Version.Val } } if m.Service.Language.IsSet() { if out.Service.Language == nil { out.Service.Language = &modelpb.Language{} } if m.Service.Language.Name.IsSet() { out.Service.Language.Name = m.Service.Language.Name.Val } if m.Service.Language.Version.IsSet() { out.Service.Language.Version = m.Service.Language.Version.Val } } if m.Service.Name.IsSet() { out.Service.Name = m.Service.Name.Val } if m.Service.Runtime.IsSet() { if out.Service.Runtime == nil { out.Service.Runtime = &modelpb.Runtime{} } if m.Service.Runtime.Name.IsSet() { out.Service.Runtime.Name = m.Service.Runtime.Name.Val } if m.Service.Runtime.Version.IsSet() { out.Service.Runtime.Version = m.Service.Runtime.Version.Val } } if m.Service.Version.IsSet() { out.Service.Version = m.Service.Version.Val } } // User if m.User.IsSet() { if out.User == nil { out.User = &modelpb.User{} } if m.User.Domain.IsSet() { out.User.Domain = m.User.Domain.Val } if m.User.ID.IsSet() { out.User.Id = fmt.Sprint(m.User.ID.Val) } if m.User.Email.IsSet() { out.User.Email = m.User.Email.Val } if m.User.Name.IsSet() { out.User.Name = m.User.Name.Val } } // Network if m.Network.Connection.Type.IsSet() { if out.Network == nil { out.Network = &modelpb.Network{} } if out.Network.Connection == nil { out.Network.Connection = &modelpb.NetworkConnection{} } out.Network.Connection.Type = m.Network.Connection.Type.Val } } func mapToTransactionMetricsetModel(from *transactionMetricset, event *modelpb.APMEvent) bool { event.Metricset = &modelpb.Metricset{} if from.Span.IsSet() { event.Span = &modelpb.Span{} if from.Span.Subtype.IsSet() { event.Span.Subtype = from.Span.Subtype.Val } if from.Span.Type.IsSet() { event.Span.Type = from.Span.Type.Val } } var ok bool if from.Samples.IsSet() { if event.Span != nil { if value := from.Samples.SpanSelfTimeCount.Value; value.IsSet() { if event.Span.SelfTime == nil { event.Span.SelfTime = &modelpb.AggregatedDuration{} } event.Span.SelfTime.Count = uint64(value.Val) ok = true } if value := from.Samples.SpanSelfTimeSum.Value; value.IsSet() { if event.Span.SelfTime == nil { event.Span.SelfTime = &modelpb.AggregatedDuration{} } event.Span.SelfTime.Sum = uint64(value.Val * 1000) ok = true } } } return ok } func mapToResponseModel(from contextResponse, out *modelpb.HTTPResponse) { if from.Headers.IsSet() { out.Headers = modeldecoderutil.HTTPHeadersToModelpb(from.Headers.Val, out.Headers) } if from.StatusCode.IsSet() { out.StatusCode = uint32(from.StatusCode.Val) } if from.TransferSize.IsSet() { val := uint64(from.TransferSize.Val) out.TransferSize = &val } if from.EncodedBodySize.IsSet() { val := uint64(from.EncodedBodySize.Val) out.EncodedBodySize = &val } if from.DecodedBodySize.IsSet() { val := uint64(from.DecodedBodySize.Val) out.DecodedBodySize = &val } } func mapToRequestModel(from contextRequest, out *modelpb.HTTPRequest) { if from.Method.IsSet() { out.Method = from.Method.Val } if len(from.Env) > 0 { out.Env = modeldecoderutil.ToKv(from.Env, out.Env) } if from.Headers.IsSet() { out.Headers = modeldecoderutil.HTTPHeadersToModelpb(from.Headers.Val, out.Headers) } } func mapToServiceModel(from contextService, out *modelpb.Service) { if from.Environment.IsSet() { out.Environment = from.Environment.Val } if from.Framework.IsSet() { if out.Framework == nil { out.Framework = &modelpb.Framework{} } if from.Framework.Name.IsSet() { out.Framework.Name = from.Framework.Name.Val } if from.Framework.Version.IsSet() { out.Framework.Version = from.Framework.Version.Val } } if from.Language.IsSet() { if out.Language == nil { out.Language = &modelpb.Language{} } if from.Language.Name.IsSet() { out.Language.Name = from.Language.Name.Val } if from.Language.Version.IsSet() { out.Language.Version = from.Language.Version.Val } } if from.Name.IsSet() { out.Name = from.Name.Val out.Version = from.Version.Val } if from.Runtime.IsSet() { if out.Runtime == nil { out.Runtime = &modelpb.Runtime{} } if from.Runtime.Name.IsSet() { out.Runtime.Name = from.Runtime.Name.Val } if from.Runtime.Version.IsSet() { out.Runtime.Version = from.Runtime.Version.Val } } } func mapToAgentModel(from contextServiceAgent, out *modelpb.Agent) { if from.Name.IsSet() { out.Name = from.Name.Val } if from.Version.IsSet() { out.Version = from.Version.Val } } func mapToSpanModel(from *span, event *modelpb.APMEvent) { out := modelpb.Span{} out.Type = "unknown" event.Span = &out // map span specific data if !from.Action.IsSet() && !from.Subtype.IsSet() { sep := "." before, after, ok := strings.Cut(from.Type.Val, sep) if before != "" { out.Type = before } if ok { out.Subtype, out.Action, _ = strings.Cut(after, sep) } } else { if from.Action.IsSet() { out.Action = from.Action.Val } if from.Subtype.IsSet() { out.Subtype = from.Subtype.Val } if from.Type.IsSet() { out.Type = from.Type.Val } } if from.Context.Destination.Address.IsSet() || from.Context.Destination.Port.IsSet() { if from.Context.Destination.Address.IsSet() { if event.Destination == nil { event.Destination = &modelpb.Destination{} } event.Destination.Address = from.Context.Destination.Address.Val } if from.Context.Destination.Port.IsSet() { if event.Destination == nil { event.Destination = &modelpb.Destination{} } event.Destination.Port = uint32(from.Context.Destination.Port.Val) } } if from.Context.Destination.Service.IsSet() { service := modelpb.DestinationService{} if from.Context.Destination.Service.Name.IsSet() { service.Name = from.Context.Destination.Service.Name.Val } if from.Context.Destination.Service.Resource.IsSet() { service.Resource = from.Context.Destination.Service.Resource.Val } if from.Context.Destination.Service.Type.IsSet() { service.Type = from.Context.Destination.Service.Type.Val } out.DestinationService = &service } if from.Context.HTTP.IsSet() { var response *modelpb.HTTPResponse if from.Context.HTTP.Method.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } event.Http.Request = &modelpb.HTTPRequest{} event.Http.Request.Method = from.Context.HTTP.Method.Val } if from.Context.HTTP.StatusCode.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } if response == nil { response = &modelpb.HTTPResponse{} } event.Http.Response = response event.Http.Response.StatusCode = uint32(from.Context.HTTP.StatusCode.Val) } if from.Context.HTTP.URL.IsSet() { if event.Url == nil { event.Url = &modelpb.URL{} } event.Url.Original = from.Context.HTTP.URL.Val } if from.Context.HTTP.Response.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } if response == nil { response = &modelpb.HTTPResponse{} } event.Http.Response = response if from.Context.HTTP.Response.DecodedBodySize.IsSet() { val := uint64(from.Context.HTTP.Response.DecodedBodySize.Val) event.Http.Response.DecodedBodySize = &val } if from.Context.HTTP.Response.EncodedBodySize.IsSet() { val := uint64(from.Context.HTTP.Response.EncodedBodySize.Val) event.Http.Response.EncodedBodySize = &val } if from.Context.HTTP.Response.TransferSize.IsSet() { val := uint64(from.Context.HTTP.Response.TransferSize.Val) event.Http.Response.TransferSize = &val } } } if from.Context.Service.IsSet() { if from.Context.Service.Name.IsSet() { if event.Service == nil { event.Service = &modelpb.Service{} } event.Service.Name = from.Context.Service.Name.Val } } if len(from.Context.Tags) > 0 { modeldecoderutil.MergeLabels(from.Context.Tags, event) } if from.Duration.IsSet() { if event.Event == nil { event.Event = &modelpb.Event{} } event.Event.Duration = uint64(from.Duration.Val * float64(time.Millisecond)) } if from.ID.IsSet() { out.Id = from.ID.Val } if from.Name.IsSet() { out.Name = from.Name.Val } if event.Event == nil { event.Event = &modelpb.Event{} } if from.Outcome.IsSet() { event.Event.Outcome = from.Outcome.Val } else { if from.Context.HTTP.StatusCode.IsSet() { statusCode := from.Context.HTTP.StatusCode.Val if statusCode >= http.StatusBadRequest { event.Event.Outcome = "failure" } else { event.Event.Outcome = "success" } } else { event.Event.Outcome = "unknown" } } if from.SampleRate.IsSet() && from.SampleRate.Val > 0 { out.RepresentativeCount = 1 / from.SampleRate.Val } if len(from.Stacktrace) > 0 { out.Stacktrace = modeldecoderutil.ResliceAndPopulateNil( out.Stacktrace, len(from.Stacktrace), modeldecoderutil.NewType[modelpb.StacktraceFrame], ) mapToStacktraceModel(from.Stacktrace, out.Stacktrace) } if from.Sync.IsSet() { val := from.Sync.Val out.Sync = &val } if from.Start.IsSet() { // event.Timestamp is initialized to the time the payload was // received; offset that by "start" milliseconds for RUM. event.Timestamp += uint64(time.Duration(float64(time.Millisecond) * from.Start.Val).Nanoseconds()) } } func mapToStacktraceModel(from []stacktraceFrame, out []*modelpb.StacktraceFrame) { for idx, eventFrame := range from { fr := out[idx] if eventFrame.AbsPath.IsSet() { fr.AbsPath = eventFrame.AbsPath.Val } if eventFrame.Classname.IsSet() { fr.Classname = eventFrame.Classname.Val } if eventFrame.ColumnNumber.IsSet() { val := uint32(eventFrame.ColumnNumber.Val) fr.Colno = &val } if eventFrame.ContextLine.IsSet() { fr.ContextLine = eventFrame.ContextLine.Val } if eventFrame.Filename.IsSet() { fr.Filename = eventFrame.Filename.Val } if eventFrame.Function.IsSet() { fr.Function = eventFrame.Function.Val } if eventFrame.LineNumber.IsSet() { val := uint32(eventFrame.LineNumber.Val) fr.Lineno = &val } if eventFrame.Module.IsSet() { fr.Module = eventFrame.Module.Val } if len(eventFrame.PostContext) > 0 { fr.PostContext = modeldecoderutil.Reslice(fr.PostContext, len(eventFrame.PostContext)) copy(fr.PostContext, eventFrame.PostContext) } if len(eventFrame.PreContext) > 0 { fr.PreContext = modeldecoderutil.Reslice(fr.PreContext, len(eventFrame.PreContext)) copy(fr.PreContext, eventFrame.PreContext) } } } func mapToTransactionModel(from *transaction, event *modelpb.APMEvent) { out := modelpb.Transaction{} out.Type = "unknown" event.Transaction = &out // overwrite metadata with event specific information if from.Context.Service.IsSet() { if event.Service == nil { event.Service = &modelpb.Service{} } mapToServiceModel(from.Context.Service, event.Service) } if from.Context.Service.Agent.IsSet() { if event.Agent == nil { event.Agent = &modelpb.Agent{} } mapToAgentModel(from.Context.Service.Agent, event.Agent) } overwriteUserInMetadataModel(from.Context.User, event) if from.Context.Request.Headers.IsSet() { if event.UserAgent == nil { event.UserAgent = &modelpb.UserAgent{} } mapToUserAgentModel(from.Context.Request.Headers, event.UserAgent) } // map transaction specific data if from.Context.IsSet() { if len(from.Context.Custom) > 0 { out.Custom = modeldecoderutil.ToKv(from.Context.Custom, out.Custom) } if len(from.Context.Tags) > 0 { modeldecoderutil.MergeLabels(from.Context.Tags, event) } if from.Context.Request.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } event.Http.Request = &modelpb.HTTPRequest{} mapToRequestModel(from.Context.Request, event.Http.Request) if from.Context.Request.HTTPVersion.IsSet() { event.Http.Version = from.Context.Request.HTTPVersion.Val } } if from.Context.Response.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } event.Http.Response = &modelpb.HTTPResponse{} mapToResponseModel(from.Context.Response, event.Http.Response) } if from.Context.Page.IsSet() { if from.Context.Page.URL.IsSet() { event.Url = modelpb.ParseURL(from.Context.Page.URL.Val, "", "") } if from.Context.Page.Referer.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } if event.Http.Request == nil { event.Http.Request = &modelpb.HTTPRequest{} } event.Http.Request.Referrer = from.Context.Page.Referer.Val } } } if from.Duration.IsSet() { if event.Event == nil { event.Event = &modelpb.Event{} } event.Event.Duration = uint64(from.Duration.Val * float64(time.Millisecond)) } if from.ID.IsSet() { out.Id = from.ID.Val } if from.Marks.IsSet() { out.Marks = make(map[string]*modelpb.TransactionMark, len(from.Marks.Events)) for event, val := range from.Marks.Events { if len(val.Measurements) > 0 { tm := modelpb.TransactionMark{} tm.Measurements = val.Measurements out.Marks[event] = &tm } } } if from.Name.IsSet() { out.Name = from.Name.Val } if event.Event == nil { event.Event = &modelpb.Event{} } if from.Outcome.IsSet() { event.Event.Outcome = from.Outcome.Val } else { if from.Context.Response.StatusCode.IsSet() { statusCode := from.Context.Response.StatusCode.Val if statusCode >= http.StatusInternalServerError { event.Event.Outcome = "failure" } else { event.Event.Outcome = "success" } } else { event.Event.Outcome = "unknown" } } if from.ParentID.IsSet() { event.ParentId = from.ParentID.Val } if from.Result.IsSet() { out.Result = from.Result.Val } sampled := true if from.Sampled.IsSet() { sampled = from.Sampled.Val } out.Sampled = sampled if from.SampleRate.IsSet() { if from.SampleRate.Val > 0 { out.RepresentativeCount = 1 / from.SampleRate.Val } } else { out.RepresentativeCount = 1 } if from.Session.ID.IsSet() { event.Session = &modelpb.Session{} event.Session.Id = from.Session.ID.Val event.Session.Sequence = uint64(from.Session.Sequence.Val) } if from.SpanCount.Dropped.IsSet() { if out.SpanCount == nil { out.SpanCount = &modelpb.SpanCount{} } dropped := uint32(from.SpanCount.Dropped.Val) out.SpanCount.Dropped = &dropped } if from.SpanCount.Started.IsSet() { if out.SpanCount == nil { out.SpanCount = &modelpb.SpanCount{} } started := uint32(from.SpanCount.Started.Val) out.SpanCount.Started = &started } if from.TraceID.IsSet() { event.Trace = &modelpb.Trace{} event.Trace.Id = from.TraceID.Val } if from.Type.IsSet() { out.Type = from.Type.Val } if from.UserExperience.IsSet() { out.UserExperience = &modelpb.UserExperience{} out.UserExperience.CumulativeLayoutShift = -1 out.UserExperience.FirstInputDelay = -1 out.UserExperience.TotalBlockingTime = -1 out.UserExperience.LongTask = nil if from.UserExperience.CumulativeLayoutShift.IsSet() { out.UserExperience.CumulativeLayoutShift = from.UserExperience.CumulativeLayoutShift.Val } if from.UserExperience.FirstInputDelay.IsSet() { out.UserExperience.FirstInputDelay = from.UserExperience.FirstInputDelay.Val } if from.UserExperience.TotalBlockingTime.IsSet() { out.UserExperience.TotalBlockingTime = from.UserExperience.TotalBlockingTime.Val } if from.UserExperience.Longtask.IsSet() { out.UserExperience.LongTask = &modelpb.LongtaskMetrics{} out.UserExperience.LongTask.Count = uint64(from.UserExperience.Longtask.Count.Val) out.UserExperience.LongTask.Sum = from.UserExperience.Longtask.Sum.Val out.UserExperience.LongTask.Max = from.UserExperience.Longtask.Max.Val } } } func mapToUserAgentModel(from nullable.HTTPHeader, out *modelpb.UserAgent) { // overwrite userAgent information if available if h := from.Val.Values(textproto.CanonicalMIMEHeaderKey("User-Agent")); len(h) > 0 { out.Original = strings.Join(h, ", ") } } func overwriteUserInMetadataModel(from user, out *modelpb.APMEvent) { // overwrite User specific values if set // either populate all User fields or none to avoid mixing // different user data if !from.Domain.IsSet() && !from.ID.IsSet() && !from.Email.IsSet() && !from.Name.IsSet() { return } out.User = &modelpb.User{} if from.Domain.IsSet() { out.User.Domain = from.Domain.Val } if from.ID.IsSet() { out.User.Id = fmt.Sprint(from.ID.Val) } if from.Email.IsSet() { out.User.Email = from.Email.Val } if from.Name.IsSet() { out.User.Name = from.Name.Val } }