Skip to content

Commit 32d35c1

Browse files
committed
Prometheus exporter support for auto instrumentation
1 parent 6973de2 commit 32d35c1

File tree

5 files changed

+129
-6
lines changed

5 files changed

+129
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
([#3423](https://github.com/open-telemetry/opentelemetry-python/pull/3423))
1414
- Make `opentelemetry_metrics_exporter` entrypoint support pull exporters
1515
([#3428](https://github.com/open-telemetry/opentelemetry-python/pull/3428))
16+
- Prometheus exporter support for auto instrumentation
17+
([#3413](https://github.com/open-telemetry/opentelemetry-python/pull/3413))
1618

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

exporter/opentelemetry-exporter-prometheus/pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@ classifiers = [
2626
]
2727
dependencies = [
2828
"opentelemetry-api ~= 1.12",
29-
"opentelemetry-sdk ~= 1.12",
29+
# DONOTMERGE: confirm that this will becomes ~= 1.20 in the next release
30+
"opentelemetry-sdk ~= 1.21.0.dev",
3031
"prometheus_client >= 0.5.0, < 1.0.0",
3132
]
3233

3334
[project.optional-dependencies]
3435
test = []
3536

36-
[project.entry-points.opentelemetry_metric_reader]
37-
prometheus = "opentelemetry.exporter.prometheus:PrometheusMetricReader"
37+
[project.entry-points.opentelemetry_metrics_exporter]
38+
prometheus = "opentelemetry.exporter.prometheus:_AutoPrometheusMetricReader"
3839

3940
[project.urls]
4041
Homepage = "https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-prometheus"

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@
6666
from itertools import chain
6767
from json import dumps
6868
from logging import getLogger
69+
from os import environ
6970
from re import IGNORECASE, UNICODE, compile
7071
from typing import Dict, Sequence, Tuple, Union
7172

73+
from prometheus_client import start_http_server
7274
from prometheus_client.core import (
7375
REGISTRY,
7476
CounterMetricFamily,
@@ -78,6 +80,10 @@
7880
)
7981
from prometheus_client.core import Metric as PrometheusMetric
8082

83+
from opentelemetry.sdk.environment_variables import (
84+
OTEL_EXPORTER_PROMETHEUS_HOST,
85+
OTEL_EXPORTER_PROMETHEUS_PORT,
86+
)
8187
from opentelemetry.sdk.metrics import Counter
8288
from opentelemetry.sdk.metrics import Histogram as HistogramInstrument
8389
from opentelemetry.sdk.metrics import (
@@ -282,7 +288,6 @@ def _translate_to_prometheus(
282288
isinstance(metric.data, Sum)
283289
and not should_convert_sum_to_gauge
284290
):
285-
286291
metric_family_id = "|".join(
287292
[pre_metric_family_id, CounterMetricFamily.__name__]
288293
)
@@ -303,7 +308,6 @@ def _translate_to_prometheus(
303308
isinstance(metric.data, Gauge)
304309
or should_convert_sum_to_gauge
305310
):
306-
307311
metric_family_id = "|".join(
308312
[pre_metric_family_id, GaugeMetricFamily.__name__]
309313
)
@@ -324,7 +328,6 @@ def _translate_to_prometheus(
324328
metric_family_id
325329
].add_metric(labels=label_values, value=value)
326330
elif isinstance(metric.data, Histogram):
327-
328331
metric_family_id = "|".join(
329332
[pre_metric_family_id, HistogramMetricFamily.__name__]
330333
)
@@ -375,3 +378,21 @@ def _create_info_metric(
375378
info = InfoMetricFamily(name, description, labels=attributes)
376379
info.add_metric(labels=list(attributes.keys()), value=attributes)
377380
return info
381+
382+
383+
class _AutoPrometheusMetricReader(PrometheusMetricReader):
384+
"""Thin wrapper around PrometheusMetricReader used for opentelemetry_metrics_exporter
385+
386+
This allows users to use the prometheus exporter with opentelemetry-instrument. It handles
387+
starting the Prometheus http server on the the correct port and host.
388+
"""
389+
390+
def __init__(self) -> None:
391+
super().__init__()
392+
393+
# Default values are specified in
394+
# https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#prometheus-exporter
395+
start_http_server(
396+
port=int(environ.get(OTEL_EXPORTER_PROMETHEUS_PORT, "9464")),
397+
addr=environ.get(OTEL_EXPORTER_PROMETHEUS_HOST, "localhost"),
398+
)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# pylint: disable=no-self-use
16+
17+
import os
18+
from unittest import TestCase
19+
from unittest.mock import ANY, Mock, patch
20+
21+
from opentelemetry.exporter.prometheus import _AutoPrometheusMetricReader
22+
from opentelemetry.sdk._configuration import _import_exporters
23+
from opentelemetry.sdk.environment_variables import (
24+
OTEL_EXPORTER_PROMETHEUS_HOST,
25+
OTEL_EXPORTER_PROMETHEUS_PORT,
26+
)
27+
28+
29+
class TestEntrypoints(TestCase):
30+
def test_import_exporters(self) -> None:
31+
"""
32+
Tests that the entrypoint can be loaded and doesn't have a typo in the name
33+
"""
34+
(
35+
_trace_exporters,
36+
metric_exporters,
37+
_logs_exporters,
38+
) = _import_exporters(
39+
trace_exporter_names=[],
40+
metric_exporter_names=["prometheus"],
41+
log_exporter_names=[],
42+
)
43+
44+
self.assertIs(
45+
metric_exporters["prometheus"],
46+
_AutoPrometheusMetricReader,
47+
)
48+
49+
@patch("opentelemetry.exporter.prometheus.start_http_server")
50+
@patch.dict(os.environ)
51+
def test_starts_http_server_defaults(
52+
self, mock_start_http_server: Mock
53+
) -> None:
54+
_AutoPrometheusMetricReader()
55+
mock_start_http_server.assert_called_once_with(
56+
port=9464, addr="localhost"
57+
)
58+
59+
@patch("opentelemetry.exporter.prometheus.start_http_server")
60+
@patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_HOST: "1.2.3.4"})
61+
def test_starts_http_server_host_envvar(
62+
self, mock_start_http_server: Mock
63+
) -> None:
64+
_AutoPrometheusMetricReader()
65+
mock_start_http_server.assert_called_once_with(
66+
port=ANY, addr="1.2.3.4"
67+
)
68+
69+
@patch("opentelemetry.exporter.prometheus.start_http_server")
70+
@patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_PORT: "9999"})
71+
def test_starts_http_server_port_envvar(
72+
self, mock_start_http_server: Mock
73+
) -> None:
74+
_AutoPrometheusMetricReader()
75+
mock_start_http_server.assert_called_once_with(port=9999, addr=ANY)

opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,27 @@
678678
experimental feature and the name of this variable and its behavior can change
679679
in a non-backwards compatible way.
680680
"""
681+
682+
OTEL_EXPORTER_PROMETHEUS_HOST = "OTEL_EXPORTER_PROMETHEUS_HOST"
683+
"""
684+
.. envvar:: OTEL_EXPORTER_PROMETHEUS_HOST
685+
686+
The :envvar:`OTEL_EXPORTER_PROMETHEUS_HOST` environment variable configures the host used by
687+
the Prometheus exporter.
688+
Default: "localhost"
689+
690+
This is an experimental environment variable and the name of this variable and its behavior can
691+
change in a non-backwards compatible way.
692+
"""
693+
694+
OTEL_EXPORTER_PROMETHEUS_PORT = "OTEL_EXPORTER_PROMETHEUS_PORT"
695+
"""
696+
.. envvar:: OTEL_EXPORTER_PROMETHEUS_PORT
697+
698+
The :envvar:`OTEL_EXPORTER_PROMETHEUS_PORT` environment variable configures the port used by
699+
the Prometheus exporter.
700+
Default: 9464
701+
702+
This is an experimental environment variable and the name of this variable and its behavior can
703+
change in a non-backwards compatible way.
704+
"""

0 commit comments

Comments
 (0)