-
Notifications
You must be signed in to change notification settings - Fork 705
Implement IdsGenerator interface for TracerProvider and include default RandomIdsGenerator #1153
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
opentelemetry.trace.ids_generator | ||
================================= | ||
|
||
.. automodule:: opentelemetry.trace.ids_generator | ||
:members: | ||
:undoc-members: | ||
:show-inheritance: |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ Submodules | |
|
||
trace.status | ||
trace.span | ||
trace.ids_generator | ||
|
||
Module contents | ||
--------------- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright The OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import abc | ||
import random | ||
|
||
|
||
class IdsGenerator(abc.ABC): | ||
@abc.abstractmethod | ||
def generate_span_id(self) -> int: | ||
"""Get a new span ID. | ||
|
||
Returns: | ||
A 64-bit int for use as a span ID | ||
""" | ||
|
||
@abc.abstractmethod | ||
def generate_trace_id(self) -> int: | ||
"""Get a new trace ID. | ||
|
||
Implementations should at least make the 64 least significant bits | ||
uniformly random. Samplers like the `TraceIdRatioBased` sampler rely on | ||
this randomness to make sampling decisions. | ||
|
||
See `the specification on TraceIdRatioBased <https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#traceidratiobased>`_. | ||
|
||
Returns: | ||
A 128-bit int for use as a trace ID | ||
NathanielRN marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
|
||
|
||
class RandomIdsGenerator(IdsGenerator): | ||
"""The default IDs generator for TracerProvider which randomly generates all | ||
bits when generating IDs. | ||
""" | ||
|
||
def generate_span_id(self) -> int: | ||
return random.getrandbits(64) | ||
|
||
def generate_trace_id(self) -> int: | ||
return random.getrandbits(128) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -663,24 +663,6 @@ def record_exception(self, exception: Exception) -> None: | |
) | ||
|
||
|
||
def generate_span_id() -> int: | ||
"""Get a new random span ID. | ||
|
||
Returns: | ||
A random 64-bit int for use as a span ID | ||
""" | ||
return random.getrandbits(64) | ||
|
||
|
||
def generate_trace_id() -> int: | ||
"""Get a new random trace ID. | ||
|
||
Returns: | ||
A random 128-bit int for use as a trace ID | ||
""" | ||
return random.getrandbits(128) | ||
|
||
|
||
class Tracer(trace_api.Tracer): | ||
"""See `opentelemetry.trace.Tracer`. | ||
|
||
|
@@ -733,7 +715,7 @@ def start_span( # pylint: disable=too-many-locals | |
|
||
if parent_context is None or not parent_context.is_valid: | ||
parent = parent_context = None | ||
trace_id = generate_trace_id() | ||
trace_id = self.source.ids_generator.generate_trace_id() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this isn't part of the tracer provider API as far as I can tell from this PR, we can't guarantee that source will have an ids_generator attribute. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point, but this is just being consistent with the assumption later in this file for the Even so, I think we can guarantee the I think that the only danger that could come about would be if you were to implement your own There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think this guarantees anything really. It's only a type hint and makes mypy or other checkers complain if they are run. There is no runtime or build/package time guarantees.
Another instance would be if someone implements a custom TracerProvider to add some functionality but wanted to return instance of the stock Tracer. I think both cases should be supported without surprises. Looks like SDK Tracer has taken an implicit dependency on the SDK TracerProvider which shouldn't be the case. Users and vendors should be able to implement just one or the other without having to satisfy undocumented APIs. I think we should either update the TracerProvider API to specify all these properties or go all in on DI and modify Tracer so that it requires all these dependencies to be explicitly specified by a tracer provider implementation. Meaning IDGenerator would be an initialization argument to the Tracer class. TracerProvider can pass it down explicitly. That way people can implement custom Tracer or custom TracerProvider without surprises. Since there are other instances of such implicit dependencies, may be we can do this in another PR but if all maintainers agree some solution now, perhaps we can start with IDGenerator now and follow up with the rest. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah we should probably remove source from both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see what you're saying, yes it makes more sense to have I would also prefer to have that as a separate PR, and minimize the new things this PR is trying to do. The PR is pretty straightforward the way it is right now, and that kind of refactor could be lost in the IDs Generator specific log messages. I wouldn't mind helping with doing that separate PR either if we can decide on what we want to do! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good to me. Tracking here: #1181 |
||
trace_flags = None | ||
trace_state = None | ||
else: | ||
|
@@ -757,7 +739,7 @@ def start_span( # pylint: disable=too-many-locals | |
) | ||
context = trace_api.SpanContext( | ||
trace_id, | ||
generate_span_id(), | ||
self.source.ids_generator.generate_span_id(), | ||
is_remote=False, | ||
trace_flags=trace_flags, | ||
trace_state=trace_state, | ||
|
@@ -826,10 +808,15 @@ def __init__( | |
active_span_processor: Union[ | ||
SynchronousMultiSpanProcessor, ConcurrentMultiSpanProcessor | ||
] = None, | ||
ids_generator: trace_api.IdsGenerator = None, | ||
): | ||
self._active_span_processor = ( | ||
active_span_processor or SynchronousMultiSpanProcessor() | ||
) | ||
if ids_generator is None: | ||
self.ids_generator = trace_api.RandomIdsGenerator() | ||
else: | ||
self.ids_generator = ids_generator | ||
self.resource = resource | ||
self.sampler = sampler | ||
self._atexit_handler = None | ||
|
Uh oh!
There was an error while loading. Please reload this page.
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.
Adding it to the docs here for visibility. Also because both
span.py
is added and they are in the same directory level and similar in that they both define an interface.