Skip to content

Commit

Permalink
update more references
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Boten committed Feb 25, 2022
1 parent 4476871 commit ee2046e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 117 deletions.
2 changes: 1 addition & 1 deletion exporter/opentelemetry-exporter-prometheus/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ test =

[options.entry_points]
opentelemetry_exporter =
prometheus = opentelemetry.exporter.prometheus:PrometheusMetricsExporter
prometheus = opentelemetry.exporter.prometheus:PrometheusMetricExporter
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
.. code:: python
from opentelemetry import metrics
from opentelemetry.exporter.prometheus import PrometheusMetricsExporter
from opentelemetry.exporter.prometheus import PrometheusMetricExporter
from opentelemetry.sdk.metrics import Meter
from prometheus_client import start_http_server
Expand All @@ -39,7 +39,7 @@
meter = metrics.get_meter(__name__)
# exporter to export metrics to Prometheus
prefix = "MyAppPrefix"
exporter = PrometheusMetricsExporter(prefix)
exporter = PrometheusMetricExporter(prefix)
# Starts the collect/export pipeline for metrics
metrics.get_meter_provider().start_pipeline(meter, exporter, 5)
Expand Down Expand Up @@ -70,17 +70,21 @@
from prometheus_client.core import (
REGISTRY,
CounterMetricFamily,
SummaryMetricFamily,
UnknownMetricFamily,
GaugeMetricFamily,
HistogramMetricFamily,
)

from opentelemetry._metrics import Counter, Histogram
from opentelemetry.sdk._metrics.export import (
ExportRecord,
MetricExporter,
MetricsExportResult,
MetricExportResult,
)
from opentelemetry.sdk._metrics.point import (
AggregationTemporality,
Gauge,
Histogram,
Metric,
Sum,
)
from opentelemetry.sdk.metrics.export.aggregate import MinMaxSumCountAggregator

logger = logging.getLogger(__name__)

Expand All @@ -97,11 +101,9 @@ def __init__(self, prefix: str = ""):
self._collector = CustomCollector(prefix)
REGISTRY.register(self._collector)

def export(
self, export_records: Sequence[ExportRecord]
) -> MetricsExportResult:
def export(self, export_records: Sequence[Metric]) -> MetricExportResult:
self._collector.add_metrics_data(export_records)
return MetricsExportResult.SUCCESS
return MetricExportResult.SUCCESS

def shutdown(self) -> None:
REGISTRY.unregister(self._collector)
Expand All @@ -119,7 +121,7 @@ def __init__(self, prefix: str = ""):
r"[^\w]", re.UNICODE | re.IGNORECASE
)

def add_metrics_data(self, export_records: Sequence[ExportRecord]) -> None:
def add_metrics_data(self, export_records: Sequence[Metric]) -> None:
self._metrics_to_export.append(export_records)

def collect(self):
Expand All @@ -137,52 +139,48 @@ def collect(self):
if prometheus_metric is not None:
yield prometheus_metric

def _translate_to_prometheus(self, export_record: ExportRecord):
def _translate_to_prometheus(self, export_record: Metric):
prometheus_metric = None
label_values = []
label_keys = []
for label_tuple in export_record.labels:
label_keys.append(self._sanitize(label_tuple[0]))
label_values.append(label_tuple[1])
for key, value in export_record.attributes.items():
label_keys.append(self._sanitize(key))
label_values.append(str(value))

metric_name = ""
if self._prefix != "":
metric_name = self._prefix + "_"
metric_name += self._sanitize(export_record.instrument.name)
metric_name += self._sanitize(export_record.name)

description = getattr(export_record.instrument, "description", "")
if isinstance(export_record.instrument, Counter):
description = export_record.description or ""
if isinstance(export_record.point, Sum):
prometheus_metric = CounterMetricFamily(
name=metric_name, documentation=description, labels=label_keys
)
prometheus_metric.add_metric(
labels=label_values, value=export_record.aggregator.checkpoint
labels=label_values, value=export_record.point.value
)
elif isinstance(export_record.point, Gauge):
prometheus_metric = GaugeMetricFamily(
name=metric_name, documentation=description, labels=label_keys
)
prometheus_metric.add_metric(
labels=label_values, value=export_record.point.value
)
# TODO: Add support for histograms when supported in OT
elif isinstance(export_record.instrument, Histogram):
value = export_record.aggregator.checkpoint
if isinstance(export_record.aggregator, MinMaxSumCountAggregator):
prometheus_metric = SummaryMetricFamily(
name=metric_name,
documentation=description,
labels=label_keys,
)
prometheus_metric.add_metric(
labels=label_values,
count_value=value.count,
sum_value=value.sum,
)
else:
prometheus_metric = UnknownMetricFamily(
name=metric_name,
documentation=description,
labels=label_keys,
)
prometheus_metric.add_metric(labels=label_values, value=value)

# elif isinstance(export_record.point, Histogram):
# value = export_record.point.sum
# prometheus_metric = HistogramMetricFamily(
# name=metric_name,
# documentation=description,
# labels=label_keys,
# )
# prometheus_metric.add_metric(labels=label_values, buckets=export_record.point.explicit_bounds, sum_value=value)
# TODO: add support for Summary once implemented
# elif isinstance(export_record.point, Summary):
else:
logger.warning(
"Unsupported metric type. %s", type(export_record.instrument)
"Unsupported metric type. %s", type(export_record.point)
)
return prometheus_metric

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,37 @@
from unittest import mock

from prometheus_client import generate_latest
from prometheus_client.core import CounterMetricFamily
from prometheus_client.core import CounterMetricFamily, GaugeMetricFamily

from opentelemetry._metrics import get_meter_provider, set_meter_provider
from opentelemetry.exporter.prometheus import (
CustomCollector,
PrometheusMetricsExporter,
PrometheusMetricExporter,
)
from opentelemetry.metrics import get_meter_provider, set_meter_provider
from opentelemetry.sdk import metrics
from opentelemetry.sdk.metrics.export import ExportRecord, MetricsExportResult
from opentelemetry.sdk.metrics.export.aggregate import (
MinMaxSumCountAggregator,
SumAggregator,
from opentelemetry.sdk._metrics import MeterProvider
from opentelemetry.sdk._metrics.export import MetricExportResult
from opentelemetry.sdk._metrics.point import (
AggregationTemporality,
Histogram,
Metric,
)
from opentelemetry.sdk.util import get_dict_as_key
from opentelemetry.test.metrictestutil import (
_generate_gauge,
_generate_metric,
_generate_sum,
_generate_unsupported_metric,
)


class TestPrometheusMetricExporter(unittest.TestCase):
def setUp(self):
set_meter_provider(metrics.MeterProvider())
set_meter_provider(MeterProvider())
self._meter = get_meter_provider().get_meter(__name__)
self._test_metric = self._meter.create_counter(
"testname", "testdesc", "unit", int,
"testname",
description="testdesc",
unit="unit",
)
labels = {"environment": "staging"}
self._labels_key = get_dict_as_key(labels)
Expand All @@ -52,70 +61,63 @@ def setUp(self):
def test_constructor(self):
"""Test the constructor."""
with self._registry_register_patch:
exporter = PrometheusMetricsExporter("testprefix")
exporter = PrometheusMetricExporter("testprefix")
self.assertEqual(exporter._collector._prefix, "testprefix")
self.assertTrue(self._mock_registry_register.called)

def test_shutdown(self):
with mock.patch(
"prometheus_client.core.REGISTRY.unregister"
) as registry_unregister_patch:
exporter = PrometheusMetricsExporter()
exporter = PrometheusMetricExporter()
exporter.shutdown()
self.assertTrue(registry_unregister_patch.called)

def test_export(self):
with self._registry_register_patch:
record = ExportRecord(
self._test_metric,
self._labels_key,
SumAggregator(),
get_meter_provider().resource,
)
exporter = PrometheusMetricsExporter()
record = _generate_sum("sum_int", 33)
exporter = PrometheusMetricExporter()
result = exporter.export([record])
# pylint: disable=protected-access
self.assertEqual(len(exporter._collector._metrics_to_export), 1)
self.assertIs(result, MetricsExportResult.SUCCESS)

def test_min_max_sum_aggregator_to_prometheus(self):
meter = get_meter_provider().get_meter(__name__)
metric = meter.create_valuerecorder(
"test@name", "testdesc", "unit", int, []
self.assertIs(result, MetricExportResult.SUCCESS)

# # TODO: Add unit test for histogram
def test_histogram_to_prometheus(self):
record = _generate_metric(
"test@name",
Histogram(
time_unix_nano=1641946016139533244,
start_time_unix_nano=1641946016139533244,
bucket_counts=[1, 1],
sum=579.0,
explicit_bounds=[123.0, 456.0],
aggregation_temporality=AggregationTemporality.DELTA,
),
)
labels = {}
key_labels = get_dict_as_key(labels)
aggregator = MinMaxSumCountAggregator()
aggregator.update(123)
aggregator.update(456)
aggregator.take_checkpoint()
record = ExportRecord(
metric, key_labels, aggregator, get_meter_provider().resource
)
collector = CustomCollector("testprefix")
collector.add_metrics_data([record])
result_bytes = generate_latest(collector)
result = result_bytes.decode("utf-8")
self.assertIn("testprefix_test_name_count 2.0", result)
self.assertIn("testprefix_test_name_sum 579.0", result)

def test_counter_to_prometheus(self):
meter = get_meter_provider().get_meter(__name__)
metric = meter.create_counter("test@name", "testdesc", "unit", int,)

# collector = CustomCollector("testprefix")
# collector.add_metrics_data([record])
# result_bytes = generate_latest(collector)
# result = result_bytes.decode("utf-8")
# self.assertIn("testprefix_test_name_count 2.0", result)
# self.assertIn("testprefix_test_name_sum 579.0", result)

def test_sum_to_prometheus(self):
labels = {"environment@": "staging", "os": "Windows"}
key_labels = get_dict_as_key(labels)
aggregator = SumAggregator()
aggregator.update(123)
aggregator.take_checkpoint()
record = ExportRecord(
metric, key_labels, aggregator, get_meter_provider().resource
record = _generate_sum(
"test@sum",
123,
attributes=labels,
description="testdesc",
unit="testunit",
)
collector = CustomCollector("testprefix")
collector.add_metrics_data([record])

for prometheus_metric in collector.collect():
self.assertEqual(type(prometheus_metric), CounterMetricFamily)
self.assertEqual(prometheus_metric.name, "testprefix_test_name")
self.assertEqual(prometheus_metric.name, "testprefix_test_sum")
self.assertEqual(prometheus_metric.documentation, "testdesc")
self.assertTrue(len(prometheus_metric.samples) == 1)
self.assertEqual(prometheus_metric.samples[0].value, 123)
Expand All @@ -127,16 +129,37 @@ def test_counter_to_prometheus(self):
prometheus_metric.samples[0].labels["os"], "Windows"
)

# TODO: Add unit test once GaugeAggregator is available
# TODO: Add unit test once Measure Aggregators are available
def test_gauge_to_prometheus(self):
labels = {"environment@": "dev", "os": "Unix"}
record = _generate_gauge(
"test@gauge",
123,
attributes=labels,
description="testdesc",
unit="testunit",
)
collector = CustomCollector("testprefix")
collector.add_metrics_data([record])

for prometheus_metric in collector.collect():
self.assertEqual(type(prometheus_metric), GaugeMetricFamily)
self.assertEqual(prometheus_metric.name, "testprefix_test_gauge")
self.assertEqual(prometheus_metric.documentation, "testdesc")
self.assertTrue(len(prometheus_metric.samples) == 1)
self.assertEqual(prometheus_metric.samples[0].value, 123)
self.assertTrue(len(prometheus_metric.samples[0].labels) == 2)
self.assertEqual(
prometheus_metric.samples[0].labels["environment_"], "dev"
)
self.assertEqual(prometheus_metric.samples[0].labels["os"], "Unix")

def test_invalid_metric(self):
meter = get_meter_provider().get_meter(__name__)
metric = StubMetric("tesname", "testdesc", "unit", int, meter)
labels = {"environment": "staging"}
key_labels = get_dict_as_key(labels)
record = ExportRecord(
metric, key_labels, None, get_meter_provider().resource
record = _generate_unsupported_metric(
"tesname",
attributes=labels,
description="testdesc",
unit="testunit",
)
collector = CustomCollector("testprefix")
collector.add_metrics_data([record])
Expand All @@ -152,18 +175,3 @@ def test_sanitize(self):
self.assertEqual(collector._sanitize(",./?;:[]{}"), "__________")
self.assertEqual(collector._sanitize("TestString"), "TestString")
self.assertEqual(collector._sanitize("aAbBcC_12_oi"), "aAbBcC_12_oi")


class StubMetric(metrics.Metric):
def __init__(
self,
name: str,
description: str,
unit: str,
value_type,
meter,
enabled: bool = True,
):
super().__init__(
name, description, unit, value_type, meter, enabled=enabled,
)

0 comments on commit ee2046e

Please sign in to comment.