-
Notifications
You must be signed in to change notification settings - Fork 377
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 option to inherit service name from the parent span #3685
base: master
Are you sure you want to change the base?
Conversation
f45244f
to
fe9c4a8
Compare
@@ -341,12 +347,13 @@ def bind_trace_events!(trace_op) | |||
events = trace_op.send(:events) | |||
|
|||
events.span_before_start.subscribe do |event_span_op, event_trace_op| | |||
event_trace_op.service ||= @default_service |
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.
A small improvement here: we used to always set @default_service
as the fallback service for a the newly created TraceOperation
. By explicity setting the value of event_trace_op.service
here, the TraceOperation
can no longer use the root span service name as its default value, which is the intended behavior:
dd-trace-rb/lib/datadog/tracing/trace_operation.rb
Lines 171 to 173 in b3c5a3d
def service | |
@service || (root_span && root_span.service) | |
end |
This PR no longer explicitly sets the service field in the active TraceOperation
, letting event_trace_op.service
handle the fallback normally, as it was originally intended.
event_span_op.service ||= @default_service | ||
sample_trace(event_trace_op) if event_span_op && event_span_op.parent_id == 0 | ||
end | ||
|
||
events.span_finished.subscribe do |event_span, event_trace_op| | ||
# Fallback in case the service was never set | ||
event_span.service ||= @default_service |
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 moved the fallback event_span.service ||= @default_service
from the span creation event to span completion evnt, because semantically a nil
span service name has the meaning of "use whatever the default behaviour is for span service naming". But before, we were not allowing this to happen because we are setting the service name explicitly too early, in the span_before_start
event.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #3685 +/- ##
=======================================
Coverage 98.10% 98.10%
=======================================
Files 1225 1225
Lines 72846 72927 +81
Branches 3489 3490 +1
=======================================
+ Hits 71463 71547 +84
+ Misses 1383 1380 -3 ☔ View full report in Codecov by Sentry. |
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.
approved for docs
|
||
expect(spans).to have(3).items | ||
context 'when inherit_parent_service is false' do | ||
it 'propagates parent span and uses default service name' do |
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.
Be explicit with conditions and useful when flipping the defaults
let(:tracer_options) { super().merge(inherit_parent_service: false) }
@@ -259,29 +273,55 @@ | |||
end | |||
|
|||
context 'when nesting spans' do | |||
it 'propagates parent span and uses default service name' do | |||
subject!(:nested_spans) do |
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.
Can we remove !
here?
This brings confusion to me with the ordering of execution, such as "Would this be executed before the let
in the nested context"?
@@ -1935,6 +1935,7 @@ For example, if `tracing.sampling.default_rate` is configured by [Remote Configu | |||
| `tracing.propagation_style` | `DD_TRACE_PROPAGATION_STYLE` | `Array` | `nil` | Distributed tracing propagation formats to extract and inject. See [Distributed Tracing](#distributed-tracing) for more details. | | |||
| `tracing.enabled` | `DD_TRACE_ENABLED` | `Bool` | `true` | Enables or disables tracing. If set to `false` instrumentation will still run, but no traces are sent to the trace agent. | | |||
| `tracing.header_tags` | `DD_TRACE_HEADER_TAGS` | `Array` | `nil` | Record HTTP headers as span tags. See [Applying header tags to root spans][header tags] for more information. | | |||
| `tracing.inherit_parent_service` | | `Bool` | `false` | Inherit the parent span's service name when creating a new child span. | |
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.
Should we be more explicit about this option is not ready for production yet?
And it might leads to breaking changes for user existing graph with various instrumentations
@@ -439,6 +443,11 @@ def message | |||
# mutation by reference; when this span is returned, | |||
# we don't want this SpanOperation to modify it further. | |||
def build_span | |||
# Use parent service if no service is set and @inherit_parent_service is set |
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 am generally supportive for moving toward this direction. What I found a larger problem is the fact that service
is a mutable field.
Things get tricky when parent span changes its service after child spans are finished. For instance:
Datadog::Tracing.trace('parent', service: 'service-parent') do |span_op, _|
Datadog::Tracing.trace('child1') {}
span_op.service = "BalaBoom!" # Change the service name after the child span is finished
end
I was not sure what the behaviour is like for instrumentation depending on ActiveSupport::Notifications
, which I remember the service field is set in the after callback.
Any thoughts about restricting the mutability of the service field?
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 agree with Tony; mutability is a problem. Generally speaking, I think moving towards an immutable world simplifies things quite a bit, the only question is how, and what kinds of trade-offs. Have to think about this more.
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.
Secondary question: how does this feature fit in with the "one service name" change we originally planned for 2.0? If we end up introducing that, is this obsolete?
# Use parent service if no service is set and @inherit_parent_service is set | ||
service = self.service || (@parent&.service if @inherit_parent_service) | ||
|
||
service_entry = @parent.nil? || (service && @parent.service != service) |
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.
What is @parent
? It concerns me that SpanOperation
has a reference to parent
, because of the deep coupling/nesting... more references means less garbage collection means more memory bloat. It also makes it harder to move data structures like this off the critical path to a background process, if there was an optimization opportunity to do so.
I know my original intention was to eliminate @parent
altogether. But I can't remember if we couldn't and if I just had to minimize its usage. I'm not hot on the idea of expanding its usage...
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.
The lib
part of the diff LGTM
Signed-off-by: Marco Costa <[email protected]>
fe9c4a8
to
c2aea03
Compare
What does this PR do?
This PR is the first step towards aligning the Ruby tracer with all other APM languages in inheriting the parent span's service name by default.
Making this change is a breaking change, so this is introduced as an option which default to "disabled".
This option should be made "enabled" by default in the next major version.
How to test the change?
Changing the setting
c.tracing.inherit_parent_service
totrue
allows you to see the new behaviour, with the span's service inheriting the value from the active parent span.