-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infer destination service resource adapt public api #1003
Changes from 11 commits
9965339
1e5a0f1
bd6aa81
a987f9d
440e222
ec067cb
e402a2a
723ba65
738a944
971620c
2bf571f
b577a55
a5af5c6
ee216c4
5c2ea80
a47d769
0acc139
3e62635
71d1d0e
ee8cb43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ import ( | |
"sync" | ||
"time" | ||
|
||
"go.elastic.co/apm/model" | ||
"go.elastic.co/apm/stacktrace" | ||
) | ||
|
||
|
@@ -64,7 +65,7 @@ func (tx *Transaction) StartSpan(name, spanType string, parent *Span) *Span { | |
// span type, subtype, and action; a single dot separates span type and | ||
// subtype, and the action will not be set. | ||
func (tx *Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) *Span { | ||
if tx == nil { | ||
if tx == nil || opts.parent.IsExitSpan() { | ||
return newDroppedSpan() | ||
} | ||
|
||
|
@@ -80,15 +81,20 @@ func (tx *Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) | |
// Lock the parent first to avoid deadlocks in breakdown metrics calculation. | ||
if opts.parent != nil { | ||
opts.parent.mu.Lock() | ||
defer opts.parent.mu.Unlock() | ||
} | ||
|
||
// Prevent tx from being ended while we're starting a span. | ||
tx.mu.RLock() | ||
defer tx.mu.RUnlock() | ||
if tx.ended() { | ||
if opts.parent != nil { | ||
opts.parent.mu.Unlock() | ||
} | ||
return tx.tracer.StartSpan(name, spanType, transactionID, opts) | ||
} | ||
if opts.parent != nil { | ||
defer opts.parent.mu.Unlock() | ||
} | ||
|
||
// Calculate the span time relative to the transaction timestamp so | ||
// that wall-clock adjustments occurring after the transaction start | ||
|
@@ -101,6 +107,9 @@ func (tx *Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) | |
span := tx.tracer.startSpan(name, spanType, transactionID, opts) | ||
span.tx = tx | ||
span.parent = opts.parent | ||
if opts.ExitSpan { | ||
span.setExitSpan(name, spanType) | ||
} | ||
|
||
// Guard access to spansCreated, spansDropped, rand, and childrenTimer. | ||
tx.TransactionData.mu.Lock() | ||
|
@@ -143,7 +152,10 @@ func (tx *Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) | |
// way will not have the "max spans" configuration applied, nor will they be | ||
// considered in any transaction's span count. | ||
func (t *Tracer) StartSpan(name, spanType string, transactionID SpanID, opts SpanOptions) *Span { | ||
if opts.Parent.Trace.Validate() != nil || opts.Parent.Span.Validate() != nil || transactionID.Validate() != nil { | ||
if opts.Parent.Trace.Validate() != nil || | ||
opts.Parent.Span.Validate() != nil || | ||
transactionID.Validate() != nil || | ||
opts.parent.IsExitSpan() { | ||
return newDroppedSpan() | ||
} | ||
if !opts.Parent.Options.Recorded() { | ||
|
@@ -179,6 +191,10 @@ type SpanOptions struct { | |
// will be generated and used instead. | ||
SpanID SpanID | ||
|
||
// Indicates whether a span is an exit span or not. All child spans | ||
// will be noop spans. | ||
ExitSpan bool | ||
|
||
// parent, if non-nil, holds the parent span. | ||
// | ||
// This is only used if Parent is zero, and is only available to internal | ||
|
@@ -239,6 +255,7 @@ type Span struct { | |
traceContext TraceContext | ||
transactionID SpanID | ||
parentID SpanID | ||
exit bool | ||
|
||
mu sync.RWMutex | ||
|
||
|
@@ -384,6 +401,35 @@ func (s *Span) ended() bool { | |
return s.SpanData == nil | ||
} | ||
|
||
func (s *Span) setExitSpan(name, spanType string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at the spec, I believe the resource is meant to be set to Subtype and Type can be set after starting a span, so I think we need to do that when ending the span. What we can do is keep track of whether SpanContext.SetDestinationService has been called (even with empty strings), and if it is never called for an exit span, then do this implicit call when ending the exit span. |
||
resource := spanType | ||
if resource == "" { | ||
resource = name | ||
} | ||
s.exit = true | ||
s.Context.SetDestinationService(DestinationServiceSpanContext{ | ||
Resource: resource, | ||
}) | ||
} | ||
|
||
// IsExitSpan returns true if the span is an exit span. | ||
func (s *Span) IsExitSpan() bool { | ||
if s == nil { | ||
return false | ||
} | ||
s.mu.RLock() | ||
defer s.mu.RUnlock() | ||
if s.SpanData == nil { | ||
return false | ||
} | ||
ctx := s.Context | ||
return s.exit || | ||
ctx.destination != model.DestinationSpanContext{} || | ||
ctx.database != model.DatabaseSpanContext{} || | ||
ctx.message != model.MessageSpanContext{} || | ||
ctx.http != model.HTTPSpanContext{} | ||
stuartnelson3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// SpanData holds the details for a span, and is embedded inside Span. | ||
// When a span is ended or discarded, its SpanData field will be set | ||
// to nil. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving the unlock away from the lock scares me a bit. TBH I'm really not a fan of this implicit exit span status, so I've raised the question with agent devs whether it is necessary to implement that part of the spec.
EDIT: point being that if we don't need to do the implicit check, and we only have explicitly identified exit spans, then "s.exit" is immutable from span start and requires no locking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 makes sense. I'm not a fan of this locking either, so let's see what happens.