Skip to content

Commit

Permalink
Implement IdsGenerator interface for TracerProvider and include defau…
Browse files Browse the repository at this point in the history
…lt RandomIdsGenerator (#1153)
  • Loading branch information
NathanielRN authored Oct 1, 2020
1 parent 0e0c3e3 commit c8df54b
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 42 deletions.
7 changes: 7 additions & 0 deletions docs/api/trace.ids_generator.rst
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:
1 change: 1 addition & 0 deletions docs/api/trace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Submodules

trace.status
trace.span
trace.ids_generator

Module contents
---------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import opentelemetry_example_app.flask_example as flask_example
from opentelemetry import trace
from opentelemetry.sdk import trace as trace_sdk


class TestFlaskExample(unittest.TestCase):
Expand All @@ -46,7 +45,8 @@ def tearDown(self):
self.send_patcher.stop()

def test_full_path(self):
trace_id = trace_sdk.generate_trace_id()
ids_generator = trace.RandomIdsGenerator()
trace_id = ids_generator.generate_trace_id()
# We need to use the Werkzeug test app because
# The headers are injected at the wsgi layer.
# The flask test app will not include these, and
Expand All @@ -58,7 +58,7 @@ def test_full_path(self):
headers={
"traceparent": "00-{:032x}-{:016x}-{:02x}".format(
trace_id,
trace_sdk.generate_span_id(),
ids_generator.generate_span_id(),
trace.TraceFlags.SAMPLED,
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ def get_as_list(dict_object, key):
class TestDatadogFormat(unittest.TestCase):
@classmethod
def setUpClass(cls):
ids_generator = trace_api.RandomIdsGenerator()
cls.serialized_trace_id = propagator.format_trace_id(
trace.generate_trace_id()
ids_generator.generate_trace_id()
)
cls.serialized_parent_id = propagator.format_span_id(
trace.generate_span_id()
ids_generator.generate_span_id()
)
cls.serialized_origin = "origin-service"

Expand Down Expand Up @@ -107,7 +108,7 @@ def test_context_propagation(self):
"child",
trace_api.SpanContext(
parent_context.trace_id,
trace.generate_span_id(),
trace_api.RandomIdsGenerator().generate_span_id(),
is_remote=False,
trace_flags=parent_context.trace_flags,
trace_state=parent_context.trace_state,
Expand Down Expand Up @@ -152,7 +153,7 @@ def test_sampling_priority_auto_reject(self):
"child",
trace_api.SpanContext(
parent_context.trace_id,
trace.generate_span_id(),
trace_api.RandomIdsGenerator().generate_span_id(),
is_remote=False,
trace_flags=parent_context.trace_flags,
trace_state=parent_context.trace_state,
Expand Down
2 changes: 2 additions & 0 deletions opentelemetry-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
([#1123](https://github.com/open-telemetry/opentelemetry-python/pull/1123))
- Store `int`s as `int`s in the global Configuration object
([#1118](https://github.com/open-telemetry/opentelemetry-python/pull/1118))
- Allow for Custom Trace and Span IDs Generation - `IdsGenerator` for TracerProvider
([#1153](https://github.com/open-telemetry/opentelemetry-python/pull/1153))

## Version 0.13b0

Expand Down
3 changes: 3 additions & 0 deletions opentelemetry-api/src/opentelemetry/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
from contextlib import contextmanager
from logging import getLogger

from opentelemetry.trace.ids_generator import IdsGenerator, RandomIdsGenerator
from opentelemetry.trace.propagation import (
get_current_span,
set_span_in_context,
Expand Down Expand Up @@ -436,6 +437,7 @@ def get_tracer_provider() -> TracerProvider:
__all__ = [
"DEFAULT_TRACE_OPTIONS",
"DEFAULT_TRACE_STATE",
"IdsGenerator",
"INVALID_SPAN",
"INVALID_SPAN_CONTEXT",
"INVALID_SPAN_ID",
Expand All @@ -446,6 +448,7 @@ def get_tracer_provider() -> TracerProvider:
"Link",
"LinkBase",
"ParentSpan",
"RandomIdsGenerator",
"Span",
"SpanContext",
"SpanKind",
Expand Down
52 changes: 52 additions & 0 deletions opentelemetry-api/src/opentelemetry/trace/ids_generator.py
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
"""


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)
2 changes: 2 additions & 0 deletions opentelemetry-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
([#1128](https://github.com/open-telemetry/opentelemetry-python/pull/1128))
- Add support for `OTEL_BSP_MAX_QUEUE_SIZE`, `OTEL_BSP_SCHEDULE_DELAY_MILLIS`, `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` and `OTEL_BSP_EXPORT_TIMEOUT_MILLIS` environment variables
([#1105](https://github.com/open-telemetry/opentelemetry-python/pull/1120))
- Allow for Custom Trace and Span IDs Generation - `IdsGenerator` for TracerProvider
([#1153](https://github.com/open-telemetry/opentelemetry-python/pull/1153))

## Version 0.13b0

Expand Down
27 changes: 7 additions & 20 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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()
trace_flags = None
trace_state = None
else:
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import opentelemetry.trace as trace
from opentelemetry.context import Context
from opentelemetry.sdk.trace import generate_span_id, generate_trace_id
from opentelemetry.trace.propagation.textmap import (
Getter,
Setter,
Expand Down Expand Up @@ -103,8 +102,9 @@ def extract(
self._trace_id_regex.fullmatch(trace_id) is None
or self._span_id_regex.fullmatch(span_id) is None
):
trace_id = generate_trace_id()
span_id = generate_span_id()
ids_generator = trace.get_tracer_provider().ids_generator
trace_id = ids_generator.generate_trace_id()
span_id = ids_generator.generate_span_id()
sampled = "0"

else:
Expand Down
25 changes: 17 additions & 8 deletions opentelemetry-sdk/tests/trace/propagation/test_b3_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_child_parent_new_carrier(old_carrier):
"child",
trace_api.SpanContext(
parent_context.trace_id,
trace.generate_span_id(),
trace_api.RandomIdsGenerator().generate_span_id(),
is_remote=False,
trace_flags=parent_context.trace_flags,
trace_state=parent_context.trace_state,
Expand All @@ -56,14 +56,15 @@ def get_child_parent_new_carrier(old_carrier):
class TestB3Format(unittest.TestCase):
@classmethod
def setUpClass(cls):
ids_generator = trace_api.RandomIdsGenerator()
cls.serialized_trace_id = b3_format.format_trace_id(
trace.generate_trace_id()
ids_generator.generate_trace_id()
)
cls.serialized_span_id = b3_format.format_span_id(
trace.generate_span_id()
ids_generator.generate_span_id()
)
cls.serialized_parent_id = b3_format.format_span_id(
trace.generate_span_id()
ids_generator.generate_span_id()
)

def test_extract_multi_header(self):
Expand Down Expand Up @@ -246,8 +247,12 @@ def test_missing_trace_id(self):
span_context = trace_api.get_current_span(ctx).get_context()
self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID)

@patch("opentelemetry.sdk.trace.propagation.b3_format.generate_trace_id")
@patch("opentelemetry.sdk.trace.propagation.b3_format.generate_span_id")
@patch(
"opentelemetry.sdk.trace.propagation.b3_format.trace.RandomIdsGenerator.generate_trace_id"
)
@patch(
"opentelemetry.sdk.trace.propagation.b3_format.trace.RandomIdsGenerator.generate_span_id"
)
def test_invalid_trace_id(
self, mock_generate_span_id, mock_generate_trace_id
):
Expand All @@ -268,8 +273,12 @@ def test_invalid_trace_id(
self.assertEqual(span_context.trace_id, 1)
self.assertEqual(span_context.span_id, 2)

@patch("opentelemetry.sdk.trace.propagation.b3_format.generate_trace_id")
@patch("opentelemetry.sdk.trace.propagation.b3_format.generate_span_id")
@patch(
"opentelemetry.sdk.trace.propagation.b3_format.trace.RandomIdsGenerator.generate_trace_id"
)
@patch(
"opentelemetry.sdk.trace.propagation.b3_format.trace.RandomIdsGenerator.generate_span_id"
)
def test_invalid_span_id(
self, mock_generate_span_id, mock_generate_trace_id
):
Expand Down
9 changes: 5 additions & 4 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,14 +615,15 @@ def test_invalid_event_attributes(self):
self.assertEqual(root.events[3].attributes, {"attr2": (1, 2)})

def test_links(self):
ids_generator = trace_api.RandomIdsGenerator()
other_context1 = trace_api.SpanContext(
trace_id=trace.generate_trace_id(),
span_id=trace.generate_span_id(),
trace_id=ids_generator.generate_trace_id(),
span_id=ids_generator.generate_span_id(),
is_remote=False,
)
other_context2 = trace_api.SpanContext(
trace_id=trace.generate_trace_id(),
span_id=trace.generate_span_id(),
trace_id=ids_generator.generate_trace_id(),
span_id=ids_generator.generate_span_id(),
is_remote=False,
)

Expand Down

0 comments on commit c8df54b

Please sign in to comment.