diff --git a/exporter/opentelemetry-exporter-otlp-customizer/README.rst b/exporter/opentelemetry-exporter-otlp-customizer/README.rst new file mode 100644 index 00000000000..f2fb093dccc --- /dev/null +++ b/exporter/opentelemetry-exporter-otlp-customizer/README.rst @@ -0,0 +1 @@ +Customizer base class for OTLP exporters. \ No newline at end of file diff --git a/exporter/opentelemetry-exporter-otlp-customizer/pyproject.toml b/exporter/opentelemetry-exporter-otlp-customizer/pyproject.toml new file mode 100644 index 00000000000..4ad14905f5f --- /dev/null +++ b/exporter/opentelemetry-exporter-otlp-customizer/pyproject.toml @@ -0,0 +1,52 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-exporter-otlp-customizer" +dynamic = ["version"] +description = "OpenTelemetry Collector Protobuf over gRPC Exporter" +readme = "README.rst" +license = {text = "Apache-2.0"} +requires-python = ">=3.8" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Framework :: OpenTelemetry", + "Framework :: OpenTelemetry :: Exporters", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "opentelemetry-exporter-otlp-proto-grpc == 1.30.0", + "opentelemetry-exporter-otlp-proto-http == 1.30.0", +] + +[project.entry-points.opentelemetry_exporter_otlp_customizer] +otlp = "opentelemetry.exporter.otlp.customizer:OTLPExporterCustomizerBase" + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-otlp-proto-grpc" +Repository = "https://github.com/open-telemetry/opentelemetry-python" + +[tool.hatch.version] +path = "src/opentelemetry/exporter/otlp/customizer/version/__init__.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/__init__.py b/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/__init__.py new file mode 100644 index 00000000000..5e234a9dfc0 --- /dev/null +++ b/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/__init__.py @@ -0,0 +1,23 @@ +from abc import ABC +from typing import Union + +from opentelemetry.exporter.otlp.proto.http._log_exporter import ( + OTLPLogExporter, +) +from opentelemetry.exporter.otlp.proto.http.metric_exporter import ( + OTLPMetricExporter, +) +from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( + OTLPSpanExporter, +) + +# TODO: import grpc exporters. + +BaseOTLPExporters = Union[ + OTLPLogExporter, OTLPSpanExporter, OTLPMetricExporter +] + + +class OTLPExporterCustomizerBase(ABC): + def customize_exporter(exporter: BaseOTLPExporters): + pass diff --git a/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/version/__init__.py b/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/version/__init__.py new file mode 100644 index 00000000000..cf81596008c --- /dev/null +++ b/exporter/opentelemetry-exporter-otlp-customizer/src/opentelemetry/exporter/otlp/customizer/version/__init__.py @@ -0,0 +1,15 @@ +# 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. + +__version__ = "1.30.0" diff --git a/opentelemetry-sdk/pyproject.toml b/opentelemetry-sdk/pyproject.toml index d265d4b2148..c8add38f540 100644 --- a/opentelemetry-sdk/pyproject.toml +++ b/opentelemetry-sdk/pyproject.toml @@ -28,8 +28,8 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "opentelemetry-api == 1.31.0.dev", - "opentelemetry-semantic-conventions == 0.52b0.dev", + "opentelemetry-api == 1.30.0", + "opentelemetry-semantic-conventions == 0.51b0", "typing-extensions >= 3.7.4", ] diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index a8f9826c31d..b94d3177a5d 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -45,6 +45,11 @@ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, + OTEL_EXPORTER_CUSTOMIZER, +) +from opentelemetry.exporter.otlp.customizer import ( + BaseOTLPExporters, + OTLPExporterCustomizerBase, ) from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import ( @@ -90,6 +95,13 @@ _logger = logging.getLogger(__name__) +def _import_config_component( + selected_component: str, entry_point_name: str +) -> object: + return _import_config_components([selected_component], entry_point_name)[ + 0 + ][1] + def _import_config_components( selected_components: List[str], entry_point_name: str ) -> Sequence[Tuple[str, object]]: @@ -194,6 +206,7 @@ def _init_tracing( id_generator: IdGenerator = None, sampler: Sampler = None, resource: Resource = None, + exporter_customizer: OTLPExporterCustomizerBase=None, ): provider = TracerProvider( id_generator=id_generator, @@ -203,9 +216,12 @@ def _init_tracing( set_tracer_provider(provider) for _, exporter_class in exporters.items(): - exporter_args = {} + if exporter_customizer and isinstance(exporter_class, BaseOTLPExporters.__args__): + exporter_instance = exporter_customizer.customize_exporter(exporter_class) + else: + exporter_instance = exporter_class() provider.add_span_processor( - BatchSpanProcessor(exporter_class(**exporter_args)) + BatchSpanProcessor(exporter_instance) ) @@ -214,6 +230,7 @@ def _init_metrics( str, Union[Type[MetricExporter], Type[MetricReader]] ], resource: Resource = None, + exporter_customizer: OTLPExporterCustomizerBase=None, ): metric_readers = [] @@ -223,9 +240,13 @@ def _init_metrics( if issubclass(exporter_or_reader_class, MetricReader): metric_readers.append(exporter_or_reader_class(**exporter_args)) else: + if exporter_customizer and isinstance(exporter_or_reader_class, BaseOTLPExporters.__args__): + exporter_instance = exporter_customizer.customize_exporter(exporter_or_reader_class) + else: + exporter_instance = exporter_or_reader_class() metric_readers.append( PeriodicExportingMetricReader( - exporter_or_reader_class(**exporter_args) + exporter_instance ) ) @@ -237,14 +258,18 @@ def _init_logging( exporters: Dict[str, Type[LogExporter]], resource: Resource = None, setup_logging_handler: bool = True, + exporter_customizer: OTLPExporterCustomizerBase=None, ): provider = LoggerProvider(resource=resource) set_logger_provider(provider) for _, exporter_class in exporters.items(): - exporter_args = {} + if exporter_customizer and isinstance(exporter_class, BaseOTLPExporters.__args__): + exporter_instance = exporter_customizer.customize_exporter(exporter_class) + else: + exporter_instance = exporter_class() provider.add_log_record_processor( - BatchLogRecordProcessor(exporter_class(**exporter_args)) + BatchLogRecordProcessor(exporter_instance) ) event_logger_provider = EventLoggerProvider(logger_provider=provider) @@ -380,6 +405,14 @@ def _initialize_components( metric_exporter_names + _get_exporter_names("metrics"), log_exporter_names + _get_exporter_names("logs"), ) + exporter_customizer = None + customizer_name = os.getenv(OTEL_EXPORTER_CUSTOMIZER) + if customizer_name: + exporter_customizer = _import_config_component( + customizer_name, "opentelemetry_otlp_exporter_customizer" + )() + if not isinstance(exporter_customizer, OTLPExporterCustomizerBase): + raise RuntimeError(f"{customizer_name} is not an OTLPExporterCustomizerBase") if sampler is None: sampler_name = _get_sampler() sampler = _import_sampler(sampler_name) @@ -402,8 +435,9 @@ def _initialize_components( id_generator=id_generator, sampler=sampler, resource=resource, + exporter_customizer=exporter_customizer, ) - _init_metrics(metric_exporters, resource) + _init_metrics(metric_exporters, resource, exporter_customizer=exporter_customizer,) if setup_logging_handler is None: setup_logging_handler = ( os.getenv( @@ -413,7 +447,7 @@ def _initialize_components( .lower() == "true" ) - _init_logging(log_exporters, resource, setup_logging_handler) + _init_logging(log_exporters, resource, setup_logging_handler, exporter_customizer=exporter_customizer) class _BaseConfigurator(ABC): diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index f09807547cc..732af3a6447 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -11,6 +11,13 @@ # 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. +OTEL_EXPORTER_CUSTOMIZER = "OTEL_EXPORTER_CUSTOMIZER" +""" +.. envvar:: OTEL_EXPORTER_CUSTOMIZER + +The :envvar:`OTEL_EXPORTER_CUSTOMIZER` environment sets a customizer for all exporters (traces, logs, and metrics). +""" +# TODO: Add environment variables for customizers specific to traces / logs / metrics. OTEL_SDK_DISABLED = "OTEL_SDK_DISABLED" """ diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/version/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/version/__init__.py index 9ac3924ed02..cf81596008c 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/version/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/version/__init__.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.31.0.dev" +__version__ = "1.30.0"