Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make opentelemetry_metrics_exporter entrypoint support pull exporters #3428

Merged
merged 6 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3335](https://github.com/open-telemetry/opentelemetry-python/pull/3335))
- Fix error when no LoggerProvider configured for LoggingHandler
([#3423](https://github.com/open-telemetry/opentelemetry-python/pull/3423))

- Make `opentelemetry_metrics_exporter` entrypoint support pull exporters
([#3428](https://github.com/open-telemetry/opentelemetry-python/pull/3428))

## Version 1.20.0/0.41b0 (2023-09-04)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import os
from abc import ABC, abstractmethod
from os import environ
from typing import Callable, Dict, List, Optional, Sequence, Tuple, Type
from typing import Callable, Dict, List, Optional, Sequence, Tuple, Type, Union

from typing_extensions import Literal

Expand All @@ -47,6 +47,7 @@
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
MetricExporter,
MetricReader,
PeriodicExportingMetricReader,
)
from opentelemetry.sdk.resources import Resource
Expand Down Expand Up @@ -210,16 +211,24 @@ def _init_tracing(


def _init_metrics(
exporters: Dict[str, Type[MetricExporter]],
exporters_or_readers: Dict[
aabmass marked this conversation as resolved.
Show resolved Hide resolved
str, Union[Type[MetricExporter], Type[MetricReader]]
],
resource: Resource = None,
):
metric_readers = []

for _, exporter_class in exporters.items():
for _, exporter_or_reader_class in exporters_or_readers.items():
exporter_args = {}
metric_readers.append(
PeriodicExportingMetricReader(exporter_class(**exporter_args))
)

if issubclass(exporter_or_reader_class, MetricReader):
metric_readers.append(exporter_or_reader_class(**exporter_args))
else:
metric_readers.append(
PeriodicExportingMetricReader(
exporter_or_reader_class(**exporter_args)
)
)

provider = MeterProvider(resource=resource, metric_readers=metric_readers)
set_meter_provider(provider)
Expand Down Expand Up @@ -249,7 +258,7 @@ def _import_exporters(
log_exporter_names: Sequence[str],
) -> Tuple[
Dict[str, Type[SpanExporter]],
Dict[str, Type[MetricExporter]],
Dict[str, Union[Type[MetricExporter], Type[MetricReader]]],
Dict[str, Type[LogExporter]],
]:
trace_exporters = {}
Expand All @@ -267,7 +276,9 @@ def _import_exporters(
for (exporter_name, exporter_impl,) in _import_config_components(
metric_exporter_names, "opentelemetry_metrics_exporter"
):
if issubclass(exporter_impl, MetricExporter):
# The metric exporter components may be push MetricExporter or pull exporters which
# subclass MetricReader directly
if issubclass(exporter_impl, (MetricExporter, MetricReader)):
metric_exporters[exporter_name] = exporter_impl
else:
raise RuntimeError(f"{exporter_name} is not a metric exporter")
Expand Down
51 changes: 49 additions & 2 deletions opentelemetry-sdk/tests/test_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from os import environ
from typing import Dict, Iterable, Optional, Sequence
from unittest import TestCase
from unittest.mock import patch
from unittest.mock import Mock, patch

from pytest import raises

Expand Down Expand Up @@ -158,6 +158,20 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
return True


# MetricReader that can be configured as a pull exporter
class DummyMetricReaderPullExporter(MetricReader):
def _receive_metrics(
self,
metrics: Iterable[Metric],
timeout_millis: float = 10_000,
**kwargs,
) -> None:
pass

def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
return True


class DummyOTLPMetricExporter:
def __init__(self, *args, **kwargs):
self.export_called = False
Expand Down Expand Up @@ -309,7 +323,6 @@ def tearDown(self):
environ, {"OTEL_RESOURCE_ATTRIBUTES": "service.name=my-test-service"}
)
def test_trace_init_default(self):

auto_resource = Resource.create(
{
"telemetry.auto.version": "test-version",
Expand Down Expand Up @@ -740,6 +753,18 @@ def test_metrics_init_exporter(self):
self.assertIsInstance(reader, DummyMetricReader)
self.assertIsInstance(reader.exporter, DummyOTLPMetricExporter)

def test_metrics_init_pull_exporter(self):
resource = Resource.create({})
_init_metrics(
{"dummy_metric_reader": DummyMetricReaderPullExporter},
resource=resource,
)
self.assertEqual(self.set_provider_mock.call_count, 1)
provider = self.set_provider_mock.call_args[0][0]
self.assertIsInstance(provider, DummyMeterProvider)
reader = provider._sdk_config.metric_readers[0]
self.assertIsInstance(reader, DummyMetricReaderPullExporter)


class TestExporterNames(TestCase):
@patch.dict(
Expand Down Expand Up @@ -835,6 +860,28 @@ def test_console_exporters(self):
ConsoleMetricExporter.__class__,
)

@patch(
"opentelemetry.sdk._configuration.entry_points",
)
def test_metric_pull_exporter(self, mock_entry_points: Mock):
def mock_entry_points_impl(group, name):
if name == "dummy_pull_exporter":
return [
IterEntryPoint(
name=name, class_type=DummyMetricReaderPullExporter
)
]
return []

mock_entry_points.side_effect = mock_entry_points_impl
_, metric_exporters, _ = _import_exporters(
[], ["dummy_pull_exporter"], []
)
self.assertIs(
metric_exporters["dummy_pull_exporter"],
DummyMetricReaderPullExporter,
)


class TestImportConfigComponents(TestCase):
@patch(
Expand Down