Skip to content
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

Add setting a tag at the trace-level #1959

Merged
merged 21 commits into from
Apr 14, 2022
Merged

Add setting a tag at the trace-level #1959

merged 21 commits into from
Apr 14, 2022

Conversation

lloeki
Copy link
Contributor

@lloeki lloeki commented Apr 4, 2022

Since trace transport does not have a concept of trace, tags are set on the topmost span.

When partial flushing is involved, the topmost span will be sent upon last flush, therefore tags will only appear in the UI when that final segment is processed.

@lloeki lloeki mentioned this pull request Apr 4, 2022
@lloeki lloeki marked this pull request as ready for review April 4, 2022 12:30
@lloeki lloeki requested a review from a team April 4, 2022 12:30
@lloeki lloeki force-pushed the add-trace-set-tag branch 2 times, most recently from a03d7cd to 1da0d11 Compare April 5, 2022 12:45
Since trace transport does not have a concept of trace, tags are set on
the topmost span.

When partial flushing is involved, the topmost span will be sent upon
last flush, therefore tags will only appear in the UI when that final
segment is processed.
TraceOperation is largely oblivious to the root span concept. The lack
of a concept of trace is part of the Trace API transport, therefore
TraceFormatter is more appropriate to carry and decide where to put the
trace-level values.

Trace tags explicitly do not carry to partially flushed traces in order
to avoid double processing.
Copy link
Contributor

@delner delner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally speaking this is what I was expecting. Shared a few points that likely need to be addressed but looking good so far.

lib/datadog/tracing/trace_operation.rb Outdated Show resolved Hide resolved
lib/datadog/tracing/trace_operation.rb Outdated Show resolved Hide resolved
lib/datadog/appsec/event.rb Outdated Show resolved Hide resolved
TraceOperation passes its tags unconditionally, therefore TraceSegment
now carries trace tags all the way to TraceFormatter, which has the
responsibility to decide whether to apply them or not to one of the
spans.
lib/datadog/tracing/trace_operation.rb Outdated Show resolved Hide resolved
lib/datadog/tracing/trace_segment.rb Outdated Show resolved Hide resolved
lib/ddtrace/transport/trace_formatter.rb Outdated Show resolved Hide resolved
end

def hostname=(value)
if value.nil?
tags.delete(Metadata::Ext::NET::TAG_HOSTNAME)
clear_tag(Metadata::Ext::NET::TAG_HOSTNAME)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that clear_tag stands out as it only clears keys in meta, whereas both set_tag and get_tag operate on both metrics and meta, as well as tags arguments being able to contain both metrics and meta.

Maybe we should align clear_tag and make it clear the key on both meta and metrics.

return
end

tags[Metadata::Ext::NET::TAG_HOSTNAME] = value
set_tag(Metadata::Ext::NET::TAG_HOSTNAME, value)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I wonder if we should have a slightly stronger typed set_meta, which would not silently allow these keys to land into metrics when they are known not to be metrics.

@@ -59,7 +59,7 @@ def set_resource!
# If the trace resource is undefined, or the root span wasn't
# specified, don't set this. We don't want to overwrite the
# resource of a span that is in the middle of the trace.
return if trace.resource.nil? || !@found_root_span
return if trace.resource.nil? || partial?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@found_root_span kind of comes from TraceSegment.root_span_id, which comes from voluntarily not passing root_span.id in TraceOperation when it is known partial (from TraceOperation#finished?), so @found_root_span seems like a roundabout way to infer that this is a partial trace.

I wonder if we should just pass the finished?/partial information via TraceSegment instead of relying on second-order divination.

In fact, it wasn't clear to me whether resource being nil was supposed to be part of that partial? predicate or not, but either way it does feel like divination from external behaviour.

@@ -165,6 +165,10 @@ def tag_sampling_priority!

private

def partial?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't comment on the line below but it turns out this comment I added because things were unclear to me and I had to retrace logic across three classes might just vanish by using this predicate.

       # when root span is not found, fall back to last span (partial flush)
       root_span || trace.spans.last

This keeps the meta/metrics split but removes the Metadata::Tagging
behaviour which is redundantly executed (TraceOperation is supposed to
having handled that). `meta` and `metrics` become protected accessors
and internal details.

Additionally, setting meta and metrics is split, avoiding a hash merge.
Copy link
Contributor

@delner delner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking pretty good, but one suggestion about managing attributes/tags in TraceSegment.

lib/datadog/tracing/trace_segment.rb Outdated Show resolved Hide resolved
lib/datadog/tracing/trace_segment.rb Outdated Show resolved Hide resolved
The previous attempt had the issue of always falling back to the RHS of
or-assignments when the values are `nil`.
Even though they are not used anymore after initialization, they are
also harmless since they're publicly invisible.
@delner delner added core Involves Datadog core libraries feature Involves a product feature labels Apr 14, 2022
@delner delner added this to the 1.0.0.beta2 milestone Apr 14, 2022
@delner delner added this to Review in progress in 1.0 Apr 14, 2022
Copy link
Contributor

@delner delner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks!

@delner delner merged commit 4022d99 into master Apr 14, 2022
@delner delner deleted the add-trace-set-tag branch April 14, 2022 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Involves Datadog core libraries feature Involves a product feature
Projects
1.0
Review in progress
Development

Successfully merging this pull request may close these issues.

None yet

3 participants