Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4958](https://github.com/open-telemetry/opentelemetry-python/pull/4958))
- `opentelemetry-sdk`: fix type annotations on `MetricReader` and related types
([#4938](https://github.com/open-telemetry/opentelemetry-python/pull/4938/))
- Implement log creation metric
- `opentelemetry-sdk`: implement log creation metric
([#4935](https://github.com/open-telemetry/opentelemetry-python/pull/4935))
- `opentelemetry-sdk`: implement metric reader metrics
([#4970](https://github.com/open-telemetry/opentelemetry-python/pull/4970))
- `opentelemetry-sdk`: upgrade vendored OTel configuration schema from v1.0.0-rc.3 to v1.0.0
([#4965](https://github.com/open-telemetry/opentelemetry-python/pull/4965))
- `opentelemetry-exporter-prometheus`: Fix metric name prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@
MetricsData,
Sum,
)
from opentelemetry.semconv._incubating.attributes.otel_attributes import (
OtelComponentTypeValues,
)
from opentelemetry.util.types import Attributes

_logger = getLogger(__name__)
Expand Down Expand Up @@ -142,7 +145,8 @@ def __init__(
ObservableCounter: AggregationTemporality.CUMULATIVE,
ObservableUpDownCounter: AggregationTemporality.CUMULATIVE,
ObservableGauge: AggregationTemporality.CUMULATIVE,
}
},
otel_component_type=OtelComponentTypeValues.PROMETHEUS_HTTP_TEXT_METRIC_EXPORTER.value,
)
self._collector = _CustomCollector(
disable_target_info=disable_target_info, prefix=prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
PrometheusMetricReader,
_CustomCollector,
)
from opentelemetry.metrics import NoOpMeterProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
AggregationTemporality,
Expand Down Expand Up @@ -332,6 +333,8 @@ def test_check_value(self):
def test_multiple_collection_calls(self):
metric_reader = PrometheusMetricReader()
provider = MeterProvider(metric_readers=[metric_reader])
# Disable SDK metrics since they are not constant across collections
metric_reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("getting-started", "0.1.2")
counter = meter.create_counter("counter")
counter.add(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ def __init__(
metric_reader._set_collect_callback(
self._measurement_consumer.collect
)
metric_reader._set_meter_provider(self)

def force_flush(self, timeout_millis: float = 10_000) -> bool:
deadline_ns = time_ns() + timeout_millis * 10**6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from os import environ, linesep
from sys import stdout
from threading import Event, Lock, RLock, Thread
from time import time_ns
from time import perf_counter, time_ns
from typing import IO, Callable, Iterable, Optional

from typing_extensions import final
Expand All @@ -35,6 +35,7 @@
detach,
set_value,
)
from opentelemetry.metrics import MeterProvider, NoOpMeterProvider
from opentelemetry.sdk.environment_variables import (
OTEL_METRIC_EXPORT_INTERVAL,
OTEL_METRIC_EXPORT_TIMEOUT,
Expand All @@ -61,8 +62,13 @@
_UpDownCounter,
)
from opentelemetry.sdk.metrics._internal.point import MetricsData
from opentelemetry.semconv._incubating.attributes.otel_attributes import (
OtelComponentTypeValues,
)
from opentelemetry.util._once import Once

from ._metric_reader_metrics import MetricReaderMetrics

_logger = getLogger(__name__)


Expand Down Expand Up @@ -220,6 +226,8 @@ def __init__(
type, "opentelemetry.sdk.metrics.view.Aggregation"
]
| None = None,
*,
otel_component_type: str | None = None,
) -> None:
self._collect: Callable[
[
Expand Down Expand Up @@ -318,6 +326,13 @@ def __init__(
else:
raise Exception(f"Invalid instrument class found {typ}")

self._otel_component_type = (
otel_component_type or type(self).__qualname__
)
self._metrics = MetricReaderMetrics(
self._otel_component_type, NoOpMeterProvider()
)

@final
def collect(self, timeout_millis: float = 10_000) -> None:
"""Collects the metrics from the internal SDK state and
Expand All @@ -337,7 +352,11 @@ def collect(self, timeout_millis: float = 10_000) -> None:
)
return

metrics = self._collect(self, timeout_millis=timeout_millis)
start_time = perf_counter()
try:
metrics = self._collect(self, timeout_millis=timeout_millis)
finally:
self._metrics.record_collection(perf_counter() - start_time)

if metrics is not None:
self._receive_metrics(
Expand Down Expand Up @@ -368,6 +387,11 @@ def _receive_metrics(
) -> None:
"""Called by `MetricReader.collect` when it receives a batch of metrics"""

def _set_meter_provider(self, meter_provider: MeterProvider) -> None:
self._metrics = MetricReaderMetrics(
self._otel_component_type, meter_provider
)

def force_flush(self, timeout_millis: float = 10_000) -> bool:
self.collect(timeout_millis=timeout_millis)
return True
Expand Down Expand Up @@ -451,6 +475,7 @@ def __init__(
super().__init__(
preferred_temporality=exporter._preferred_temporality,
preferred_aggregation=exporter._preferred_aggregation,
otel_component_type=OtelComponentTypeValues.PERIODIC_METRIC_READER.value,
)

# This lock is held whenever calling self._exporter.export() to prevent concurrent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from collections import Counter

from opentelemetry.metrics import MeterProvider
from opentelemetry.semconv._incubating.attributes.otel_attributes import (
OTEL_COMPONENT_NAME,
OTEL_COMPONENT_TYPE,
)
from opentelemetry.semconv._incubating.metrics.otel_metrics import (
create_otel_sdk_metric_reader_collection_duration,
)

_component_counter = Counter()


class MetricReaderMetrics:
def __init__(
self, component_type: str, meter_provider: MeterProvider
) -> None:
meter = meter_provider.get_meter("opentelemetry-sdk")

count = _component_counter[component_type]
_component_counter[component_type] = count + 1

self._standard_attrs = {
OTEL_COMPONENT_TYPE: component_type,
OTEL_COMPONENT_NAME: f"{component_type}/{count}",
}

self._collection_duration = (
create_otel_sdk_metric_reader_collection_duration(meter)
)

def record_collection(self, duration: float) -> None:
self._collection_duration.record(duration, self._standard_attrs)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from pytest import mark

from opentelemetry.metrics import NoOpMeterProvider
from opentelemetry.sdk.metrics import Histogram, MeterProvider
from opentelemetry.sdk.metrics.export import (
AggregationTemporality,
Expand Down Expand Up @@ -46,6 +47,9 @@ def test_synchronous_delta_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

histogram = meter.create_histogram("histogram")
Expand Down Expand Up @@ -159,7 +163,7 @@ def test_synchronous_delta_temporality(self):
provider.shutdown()

@mark.skipif(
system() != "Linux",
system() == "Windows",
reason=(
"Tests fail because Windows time_ns resolution is too low so "
"two different time measurements may end up having the exact same"
Expand All @@ -177,6 +181,9 @@ def test_synchronous_cumulative_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

histogram = meter.create_histogram("histogram")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from pytest import mark

from opentelemetry.metrics import NoOpMeterProvider
from opentelemetry.sdk.metrics import Histogram, MeterProvider
from opentelemetry.sdk.metrics.export import (
AggregationTemporality,
Expand Down Expand Up @@ -57,6 +58,9 @@ def test_synchronous_delta_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

histogram = meter.create_histogram("histogram")
Expand Down Expand Up @@ -191,6 +195,9 @@ def test_synchronous_cumulative_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

histogram = meter.create_histogram("histogram")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pytest import mark

from opentelemetry.context import Context
from opentelemetry.metrics import Observation
from opentelemetry.metrics import NoOpMeterProvider, Observation
from opentelemetry.sdk.metrics import Counter, MeterProvider, ObservableCounter
from opentelemetry.sdk.metrics._internal.exemplar import AlwaysOnExemplarFilter
from opentelemetry.sdk.metrics.export import (
Expand All @@ -33,7 +33,7 @@

class TestSumAggregation(TestCase):
@mark.skipif(
system() != "Linux",
system() == "Windows",
reason=(
"Tests fail because Windows time_ns resolution is too low so "
"two different time measurements may end up having the exact same"
Expand Down Expand Up @@ -68,6 +68,9 @@ def observable_counter_callback(callback_options):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

meter.create_observable_counter(
Expand Down Expand Up @@ -156,7 +159,7 @@ def observable_counter_callback(callback_options):
self.assertIsNone(metrics_data)

@mark.skipif(
system() != "Linux",
system() == "Windows",
reason=(
"Tests fail because Windows time_ns resolution is too low so "
"two different time measurements may end up having the exact same"
Expand Down Expand Up @@ -191,6 +194,9 @@ def observable_counter_callback(callback_options):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

meter.create_observable_counter(
Expand Down Expand Up @@ -251,7 +257,7 @@ def observable_counter_callback(callback_options):
self.assertIsNone(metrics_data)

@mark.skipif(
system() != "Linux",
system() == "Windows",
reason=(
"Tests fail because Windows time_ns resolution is too low so "
"two different time measurements may end up having the exact same"
Expand All @@ -267,6 +273,9 @@ def test_synchronous_delta_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

counter = meter.create_counter("counter")
Expand Down Expand Up @@ -378,7 +387,7 @@ def test_synchronous_delta_temporality(self):
provider.shutdown()

@mark.skipif(
system() != "Linux",
system() == "Windows",
reason=(
"Tests fail because Windows time_ns resolution is too low so "
"two different time measurements may end up having the exact same"
Expand All @@ -394,6 +403,9 @@ def test_synchronous_cumulative_temporality(self):
)

provider = MeterProvider(metric_readers=[reader])
# Disable SDK metrics
# pylint: disable=protected-access
reader._set_meter_provider(NoOpMeterProvider())
meter = provider.get_meter("name", "version")

counter = meter.create_counter("counter")
Expand Down
Loading
Loading