Add support for B3 parentspanid#286
Conversation
|
Hello I think the CI failure is related to lint, specifically E1137. It kinda looks like a false positive, it has been reported before for circumstances similar to this one: Here is the offending line. Does this looks like a false positive to you too? |
|
I signed it |
|
This is arguably a true positive, since the trace state is supposed to be immutable. Of course it is implemented with a EDIT2: Probably pylint-dev/pylint#2420 We might be able to workaround this by adding |
|
Ok! I'll try that, @Oberon00 👍 |
|
When I introduced this change:
So, I updated this commit to simply ignore |
Codecov Report
@@ Coverage Diff @@
## master #286 +/- ##
==========================================
+ Coverage 84.82% 84.92% +0.09%
==========================================
Files 38 38
Lines 1839 1844 +5
Branches 217 218 +1
==========================================
+ Hits 1560 1566 +6
+ Misses 214 213 -1
Partials 65 65
Continue to review full report at Codecov.
|
toumorokoshi
left a comment
There was a problem hiding this comment.
Sorry for the wild goosechase here. From the discussion in #236, the only new behavior we should handle is extracting the parent span id as ParentSpanId. To do so, this would require passing in spans vs span context to the injector interface, which should be fine.
2bfe070 to
09f6c35
Compare
|
Ok, implemented the fix, please let me know if this is the right approach. It fails How should this be handled? That interface should also receive a |
toumorokoshi
left a comment
There was a problem hiding this comment.
Good start! I think the API interface change not being propagated through is the major blocker here. Otherwise there's a stylistic choice to spawn a child span to exercise propagation. I generally prefer simple so just use the existing Span, but creating a new one is ok.
| set_in_carrier( | ||
| carrier, | ||
| cls.PARENT_SPAN_ID_KEY, | ||
| format_span_id(span.parent.context.span_id), |
There was a problem hiding this comment.
the parent can be empty, so there should be a conditional here to check that first.
There was a problem hiding this comment.
Ok, added the check 👍
| trace.generate_span_id() | ||
| ) | ||
|
|
||
| def test_extract_multi_header(self): |
There was a problem hiding this comment.
it feels to me that this test was sufficient by itself (since it exercises the base case of serialization / de-serialization), and have a separate test that verifies the parent_id propagation.
This test as is would also have been a good test for an empty parent.
There was a problem hiding this comment.
Sorry, I don't understand this comment, can you explain further, please?
There was a problem hiding this comment.
Yep definitely. What I was trying to say was: this test already should just work, and actually exercises a valuable case where the span has no parent.
So I was arguing to not modify this test case at all, and instead add another one that verifies that a parent_id field is set if a span has a parent.
There was a problem hiding this comment.
Sure, since you already approved these changes, @toumorokoshi, do you prefer if I open separate issues for your pending requests like this one or is if ok for you if I commit them directly in this PR again?
| @classmethod | ||
| def inject(cls, context, set_in_carrier, carrier): | ||
| sampled = (trace.TraceOptions.SAMPLED & context.trace_options) != 0 | ||
| def inject( |
There was a problem hiding this comment.
this interface change will also need to be propagated up to the API layer as well. There are multiple propagators (tracecontext) that implement the previous API, and those will need to be changed as part of this.
| parent_span = trace.Span( | ||
| "parent", FORMAT.extract(get_as_list, carrier) | ||
| ) | ||
| child_span = trace.Tracer().start_span("child", parent=parent_span) |
There was a problem hiding this comment.
I believe you could just instantiate a raw Span object yourself from the SDK, rather than use a whole trace to do so.
| parent_span = trace.Span( | ||
| "parent", FORMAT.extract(get_as_list, carrier) | ||
| ) | ||
| child_span = trace.Tracer().start_span("child", parent=parent_span) |
There was a problem hiding this comment.
there's a lot of boilerplate in these tests now. Could they be refactored into a few test helper methods?
b5e405b to
db91e97
Compare
7f54d56 to
352de67
Compare
toumorokoshi
left a comment
There was a problem hiding this comment.
Looks really good!
I think before merging we should be adding a test case for b3 propagator if a parent does not exist. But everything else looks great. Thanks!
c24t
left a comment
There was a problem hiding this comment.
This looks like a sensible change, but it might be in violation of the spec depending on how you interpret "the value to be injected can be SpanContext or DistributedContext". It might be worth it to check that we're only violating the letter of the law here, and not the spirit.
The discussion in open-telemetry/opentelemetry-specification#359 didn't cover the details of the implementation, I'm interested to see how other languages decide to handle this.
My only blocking comment is that we shouldn't require the SDK in the opentracing shim.
| sampled = (trace.TraceOptions.SAMPLED & context.trace_options) != 0 | ||
| def inject( | ||
| cls, span, set_in_carrier, carrier | ||
| ): # pylint: disable=arguments-differ |
opentelemetry-api/src/opentelemetry/context/propagation/httptextformat.py
Outdated
Show resolved
Hide resolved
|
|
||
| propagator.inject( | ||
| span_context.unwrap(), type(carrier).__setitem__, carrier | ||
| Span("", span_context.unwrap()), type(carrier).__setitem__, carrier |
There was a problem hiding this comment.
It seems like a problem to require the opentelemetry SDK in code that only previously required the opentracing API. You could use DefaultSpan here, but it's not a beautiful solution.
It's also pretty surprising to see bare span creation here when we usually create them via the tracer, but I guess that's an unavoidable consequence of the API change.
There was a problem hiding this comment.
I changed Span for DefaultSpan. I'm just curious, why is that you don't find this to be beautiful?
There was a problem hiding this comment.
Reviewing again, the reason I think this is a kludge is that we're only using the DefaultSpan to smuggle the span context to the propagator. We're taking advantage of the fact that DefaultSpans aren't exported here, but everywhere else they're used interchangeably with regular Spans, with the expectation that the export behavior is left up to the user.
If the signature hadn't changed to require this to be a span, we wouldn't normally create a span here. That looks to me like evidence that we shouldn't change the API in this way.
…xtformat.py Co-Authored-By: Chris Kleinknecht <libc@google.com>
This is done in order to avoid using the SDK in opentracing_shim
|
@c24t yes, I think this is a violation of the spec since inject will receive now a |
Supporting B3's technical definition of a parentspanid, by sourcing the span id of the parent span during injection from the propagator.
* chore: remove all references to SpanData * yarn fix
Fixes #236