-
Notifications
You must be signed in to change notification settings - Fork 161
Implement ScopeManager for in-process propagation #63
Conversation
…opeManager propagation
e529e27
to
9f406cf
Compare
""" | ||
return True | ||
|
||
def is_parent(self, parent, 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.
don't know if it's really needed, but it would be great that tests available in the api_check.py
tests also the parenting so that a ScopeManager
can be tested automatically when a new Tracer
implementation is created.
def __init__(self): | ||
# TODO: `tracer` should not be None, but we don't have a reference; | ||
# should we move the NOOP SpanContext, Span, Scope to somewhere | ||
# else so that they're globally reachable? |
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 I mean here is that maybe everywhere in the repo we can simply:
from opentracing.ext import noop # or something similar
self._noop_span = noop.SPAN
self._noop_scope = noop.SCOPE
The noop
module may be initialized when the Tracer
is created (so in the __init__.py
at the moment?) so we have references of Tracer
and ScopeManager
, avoiding creating every time a no-op of something.
Let me know if I'm missing something!
@@ -45,3 +49,46 @@ def test_baggage_check_works(self): | |||
# second check that assert on empty baggage will fail too | |||
with self.assertRaises(AssertionError): | |||
api_check.test_context_baggage() | |||
|
|||
def test_scope_manager_check_works(self): |
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.
Not sure we need that (other than coverage?). I've followed the approach above.
@carlosalberto @tedsuo it would be great having a pass on this PR as a follow-up of the Java API. Currently this API is good enough for us since it grants the flexibility we need for in-process propagation. I'm going to publish the reference implementation PR too, so I can update the PR description with the link. Thanks in advance for spending time reviewing the PR! EDIT: link to the reference implementation -> opentracing/basictracer-python#24 |
self._manager = manager | ||
self._span = span | ||
|
||
def span(self): |
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 would prefer this one as a @property
so scope.span
instead of scope.span()
but it's something we can discuss.
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'd say we keep a property as well - I know some people don't like it, but then again, we already have Span's context and tracer as properties ;)
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.
Totally agree!
"""ScopeManager accessor""" | ||
return self._scope_manager | ||
|
||
def start_active(self, |
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.
nomenclature nitpick: i don't like the naming of start_active
vs start_manual
. start_active
will be used 95% of the time, so i think it should just be called start
and then there can be start_{whatever_you_choose}
for the rest.
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.
that's an interesting point since the most common API may be the shortest possible, let's see what others are thinking!
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.
@carlosalberto thoughts?
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 would vote to keep the api as close to the other language implementations as possible. On a similar note, should something about in process span management be added to the opentracing specification?
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.
@wkiser I agree on the uniformity point.
About the standard inclusion: I think it will be added eventually, after the implementation proves to be sufficient and tracer authors are fine with it (for reference: for the Java api it took a pair of iterations to get it right ;) )
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.
+1, "manual" was removed from the Java API.
Even though start_active_span
will be used more often, it's worth keeping the full name to be in sync with other languages and emphasize the side effects. It also doesn't return a Span the way start_span
does.
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.
It also doesn't return a Span the way start_span does.
Ah - I overlooked that. Seems like it should beTracer.start_active_scope()
.
I've submitted a PR to @palazzem's branch with these naming updates (palazzem#1).
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 think it should be start_active_span
, since Span is the main thing that's being created here, it's just wrapped in a Scope for management.
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 don't have a strong opinion on _active_
, so I'm happy to adjust it.
Here's the difference in practice:
with tracer.start_active_span('...') as scope:
scope.span().set_tag('http.method', 'GET')
do_some_work()
vs.
with tracer.start_active_scope('...') as scope:
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.
Sure thing! I definitely think that start_manual*
must be out of the Python API. Let's make this change.
:param finish_on_close: whether span should automatically be | ||
finished when `Scope#close()` is called | ||
""" | ||
self._manager = manager |
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.
If you are saving manager
, why not expose it too (through a property)? Else, well, don't save it (and let implementations do on that ;) )
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 think it may be better to not expose the manager
since the source of truth for the ScopeManager
should be the Tracer
(right?). If that makes sense, I'd say to remove that line and let the implementation do that.
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.
Though we need to keep it in the constructor signature since implementations need (in 99% of cases) that.
# TODO: `tracer` should not be None, but we don't have a reference; | ||
# should we move the NOOP SpanContext, Span, Scope to somewhere | ||
# else so that they're globally reachable? | ||
self._noop_span = Span(tracer=None, context=SpanContext()) |
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.
One idea: creating a Tracer
and use its noop_span
is an alternative, even if not a perfect one (as then we would end up with two noop Tracer
objects).
@@ -38,33 +40,88 @@ class Tracer(object): | |||
_supported_formats = [Format.TEXT_MAP, Format.BINARY, Format.HTTP_HEADERS] | |||
|
|||
def __init__(self): | |||
self._scope_manager = ScopeManager() |
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.
Why not call it _noop_scope_manager?
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.
Correct!
Upon further review when working on the
Let me know. Hopefully it helps! I will be pushing soon an update with the |
@carlosalberto since my work has been already merged, I think we should close this PR because it has been superseded by #64 ? |
@palazzem Yes. Closing it now. Thanks ;) |
Overview
This PR aims to solve in-process context propagation for Python. It has two aims:
start_active()
andstart_manual()
)ScopeManager
) that allows tracing async operations with all the common frameworks - threads, asyncio, tornado, etcImplementation details are available in another PR (opentracing/basictracer-python#24).
Details
With this PR,
Scope
is implemented as a wrapper ofSpan
class. No changes have been made to the currentSpan
andSpanContext
, making the propagation something built on top of current data models.A
Scope
formalizes the activation and deactivation of aSpan
, that is handled using aScopeManager
available in theTracer
itself. It can be used automatically using tracing methods, or manually if you need to retrieve the current activeSpan
. Simple examples are:Opened questions
get_something
/set_something
instead of justsomething
). In Python such approach is not really idiomatic, though properties are. Because of that I suggest to have some internal attributes "protected" via a property like:Continuation
(and so the counter) is not part of this API, though it could be acontrib
module in case we "really" need it in the future.References