-
Notifications
You must be signed in to change notification settings - Fork 250
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
Update Tracer#in_span to finish the Span #118
Conversation
I'm going to walk back my 'like' for this. This is a convenience API that now wraps 3 things that a client can already do with the API:
span = nil
result = OpenTelemetry.tracer.in_span('do-the-thing', finish: false) do |new_span|
span = new_span
compute_the_thing
end
...
span.finish with: span = OpenTelemetry.tracer.start_span('do-the-thing')
result = OpenTelemetry.tracer.with_span(span) { compute_the_thing }
...
span.finish I'd argue the latter is cleaner, easier to understand, and easier to use. |
@fbogsany Totally agree with this. Looking closer, the Python folks have added the optional flag to Keep OpenTelemetry.tracer.in_span('do-the-thing') do |new_span|
compute_the_thing
end
span = OpenTelemetry.tracer.start_span('do-the-thing')
result = OpenTelemetry.tracer.with_span(span) { compute_the_thing }
# ...
span.finish
span = OpenTelemetry.tracer.start_span('do-the-thing')
result = OpenTelemetry.tracer.with_span(span, finish: true) { compute_the_thing } Since |
I think it is worth laying out the common use-cases of each method:
def foo
span = tracer.start_root_span('foo')
... # maybe tracer.with_span(span) at some point
ensure
span.finish
end
def foo(parent_span)
span = tracer.start_span('foo', with_parent: parent_span)
... # maybe tracer.with_span(span) at some point
ensure
span.finish
end
def foo
span = tracer.start_span('foo') # implicit parent span from current context
Thread.new(span) do |span|
... # maybe tracer.with_span(span) at some point
ensure
span.finish
end
end
def leaf_method
span = start_span('leaf') # implicit parent span from current context
do_the_thing
ensure
span.finish
end
def framework_method
leaf_method
end
def service_method
wire_context = tracer.http_text_format.extract(headers) { |headers, key| headers[key] } # what a horrible API, in retrospect
span = tracer.start_span('service', with_parent_context: wire_context)
result = tracer.with_span(span) { framework_method }
format_result(result)
ensure
span.finish
end
def my_wonderful_but_maybe_slow_method
tracer.in_span('my_wonderful_but_maybe_slow_method') do
sleep(30)
do_something
end
end
def i_just_figured_it_out!
tracer.current_span['answer'] = 42
end From this perspective, I don't think |
|
||
it 'returns a span with the same context as the parent' do | ||
span = tracer.start_span('op', with_parent: parent) | ||
span.context.must_equal(parent.context) |
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.
This behaviour is wrong. Or maybe it isn't. It's definitely up for discussion, with the Named Tracers change. The SDK does not behave in this way, and I don't think the API's "no-op" implementation should either. Specifically, the new Span should share the parent span's trace ID, but should have a different span ID.
opentelemetry-ruby/api/lib/opentelemetry/trace/tracer.rb
Lines 48 to 50 in 3b52ae0
span_context = with_parent&.context || with_parent_context || current_span.context | |
if span_context.valid? | |
Span.new(span_context: span_context) |
vs.
OpenTelemetry::Trace::Span.new(span_context: OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id)) |
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.
Let's stick with the current behaviour for now. This matches the Java implementation of DefaultSpan
. There's some related debate in open-telemetry/opentelemetry-specification#208
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.
LGTM. Some things will need to move after #122 lands, but we can deal with that then.
It looks like #122 has landed, and this is conflicted. What do we need to do to move this forward? |
@mwear I will make the moves on Friday and see if I can get it over the line. |
Adds tests to the current API `Tracer` implementation.
Updates `Tracer#in_span` to call `Span#finish` at the end of the `in_span` block. Adds tests for both the API and SDK implementations to ensure the Span is finished as expected.
@fbogsany I've addressed all the suggestions/issues you raised with the exception of changing the behavior you mentioned in this comment. @mwear this has been rebased and the Minitest deprecations have also been addressed. I believe it's good to go. |
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.
Thanks for this and the test cases ✨ @elskwid.
Overview
Updates
Tracer#in_span
to callSpan#finish
at the end of the block and adds API tests forTracer
.Details
While creating some examples based on the DataDog auto-instrumentation work I noticed that the
Tracer#in_span
implementation wasn't finishing the span as expected. I looked into the Python implementation and saw the call theend()
. This adds the call to#finish
and adds tests to both the API and SDK.The tests are going through some slight acrobatics to verify things are working as expected. Please let me know if there are better ways to do this given the implementation(s).
I added tests for the existing API
Tracer
implementation before updating#in_span
to make sure the changes wouldn't cause us trouble in other methods.Thoughts
finish
/end
optional. If we're interested in that I can open a new PR for that functionality. @fbogsany mentioned we may want to do this.Span#ended?
?