Skip to content
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

Merged
merged 6 commits into from
Oct 15, 2019

Conversation

carlosalberto
Copy link
Contributor

  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.

Notes:

  • Made Span implement the context manager interface so it can be used in with blocks, by simply ending it.
  • No end_on_close parameter for start_as_current_span() - I think this should stay as an advanced scenario, which can be obtained by directly using use_span().
  • I'm not totally bought on the name, so feel free to suggest a better name ;)
  • Refactored the Span creation tests to use Tracer.start_span() . instead, and have extra (minimalistic) tests for start_as_current_span() that simply assert the current Span handling.

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.
Copy link
Member

@c24t c24t left a 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.
Copy link
Member

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.

Copy link
Contributor Author

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Copy link
Contributor Author

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
Copy link
Member

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)

Copy link
Contributor Author

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) -> 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.

Copy link
Contributor Author

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 ;) )

opentelemetry-api/src/opentelemetry/trace/__init__.py Outdated Show resolved Hide resolved
# pylint: disable=unused-argument,no-self-use
return INVALID_SPAN

@contextmanager # type: ignore
Copy link
Member

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?

Copy link
Contributor Author

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 <libc@google.com>
@carlosalberto
Copy link
Contributor Author

So I'd have no problem making start_as_current_span() the default, as long as the 'standard' start_span() does not set the new Span as the current one (to keep uniformity with other implementations). And yeah, I'd also expect more calls to start_as_current_span().

(Btw, in OpenTracing we had start_active_span() which was fine for us, but using start_current_span() will probably not be a popular choice here ;) )

@Oberon00
Copy link
Member

Oberon00 commented Oct 3, 2019

Seeing open-telemetry/opentelemetry-specification#21, what about instead of having a start_as_current_span on the tracer, we just have start_span on the tracer (that starts a new span but does not set it as active) and instead of having Tracer.use_span, we have Span.use() with the same functionality (implicitly using the Tracer that created the span). Then you would write a typical example like this:

with tracer().start_span("foo").use() as span:
   span.set_attribute("foo", "bar")

return span

@contextmanager
def start_as_current_span(
Copy link
Member

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

Copy link
Member

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.

Copy link
Member

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".

Copy link
Member

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.

Copy link
Member

@reyang reyang left a 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?

Copy link
Member

@Oberon00 Oberon00 left a 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":
Copy link
Member

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`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd re-add

Suggested change
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)
Copy link
Member

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).

Copy link
Contributor Author

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(
Copy link
Member

@Oberon00 Oberon00 Oct 10, 2019

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"]:
Copy link
Member

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

Copy link
Contributor Author

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)

Copy link
Member

@Oberon00 Oberon00 Oct 10, 2019

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.

Copy link
Contributor Author

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 ;)

Copy link
Member

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--> #219

@carlosalberto
Copy link
Contributor Author

So I think this is ready to go, after applying the latest of @Oberon00 's feedback.

We can iterate the the mypy/start_as_current_span() in the API changes in other PRs. Let me know ;)

@Oberon00 Oberon00 merged commit 63f559e into open-telemetry:master Oct 15, 2019
hectorhdzg added a commit to hectorhdzg/opentelemetry-python that referenced this pull request Oct 21, 2019
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 <reyang@microsoft.com>
Co-Authored-By: Chris Kleinknecht <libc@google.com>

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 <libc@google.com>

Add set_status to Span (open-telemetry#213)

Initial commit

Initial version
srikanthccv pushed a commit to srikanthccv/opentelemetry-python that referenced this pull request Nov 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants