Skip to content

Commit 8aa3200

Browse files
authored
Merge branch 'master' into django-request-attrs
2 parents b4ce083 + 2b46d11 commit 8aa3200

File tree

2 files changed

+58
-24
lines changed

2 files changed

+58
-24
lines changed

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

+30-20
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,22 @@
6767
import collections
6868
import logging
6969
import re
70-
from typing import Sequence
70+
from typing import Iterable, Optional, Sequence, Union
7171

72-
from prometheus_client import start_http_server
7372
from prometheus_client.core import (
7473
REGISTRY,
75-
CollectorRegistry,
7674
CounterMetricFamily,
75+
SummaryMetricFamily,
7776
UnknownMetricFamily,
7877
)
7978

80-
from opentelemetry.metrics import Counter, Metric, ValueRecorder
79+
from opentelemetry.metrics import Counter, ValueRecorder
8180
from opentelemetry.sdk.metrics.export import (
8281
MetricRecord,
8382
MetricsExporter,
8483
MetricsExportResult,
8584
)
85+
from opentelemetry.sdk.metrics.export.aggregate import MinMaxSumCountAggregator
8686

8787
logger = logging.getLogger(__name__)
8888

@@ -110,8 +110,8 @@ def shutdown(self) -> None:
110110

111111

112112
class CustomCollector:
113-
""" CustomCollector represents the Prometheus Collector object
114-
https://github.com/prometheus/client_python#custom-collectors
113+
"""CustomCollector represents the Prometheus Collector object
114+
https://github.com/prometheus/client_python#custom-collectors
115115
"""
116116

117117
def __init__(self, prefix: str = ""):
@@ -121,7 +121,7 @@ def __init__(self, prefix: str = ""):
121121
r"[^\w]", re.UNICODE | re.IGNORECASE
122122
)
123123

124-
def add_metrics_data(self, metric_records: Sequence[MetricRecord]):
124+
def add_metrics_data(self, metric_records: Sequence[MetricRecord]) -> None:
125125
self._metrics_to_export.append(metric_records)
126126

127127
def collect(self):
@@ -152,34 +152,44 @@ def _translate_to_prometheus(self, metric_record: MetricRecord):
152152
metric_name = self._prefix + "_"
153153
metric_name += self._sanitize(metric_record.instrument.name)
154154

155+
description = getattr(metric_record.instrument, "description", "")
155156
if isinstance(metric_record.instrument, Counter):
156157
prometheus_metric = CounterMetricFamily(
157-
name=metric_name,
158-
documentation=metric_record.instrument.description,
159-
labels=label_keys,
158+
name=metric_name, documentation=description, labels=label_keys
160159
)
161160
prometheus_metric.add_metric(
162161
labels=label_values, value=metric_record.aggregator.checkpoint
163162
)
164163
# TODO: Add support for histograms when supported in OT
165164
elif isinstance(metric_record.instrument, ValueRecorder):
166-
prometheus_metric = UnknownMetricFamily(
167-
name=metric_name,
168-
documentation=metric_record.instrument.description,
169-
labels=label_keys,
170-
)
171-
prometheus_metric.add_metric(
172-
labels=label_values, value=metric_record.aggregator.checkpoint
173-
)
165+
value = metric_record.aggregator.checkpoint
166+
if isinstance(metric_record.aggregator, MinMaxSumCountAggregator):
167+
prometheus_metric = SummaryMetricFamily(
168+
name=metric_name,
169+
documentation=description,
170+
labels=label_keys,
171+
)
172+
prometheus_metric.add_metric(
173+
labels=label_values,
174+
count_value=value.count,
175+
sum_value=value.sum,
176+
)
177+
else:
178+
prometheus_metric = UnknownMetricFamily(
179+
name=metric_name,
180+
documentation=description,
181+
labels=label_keys,
182+
)
183+
prometheus_metric.add_metric(labels=label_values, value=value)
174184

175185
else:
176186
logger.warning(
177187
"Unsupported metric type. %s", type(metric_record.instrument)
178188
)
179189
return prometheus_metric
180190

181-
def _sanitize(self, key):
182-
""" sanitize the given metric name or label according to Prometheus rule.
191+
def _sanitize(self, key: str) -> str:
192+
"""sanitize the given metric name or label according to Prometheus rule.
183193
Replace all characters other than [A-Za-z0-9_] with '_'.
184194
"""
185195
return self._non_letters_nor_digits_re.sub("_", key)

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

+28-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import unittest
1616
from unittest import mock
1717

18+
from prometheus_client import generate_latest
1819
from prometheus_client.core import CounterMetricFamily
1920

2021
from opentelemetry.exporter.prometheus import (
@@ -24,7 +25,11 @@
2425
from opentelemetry.metrics import get_meter_provider, set_meter_provider
2526
from opentelemetry.sdk import metrics
2627
from opentelemetry.sdk.metrics.export import MetricRecord, MetricsExportResult
27-
from opentelemetry.sdk.metrics.export.aggregate import SumAggregator
28+
from opentelemetry.sdk.metrics.export.aggregate import (
29+
MinMaxSumCountAggregator,
30+
SumAggregator,
31+
)
32+
from opentelemetry.sdk.util import get_dict_as_key
2833

2934

3035
class TestPrometheusMetricExporter(unittest.TestCase):
@@ -35,7 +40,7 @@ def setUp(self):
3540
"testname", "testdesc", "unit", int, metrics.Counter,
3641
)
3742
labels = {"environment": "staging"}
38-
self._labels_key = metrics.get_dict_as_key(labels)
43+
self._labels_key = get_dict_as_key(labels)
3944

4045
self._mock_registry_register = mock.Mock()
4146
self._registry_register_patch = mock.patch(
@@ -70,13 +75,32 @@ def test_export(self):
7075
self.assertEqual(len(exporter._collector._metrics_to_export), 1)
7176
self.assertIs(result, MetricsExportResult.SUCCESS)
7277

78+
def test_min_max_sum_aggregator_to_prometheus(self):
79+
meter = get_meter_provider().get_meter(__name__)
80+
metric = meter.create_metric(
81+
"test@name", "testdesc", "unit", int, metrics.ValueRecorder, []
82+
)
83+
labels = {}
84+
key_labels = get_dict_as_key(labels)
85+
aggregator = MinMaxSumCountAggregator()
86+
aggregator.update(123)
87+
aggregator.update(456)
88+
aggregator.take_checkpoint()
89+
record = MetricRecord(metric, key_labels, aggregator)
90+
collector = CustomCollector("testprefix")
91+
collector.add_metrics_data([record])
92+
result_bytes = generate_latest(collector)
93+
result = result_bytes.decode("utf-8")
94+
self.assertIn("testprefix_test_name_count 2.0", result)
95+
self.assertIn("testprefix_test_name_sum 579.0", result)
96+
7397
def test_counter_to_prometheus(self):
7498
meter = get_meter_provider().get_meter(__name__)
7599
metric = meter.create_metric(
76100
"test@name", "testdesc", "unit", int, metrics.Counter,
77101
)
78102
labels = {"environment@": "staging", "os": "Windows"}
79-
key_labels = metrics.get_dict_as_key(labels)
103+
key_labels = get_dict_as_key(labels)
80104
aggregator = SumAggregator()
81105
aggregator.update(123)
82106
aggregator.take_checkpoint()
@@ -107,7 +131,7 @@ def test_invalid_metric(self):
107131
"tesname", "testdesc", "unit", int, StubMetric
108132
)
109133
labels = {"environment": "staging"}
110-
key_labels = metrics.get_dict_as_key(labels)
134+
key_labels = get_dict_as_key(labels)
111135
record = MetricRecord(metric, key_labels, None)
112136
collector = CustomCollector("testprefix")
113137
collector.add_metrics_data([record])

0 commit comments

Comments
 (0)