Skip to content

Commit da7597c

Browse files
authored
Add IDs Generator as Configurable Property of Auto Instrumentation (open-telemetry#1404)
1 parent 4afa775 commit da7597c

File tree

6 files changed

+131
-17
lines changed

6 files changed

+131
-17
lines changed

opentelemetry-api/setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ opentelemetry_tracer_provider =
5757
opentelemetry_propagator =
5858
tracecontext = opentelemetry.trace.propagation.tracecontext:TraceContextTextMapPropagator
5959
baggage = opentelemetry.baggage.propagation:BaggagePropagator
60+
opentelemetry_ids_generator =
61+
random = opentelemetry.trace.ids_generator:RandomIdsGenerator
6062

6163
[options.extras_require]
6264
test =

opentelemetry-instrumentation/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Add IDs Generator as Configurable Property of Auto Instrumentation
6+
([#1404](https://github.com/open-telemetry/opentelemetry-python/pull/1404))
57
- Added support for `OTEL_EXPORTER` to the `opentelemetry-instrument` command ([#1036](https://github.com/open-telemetry/opentelemetry-python/pull/1036))
68

79
## Version 0.14b0

opentelemetry-instrumentation/README.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ Well known trace exporter names:
7373

7474
When present the value is passed on to the relevant exporter initializer as ``service_name`` argument.
7575

76+
* ``--ids-generator`` or ``OTEL_IDS_GENERATOR``
77+
78+
Used to specify which IDs Generator to use for the global Tracer Provider. By default, it
79+
will use the random IDs generator.
80+
7681
The code in ``program.py`` needs to use one of the packages for which there is
7782
an OpenTelemetry integration. For a list of the available integrations please
7883
check `here <https://opentelemetry-python.readthedocs.io/en/stable/index.html#integrations>`_
@@ -93,6 +98,13 @@ The above command will pass ``-e otlp`` to the instrument command and ``--port=3
9398
The above command will configure global trace provider, attach zipkin and otlp exporters to it and then
9499
start celery with the rest of the arguments.
95100

101+
::
102+
103+
opentelemetry-instrument --ids-generator random flask run --port=3000
104+
105+
The above command will configure the global trace provider to use the Random IDs Generator, and then
106+
pass ``--port=3000`` to ``flask run``.
107+
96108
References
97109
----------
98110

opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ def parse_args():
4747
""",
4848
)
4949

50+
parser.add_argument(
51+
"--ids-generator",
52+
required=False,
53+
help="""
54+
The IDs Generator to be used with the Tracer Provider.
55+
56+
Examples:
57+
58+
--ids-generator=random
59+
""",
60+
)
61+
5062
parser.add_argument(
5163
"-s",
5264
"--service-name",
@@ -70,6 +82,8 @@ def load_config_from_cli_args(args):
7082
environ["OTEL_EXPORTER"] = args.exporter
7183
if args.service_name:
7284
environ["OTEL_SERVICE_NAME"] = args.service_name
85+
if args.ids_generator:
86+
environ["OTEL_IDS_GENERATOR"] = args.ids_generator
7387

7488

7589
def run() -> None:

opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/components.py

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
EXPORTER_OTLP_METRIC = "otlp_metric"
3535
_DEFAULT_EXPORTER = EXPORTER_OTLP
3636

37+
RANDOM_IDS_GENERATOR = "random"
38+
_DEFAULT_IDS_GENERATOR = RANDOM_IDS_GENERATOR
39+
40+
41+
def get_ids_generator() -> str:
42+
return Configuration().IDS_GENERATOR or _DEFAULT_IDS_GENERATOR
43+
3744

3845
def get_service_name() -> str:
3946
return Configuration().SERVICE_NAME or ""
@@ -55,10 +62,13 @@ def get_exporter_names() -> Sequence[str]:
5562
return names
5663

5764

58-
def init_tracing(exporters: Sequence[SpanExporter]):
65+
def init_tracing(
66+
exporters: Sequence[SpanExporter], ids_generator: trace.IdsGenerator
67+
):
5968
service_name = get_service_name()
6069
provider = TracerProvider(
6170
resource=Resource.create({"service.name": service_name}),
71+
ids_generator=ids_generator(),
6272
)
6373
trace.set_tracer_provider(provider)
6474

@@ -80,23 +90,39 @@ def init_metrics(exporters: Sequence[MetricsExporter]):
8090
logger.warning("automatic metric initialization is not supported yet.")
8191

8292

83-
def import_exporters(
84-
exporter_names: Sequence[str],
85-
) -> Tuple[Sequence[SpanExporter], Sequence[MetricsExporter]]:
86-
trace_exporters, metric_exporters = {}, {}
87-
88-
exporters = {
89-
ep.name: ep for ep in iter_entry_points("opentelemetry_exporter")
93+
def import_tracer_provider_config_components(
94+
selected_components, entry_point_name
95+
) -> Sequence[Tuple[str, object]]:
96+
component_entry_points = {
97+
ep.name: ep for ep in iter_entry_points(entry_point_name)
9098
}
91-
92-
for exporter_name in exporter_names:
93-
entry_point = exporters.get(exporter_name, None)
99+
component_impls = []
100+
for selected_component in selected_components:
101+
entry_point = component_entry_points.get(selected_component, None)
94102
if not entry_point:
95103
raise RuntimeError(
96-
"Requested exporter not found: {0}".format(exporter_name)
104+
"Requested component '{}' not found in entry points for '{}'".format(
105+
selected_component, entry_point_name
106+
)
97107
)
98108

99-
exporter_impl = entry_point.load()
109+
component_impl = entry_point.load()
110+
component_impls.append((selected_component, component_impl))
111+
112+
return component_impls
113+
114+
115+
def import_exporters(
116+
exporter_names: Sequence[str],
117+
) -> Tuple[Sequence[SpanExporter], Sequence[MetricsExporter]]:
118+
trace_exporters, metric_exporters = {}, {}
119+
120+
for (
121+
exporter_name,
122+
exporter_impl,
123+
) in import_tracer_provider_config_components(
124+
exporter_names, "opentelemetry_exporter"
125+
):
100126
if issubclass(exporter_impl, SpanExporter):
101127
trace_exporters[exporter_name] = exporter_impl
102128
elif issubclass(exporter_impl, MetricsExporter):
@@ -110,10 +136,26 @@ def import_exporters(
110136
return trace_exporters, metric_exporters
111137

112138

139+
def import_ids_generator(ids_generator_name: str) -> trace.IdsGenerator:
140+
# pylint: disable=unbalanced-tuple-unpacking
141+
[
142+
(ids_generator_name, ids_generator_impl)
143+
] = import_tracer_provider_config_components(
144+
[ids_generator_name.strip()], "opentelemetry_ids_generator"
145+
)
146+
147+
if issubclass(ids_generator_impl, trace.IdsGenerator):
148+
return ids_generator_impl
149+
150+
raise RuntimeError("{0} is not an IdsGenerator".format(ids_generator_name))
151+
152+
113153
def initialize_components():
114154
exporter_names = get_exporter_names()
115155
trace_exporters, metric_exporters = import_exporters(exporter_names)
116-
init_tracing(trace_exporters)
156+
ids_generator_name = get_ids_generator()
157+
ids_generator = import_ids_generator(ids_generator_name)
158+
init_tracing(trace_exporters, ids_generator)
117159

118160
# We don't support automatic initialization for metric yet but have added
119161
# some boilerplate in order to make sure current implementation does not

opentelemetry-instrumentation/tests/test_auto_tracing.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
from opentelemetry.configuration import Configuration
2121
from opentelemetry.instrumentation.auto_instrumentation import components
2222
from opentelemetry.sdk.resources import Resource
23+
from opentelemetry.trace.ids_generator import RandomIdsGenerator
2324

2425

2526
class Provider:
26-
def __init__(self, resource=None):
27+
def __init__(self, resource=None, ids_generator=None):
28+
self.ids_generator = ids_generator
2729
self.processor = None
2830
self.resource = resource
2931

@@ -48,6 +50,23 @@ class OTLPExporter:
4850
pass
4951

5052

53+
class IdsGenerator:
54+
pass
55+
56+
57+
class CustomIdsGenerator(IdsGenerator):
58+
pass
59+
60+
61+
class IterEntryPoint:
62+
def __init__(self, name, class_type):
63+
self.name = name
64+
self.class_type = class_type
65+
66+
def load(self):
67+
return self.class_type
68+
69+
5170
class TestTraceInit(TestCase):
5271
def setUp(self):
5372
super()
@@ -77,11 +96,12 @@ def tearDown(self):
7796
def test_trace_init_default(self):
7897
environ["OTEL_SERVICE_NAME"] = "my-test-service"
7998
Configuration._reset()
80-
components.init_tracing({"zipkin": Exporter})
99+
components.init_tracing({"zipkin": Exporter}, RandomIdsGenerator)
81100

82101
self.assertEqual(self.set_provider_mock.call_count, 1)
83102
provider = self.set_provider_mock.call_args[0][0]
84103
self.assertIsInstance(provider, Provider)
104+
self.assertIsInstance(provider.ids_generator, RandomIdsGenerator)
85105
self.assertIsInstance(provider.processor, Processor)
86106
self.assertIsInstance(provider.processor.exporter, Exporter)
87107
self.assertEqual(
@@ -91,11 +111,12 @@ def test_trace_init_default(self):
91111
def test_trace_init_otlp(self):
92112
environ["OTEL_SERVICE_NAME"] = "my-otlp-test-service"
93113
Configuration._reset()
94-
components.init_tracing({"otlp": OTLPExporter})
114+
components.init_tracing({"otlp": OTLPExporter}, RandomIdsGenerator)
95115

96116
self.assertEqual(self.set_provider_mock.call_count, 1)
97117
provider = self.set_provider_mock.call_args[0][0]
98118
self.assertIsInstance(provider, Provider)
119+
self.assertIsInstance(provider.ids_generator, RandomIdsGenerator)
99120
self.assertIsInstance(provider.processor, Processor)
100121
self.assertIsInstance(provider.processor.exporter, OTLPExporter)
101122
self.assertIsInstance(provider.resource, Resource)
@@ -104,3 +125,24 @@ def test_trace_init_otlp(self):
104125
"my-otlp-test-service",
105126
)
106127
del environ["OTEL_SERVICE_NAME"]
128+
129+
@patch.dict(environ, {"OTEL_IDS_GENERATOR": "custom_ids_generator"})
130+
@patch(
131+
"opentelemetry.instrumentation.auto_instrumentation.components.trace.IdsGenerator",
132+
new=IdsGenerator,
133+
)
134+
@patch(
135+
"opentelemetry.instrumentation.auto_instrumentation.components.iter_entry_points"
136+
)
137+
def test_trace_init_custom_ids_generator(self, mock_iter_entry_points):
138+
mock_iter_entry_points.configure_mock(
139+
return_value=[
140+
IterEntryPoint("custom_ids_generator", CustomIdsGenerator)
141+
]
142+
)
143+
Configuration._reset()
144+
ids_generator_name = components.get_ids_generator()
145+
ids_generator = components.import_ids_generator(ids_generator_name)
146+
components.init_tracing({}, ids_generator)
147+
provider = self.set_provider_mock.call_args[0][0]
148+
self.assertIsInstance(provider.ids_generator, CustomIdsGenerator)

0 commit comments

Comments
 (0)