Skip to content

Commit 191a55c

Browse files
authored
Default configurators do more for distros (#1937)
1 parent 566df33 commit 191a55c

File tree

5 files changed

+181
-148
lines changed

5 files changed

+181
-148
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.4.0-0.23b0...HEAD)
8+
- `opentelemetry-distro` & `opentelemetry-sdk` Moved Auto Instrumentation Configurator code to SDK
9+
to let distros use its default implementation
10+
([#1937](https://github.com/open-telemetry/opentelemetry-python/pull/1937))
811

912
## [1.4.0-0.23b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.4.0-0.23b0) - 2021-07-21
1013

opentelemetry-distro/setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ where = src
5252
opentelemetry_distro =
5353
distro = opentelemetry.distro:OpenTelemetryDistro
5454
opentelemetry_configurator =
55-
configurator = opentelemetry.distro:Configurator
55+
configurator = opentelemetry.distro:OpenTelemetryConfigurator
5656

5757
[options.extras_require]
5858
test =

opentelemetry-distro/src/opentelemetry/distro/__init__.py

Lines changed: 4 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -13,144 +13,14 @@
1313
# limitations under the License.
1414
#
1515
import os
16-
from logging import getLogger
17-
from os import environ
18-
from typing import Sequence, Tuple
1916

20-
from pkg_resources import iter_entry_points
21-
22-
from opentelemetry import trace
23-
from opentelemetry.environment_variables import (
24-
OTEL_PYTHON_ID_GENERATOR,
25-
OTEL_TRACES_EXPORTER,
26-
)
27-
from opentelemetry.instrumentation.configurator import BaseConfigurator
17+
from opentelemetry.environment_variables import OTEL_TRACES_EXPORTER
2818
from opentelemetry.instrumentation.distro import BaseDistro
29-
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
30-
from opentelemetry.sdk.trace import TracerProvider
31-
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
32-
from opentelemetry.sdk.trace.id_generator import IdGenerator
33-
34-
logger = getLogger(__file__)
35-
36-
37-
EXPORTER_OTLP = "otlp"
38-
EXPORTER_OTLP_SPAN = "otlp_proto_grpc_span"
39-
40-
RANDOM_ID_GENERATOR = "random"
41-
_DEFAULT_ID_GENERATOR = RANDOM_ID_GENERATOR
42-
43-
44-
def _get_id_generator() -> str:
45-
return environ.get(OTEL_PYTHON_ID_GENERATOR, _DEFAULT_ID_GENERATOR)
46-
47-
48-
def _get_exporter_names() -> Sequence[str]:
49-
trace_exporters = environ.get(OTEL_TRACES_EXPORTER)
50-
51-
exporters = set()
52-
53-
if trace_exporters and trace_exporters.lower().strip() != "none":
54-
exporters.update(
55-
{
56-
trace_exporter.strip()
57-
for trace_exporter in trace_exporters.split(",")
58-
}
59-
)
60-
61-
if EXPORTER_OTLP in exporters:
62-
exporters.remove(EXPORTER_OTLP)
63-
exporters.add(EXPORTER_OTLP_SPAN)
64-
65-
return list(exporters)
66-
67-
68-
def _init_tracing(
69-
exporters: Sequence[SpanExporter], id_generator: IdGenerator
70-
):
71-
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
72-
# from the env variable else defaults to "unknown_service"
73-
provider = TracerProvider(
74-
id_generator=id_generator(),
75-
)
76-
trace.set_tracer_provider(provider)
77-
78-
for _, exporter_class in exporters.items():
79-
exporter_args = {}
80-
provider.add_span_processor(
81-
BatchSpanProcessor(exporter_class(**exporter_args))
82-
)
19+
from opentelemetry.sdk._configuration import _OTelSDKConfigurator
8320

8421

85-
def _import_tracer_provider_config_components(
86-
selected_components, entry_point_name
87-
) -> Sequence[Tuple[str, object]]:
88-
component_entry_points = {
89-
ep.name: ep for ep in iter_entry_points(entry_point_name)
90-
}
91-
component_impls = []
92-
for selected_component in selected_components:
93-
entry_point = component_entry_points.get(selected_component, None)
94-
if not entry_point:
95-
raise RuntimeError(
96-
"Requested component '{}' not found in entry points for '{}'".format(
97-
selected_component, entry_point_name
98-
)
99-
)
100-
101-
component_impl = entry_point.load()
102-
component_impls.append((selected_component, component_impl))
103-
104-
return component_impls
105-
106-
107-
def _import_exporters(
108-
exporter_names: Sequence[str],
109-
) -> Sequence[SpanExporter]:
110-
trace_exporters = {}
111-
112-
for (
113-
exporter_name,
114-
exporter_impl,
115-
) in _import_tracer_provider_config_components(
116-
exporter_names, "opentelemetry_exporter"
117-
):
118-
if issubclass(exporter_impl, SpanExporter):
119-
trace_exporters[exporter_name] = exporter_impl
120-
else:
121-
raise RuntimeError(
122-
"{0} is not a trace exporter".format(exporter_name)
123-
)
124-
return trace_exporters
125-
126-
127-
def _import_id_generator(id_generator_name: str) -> IdGenerator:
128-
# pylint: disable=unbalanced-tuple-unpacking
129-
[
130-
(id_generator_name, id_generator_impl)
131-
] = _import_tracer_provider_config_components(
132-
[id_generator_name.strip()], "opentelemetry_id_generator"
133-
)
134-
135-
if issubclass(id_generator_impl, IdGenerator):
136-
return id_generator_impl
137-
138-
raise RuntimeError("{0} is not an IdGenerator".format(id_generator_name))
139-
140-
141-
def _initialize_components():
142-
exporter_names = _get_exporter_names()
143-
trace_exporters = _import_exporters(exporter_names)
144-
id_generator_name = _get_id_generator()
145-
id_generator = _import_id_generator(id_generator_name)
146-
_init_tracing(trace_exporters, id_generator)
147-
148-
149-
class Configurator(BaseConfigurator):
150-
151-
# pylint: disable=no-self-use
152-
def _configure(self, **kwargs):
153-
_initialize_components()
22+
class OpenTelemetryConfigurator(_OTelSDKConfigurator):
23+
pass
15424

15525

15626
class OpenTelemetryDistro(BaseDistro):
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
"""
17+
OpenTelemetry SDK Configurator for Easy Instrumentation with Distros
18+
"""
19+
20+
from os import environ
21+
from typing import Sequence, Tuple
22+
23+
from pkg_resources import iter_entry_points
24+
25+
from opentelemetry import trace
26+
from opentelemetry.environment_variables import (
27+
OTEL_PYTHON_ID_GENERATOR,
28+
OTEL_TRACES_EXPORTER,
29+
)
30+
from opentelemetry.instrumentation.configurator import BaseConfigurator
31+
from opentelemetry.sdk.trace import TracerProvider
32+
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
33+
from opentelemetry.sdk.trace.id_generator import IdGenerator
34+
35+
_EXPORTER_OTLP = "otlp"
36+
_EXPORTER_OTLP_SPAN = "otlp_proto_grpc_span"
37+
38+
_RANDOM_ID_GENERATOR = "random"
39+
_DEFAULT_ID_GENERATOR = _RANDOM_ID_GENERATOR
40+
41+
42+
def _get_id_generator() -> str:
43+
return environ.get(OTEL_PYTHON_ID_GENERATOR, _DEFAULT_ID_GENERATOR)
44+
45+
46+
def _get_exporter_names() -> Sequence[str]:
47+
trace_exporters = environ.get(OTEL_TRACES_EXPORTER)
48+
49+
exporters = set()
50+
51+
if trace_exporters and trace_exporters.lower().strip() != "none":
52+
exporters.update(
53+
{
54+
trace_exporter.strip()
55+
for trace_exporter in trace_exporters.split(",")
56+
}
57+
)
58+
59+
if _EXPORTER_OTLP in exporters:
60+
exporters.remove(_EXPORTER_OTLP)
61+
exporters.add(_EXPORTER_OTLP_SPAN)
62+
63+
return list(exporters)
64+
65+
66+
def _init_tracing(
67+
exporters: Sequence[SpanExporter], id_generator: IdGenerator
68+
):
69+
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
70+
# from the env variable else defaults to "unknown_service"
71+
provider = TracerProvider(
72+
id_generator=id_generator(),
73+
)
74+
trace.set_tracer_provider(provider)
75+
76+
for _, exporter_class in exporters.items():
77+
exporter_args = {}
78+
provider.add_span_processor(
79+
BatchSpanProcessor(exporter_class(**exporter_args))
80+
)
81+
82+
83+
def _import_tracer_provider_config_components(
84+
selected_components, entry_point_name
85+
) -> Sequence[Tuple[str, object]]:
86+
component_entry_points = {
87+
ep.name: ep for ep in iter_entry_points(entry_point_name)
88+
}
89+
component_impls = []
90+
for selected_component in selected_components:
91+
entry_point = component_entry_points.get(selected_component, None)
92+
if not entry_point:
93+
raise RuntimeError(
94+
"Requested component '{}' not found in entry points for '{}'".format(
95+
selected_component, entry_point_name
96+
)
97+
)
98+
99+
component_impl = entry_point.load()
100+
component_impls.append((selected_component, component_impl))
101+
102+
return component_impls
103+
104+
105+
def _import_exporters(
106+
exporter_names: Sequence[str],
107+
) -> Sequence[SpanExporter]:
108+
trace_exporters = {}
109+
110+
for (
111+
exporter_name,
112+
exporter_impl,
113+
) in _import_tracer_provider_config_components(
114+
exporter_names, "opentelemetry_exporter"
115+
):
116+
if issubclass(exporter_impl, SpanExporter):
117+
trace_exporters[exporter_name] = exporter_impl
118+
else:
119+
raise RuntimeError(
120+
"{0} is not a trace exporter".format(exporter_name)
121+
)
122+
return trace_exporters
123+
124+
125+
def _import_id_generator(id_generator_name: str) -> IdGenerator:
126+
# pylint: disable=unbalanced-tuple-unpacking
127+
[
128+
(id_generator_name, id_generator_impl)
129+
] = _import_tracer_provider_config_components(
130+
[id_generator_name.strip()], "opentelemetry_id_generator"
131+
)
132+
133+
if issubclass(id_generator_impl, IdGenerator):
134+
return id_generator_impl
135+
136+
raise RuntimeError("{0} is not an IdGenerator".format(id_generator_name))
137+
138+
139+
def _initialize_components():
140+
exporter_names = _get_exporter_names()
141+
trace_exporters = _import_exporters(exporter_names)
142+
id_generator_name = _get_id_generator()
143+
id_generator = _import_id_generator(id_generator_name)
144+
_init_tracing(trace_exporters, id_generator)
145+
146+
147+
class _OTelSDKConfigurator(BaseConfigurator):
148+
"""A basic Configurator by OTel Python for initalizing OTel SDK components
149+
150+
Initializes several crucial OTel SDK components (i.e. TracerProvider,
151+
MeterProvider, Processors...) according to a default implementation. Other
152+
Configurators can subclass and slightly alter this initialization.
153+
154+
NOTE: This class should not be instantiated nor should it become an entry
155+
point on the `opentelemetry-sdk` package. Instead, distros should subclass
156+
this Configurator and enchance it as needed.
157+
"""
158+
159+
def _configure(self, **kwargs):
160+
_initialize_components()

opentelemetry-distro/tests/test_configurator.py renamed to opentelemetry-sdk/tests/test_configurator.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
from unittest.mock import patch
1919

2020
from opentelemetry import trace
21-
from opentelemetry.distro import (
22-
EXPORTER_OTLP,
23-
EXPORTER_OTLP_SPAN,
21+
from opentelemetry.environment_variables import (
22+
OTEL_PYTHON_ID_GENERATOR,
23+
OTEL_TRACES_EXPORTER,
24+
)
25+
from opentelemetry.sdk._configuration import (
26+
_EXPORTER_OTLP,
27+
_EXPORTER_OTLP_SPAN,
2428
_get_exporter_names,
2529
_get_id_generator,
2630
_import_id_generator,
2731
_init_tracing,
2832
)
29-
from opentelemetry.environment_variables import (
30-
OTEL_PYTHON_ID_GENERATOR,
31-
OTEL_TRACES_EXPORTER,
32-
)
3333
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
3434
from opentelemetry.sdk.trace.id_generator import IdGenerator, RandomIdGenerator
3535

@@ -87,10 +87,10 @@ class TestTraceInit(TestCase):
8787
def setUp(self):
8888
super()
8989
self.get_provider_patcher = patch(
90-
"opentelemetry.distro.TracerProvider", Provider
90+
"opentelemetry.sdk._configuration.TracerProvider", Provider
9191
)
9292
self.get_processor_patcher = patch(
93-
"opentelemetry.distro.BatchSpanProcessor", Processor
93+
"opentelemetry.sdk._configuration.BatchSpanProcessor", Processor
9494
)
9595
self.set_provider_patcher = patch(
9696
"opentelemetry.trace.set_tracer_provider"
@@ -143,8 +143,8 @@ def test_trace_init_otlp(self):
143143
)
144144

145145
@patch.dict(environ, {OTEL_PYTHON_ID_GENERATOR: "custom_id_generator"})
146-
@patch("opentelemetry.distro.IdGenerator", new=IdGenerator)
147-
@patch("opentelemetry.distro.iter_entry_points")
146+
@patch("opentelemetry.sdk._configuration.IdGenerator", new=IdGenerator)
147+
@patch("opentelemetry.sdk._configuration.iter_entry_points")
148148
def test_trace_init_custom_id_generator(self, mock_iter_entry_points):
149149
mock_iter_entry_points.configure_mock(
150150
return_value=[
@@ -160,9 +160,9 @@ def test_trace_init_custom_id_generator(self, mock_iter_entry_points):
160160

161161
class TestExporterNames(TestCase):
162162
def test_otlp_exporter_overwrite(self):
163-
for exporter in [EXPORTER_OTLP, EXPORTER_OTLP_SPAN]:
163+
for exporter in [_EXPORTER_OTLP, _EXPORTER_OTLP_SPAN]:
164164
with patch.dict(environ, {OTEL_TRACES_EXPORTER: exporter}):
165-
self.assertEqual(_get_exporter_names(), [EXPORTER_OTLP_SPAN])
165+
self.assertEqual(_get_exporter_names(), [_EXPORTER_OTLP_SPAN])
166166

167167
@patch.dict(environ, {OTEL_TRACES_EXPORTER: "jaeger,zipkin"})
168168
def test_multiple_exporters(self):

0 commit comments

Comments
 (0)