in module/apmslog/handler.go [69:156]
func (h *ApmHandler) Handle(ctx context.Context, r slog.Record) error {
// attempt to extract any available trace info from context
var traceId apm.TraceID
var transactionId apm.SpanID
var parentId apm.SpanID
if tx := apm.TransactionFromContext(ctx); tx != nil {
traceId = tx.TraceContext().Trace
transactionId = tx.TraceContext().Span
parentId = tx.TraceContext().Span
// add trace/transaction ids to slog record to be logged
r.Add(FieldKeyTraceID, traceId)
r.Add(FieldKeyTransactionID, transactionId)
}
if span := apm.SpanFromContext(ctx); span != nil {
parentId = span.TraceContext().Span
// add span id to slog record to be logged
r.Add(FieldKeySpanID, parentId)
}
// report record as APM error
if h.tracer != nil && h.tracer.Recording() && slices.Contains(h.reportLevels, r.Level) {
// attempt to find error attributes
// slog doesnt have a standard way of attaching an
// error to a record, so attempting to grab any attribute
// that has error/err keys OR keys user has defined as reportable
// and extracting the values seems like a likely way to do it.
errorsToAttach := []error{}
r.Attrs(func(a slog.Attr) bool {
if slices.Contains(h.errorRecordAttrs, a.Key) {
var err error
// first check if value is of error type to retain as much info as possible
if v, ok := a.Value.Any().(error); ok {
errorsToAttach = append(errorsToAttach, v)
// else just convert reportable error value as string
} else {
errorsToAttach = append(errorsToAttach, errors.Join(err, fmt.Errorf("%s", a.Value.String())))
}
}
return true
})
// If there are multiple reportable error attributes, create a new
// apm.ErrorLogRecord for each. Otherwise just create one apm.ErrorLogRecord
// with no Error.
errLogRecords := []apm.ErrorLogRecord{}
if len(errorsToAttach) == 0 {
errRecord := apm.ErrorLogRecord{
Message: r.Message,
Level: strings.ToLower(r.Level.String()),
}
errLogRecords = append(errLogRecords, errRecord)
} else {
for _, err := range errorsToAttach {
errRecord := apm.ErrorLogRecord{
Message: r.Message,
Level: strings.ToLower(r.Level.String()),
Error: err,
}
errLogRecords = append(errLogRecords, errRecord)
}
}
// for each errRecord, send to apm
for _, errRecord := range errLogRecords {
errlog := h.tracer.NewErrorLog(errRecord)
errlog.Handled = true
errlog.Timestamp = r.Time.UTC()
errlog.SetStacktrace(2)
// add available trace info if not zero type
if traceId != (apm.TraceID{}) {
errlog.TraceID = traceId
}
if transactionId != (apm.SpanID{}) {
errlog.TransactionID = transactionId
}
if parentId != (apm.SpanID{}) {
errlog.ParentID = parentId
}
// send error to APM
errlog.Send()
}
}
return h.handler.Handle(ctx, r)
}