Skip to content

Commit 20a99da

Browse files
committed
Propose way to customize exporters.
1 parent f42041a commit 20a99da

File tree

8 files changed

+142
-10
lines changed

8 files changed

+142
-10
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Customizer base class for OTLP exporters.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "opentelemetry-exporter-otlp-customizer"
7+
dynamic = ["version"]
8+
description = "OpenTelemetry Collector Protobuf over gRPC Exporter"
9+
readme = "README.rst"
10+
license = {text = "Apache-2.0"}
11+
requires-python = ">=3.8"
12+
authors = [
13+
{ name = "OpenTelemetry Authors", email = "[email protected]" },
14+
]
15+
classifiers = [
16+
"Development Status :: 5 - Production/Stable",
17+
"Framework :: OpenTelemetry",
18+
"Framework :: OpenTelemetry :: Exporters",
19+
"Intended Audience :: Developers",
20+
"License :: OSI Approved :: Apache Software License",
21+
"Programming Language :: Python",
22+
"Programming Language :: Python :: 3",
23+
"Programming Language :: Python :: 3.8",
24+
"Programming Language :: Python :: 3.9",
25+
"Programming Language :: Python :: 3.10",
26+
"Programming Language :: Python :: 3.11",
27+
"Programming Language :: Python :: 3.12",
28+
"Programming Language :: Python :: 3.13",
29+
]
30+
dependencies = [
31+
"opentelemetry-exporter-otlp-proto-grpc == 1.30.0",
32+
"opentelemetry-exporter-otlp-proto-http == 1.30.0",
33+
]
34+
35+
[project.entry-points.opentelemetry_exporter_otlp_customizer]
36+
otlp = "opentelemetry.exporter.otlp.customizer:OTLPExporterCustomizerBase"
37+
38+
[project.urls]
39+
Homepage = "https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-otlp-proto-grpc"
40+
Repository = "https://github.com/open-telemetry/opentelemetry-python"
41+
42+
[tool.hatch.version]
43+
path = "src/opentelemetry/exporter/otlp/customizer/version/__init__.py"
44+
45+
[tool.hatch.build.targets.sdist]
46+
include = [
47+
"/src",
48+
"/tests",
49+
]
50+
51+
[tool.hatch.build.targets.wheel]
52+
packages = ["src/opentelemetry"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from abc import ABC
2+
from typing import Union
3+
4+
from opentelemetry.exporter.otlp.proto.http._log_exporter import (
5+
OTLPLogExporter,
6+
)
7+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import (
8+
OTLPMetricExporter,
9+
)
10+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
11+
OTLPSpanExporter,
12+
)
13+
14+
# TODO: import grpc exporters.
15+
16+
BaseOTLPExporters = Union[
17+
OTLPLogExporter, OTLPSpanExporter, OTLPMetricExporter
18+
]
19+
20+
21+
class OTLPExporterCustomizerBase(ABC):
22+
def customize_exporter(exporter: BaseOTLPExporters):
23+
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
__version__ = "1.30.0"

opentelemetry-sdk/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ classifiers = [
2828
"Typing :: Typed",
2929
]
3030
dependencies = [
31-
"opentelemetry-api == 1.31.0.dev",
32-
"opentelemetry-semantic-conventions == 0.52b0.dev",
31+
"opentelemetry-api == 1.30.0",
32+
"opentelemetry-semantic-conventions == 0.51b0",
3333
"typing-extensions >= 3.7.4",
3434
]
3535

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
4646
OTEL_TRACES_SAMPLER,
4747
OTEL_TRACES_SAMPLER_ARG,
48+
OTEL_EXPORTER_CUSTOMIZER,
49+
)
50+
from opentelemetry.exporter.otlp.customizer import (
51+
BaseOTLPExporters,
52+
OTLPExporterCustomizerBase,
4853
)
4954
from opentelemetry.sdk.metrics import MeterProvider
5055
from opentelemetry.sdk.metrics.export import (
@@ -90,6 +95,13 @@
9095
_logger = logging.getLogger(__name__)
9196

9297

98+
def _import_config_component(
99+
selected_component: str, entry_point_name: str
100+
) -> object:
101+
return _import_config_components([selected_component], entry_point_name)[
102+
0
103+
][1]
104+
93105
def _import_config_components(
94106
selected_components: List[str], entry_point_name: str
95107
) -> Sequence[Tuple[str, object]]:
@@ -194,6 +206,7 @@ def _init_tracing(
194206
id_generator: IdGenerator = None,
195207
sampler: Sampler = None,
196208
resource: Resource = None,
209+
exporter_customizer: OTLPExporterCustomizerBase=None,
197210
):
198211
provider = TracerProvider(
199212
id_generator=id_generator,
@@ -203,9 +216,12 @@ def _init_tracing(
203216
set_tracer_provider(provider)
204217

205218
for _, exporter_class in exporters.items():
206-
exporter_args = {}
219+
if exporter_customizer and isinstance(exporter_class, BaseOTLPExporters.__args__):
220+
exporter_instance = exporter_customizer.customize_exporter(exporter_class)
221+
else:
222+
exporter_instance = exporter_class()
207223
provider.add_span_processor(
208-
BatchSpanProcessor(exporter_class(**exporter_args))
224+
BatchSpanProcessor(exporter_instance)
209225
)
210226

211227

@@ -214,6 +230,7 @@ def _init_metrics(
214230
str, Union[Type[MetricExporter], Type[MetricReader]]
215231
],
216232
resource: Resource = None,
233+
exporter_customizer: OTLPExporterCustomizerBase=None,
217234
):
218235
metric_readers = []
219236

@@ -223,9 +240,13 @@ def _init_metrics(
223240
if issubclass(exporter_or_reader_class, MetricReader):
224241
metric_readers.append(exporter_or_reader_class(**exporter_args))
225242
else:
243+
if exporter_customizer and isinstance(exporter_or_reader_class, BaseOTLPExporters.__args__):
244+
exporter_instance = exporter_customizer.customize_exporter(exporter_or_reader_class)
245+
else:
246+
exporter_instance = exporter_or_reader_class()
226247
metric_readers.append(
227248
PeriodicExportingMetricReader(
228-
exporter_or_reader_class(**exporter_args)
249+
exporter_instance
229250
)
230251
)
231252

@@ -237,14 +258,18 @@ def _init_logging(
237258
exporters: Dict[str, Type[LogExporter]],
238259
resource: Resource = None,
239260
setup_logging_handler: bool = True,
261+
exporter_customizer: OTLPExporterCustomizerBase=None,
240262
):
241263
provider = LoggerProvider(resource=resource)
242264
set_logger_provider(provider)
243265

244266
for _, exporter_class in exporters.items():
245-
exporter_args = {}
267+
if exporter_customizer and isinstance(exporter_class, BaseOTLPExporters.__args__):
268+
exporter_instance = exporter_customizer.customize_exporter(exporter_class)
269+
else:
270+
exporter_instance = exporter_class()
246271
provider.add_log_record_processor(
247-
BatchLogRecordProcessor(exporter_class(**exporter_args))
272+
BatchLogRecordProcessor(exporter_instance)
248273
)
249274

250275
event_logger_provider = EventLoggerProvider(logger_provider=provider)
@@ -380,6 +405,14 @@ def _initialize_components(
380405
metric_exporter_names + _get_exporter_names("metrics"),
381406
log_exporter_names + _get_exporter_names("logs"),
382407
)
408+
exporter_customizer = None
409+
customizer_name = os.getenv(OTEL_EXPORTER_CUSTOMIZER)
410+
if customizer_name:
411+
exporter_customizer = _import_config_component(
412+
customizer_name, "opentelemetry_otlp_exporter_customizer"
413+
)()
414+
if not isinstance(exporter_customizer, OTLPExporterCustomizerBase):
415+
raise RuntimeError(f"{customizer_name} is not an OTLPExporterCustomizerBase")
383416
if sampler is None:
384417
sampler_name = _get_sampler()
385418
sampler = _import_sampler(sampler_name)
@@ -402,8 +435,9 @@ def _initialize_components(
402435
id_generator=id_generator,
403436
sampler=sampler,
404437
resource=resource,
438+
exporter_customizer=exporter_customizer,
405439
)
406-
_init_metrics(metric_exporters, resource)
440+
_init_metrics(metric_exporters, resource, exporter_customizer=exporter_customizer,)
407441
if setup_logging_handler is None:
408442
setup_logging_handler = (
409443
os.getenv(
@@ -413,7 +447,7 @@ def _initialize_components(
413447
.lower()
414448
== "true"
415449
)
416-
_init_logging(log_exporters, resource, setup_logging_handler)
450+
_init_logging(log_exporters, resource, setup_logging_handler, exporter_customizer=exporter_customizer)
417451

418452

419453
class _BaseConfigurator(ABC):

opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
OTEL_EXPORTER_CUSTOMIZER = "OTEL_EXPORTER_CUSTOMIZER"
15+
"""
16+
.. envvar:: OTEL_EXPORTER_CUSTOMIZER
17+
18+
The :envvar:`OTEL_EXPORTER_CUSTOMIZER` environment sets a customizer for all exporters (traces, logs, and metrics).
19+
"""
20+
# TODO: Add environment variables for customizers specific to traces / logs / metrics.
1421

1522
OTEL_SDK_DISABLED = "OTEL_SDK_DISABLED"
1623
"""

opentelemetry-sdk/src/opentelemetry/sdk/version/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "1.31.0.dev"
15+
__version__ = "1.30.0"

0 commit comments

Comments
 (0)