-
Notifications
You must be signed in to change notification settings - Fork 11
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
Enrich root spans that represent a dependency #125
base: main
Are you sure you want to change the base?
Changes from 1 commit
1223b97
3ccfaae
aedf6aa
3def749
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 |
---|---|---|
|
@@ -189,6 +189,7 @@ func (s *spanEnrichmentContext) Enrich(span ptrace.Span, cfg config.Config) { | |
func (s *spanEnrichmentContext) enrich(span ptrace.Span, cfg config.Config) { | ||
if s.isTransaction { | ||
s.enrichTransaction(span, cfg.Transaction) | ||
s.enrichExitSpanTransaction(span, cfg) | ||
} else { | ||
s.enrichSpan(span, cfg.Span) | ||
} | ||
|
@@ -237,6 +238,39 @@ func (s *spanEnrichmentContext) enrichTransaction( | |
} | ||
} | ||
|
||
// In OTel a root span can represent an outgoing call or a producer span | ||
gregkalapos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// In such cases, the span is still mapped into a transaction, but such spans are enriched | ||
gregkalapos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// with additional attributes that are specific to the outgoing call or producer span. | ||
func (s *spanEnrichmentContext) enrichExitSpanTransaction( | ||
span ptrace.Span, | ||
cfg config.Config, | ||
) { | ||
if span.Kind() == ptrace.SpanKindClient || span.Kind() == ptrace.SpanKindProducer { | ||
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. I'm not sure we can rely on that condition, tbh. Since that entire situation we try to handle here is an instrumentation bug in itself (IN THEORY: there never should be a single span that is entry and exit at the same time, but IN PRACTICE that happens in some situations), I don't think we should rely on For example, what if the SpanKind == How about, we use heuristics similar to how we do it for deriving 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. This is a valid point and was thinking about this as well. My idea was to be on the safe side and only enrich real exit spans with the necessary attributes. I understand we have this issue with nginx proxy spans that are a single span for both incoming and outgoing calls. I don't know what's the span type there, but if it's But that use-case is already a bug and I'm not sure how much we want to unwind such bugs.
I think that's bug in the instrumentation. SemConv says :
and
So for HTTP that goes against the spec and I'm not sure how much we should fight these bugs.
We could explore that, but I'm not sure how reliable it is. The check if something is an exit span is a bit different - there is no differentiation in that check between incoming and outgoing spans, because incomings are already assumed to be transactions, so all those cases are already filtered out at that point by only doing the check for spans. I just quickly looked at HTTP spans, what I see, the server side only has Overall I feel we'd end up with a messy heuristic which may not work in all cases and may not even unwind these bugs in a way we'd want to. If we relax this check here, I think the risk we run here is that we may categorize some incoming calls as exit spans and we start calculating dependencies for those. That'd be very bad. If we can come up with something to avoid that, then I'd feel more confident to relax this. |
||
if cfg.Span.TypeSubtype.Enabled { | ||
s.setSpanTypeSubtype(span) | ||
} | ||
if cfg.Span.ServiceTarget.Enabled { | ||
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. @gregkalapos What about the thing we discussed about having two 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. I tested it and that triggers an error when the water-flow chart is generated. These transactions will be also returned for all queries that look for spans and there were some missing span related fields there. @axw had a related idea: we could just remove the filter on 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. Discussed this with @AlexanderWert and we said, the correct way would be to still set both In 3def749 I changed this. Now that we share the ![]() However, order matters here. This is the code in Kibana that builds up the chart - and if it's So, it seems we can set both |
||
s.setServiceTarget(span) | ||
} | ||
if cfg.Span.DestinationService.Enabled { | ||
s.setDestinationService(span) | ||
} | ||
if cfg.Span.Name.Enabled { | ||
span.Attributes().PutStr(AttributeSpanName, span.Name()) | ||
} | ||
if cfg.Transaction.Type.Enabled { | ||
spanTypeAttr, hasType := span.Attributes().Get(AttributeSpanType) | ||
if hasType { | ||
transactionType := spanTypeAttr.Str() | ||
if spanSubtypeAttr, hasSubType := span.Attributes().Get(AttributeSpanSubtype); hasSubType { | ||
transactionType += "." + spanSubtypeAttr.Str() | ||
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. I'd be happy to hear opinion on this one. The APM UI groups transactions based on transaction type. The idea here is that for such exit&root spans we'd want to use a different transaction type so they don't end up in the same group with incoming transactions. ![]() E.g. the default transaction type for incoming HTTP is Alternatively to 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. will that impact other things like service map or so? 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. So far, I haven't seen any impact. Service map is mostly driven by the The dependency list has icons - that is based on this span, but that is not driven by |
||
} | ||
span.Attributes().PutStr(AttributeTransactionType, transactionType) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (s *spanEnrichmentContext) enrichSpan( | ||
span ptrace.Span, | ||
cfg config.ElasticSpanConfig, | ||
|
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.
Feel free to ignore, maybe this is personal preference. But the code may be a bit easier to follow when pulling in the if condition to this method, so that it's clear that only transactions that are of type client or producer get enriched.
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.
I'm wondering whether we need a dedicated method for this at all.
Couldn't we just have some heuristic method in addition that just identifies whether a span is an exist span, use that in an additional condition here, but then just calling the existing
enrichSpan()
method.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.
I still needed to extend
enrichSpan()
a bit, but now I got rid ofenrichExitSpanTransaction
- so there is onlyenrichSpan
andenrichTransaction
as we had it originally.The 2 main differences in
enrichExitSpanTransaction
where:processor.event
tospan
transaction.type
We handle these now with a condition.
I also moved the check up to this line.