-
Notifications
You must be signed in to change notification settings - Fork 624
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
Refactor current span handling for newly created spans. #198
Refactor current span handling for newly created spans. #198
Conversation
1. Make Tracer.start_span() simply create and start the Span, without setting it as the current instance. 2. Add an extra Tracer.start_as_current_span() to create the Span and set it as the current instance automatically.
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 few non-blocking comments. The changes look good, but I'm worried this makes the API more cumbersome since I'd expect more calls to start_as_current_span
than start_span
.
|
||
By default the current span will be used as parent, but an explicit | ||
parent can also be specified, either a `Span` or a `SpanContext`. If | ||
the specified value is `None`, the created span will be a root span. | ||
|
||
On exiting the context manager stop the span and set its parent as the | ||
On exiting the context manager ends the 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.
This is kind of confusing since Span
is the context manager now, not start_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.
Oh, right, this needs to be cleared up.
|
||
# tracer.get_current_span() will be used as the implicit parent. | ||
# If none is found, the created span will be a root instance. | ||
with tracer.start_span("two") as child: |
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.
with tracer.start_span("two") as child: | |
with tracer.start_span("one") as child: |
If you want to make this consistent with the other example.
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.
Makes sense, will update.
"""See `opentelemetry.trace.Tracer.start_as_current_span`.""" | ||
|
||
span = self.start_span(name, parent, kind) | ||
with self.use_span(span, True): | ||
yield 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.
Unless I'm missing some use case, now that Span
calls end
on exit it looks like you could lose end_on_exit
and just let use_span
be responsible for setting the context:
with self.start_span(name, parent, kind) as span:
with self.use_span(span):
yield(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.
This one didn't work - calling yield()
on the Span
didn't to the trick/chaining, so I had to keep the original one ;)
exc_type: typing.Optional[typing.Type[BaseException]], | ||
exc_val: typing.Optional[BaseException], | ||
exc_tb: typing.Optional[python_types.TracebackType], | ||
) -> bool: |
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.
) -> bool: | |
) -> Optional[bool]: |
According to https://github.com/python/mypy/blob/master/docs/source/protocols.rst#context-manager-protocols, and IIRC most context managers like this return null.
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.
Yeah, I was wondering about this one later on (specially about the null
case - I'm wondering why there's nothing for this already available in the typing
module ;) )
# pylint: disable=unused-argument,no-self-use | ||
return INVALID_SPAN | ||
|
||
@contextmanager # type: ignore |
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 keep this one a context manager instead of returning the span like the other?
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.
Oh, I didn't try that out. I will give it a spin and see how it looks ;)
Co-Authored-By: Chris Kleinknecht <[email protected]>
So I'd have no problem making (Btw, in OpenTracing we had |
Seeing open-telemetry/opentelemetry-specification#21, what about instead of having a with tracer().start_span("foo").use() as span:
span.set_attribute("foo", "bar") |
return span | ||
|
||
@contextmanager | ||
def start_as_current_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.
I've always been struggling with naming.
Given this technically is start_span
then use_span
, maybe we should just call it start_and_use_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.
I can add one more suggestion: use_new_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.
I'd actually argue that "start_span" should remain as is, and we should maybe provide separate terminology for the two components of span creation and use.
I don't imagine most consumers will really need to separate span creation and use, and may find it as needlessly verbose for "start_and_use_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.
This is also about consistency across languages.
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. We might want to update the examples as well?
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.
Definitely an improvement. We shouldn't bikeshed for too long here. @carlosalberto please merge if you yourself think this is ready.
@@ -226,6 +227,26 @@ def is_recording_events(self) -> bool: | |||
events with the add_event operation and attributes using set_attribute. | |||
""" | |||
|
|||
def __enter__(self) -> "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.
👍
exc_val: typing.Optional[BaseException], | ||
exc_tb: typing.Optional[python_types.TracebackType], | ||
) -> typing.Optional[bool]: | ||
"""Ends context manager and calls end() on the `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.
"""Ends context manager and calls end() on the `Span`. | |
"""Ends context manager and calls `.end` on the `Span`. |
"""See `opentelemetry.trace.Tracer.start_as_current_span`.""" | ||
|
||
span = self.start_span(name, parent, kind) | ||
with self.use_span(span, True): |
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 re-add
with self.use_span(span, True): | |
with self.use_span(span, end_on_exit=True): |
) -> typing.Iterator[trace_api.Span]: | ||
"""See `opentelemetry.trace.Tracer.start_as_current_span`.""" | ||
|
||
span = self.start_span(name, parent, kind) |
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.
Actually the function can be implemented more simply and efficiently without @contextmanager
and Iterator
by replaing the with
statement: return self.use_span(span, True)
.
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.
Hah! Right. I remember this is how I envisioned it first, but I guess I was decaffeinated when I wrote it ;(
# pylint: disable=unused-argument,no-self-use | ||
return INVALID_SPAN | ||
|
||
def start_as_current_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.
Actually, I think we should implement start_as_current_span
in the API. Other API-implementations that need special behavior here can still override. EDIT: But this is not why I "requested changes".
name: str, | ||
parent: ParentSpan = CURRENT_SPAN, | ||
kind: SpanKind = SpanKind.INTERNAL, | ||
) -> typing.Iterator["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.
Iterator is the wrong type here. Correct would be ContextManger[Span]
but that does not exist in Python 3.5. So I guess this is a case where we have to use something like -> SpanContextManager
and above
MYPY = False
if MYPY:
SpanContextManager = typing.ContextManager[Span]
else:
SpanContextManager = typing.Any
https://mypy.readthedocs.io/en/latest/common_issues.html#import-cycles
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.
Honestly I'd leave this out for now, as it makes the code ugly ;)
(Else, I'd add it in another PR)
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 want to hold this PR up and I don't know why mypy accepts it and I agree that this (my suggested) code is very ugly. But: If I'm reading this correctly, the annotation is in fact wrong. If it were correct, you'd use this function as for span in tracer().start_as_current_span()
. An iterator has no set_attribute
, but it has __next__
. A context manager has neither.
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 honestly feel like this is not the place to discuss this - this change it's even now, as we speak, in master
- check out https://github.com/open-telemetry/opentelemetry-python/blob/master/opentelemetry-api/src/opentelemetry/trace/__init__.py#L385
-> It's still defined as start_span
instead of start_as_current_span
and in both cases, a Span
is yielded.
I have no problem adjusting things that were changed in this PR, but I honestly see no reason to change things that were there before, unless they are fatal. Otherwise, we will in my next review something else that could be improved, and then we will have to discuss them and have yet another iteration ;)
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 point is that your removed the @contextmanager
and consequently changed yield
to return
so it keeps working fine at runtime, but I think it messes up the type annotation. Unless the interaction between @contextmanager
and the function return type is not taken into account by mypy, then it would already have been wrong before.
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.
--> #219
This is for keeping mypy happy (mostly).
So I think this is ready to go, after applying the latest of @Oberon00 's feedback. We can iterate the the mypy/ |
for start_time and end_time Make lint happy Addressing comments Addressing comments Allowing 0 as start and end time Fix lint issues Metrics API RFC 0003 cont'd (open-telemetry#136) * Create functions Comments for Meter More comments Add more comments Fix typos * fix lint * Fix lint * fix typing * Remove options, constructors, seperate labels * Consistent naming for float and int * Abstract time series * Use ABC * Fix typo * Fix docs * seperate measure classes * Add examples * fix lint * Update to RFC 0003 * Add spancontext, measurebatch * Fix docs * Fix comments * fix lint * fix lint * fix lint * skip examples * white space * fix spacing * fix imports * fix imports * LabelValues to str * Black formatting * fix isort * Remove aggregation * Fix names * Remove aggregation from docs * Fix lint * metric changes * Typing * Fix lint * Fix lint * Add space * Fix lint * fix comments * address comments * fix comments Adding a working propagator, adding to integrations and example (open-telemetry#137) Adding a full, end-to-end example of propagation at work in the example application, including a test. Adding the use of propagators into the integrations. Metrics API RFC 0009 (open-telemetry#140) * Create functions Comments for Meter More comments Add more comments Fix typos * fix lint * Fix lint * fix typing * Remove options, constructors, seperate labels * Consistent naming for float and int * Abstract time series * Use ABC * Fix typo * Fix docs * seperate measure classes * Add examples * fix lint * Update to RFC 0003 * Add spancontext, measurebatch * Fix docs * Fix comments * fix lint * fix lint * fix lint * skip examples * white space * fix spacing * fix imports * fix imports * LabelValues to str * Black formatting * fix isort * Remove aggregation * Fix names * Remove aggregation from docs * Fix lint * metric changes * Typing * Fix lint * Fix lint * Add space * Fix lint * fix comments * handle, recordbatch * docs * Update recordbatch * black * Fix typo * remove ValueType * fix lint Console exporter (open-telemetry#156) Make use_span more flexible (closes open-telemetry#147). (open-telemetry#154) Co-Authored-By: Reiley Yang <[email protected]> Co-Authored-By: Chris Kleinknecht <[email protected]> WSGI fixes (open-telemetry#148) Fix http.url. Don't delay calling wrapped app. Skeleton for azure monitor exporters (open-telemetry#151) Add link to docs to README (open-telemetry#170) Move example app to the examples folder (open-telemetry#172) WSGI: Fix port 80 always appended in http.host (open-telemetry#173) Build and host docs via github action (open-telemetry#167) Add missing license boilerplate to a few files (open-telemetry#176) sdk/trace/exporters: add batch span processor exporter (open-telemetry#153) The exporters specification states that two built-in span processors should be implemented, the simple processor span and the batch processor span. This commit implements the latter, it is mainly based on the opentelemetry/java one. The algorithm implements the following logic: - a condition variable is used to notify the worker thread in case the queue is half full, so that exporting can start before the queue gets full and spans are dropped. - export is called each schedule_delay_millis if there is a least one new span to export. - when the processor is shutdown all remaining spans are exported. Implementing W3C TraceContext (fixes open-telemetry#116) (open-telemetry#180) * Implementing TraceContext (fixes open-telemetry#116) This introduces a w3c TraceContext propagator, primarily inspired by opencensus. fix time conversion bug (open-telemetry#182) Introduce Context.suppress_instrumentation (open-telemetry#181) Metrics Implementation (open-telemetry#160) * Create functions Comments for Meter More comments Add more comments Fix typos * fix lint * Fix lint * fix typing * Remove options, constructors, seperate labels * Consistent naming for float and int * Abstract time series * Use ABC * Fix typo * Fix docs * seperate measure classes * Add examples * fix lint * Update to RFC 0003 * Add spancontext, measurebatch * Fix docs * Fix comments * fix lint * fix lint * fix lint * skip examples * white space * fix spacing * fix imports * fix imports * LabelValues to str * Black formatting * fix isort * Remove aggregation * Fix names * Remove aggregation from docs * Fix lint * metric changes * Typing * Fix lint * Fix lint * Add space * Fix lint * fix comments * handle, recordbatch * docs * Update recordbatch * black * Fix typo * remove ValueType * fix lint * sdk * metrics * example * counter * Tests * Address comments * ADd tests * Fix typing and examples * black * fix lint * remove override * Fix tests * mypy * fix lint * fix type * fix typing * fix tests * isort * isort * isort * isort * noop * lint * lint * fix tuple typing * fix type * black * address comments * fix type * fix lint * remove imports * default tests * fix lint * usse sequence * remove ellipses * remove ellipses * black * Fix typo * fix example * fix type * fix type * address comments Implement Azure Monitor Exporter (open-telemetry#175) Span add override parameters for start_time and end_time (open-telemetry#179) CONTRIBUTING.md: Fix clone URL (open-telemetry#177) Add B3 exporter to alpha release table (open-telemetry#164) Update README for alpha release (open-telemetry#189) Update Contributing.md doc (open-telemetry#194) Add **simple** client/server examples (open-telemetry#191) Remove unused dev-requirements.txt (open-telemetry#200) The requirements are contained in tox.ini now. Fx bug in BoundedList for Python 3.4 and add tests (open-telemetry#199) * fix bug in BoundedList for python 3.4 and add tests collections.deque.copy() was introduced in python 3.5, this commit changes that by the deque constructor and adds some tests to BoundedList and BoundedDict to avoid similar problems in the future. Also, improve docstrings of BoundedList and BoundedDict classes Move util.time_ns to API. (open-telemetry#205) Add Jaeger exporter (open-telemetry#174) This adds a Jeager exporter for OpenTelemetry. This exporter is based on https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-jaeger. The exporter uses thrift and can be configured to send data to the agent and also to a remote collector. There is a long discussion going on about how to include generated files in the repo, so for now just put them here. Add code coverage Revert latest commit Fix some "errors" found by mypy. (open-telemetry#204) Fix some errors found by mypy (split from open-telemetry#201). Update README for new milestones (open-telemetry#218) Refactor current span handling for newly created spans. (open-telemetry#198) 1. Make Tracer.start_span() simply create and start the Span, without setting it as the current instance. 2. Add an extra Tracer.start_as_current_span() to create the Span and set it as the current instance automatically. Co-Authored-By: Chris Kleinknecht <[email protected]> Add set_status to Span (open-telemetry#213) Initial commit Initial version
without setting it as the current instance.
Span and set it as the current instance automatically.
Notes:
Span
implement the context manager interface so it can be used inwith
blocks, by simply ending it.end_on_close
parameter forstart_as_current_span()
- I think this should stay as an advanced scenario, which can be obtained by directly usinguse_span()
.Span
creation tests to useTracer.start_span()
. instead, and have extra (minimalistic) tests forstart_as_current_span()
that simply assert the currentSpan
handling.