go.mod: update sentry

Update sentry dep and code that was required.
This commit is contained in:
Lukas Zapletal 2025-07-08 15:35:59 +02:00 committed by Tomáš Hozza
parent d7686244cd
commit 15ec2fc431
46 changed files with 2472 additions and 1832 deletions

View file

@ -8,6 +8,7 @@ import (
"fmt"
"net/http"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -18,25 +19,42 @@ const (
SentryBaggageHeader = "baggage"
)
// SpanOrigin indicates what created a trace or a span. See: https://develop.sentry.dev/sdk/performance/trace-origin/
type SpanOrigin string
const (
SpanOriginManual = "manual"
SpanOriginEcho = "auto.http.echo"
SpanOriginFastHTTP = "auto.http.fasthttp"
SpanOriginFiber = "auto.http.fiber"
SpanOriginGin = "auto.http.gin"
SpanOriginStdLib = "auto.http.stdlib"
SpanOriginIris = "auto.http.iris"
SpanOriginNegroni = "auto.http.negroni"
)
// A Span is the building block of a Sentry transaction. Spans build up a tree
// structure of timed operations. The span tree makes up a transaction event
// that is sent to Sentry when the root span is finished.
//
// Spans must be started with either StartSpan or Span.StartChild.
type Span struct { //nolint: maligned // prefer readability over optimal memory layout (see note below *)
TraceID TraceID `json:"trace_id"`
SpanID SpanID `json:"span_id"`
ParentSpanID SpanID `json:"parent_span_id"`
Name string `json:"name,omitempty"`
Op string `json:"op,omitempty"`
Description string `json:"description,omitempty"`
Status SpanStatus `json:"status,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
StartTime time.Time `json:"start_timestamp"`
EndTime time.Time `json:"timestamp"`
Data map[string]interface{} `json:"data,omitempty"`
Sampled Sampled `json:"-"`
Source TransactionSource `json:"-"`
TraceID TraceID `json:"trace_id"`
SpanID SpanID `json:"span_id"`
ParentSpanID SpanID `json:"parent_span_id"`
Name string `json:"name,omitempty"`
Op string `json:"op,omitempty"`
Description string `json:"description,omitempty"`
Status SpanStatus `json:"status,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
StartTime time.Time `json:"start_timestamp"`
EndTime time.Time `json:"timestamp"`
// Deprecated: use Data instead. To be removed in 0.33.0
Extra map[string]interface{} `json:"-"`
Data map[string]interface{} `json:"data,omitempty"`
Sampled Sampled `json:"-"`
Source TransactionSource `json:"-"`
Origin SpanOrigin `json:"origin,omitempty"`
// mu protects concurrent writes to map fields
mu sync.RWMutex
@ -53,10 +71,10 @@ type Span struct { //nolint: maligned // prefer readability over optimal memory
recorder *spanRecorder
// span context, can only be set on transactions
contexts map[string]Context
// collectProfile is a function that collects a profile of the current transaction. May be nil.
collectProfile transactionProfiler
// a Once instance to make sure that Finish() is only called once.
finishOnce sync.Once
// explicitSampled is a flag for configuring sampling by using `WithSpanSampled` option.
explicitSampled Sampled
}
// TraceParentContext describes the context of a (remote) parent span.
@ -113,11 +131,19 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp
parent: parent,
}
_, err := rand.Read(span.SpanID[:])
if err != nil {
panic(err)
}
if hasParent {
span.TraceID = parent.TraceID
span.ParentSpanID = parent.SpanID
span.Origin = parent.Origin
} else {
// Only set the Source if this is a transaction
span.Source = SourceCustom
span.Origin = SpanOriginManual
// Implementation note:
//
@ -154,13 +180,6 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp
panic(err)
}
}
_, err := rand.Read(span.SpanID[:])
if err != nil {
panic(err)
}
if hasParent {
span.ParentSpanID = parent.SpanID
}
// Apply options to override defaults.
for _, option := range options {
@ -176,15 +195,10 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp
span.recorder.record(&span)
hub := hubFromContext(ctx)
// Update scope so that all events include a trace context, allowing
// Sentry to correlate errors to transactions/spans.
hub.Scope().SetContext("trace", span.traceContext().Map())
// Start profiling only if it's a sampled root transaction.
if span.IsTransaction() && span.Sampled.Bool() {
span.sampleTransactionProfile()
clientOptions := span.clientOptions()
if clientOptions.EnableTracing {
hub := hubFromContext(ctx)
hub.Scope().SetSpan(&span)
}
return &span
@ -287,7 +301,7 @@ func (s *Span) GetTransaction() *Span {
// func (s *Span) TransactionName() string
// func (s *Span) SetTransactionName(name string)
// ToSentryTrace returns the seralized TraceParentContext from a transaction/span.
// ToSentryTrace returns the serialized TraceParentContext from a transaction/span.
// Use this function to propagate the TraceParentContext to a downstream SDK,
// either as the value of the "sentry-trace" HTTP header, or as an html "sentry-trace" meta tag.
func (s *Span) ToSentryTrace() string {
@ -308,17 +322,21 @@ func (s *Span) ToSentryTrace() string {
// Use this function to propagate the DynamicSamplingContext to a downstream SDK,
// either as the value of the "baggage" HTTP header, or as an html "baggage" meta tag.
func (s *Span) ToBaggage() string {
if containingTransaction := s.GetTransaction(); containingTransaction != nil {
// In case there is currently no frozen DynamicSamplingContext attached to the transaction,
// create one from the properties of the transaction.
if !s.dynamicSamplingContext.IsFrozen() {
// This will return a frozen DynamicSamplingContext.
s.dynamicSamplingContext = DynamicSamplingContextFromTransaction(containingTransaction)
}
return containingTransaction.dynamicSamplingContext.String()
t := s.GetTransaction()
if t == nil {
return ""
}
return ""
// In case there is currently no frozen DynamicSamplingContext attached to the transaction,
// create one from the properties of the transaction.
if !s.dynamicSamplingContext.IsFrozen() {
// This will return a frozen DynamicSamplingContext.
if dsc := DynamicSamplingContextFromTransaction(t); dsc.HasEntries() {
t.dynamicSamplingContext = dsc
}
}
return t.dynamicSamplingContext.String()
}
// SetDynamicSamplingContext sets the given dynamic sampling context on the
@ -335,6 +353,13 @@ func (s *Span) doFinish() {
s.EndTime = monotonicTimeSince(s.StartTime)
}
hub := hubFromContext(s.ctx)
if !s.IsTransaction() {
if s.parent != nil {
hub.Scope().SetSpan(s.parent)
}
}
if !s.Sampled.Bool() {
return
}
@ -343,14 +368,9 @@ func (s *Span) doFinish() {
return
}
if s.collectProfile != nil {
event.sdkMetaData.transactionProfile = s.collectProfile(s)
}
// TODO(tracing): add breadcrumbs
// (see https://github.com/getsentry/sentry-python/blob/f6f3525f8812f609/sentry_sdk/tracing.py#L372)
hub := hubFromContext(s.ctx)
hub.CaptureEvent(event)
}
@ -429,21 +449,21 @@ func (s *Span) sample() Sampled {
// https://develop.sentry.dev/sdk/performance/#sampling
// #1 tracing is not enabled.
if !clientOptions.EnableTracing {
Logger.Printf("Dropping transaction: EnableTracing is set to %t", clientOptions.EnableTracing)
DebugLogger.Printf("Dropping transaction: EnableTracing is set to %t", clientOptions.EnableTracing)
s.sampleRate = 0.0
return SampledFalse
}
// #2 explicit sampling decision via StartSpan/StartTransaction options.
if s.Sampled != SampledUndefined {
Logger.Printf("Using explicit sampling decision from StartSpan/StartTransaction: %v", s.Sampled)
switch s.Sampled {
if s.explicitSampled != SampledUndefined {
DebugLogger.Printf("Using explicit sampling decision from StartSpan/StartTransaction: %v", s.explicitSampled)
switch s.explicitSampled {
case SampledTrue:
s.sampleRate = 1.0
case SampledFalse:
s.sampleRate = 0.0
}
return s.Sampled
return s.explicitSampled
}
// Variant for non-transaction spans: they inherit the parent decision.
@ -464,42 +484,52 @@ func (s *Span) sample() Sampled {
if sampler != nil {
tracesSamplerSampleRate := sampler.Sample(samplingContext)
s.sampleRate = tracesSamplerSampleRate
// tracesSampler can update the sample_rate on frozen DSC
if s.dynamicSamplingContext.HasEntries() {
s.dynamicSamplingContext.Entries["sample_rate"] = strconv.FormatFloat(tracesSamplerSampleRate, 'f', -1, 64)
}
if tracesSamplerSampleRate < 0.0 || tracesSamplerSampleRate > 1.0 {
Logger.Printf("Dropping transaction: Returned TracesSampler rate is out of range [0.0, 1.0]: %f", tracesSamplerSampleRate)
DebugLogger.Printf("Dropping transaction: Returned TracesSampler rate is out of range [0.0, 1.0]: %f", tracesSamplerSampleRate)
return SampledFalse
}
if tracesSamplerSampleRate == 0 {
Logger.Printf("Dropping transaction: Returned TracesSampler rate is: %f", tracesSamplerSampleRate)
if tracesSamplerSampleRate == 0.0 {
DebugLogger.Printf("Dropping transaction: Returned TracesSampler rate is: %f", tracesSamplerSampleRate)
return SampledFalse
}
if rng.Float64() < tracesSamplerSampleRate {
return SampledTrue
}
Logger.Printf("Dropping transaction: TracesSampler returned rate: %f", tracesSamplerSampleRate)
DebugLogger.Printf("Dropping transaction: TracesSampler returned rate: %f", tracesSamplerSampleRate)
return SampledFalse
}
// #4 inherit parent decision.
if s.parent != nil {
Logger.Printf("Using sampling decision from parent: %v", s.parent.Sampled)
switch s.parent.Sampled {
if s.Sampled != SampledUndefined {
DebugLogger.Printf("Using sampling decision from parent: %v", s.Sampled)
switch s.Sampled {
case SampledTrue:
s.sampleRate = 1.0
case SampledFalse:
s.sampleRate = 0.0
}
return s.parent.Sampled
return s.Sampled
}
// #5 use TracesSampleRate from ClientOptions.
sampleRate := clientOptions.TracesSampleRate
s.sampleRate = sampleRate
// tracesSampleRate can update the sample_rate on frozen DSC
if s.dynamicSamplingContext.HasEntries() {
s.dynamicSamplingContext.Entries["sample_rate"] = strconv.FormatFloat(sampleRate, 'f', -1, 64)
}
if sampleRate < 0.0 || sampleRate > 1.0 {
Logger.Printf("Dropping transaction: TracesSamplerRate out of range [0.0, 1.0]: %f", sampleRate)
DebugLogger.Printf("Dropping transaction: TracesSampleRate out of range [0.0, 1.0]: %f", sampleRate)
return SampledFalse
}
if sampleRate == 0.0 {
Logger.Printf("Dropping transaction: TracesSampleRate rate is: %f", sampleRate)
DebugLogger.Printf("Dropping transaction: TracesSampleRate rate is: %f", sampleRate)
return SampledFalse
}
@ -522,7 +552,7 @@ func (s *Span) toEvent() *Event {
finished := make([]*Span, 0, len(children))
for _, child := range children {
if child.EndTime.IsZero() {
Logger.Printf("Dropped unfinished span: Op=%q TraceID=%s SpanID=%s", child.Op, child.TraceID, child.SpanID)
DebugLogger.Printf("Dropped unfinished span: Op=%q TraceID=%s SpanID=%s", child.Op, child.TraceID, child.SpanID)
continue
}
finished = append(finished, child)
@ -534,7 +564,7 @@ func (s *Span) toEvent() *Event {
s.dynamicSamplingContext = DynamicSamplingContextFromTransaction(s)
}
contexts := map[string]Context{}
contexts := make(map[string]Context, len(s.contexts)+1)
for k, v := range s.contexts {
contexts[k] = cloneContext(v)
}
@ -551,7 +581,6 @@ func (s *Span) toEvent() *Event {
Transaction: s.Name,
Contexts: contexts,
Tags: s.Tags,
Extra: s.Data,
Timestamp: s.EndTime,
StartTime: s.StartTime,
Spans: finished,
@ -570,6 +599,7 @@ func (s *Span) traceContext() *TraceContext {
SpanID: s.SpanID,
ParentSpanID: s.ParentSpanID,
Op: s.Op,
Data: s.Data,
Description: s.Description,
Status: s.Status,
}
@ -706,31 +736,32 @@ const (
maxSpanStatus
)
var spanStatuses = [maxSpanStatus]string{
"",
"ok",
"cancelled", // [sic]
"unknown",
"invalid_argument",
"deadline_exceeded",
"not_found",
"already_exists",
"permission_denied",
"resource_exhausted",
"failed_precondition",
"aborted",
"out_of_range",
"unimplemented",
"internal_error",
"unavailable",
"data_loss",
"unauthenticated",
}
func (ss SpanStatus) String() string {
if ss >= maxSpanStatus {
return ""
}
m := [maxSpanStatus]string{
"",
"ok",
"cancelled", // [sic]
"unknown",
"invalid_argument",
"deadline_exceeded",
"not_found",
"already_exists",
"permission_denied",
"resource_exhausted",
"failed_precondition",
"aborted",
"out_of_range",
"unimplemented",
"internal_error",
"unavailable",
"data_loss",
"unauthenticated",
}
return m[ss]
return spanStatuses[ss]
}
func (ss SpanStatus) MarshalJSON() ([]byte, error) {
@ -744,12 +775,13 @@ func (ss SpanStatus) MarshalJSON() ([]byte, error) {
// A TraceContext carries information about an ongoing trace and is meant to be
// stored in Event.Contexts (as *TraceContext).
type TraceContext struct {
TraceID TraceID `json:"trace_id"`
SpanID SpanID `json:"span_id"`
ParentSpanID SpanID `json:"parent_span_id"`
Op string `json:"op,omitempty"`
Description string `json:"description,omitempty"`
Status SpanStatus `json:"status,omitempty"`
TraceID TraceID `json:"trace_id"`
SpanID SpanID `json:"span_id"`
ParentSpanID SpanID `json:"parent_span_id"`
Op string `json:"op,omitempty"`
Description string `json:"description,omitempty"`
Status SpanStatus `json:"status,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
}
func (tc *TraceContext) MarshalJSON() ([]byte, error) {
@ -792,6 +824,10 @@ func (tc TraceContext) Map() map[string]interface{} {
m["status"] = tc.Status
}
if len(tc.Data) > 0 {
m["data"] = tc.Data
}
return m
}
@ -866,10 +902,29 @@ func WithTransactionSource(source TransactionSource) SpanOption {
// WithSpanSampled updates the sampling flag for a given span.
func WithSpanSampled(sampled Sampled) SpanOption {
return func(s *Span) {
s.Sampled = sampled
s.explicitSampled = sampled
}
}
// WithSpanOrigin sets the origin of the span.
func WithSpanOrigin(origin SpanOrigin) SpanOption {
return func(s *Span) {
s.Origin = origin
}
}
// ContinueTrace continues a trace based on traceparent and baggage values.
// If the SDK is configured with tracing enabled,
// this function returns populated SpanOption.
// In any other cases, it populates the propagation context on the scope.
func ContinueTrace(hub *Hub, traceparent, baggage string) SpanOption {
scope := hub.Scope()
propagationContext, _ := PropagationContextFromHeaders(traceparent, baggage)
scope.SetPropagationContext(propagationContext)
return ContinueFromHeaders(traceparent, baggage)
}
// ContinueFromRequest returns a span option that updates the span to continue
// an existing trace. If it cannot detect an existing trace in the request, the
// span will be left unchanged.
@ -887,16 +942,17 @@ func ContinueFromHeaders(trace, baggage string) SpanOption {
return func(s *Span) {
if trace != "" {
s.updateFromSentryTrace([]byte(trace))
}
if baggage != "" {
s.updateFromBaggage([]byte(baggage))
}
// In case a sentry-trace header is present but there are no sentry-related
// values in the baggage, create an empty, frozen DynamicSamplingContext.
if trace != "" && !s.dynamicSamplingContext.HasEntries() {
s.dynamicSamplingContext = DynamicSamplingContext{
Frozen: true,
if baggage != "" {
s.updateFromBaggage([]byte(baggage))
}
// In case a sentry-trace header is present but there are no sentry-related
// values in the baggage, create an empty, frozen DynamicSamplingContext.
if !s.dynamicSamplingContext.HasEntries() {
s.dynamicSamplingContext = DynamicSamplingContext{
Frozen: true,
}
}
}
}
@ -939,6 +995,7 @@ func SpanFromContext(ctx context.Context) *Span {
func StartTransaction(ctx context.Context, name string, options ...SpanOption) *Span {
currentTransaction, exists := ctx.Value(spanContextKey{}).(*Span)
if exists {
currentTransaction.ctx = ctx
return currentTransaction
}