Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 680e662

Browse files
author
Alex Boten
committed
implement pull metric reader
1 parent 629b937 commit 680e662

File tree

3 files changed

+60
-22
lines changed

3 files changed

+60
-22
lines changed

exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,29 @@
2727
2828
.. code:: python
2929
30-
from opentelemetry import metrics
31-
from opentelemetry.exporter.prometheus import PrometheusMetricExporter
32-
from opentelemetry.sdk.metrics import Meter
3330
from prometheus_client import start_http_server
3431
32+
from opentelemetry._metrics import get_meter_provider, set_meter_provider
33+
from opentelemetry.exporter.prometheus import PrometheusMetricExporter
34+
from opentelemetry.sdk._metrics import MeterProvider
35+
from opentelemetry.sdk._metrics.export import PullMetricExporterReader
36+
3537
# Start Prometheus client
3638
start_http_server(port=8000, addr="localhost")
3739
38-
# Meter is responsible for creating and recording metrics
39-
metrics.set_meter_provider(MeterProvider())
40-
meter = metrics.get_meter(__name__)
4140
# exporter to export metrics to Prometheus
4241
prefix = "MyAppPrefix"
4342
exporter = PrometheusMetricExporter(prefix)
44-
# Starts the collect/export pipeline for metrics
45-
metrics.get_meter_provider().start_pipeline(meter, exporter, 5)
43+
reader = PullMetricExporterReader(exporter)
44+
45+
# Meter is responsible for creating and recording metrics
46+
set_meter_provider(MeterProvider(metric_readers=[reader]))
47+
meter = get_meter_provider().get_meter(__name__)
4648
4749
counter = meter.create_counter(
4850
"requests",
49-
"number of requests",
5051
"requests",
51-
int,
52+
"number of requests",
5253
)
5354
5455
# Labels are used to identify key-values that are associated with a specific
@@ -71,12 +72,12 @@
7172
from prometheus_client import core
7273

7374
from opentelemetry.sdk._metrics.export import (
74-
MetricExporter,
7575
MetricExportResult,
76+
PullMetricExporter,
7677
)
7778
from opentelemetry.sdk._metrics.point import Gauge, Histogram, Metric, Sum
7879

79-
logger = logging.getLogger(__name__)
80+
_logger = logging.getLogger(__name__)
8081

8182

8283
def _convert_buckets(metric: Metric) -> Sequence[Tuple[str, int]]:
@@ -93,7 +94,7 @@ def _convert_buckets(metric: Metric) -> Sequence[Tuple[str, int]]:
9394
return buckets
9495

9596

96-
class PrometheusMetricExporter(MetricExporter):
97+
class PrometheusMetricExporter(PullMetricExporter):
9798
"""Prometheus metric exporter for OpenTelemetry.
9899
99100
Args:
@@ -102,7 +103,8 @@ class PrometheusMetricExporter(MetricExporter):
102103
"""
103104

104105
def __init__(self, prefix: str = ""):
105-
self._collector = _CustomCollector(prefix)
106+
self._collect = None
107+
self._collector = _CustomCollector(self.collect, prefix)
106108
core.REGISTRY.register(self._collector)
107109

108110
def export(self, metrics: Sequence[Metric]) -> MetricExportResult:
@@ -118,8 +120,9 @@ class _CustomCollector:
118120
https://github.com/prometheus/client_python#custom-collectors
119121
"""
120122

121-
def __init__(self, prefix: str = ""):
123+
def __init__(self, callback, prefix: str = ""):
122124
self._prefix = prefix
125+
self._callback = callback
123126
self._metrics_to_export = collections.deque()
124127
self._non_letters_nor_digits_re = re.compile(
125128
r"[^\w]", re.UNICODE | re.IGNORECASE
@@ -135,6 +138,8 @@ def collect(self) -> None:
135138
Collect is invoked every time a prometheus.Gatherer is run
136139
for example when the HTTP endpoint is invoked by Prometheus.
137140
"""
141+
if self._callback:
142+
self._callback()
138143

139144
while self._metrics_to_export:
140145
for export_record in self._metrics_to_export.popleft():
@@ -193,7 +198,7 @@ def _translate_to_prometheus(
193198
labels=label_values, buckets=buckets, sum_value=value
194199
)
195200
else:
196-
logger.warning("Unsupported metric type. %s", type(metric.point))
201+
_logger.warning("Unsupported metric type. %s", type(metric.point))
197202
return prometheus_metric
198203

199204
def _sanitize(self, key: str) -> str:

exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
from prometheus_client.core import CounterMetricFamily, GaugeMetricFamily
2020

2121
from opentelemetry.exporter.prometheus import (
22-
_CustomCollector,
2322
PrometheusMetricExporter,
23+
_CustomCollector,
2424
)
2525
from opentelemetry.sdk._metrics.export import MetricExportResult
2626
from opentelemetry.sdk._metrics.point import AggregationTemporality, Histogram
@@ -79,7 +79,7 @@ def test_histogram_to_prometheus(self):
7979
attributes={"histo": 1},
8080
)
8181

82-
collector = _CustomCollector("testprefix")
82+
collector = _CustomCollector(mock.Mock(), "testprefix")
8383
collector.add_metrics_data([record])
8484
result_bytes = generate_latest(collector)
8585
result = result_bytes.decode("utf-8")
@@ -95,7 +95,7 @@ def test_sum_to_prometheus(self):
9595
description="testdesc",
9696
unit="testunit",
9797
)
98-
collector = _CustomCollector("testprefix")
98+
collector = _CustomCollector(mock.Mock(), "testprefix")
9999
collector.add_metrics_data([record])
100100

101101
for prometheus_metric in collector.collect():
@@ -123,7 +123,7 @@ def test_gauge_to_prometheus(self):
123123
description="testdesc",
124124
unit="testunit",
125125
)
126-
collector = _CustomCollector("testprefix")
126+
collector = _CustomCollector(mock.Mock(), "testprefix")
127127
collector.add_metrics_data([record])
128128

129129
for prometheus_metric in collector.collect():
@@ -148,13 +148,13 @@ def test_invalid_metric(self):
148148
description="testdesc",
149149
unit="testunit",
150150
)
151-
collector = _CustomCollector("testprefix")
151+
collector = _CustomCollector(mock.Mock(), "testprefix")
152152
collector.add_metrics_data([record])
153153
collector.collect()
154154
self.assertLogs("opentelemetry.exporter.prometheus", level="WARNING")
155155

156156
def test_sanitize(self):
157-
collector = _CustomCollector("testprefix")
157+
collector = _CustomCollector(mock.Mock(), "testprefix")
158158
self.assertEqual(
159159
collector._sanitize("1!2@3#4$5%6^7&8*9(0)_-"),
160160
"1_2_3_4_5_6_7_8_9_0___",

opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
from threading import Event, Thread
2222
from typing import IO, Callable, Iterable, Optional, Sequence
2323

24+
from typing_extensions import final
25+
2426
from opentelemetry.context import (
2527
_SUPPRESS_INSTRUMENTATION_KEY,
2628
attach,
@@ -176,3 +178,34 @@ def _shutdown():
176178
self._daemon_thread.join()
177179
self._exporter.shutdown()
178180
return True
181+
182+
183+
class PullMetricExporter(MetricExporter):
184+
@final
185+
def collect(self) -> None:
186+
if self._collect:
187+
self._collect()
188+
189+
190+
class PullMetricExporterReader(MetricReader):
191+
def __init__(
192+
self,
193+
exporter: PullMetricExporter,
194+
):
195+
super().__init__(preferred_temporality=exporter.preferred_temporality)
196+
self._exporter = exporter
197+
self._exporter._collect = self.collect
198+
199+
def _receive_metrics(self, metrics: Iterable[Metric]) -> None:
200+
if metrics is None:
201+
return
202+
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
203+
try:
204+
self._exporter.export(metrics)
205+
except Exception as e: # pylint: disable=broad-except,invalid-name
206+
_logger.exception("Exception while exporting metrics %s", str(e))
207+
detach(token)
208+
209+
def shutdown(self) -> bool:
210+
self._exporter.shutdown()
211+
return True

0 commit comments

Comments
 (0)