Skip to content

Commit cc827f5

Browse files
authored
Merge branch 'main' into pyright-sdk-trace
2 parents 3f898b8 + 9d90db4 commit cc827f5

File tree

8 files changed

+63
-22
lines changed

8 files changed

+63
-22
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
([#4965](https://github.com/open-telemetry/opentelemetry-python/pull/4965))
2525
- Resolve some Pyright type errors in Span/ReadableSpan and utility stubs
2626
([#4973](https://github.com/open-telemetry/opentelemetry-python/pull/4973))
27+
- `opentelemetry-exporter-prometheus`: Fix metric name prefix
28+
([#4895](https://github.com/open-telemetry/opentelemetry-python/pull/4895))
2729

2830
## Version 1.40.0/0.61b0 (2026-03-04)
2931

docs/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@
202202
"exclude-members": ",".join(_exclude_members),
203203
}
204204

205+
# Napoleon configuration to avoid duplication with autodoc for dataclass fields
206+
# Use ivar (instance variable) style for documenting attributes
207+
napoleon_use_ivar = True
208+
205209
# -- Options for HTML output -------------------------------------------------
206210

207211
# The theme to use for HTML and HTML Help pages. See the documentation for

docs/examples/metrics/prometheus-grafana/prometheus-monitor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
start_http_server(port=8000, addr="localhost")
1212
# Exporter to export metrics to Prometheus
1313
prefix = "MyAppPrefix"
14-
reader = PrometheusMetricReader(prefix)
14+
reader = PrometheusMetricReader(prefix=prefix)
1515
# Meter is responsible for creating and recording metrics
1616
set_meter_provider(MeterProvider(metric_readers=[reader]))
1717
meter = get_meter_provider().get_meter("view-name-change", "0.1.2")

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
3939
# Exporter to export metrics to Prometheus
4040
prefix = "MyAppPrefix"
41-
reader = PrometheusMetricReader(prefix)
41+
reader = PrometheusMetricReader(prefix=prefix)
4242
4343
# Meter is responsible for creating and recording metrics
4444
set_meter_provider(MeterProvider(metric_readers=[reader]))
@@ -131,7 +131,9 @@ def _convert_buckets(
131131
class PrometheusMetricReader(MetricReader):
132132
"""Prometheus metric exporter for OpenTelemetry."""
133133

134-
def __init__(self, disable_target_info: bool = False) -> None:
134+
def __init__(
135+
self, disable_target_info: bool = False, prefix: str = ""
136+
) -> None:
135137
super().__init__(
136138
preferred_temporality={
137139
Counter: AggregationTemporality.CUMULATIVE,
@@ -142,9 +144,12 @@ def __init__(self, disable_target_info: bool = False) -> None:
142144
ObservableGauge: AggregationTemporality.CUMULATIVE,
143145
}
144146
)
145-
self._collector = _CustomCollector(disable_target_info)
147+
self._collector = _CustomCollector(
148+
disable_target_info=disable_target_info, prefix=prefix
149+
)
146150
REGISTRY.register(self._collector)
147151
self._collector._callback = self.collect
152+
self._prefix = prefix
148153

149154
def _receive_metrics(
150155
self,
@@ -167,11 +172,12 @@ class _CustomCollector:
167172
https://github.com/prometheus/client_python#custom-collectors
168173
"""
169174

170-
def __init__(self, disable_target_info: bool = False):
175+
def __init__(self, disable_target_info: bool = False, prefix: str = ""):
171176
self._callback = None
172177
self._metrics_datas: Deque[MetricsData] = deque()
173178
self._disable_target_info = disable_target_info
174179
self._target_info = None
180+
self._prefix = prefix
175181

176182
def add_metrics_data(self, metrics_data: MetricsData) -> None:
177183
"""Add metrics to Prometheus data"""
@@ -227,7 +233,10 @@ def _translate_to_prometheus(
227233
label_values_data_points = []
228234
values = []
229235

230-
metric_name = sanitize_full_name(metric.name)
236+
metric_name = metric.name
237+
if self._prefix:
238+
metric_name = self._prefix + "_" + metric_name
239+
metric_name = sanitize_full_name(metric_name)
231240
metric_description = metric.description or ""
232241
metric_unit = map_unit(metric.unit)
233242

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def setUp(self):
5555
)
5656

5757
def verify_text_format(
58-
self, metric: Metric, expect_prometheus_text: str
58+
self, metric: Metric, expect_prometheus_text: str, prefix: str = ""
5959
) -> None:
6060
metrics_data = MetricsData(
6161
resource_metrics=[
@@ -73,7 +73,7 @@ def verify_text_format(
7373
]
7474
)
7575

76-
collector = _CustomCollector(disable_target_info=True)
76+
collector = _CustomCollector(disable_target_info=True, prefix=prefix)
7777
collector.add_metrics_data(metrics_data)
7878
result_bytes = generate_latest(collector)
7979
result = result_bytes.decode("utf-8")
@@ -463,6 +463,30 @@ def test_metric_name(self):
463463
"""
464464
),
465465
)
466+
self.verify_text_format(
467+
_generate_sum(name="test_counter_w_prefix", value=1, unit=""),
468+
dedent(
469+
"""\
470+
# HELP foo_test_counter_w_prefix_total foo
471+
# TYPE foo_test_counter_w_prefix_total counter
472+
foo_test_counter_w_prefix_total{a="1",b="true"} 1.0
473+
"""
474+
),
475+
prefix="foo",
476+
)
477+
self.verify_text_format(
478+
_generate_sum(
479+
name="test_counter_w_invalid_chars_prefix", value=1, unit=""
480+
),
481+
dedent(
482+
"""\
483+
# HELP _foo_test_counter_w_invalid_chars_prefix_total foo
484+
# TYPE _foo_test_counter_w_invalid_chars_prefix_total counter
485+
_foo_test_counter_w_invalid_chars_prefix_total{a="1",b="true"} 1.0
486+
"""
487+
),
488+
prefix="#foo",
489+
)
466490
self.verify_text_format(
467491
_generate_sum(name="1leading_digit", value=1, unit=""),
468492
dedent(

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,25 @@ class MeterProvider(APIMeterProvider):
377377
metric_readers: Register metric readers to collect metrics from the SDK
378378
on demand. Each :class:`opentelemetry.sdk.metrics.export.MetricReader` is
379379
completely independent and will collect separate streams of
380-
metrics. TODO: reference ``PeriodicExportingMetricReader`` usage with push
381-
exporters here.
380+
metrics. For push-based export, use
381+
:class:`opentelemetry.sdk.metrics.export.PeriodicExportingMetricReader`.
382382
resource: The resource representing what the metrics emitted from the SDK pertain to.
383383
shutdown_on_exit: If true, registers an `atexit` handler to call
384384
`MeterProvider.shutdown`
385385
views: The views to configure the metric output the SDK
386386
387+
.. code-block:: python
388+
:caption: Push-based export with PeriodicExportingMetricReader
389+
390+
from opentelemetry.sdk.metrics import MeterProvider
391+
from opentelemetry.sdk.metrics.export import (
392+
ConsoleMetricExporter,
393+
PeriodicExportingMetricReader,
394+
)
395+
396+
reader = PeriodicExportingMetricReader(ConsoleMetricExporter())
397+
provider = MeterProvider(metric_readers=[reader])
398+
387399
By default, instruments which do not match any :class:`opentelemetry.sdk.metrics.view.View` (or if no :class:`opentelemetry.sdk.metrics.view.View`\ s
388400
are provided) will report metrics with the default aggregation for the
389401
instrument's kind. To disable instruments by default, configure a match-all

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/exemplar/exemplar.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Exemplar:
2626
was recorded, for example the span and trace ID of the active span when the
2727
exemplar was recorded.
2828
29-
Attributes
29+
Attributes:
3030
trace_id: (optional) The trace associated with a recording
3131
span_id: (optional) The span associated with a recording
3232
time_unix_nano: The time of the observation
@@ -38,11 +38,6 @@ class Exemplar:
3838
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar
3939
"""
4040

41-
# TODO Fix doc - if using valid Google `Attributes:` key, the attributes are duplicated
42-
# one will come from napoleon extension and the other from autodoc extension. This
43-
# will raise an sphinx error of duplicated object description
44-
# See https://github.com/sphinx-doc/sphinx/issues/8664
45-
4641
filtered_attributes: Attributes
4742
value: Union[int, float]
4843
time_unix_nano: int

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/measurement.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,14 @@ class Measurement:
2525
"""
2626
Represents a data point reported via the metrics API to the SDK.
2727
28-
Attributes
28+
Attributes:
2929
value: Measured value
3030
time_unix_nano: The time the API call was made to record the Measurement
3131
instrument: The instrument that produced this `Measurement`.
3232
context: The active Context of the Measurement at API call time.
3333
attributes: Measurement attributes
3434
"""
3535

36-
# TODO Fix doc - if using valid Google `Attributes:` key, the attributes are duplicated
37-
# one will come from napoleon extension and the other from autodoc extension. This
38-
# will raise an sphinx error of duplicated object description
39-
# See https://github.com/sphinx-doc/sphinx/issues/8664
40-
4136
value: Union[int, float]
4237
time_unix_nano: int
4338
instrument: Instrument

0 commit comments

Comments
 (0)