Skip to content

Commit

Permalink
Prometheus exporter support for auto instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
aabmass committed Sep 18, 2023
1 parent 6973de2 commit 286f8dd
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 6 deletions.
7 changes: 4 additions & 3 deletions exporter/opentelemetry-exporter-prometheus/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ classifiers = [
]
dependencies = [
"opentelemetry-api ~= 1.12",
"opentelemetry-sdk ~= 1.12",
# DONOTMERGE: confirm that this will becomes ~= 1.20 in the next release
"opentelemetry-sdk ~= 1.21.0.dev",
"prometheus_client >= 0.5.0, < 1.0.0",
]

[project.optional-dependencies]
test = []

[project.entry-points.opentelemetry_metric_reader]
prometheus = "opentelemetry.exporter.prometheus:PrometheusMetricReader"
[project.entry-points.opentelemetry_metrics_exporter]
prometheus = "opentelemetry.exporter.prometheus:_AutoPrometheusMetricReader"

[project.urls]
Homepage = "https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-prometheus"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@
from itertools import chain
from json import dumps
from logging import getLogger
from os import environ
from re import IGNORECASE, UNICODE, compile
from typing import Dict, Sequence, Tuple, Union

from prometheus_client import start_http_server
from prometheus_client.core import (
REGISTRY,
CounterMetricFamily,
Expand All @@ -78,6 +80,10 @@
)
from prometheus_client.core import Metric as PrometheusMetric

from opentelemetry.sdk.environment_variables import (
OTEL_EXPORTER_PROMETHEUS_HOST,
OTEL_EXPORTER_PROMETHEUS_PORT,
)
from opentelemetry.sdk.metrics import Counter
from opentelemetry.sdk.metrics import Histogram as HistogramInstrument
from opentelemetry.sdk.metrics import (
Expand Down Expand Up @@ -282,7 +288,6 @@ def _translate_to_prometheus(
isinstance(metric.data, Sum)
and not should_convert_sum_to_gauge
):

metric_family_id = "|".join(
[pre_metric_family_id, CounterMetricFamily.__name__]
)
Expand All @@ -303,7 +308,6 @@ def _translate_to_prometheus(
isinstance(metric.data, Gauge)
or should_convert_sum_to_gauge
):

metric_family_id = "|".join(
[pre_metric_family_id, GaugeMetricFamily.__name__]
)
Expand All @@ -324,7 +328,6 @@ def _translate_to_prometheus(
metric_family_id
].add_metric(labels=label_values, value=value)
elif isinstance(metric.data, Histogram):

metric_family_id = "|".join(
[pre_metric_family_id, HistogramMetricFamily.__name__]
)
Expand Down Expand Up @@ -375,3 +378,21 @@ def _create_info_metric(
info = InfoMetricFamily(name, description, labels=attributes)
info.add_metric(labels=list(attributes.keys()), value=attributes)
return info


class _AutoPrometheusMetricReader(PrometheusMetricReader):
"""Thin wrapper around PrometheusMetricReader used for opentelemetry_metrics_exporter
This allows users to use the prometheus exporter with opentelemetry-instrument. It handles
starting the Prometheus http server on the the correct port and host.
"""

def __init__(self) -> None:
super().__init__()

# Default values are specified in
# https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#prometheus-exporter
start_http_server(
port=int(environ.get(OTEL_EXPORTER_PROMETHEUS_PORT, "9464")),
addr=environ.get(OTEL_EXPORTER_PROMETHEUS_HOST, "localhost"),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=no-self-use

import os
from unittest import TestCase
from unittest.mock import ANY, Mock, patch

from opentelemetry.exporter.prometheus import _AutoPrometheusMetricReader
from opentelemetry.sdk._configuration import _import_exporters
from opentelemetry.sdk.environment_variables import (
OTEL_EXPORTER_PROMETHEUS_HOST,
OTEL_EXPORTER_PROMETHEUS_PORT,
)


class TestEntrypoints(TestCase):
def test_import_exporters(self) -> None:
"""
Tests that the entrypoint can be loaded and doesn't have a typo in the name
"""
(
_trace_exporters,
metric_exporters,
_logs_exporters,
) = _import_exporters(
trace_exporter_names=[],
metric_exporter_names=["prometheus"],
log_exporter_names=[],
)

self.assertIs(
metric_exporters["prometheus"],
_AutoPrometheusMetricReader,
)

@patch("opentelemetry.exporter.prometheus.start_http_server")
@patch.dict(os.environ)
def test_starts_http_server_defaults(
self, mock_start_http_server: Mock
) -> None:
_AutoPrometheusMetricReader()
mock_start_http_server.assert_called_once_with(
port=9464, addr="localhost"
)

@patch("opentelemetry.exporter.prometheus.start_http_server")
@patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_HOST: "1.2.3.4"})
def test_starts_http_server_host_envvar(
self, mock_start_http_server: Mock
) -> None:
_AutoPrometheusMetricReader()
mock_start_http_server.assert_called_once_with(
port=ANY, addr="1.2.3.4"
)

@patch("opentelemetry.exporter.prometheus.start_http_server")
@patch.dict(os.environ, {OTEL_EXPORTER_PROMETHEUS_PORT: "9999"})
def test_starts_http_server_port_envvar(
self, mock_start_http_server: Mock
) -> None:
_AutoPrometheusMetricReader()
mock_start_http_server.assert_called_once_with(port=9999, addr=ANY)
24 changes: 24 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,27 @@
experimental feature and the name of this variable and its behavior can change
in a non-backwards compatible way.
"""

OTEL_EXPORTER_PROMETHEUS_HOST = "OTEL_EXPORTER_PROMETHEUS_HOST"
"""
.. envvar:: OTEL_EXPORTER_PROMETHEUS_HOST
The :envvar:`OTEL_EXPORTER_PROMETHEUS_HOST` environment variable configures the host used by
the Prometheus exporter.
Default: "localhost"
This is an experimental environment variable and the name of this variable and its behavior can
change in a non-backwards compatible way.
"""

OTEL_EXPORTER_PROMETHEUS_PORT = "OTEL_EXPORTER_PROMETHEUS_PORT"
"""
.. envvar:: OTEL_EXPORTER_PROMETHEUS_PORT
The :envvar:`OTEL_EXPORTER_PROMETHEUS_PORT` environment variable configures the port used by
the Prometheus exporter.
Default: 9464
This is an experimental environment variable and the name of this variable and its behavior can
change in a non-backwards compatible way.
"""

0 comments on commit 286f8dd

Please sign in to comment.