Skip to content

Commit 67d66dc

Browse files
authored
Merge branch 'main' into exporter-metrics
2 parents 8174777 + 90c0319 commit 67d66dc

13 files changed

Lines changed: 159 additions & 60 deletions

File tree

.github/workflows/check-links.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ on:
44
branches: [ main ]
55
paths:
66
- '**/*.md'
7+
- '**/*.rst'
78
- '.github/workflows/check-links.yml'
89
- '.github/workflows/check_links_config.json'
910
pull_request:
1011
paths:
1112
- '**/*.md'
13+
- '**/*.rst'
1214
- '.github/workflows/check-links.yml'
1315
- '.github/workflows/check_links_config.json'
1416

@@ -34,6 +36,7 @@ jobs:
3436
with:
3537
files: |
3638
**/*.md
39+
**/*.rst
3740
3841
- name: Install markdown-link-check
3942
if: steps.changed-files.outputs.any_changed == 'true'

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
## Unreleased
1414

15+
- Fix incorrect code example in `create_tracer()` docstring
16+
([#5072](https://github.com/open-telemetry/opentelemetry-python/issues/5072))
17+
- `opentelemetry-sdk`: add `load_entry_point` shared utility to declarative file configuration for loading plugins via entry points; refactor propagator loading to use it
18+
([#5093](https://github.com/open-telemetry/opentelemetry-python/pull/5093))
1519
- `opentelemetry-sdk`: fix YAML structure injection via environment variable substitution in declarative file configuration; values containing newlines are now emitted as quoted YAML scalars per spec requirement
1620
([#5091](https://github.com/open-telemetry/opentelemetry-python/pull/5091))
1721
- `opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration, enabling LoggerProvider instantiation from config files without reading env vars

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_common.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,39 @@
1515
from __future__ import annotations
1616

1717
import logging
18-
from typing import Optional
18+
from typing import Optional, Type
19+
20+
from opentelemetry.sdk._configuration._exceptions import ConfigurationError
21+
from opentelemetry.util._importlib_metadata import entry_points
1922

2023
_logger = logging.getLogger(__name__)
2124

2225

26+
def load_entry_point(group: str, name: str) -> Type:
27+
"""Load a plugin class from an entry point group by name.
28+
29+
Returns the loaded class — callers are responsible for instantiation
30+
with whatever arguments their config requires.
31+
32+
Raises:
33+
ConfigurationError: If the entry point is not found or fails to load.
34+
"""
35+
try:
36+
ep = next(iter(entry_points(group=group, name=name)), None)
37+
if ep is None:
38+
raise ConfigurationError(
39+
f"Plugin '{name}' not found in group '{group}'. "
40+
"Make sure the package providing this plugin is installed."
41+
)
42+
return ep.load()
43+
except ConfigurationError:
44+
raise
45+
except Exception as exc:
46+
raise ConfigurationError(
47+
f"Failed to load plugin '{name}' from group '{group}': {exc}"
48+
) from exc
49+
50+
2351
def _parse_headers(
2452
headers: Optional[list],
2553
headers_list: Optional[str],

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_propagator.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from opentelemetry.propagate import set_global_textmap
2121
from opentelemetry.propagators.composite import CompositePropagator
2222
from opentelemetry.propagators.textmap import TextMapPropagator
23-
from opentelemetry.sdk._configuration._exceptions import ConfigurationError
23+
from opentelemetry.sdk._configuration._common import load_entry_point
2424
from opentelemetry.sdk._configuration.models import (
2525
Propagator as PropagatorConfig,
2626
)
@@ -30,28 +30,11 @@
3030
from opentelemetry.trace.propagation.tracecontext import (
3131
TraceContextTextMapPropagator,
3232
)
33-
from opentelemetry.util._importlib_metadata import entry_points
3433

3534

3635
def _load_entry_point_propagator(name: str) -> TextMapPropagator:
37-
"""Load a propagator by name from the opentelemetry_propagator entry point group."""
38-
try:
39-
ep = next(
40-
iter(entry_points(group="opentelemetry_propagator", name=name)),
41-
None,
42-
)
43-
if not ep:
44-
raise ConfigurationError(
45-
f"Propagator '{name}' not found. "
46-
"It may not be installed or may be misspelled."
47-
)
48-
return ep.load()()
49-
except ConfigurationError:
50-
raise
51-
except Exception as exc:
52-
raise ConfigurationError(
53-
f"Failed to load propagator '{name}': {exc}"
54-
) from exc
36+
"""Load and instantiate a propagator by name."""
37+
return load_entry_point("opentelemetry_propagator", name)()
5538

5639

5740
def _propagators_from_textmap_config(

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
from time import time_ns
1919
from typing import Dict, List, Optional, Sequence
2020

21-
from opentelemetry.metrics import Instrument
2221
from opentelemetry.sdk.metrics._internal.aggregation import (
2322
Aggregation,
2423
AggregationTemporality,
2524
DefaultAggregation,
2625
_Aggregation,
2726
_SumAggregation,
2827
)
28+
from opentelemetry.sdk.metrics._internal.instrument import _Instrument
2929
from opentelemetry.sdk.metrics._internal.measurement import Measurement
3030
from opentelemetry.sdk.metrics._internal.point import DataPointT
3131
from opentelemetry.sdk.metrics._internal.view import View
@@ -37,7 +37,7 @@ class _ViewInstrumentMatch:
3737
def __init__(
3838
self,
3939
view: View,
40-
instrument: Instrument,
40+
instrument: _Instrument,
4141
instrument_class_aggregation: Dict[type, Aggregation],
4242
):
4343
self._view = view

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
Asynchronous,
3636
Counter,
3737
Histogram,
38-
Instrument,
3938
ObservableCounter,
4039
ObservableGauge,
4140
ObservableUpDownCounter,
@@ -59,6 +58,7 @@
5958
from opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.logarithm_mapping import (
6059
LogarithmMapping,
6160
)
61+
from opentelemetry.sdk.metrics._internal.instrument import _Instrument
6262
from opentelemetry.sdk.metrics._internal.measurement import Measurement
6363
from opentelemetry.sdk.metrics._internal.point import Buckets as BucketsPoint
6464
from opentelemetry.sdk.metrics._internal.point import (
@@ -1200,7 +1200,7 @@ class Aggregation(ABC):
12001200
@abstractmethod
12011201
def _create_aggregation(
12021202
self,
1203-
instrument: Instrument,
1203+
instrument: _Instrument,
12041204
attributes: Attributes,
12051205
reservoir_factory: Callable[
12061206
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1231,7 +1231,7 @@ class DefaultAggregation(Aggregation):
12311231

12321232
def _create_aggregation(
12331233
self,
1234-
instrument: Instrument,
1234+
instrument: _Instrument,
12351235
attributes: Attributes,
12361236
reservoir_factory: Callable[
12371237
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1323,7 +1323,7 @@ def __init__(
13231323

13241324
def _create_aggregation(
13251325
self,
1326-
instrument: Instrument,
1326+
instrument: _Instrument,
13271327
attributes: Attributes,
13281328
reservoir_factory: Callable[
13291329
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1372,7 +1372,7 @@ def __init__(
13721372

13731373
def _create_aggregation(
13741374
self,
1375-
instrument: Instrument,
1375+
instrument: _Instrument,
13761376
attributes: Attributes,
13771377
reservoir_factory: Callable[
13781378
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1416,7 +1416,7 @@ class SumAggregation(Aggregation):
14161416

14171417
def _create_aggregation(
14181418
self,
1419-
instrument: Instrument,
1419+
instrument: _Instrument,
14201420
attributes: Attributes,
14211421
reservoir_factory: Callable[
14221422
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1450,7 +1450,7 @@ class LastValueAggregation(Aggregation):
14501450

14511451
def _create_aggregation(
14521452
self,
1453-
instrument: Instrument,
1453+
instrument: _Instrument,
14541454
attributes: Attributes,
14551455
reservoir_factory: Callable[
14561456
[Type[_Aggregation]], ExemplarReservoirBuilder
@@ -1468,7 +1468,7 @@ class DropAggregation(Aggregation):
14681468

14691469
def _create_aggregation(
14701470
self,
1471-
instrument: Instrument,
1471+
instrument: _Instrument,
14721472
attributes: Attributes,
14731473
reservoir_factory: Callable[
14741474
[Type[_Aggregation]], ExemplarReservoirBuilder

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717

1818
from logging import getLogger
1919
from time import time_ns
20-
from typing import TYPE_CHECKING, Generator, Iterable, List, Sequence, Union
20+
from typing import (
21+
TYPE_CHECKING,
22+
Generator,
23+
Iterable,
24+
List,
25+
Protocol,
26+
Sequence,
27+
Union,
28+
cast,
29+
runtime_checkable,
30+
)
2131

2232
# This kind of import is needed to avoid Sphinx errors.
2333
from opentelemetry.context import Context, get_current
24-
from opentelemetry.metrics import CallbackT
34+
from opentelemetry.metrics import Asynchronous, CallbackT, Synchronous
2535
from opentelemetry.metrics import Counter as APICounter
2636
from opentelemetry.metrics import Histogram as APIHistogram
2737
from opentelemetry.metrics import ObservableCounter as APIObservableCounter
@@ -55,7 +65,15 @@
5565
)
5666

5767

58-
class _Synchronous:
68+
@runtime_checkable
69+
class _Instrument(Protocol):
70+
name: str
71+
unit: str
72+
description: str
73+
instrumentation_scope: InstrumentationScope
74+
75+
76+
class _Synchronous(_Instrument, Synchronous):
5977
def __init__(
6078
self,
6179
name: str,
@@ -79,7 +97,7 @@ def __init__(
7997

8098
name = result["name"]
8199
unit = result["unit"]
82-
description = result["description"]
100+
description = cast(str, result["description"])
83101

84102
self.name = name.lower()
85103
self.unit = unit
@@ -93,13 +111,13 @@ def _is_enabled(self) -> bool:
93111
return self._meter_config is None or self._meter_config.is_enabled
94112

95113

96-
class _Asynchronous:
114+
class _Asynchronous(_Instrument, Asynchronous):
97115
def __init__(
98116
self,
99117
name: str,
100118
instrumentation_scope: InstrumentationScope,
101119
measurement_consumer: MeasurementConsumer,
102-
callbacks: Iterable[CallbackT] | None = None,
120+
callbacks: Sequence[CallbackT] | None = None,
103121
unit: str = "",
104122
description: str = "",
105123
*,
@@ -118,7 +136,7 @@ def __init__(
118136

119137
name = result["name"]
120138
unit = result["unit"]
121-
description = result["description"]
139+
description = cast(str, result["description"])
122140

123141
self.name = name.lower()
124142
self.unit = unit

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from __future__ import annotations
16+
1517
from dataclasses import dataclass
16-
from typing import Union
18+
from typing import TYPE_CHECKING, Union
1719

1820
from opentelemetry.context import Context
19-
from opentelemetry.metrics import Instrument
2021
from opentelemetry.util.types import Attributes
2122

23+
if TYPE_CHECKING:
24+
from opentelemetry.sdk.metrics._internal.instrument import _Instrument
25+
2226

2327
@dataclass(frozen=True)
2428
class Measurement:
@@ -35,6 +39,6 @@ class Measurement:
3539

3640
value: Union[int, float]
3741
time_unix_nano: int
38-
instrument: Instrument
42+
instrument: _Instrument
3943
context: Context
4044
attributes: Attributes = None

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from opentelemetry.metrics import (
2121
Asynchronous,
2222
Counter,
23-
Instrument,
2423
ObservableCounter,
2524
)
2625
from opentelemetry.sdk.metrics._internal._view_instrument_match import (
@@ -36,6 +35,7 @@
3635
_LastValueAggregation,
3736
_SumAggregation,
3837
)
38+
from opentelemetry.sdk.metrics._internal.instrument import _Instrument
3939
from opentelemetry.sdk.metrics._internal.measurement import Measurement
4040
from opentelemetry.sdk.metrics._internal.point import (
4141
ExponentialHistogram,
@@ -70,13 +70,13 @@ def __init__(
7070
self._lock = RLock()
7171
self._sdk_config = sdk_config
7272
self._instrument_view_instrument_matches: Dict[
73-
Instrument, List[_ViewInstrumentMatch]
73+
_Instrument, List[_ViewInstrumentMatch]
7474
] = {}
7575
self._instrument_class_temporality = instrument_class_temporality
7676
self._instrument_class_aggregation = instrument_class_aggregation
7777

7878
def _get_or_init_view_instrument_match(
79-
self, instrument: Instrument
79+
self, instrument: _Instrument
8080
) -> List[_ViewInstrumentMatch]:
8181
# Optimistically get the relevant views for the given instrument. Once set for a given
8282
# instrument, the mapping will never change
@@ -253,7 +253,7 @@ def collect(self) -> Optional[MetricsData]:
253253

254254
def _handle_view_instrument_match(
255255
self,
256-
instrument: Instrument,
256+
instrument: _Instrument,
257257
view_instrument_matches: List["_ViewInstrumentMatch"],
258258
) -> None:
259259
for view in self._sdk_config.views:
@@ -292,7 +292,7 @@ def _handle_view_instrument_match(
292292

293293
@staticmethod
294294
def _check_view_instrument_compatibility(
295-
view: View, instrument: Instrument
295+
view: View, instrument: _Instrument
296296
) -> bool:
297297
"""
298298
Checks if a view and an instrument are compatible.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
ExemplarReservoirBuilder,
3131
SimpleFixedSizeExemplarReservoir,
3232
)
33+
from opentelemetry.sdk.metrics._internal.instrument import _Instrument
3334

3435
_logger = getLogger(__name__)
3536

@@ -164,7 +165,7 @@ def __init__(
164165

165166
# pylint: disable=too-many-return-statements
166167
# pylint: disable=too-many-branches
167-
def _match(self, instrument: Instrument) -> bool:
168+
def _match(self, instrument: _Instrument) -> bool:
168169
if self._instrument_type is not None:
169170
if not isinstance(instrument, self._instrument_type):
170171
return False

0 commit comments

Comments
 (0)