Skip to content

Commit d25e09a

Browse files
herin049xrmx
andauthored
opentelemetry-sdk: Implement meter configurator (#4966)
* Initial changes to add support for MeterConfigurator * fix lint errors * update SDK configuration to utilize Meter configurator * add basic Meter configurator benchmark * fix imports * Make meter configurator application more robust. * add update_rules method to _RuleBasedMeterConfigurator * fix lint errors * Update instrument.py: fix mismerge --------- Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
1 parent 02bcc17 commit d25e09a

File tree

12 files changed

+664
-37
lines changed

12 files changed

+664
-37
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4343
([#4910](https://github.com/open-telemetry/opentelemetry-python/pull/4910))
4444
- Add configurable `max_export_batch_size` to OTLP HTTP metrics exporter
4545
([#4576](https://github.com/open-telemetry/opentelemetry-python/pull/4576))
46+
- `opentelemetry-sdk`: Implement experimental Meter configurator
47+
([#4966](https://github.com/open-telemetry/opentelemetry-python/pull/4966))
4648
- `opentelemetry-exporter-otlp-proto-http`: use consistent protobuf for export request
4749
([#5015](https://github.com/open-telemetry/opentelemetry-python/pull/5015))
4850
- `opentelemetry-sdk`: cache TracerConfig into the tracer, this changes an internal interface. Only one Tracer with the same instrumentation scope will be created

opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,17 @@
1414
import pytest
1515

1616
from opentelemetry.sdk.metrics import Counter, MeterProvider
17+
from opentelemetry.sdk.metrics._internal import (
18+
_default_meter_configurator,
19+
_disable_meter_configurator,
20+
_MeterConfig,
21+
_RuleBasedMeterConfigurator,
22+
)
1723
from opentelemetry.sdk.metrics.export import (
1824
AggregationTemporality,
1925
InMemoryMetricReader,
2026
)
27+
from opentelemetry.sdk.util.instrumentation import _scope_name_matches_glob
2128

2229
reader_cumulative = InMemoryMetricReader()
2330
reader_delta = InMemoryMetricReader(
@@ -77,3 +84,43 @@ def benchmark_up_down_counter_add():
7784
udcounter.add(1, labels)
7885

7986
benchmark(benchmark_up_down_counter_add)
87+
88+
89+
@pytest.fixture(params=[None, 0, 1, 10, 50])
90+
def num_meter_configurator_rules(request):
91+
return request.param
92+
93+
94+
# pylint: disable=protected-access,redefined-outer-name
95+
def test_counter_add_with_meter_configurator_rules(
96+
benchmark, num_meter_configurator_rules
97+
):
98+
def benchmark_counter_add():
99+
counter_cumulative.add(1, {})
100+
101+
if num_meter_configurator_rules is None:
102+
provider_reader_cumulative._set_meter_configurator(
103+
meter_configurator=_disable_meter_configurator
104+
)
105+
else:
106+
107+
def meter_configurator(meter_scope):
108+
return _RuleBasedMeterConfigurator(
109+
rules=[
110+
(
111+
_scope_name_matches_glob(glob_pattern=str(i)),
112+
_MeterConfig(is_enabled=True),
113+
)
114+
for i in range(num_meter_configurator_rules)
115+
],
116+
default_config=_MeterConfig(is_enabled=True),
117+
)(meter_scope)
118+
119+
provider_reader_cumulative._set_meter_configurator(
120+
meter_configurator=meter_configurator
121+
)
122+
123+
benchmark(benchmark_counter_add)
124+
provider_reader_cumulative._set_meter_configurator(
125+
meter_configurator=_default_meter_configurator
126+
)

opentelemetry-sdk/benchmarks/trace/test_benchmark_trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
TracerProvider,
2222
_default_tracer_configurator,
2323
_RuleBasedTracerConfigurator,
24-
_scope_name_matches_glob,
2524
_TracerConfig,
2625
sampling,
2726
)
27+
from opentelemetry.sdk.util.instrumentation import _scope_name_matches_glob
2828

2929
tracer_provider = TracerProvider(
3030
sampler=sampling.DEFAULT_ON,

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

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@
5252
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
5353
OTEL_EXPORTER_OTLP_PROTOCOL,
5454
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
55+
OTEL_PYTHON_METER_CONFIGURATOR,
5556
OTEL_PYTHON_TRACER_CONFIGURATOR,
5657
OTEL_TRACES_SAMPLER,
5758
OTEL_TRACES_SAMPLER_ARG,
5859
)
5960
from opentelemetry.sdk.metrics import MeterProvider
61+
from opentelemetry.sdk.metrics._internal import _MeterConfiguratorT
6062
from opentelemetry.sdk.metrics.export import (
6163
MetricExporter,
6264
MetricReader,
@@ -171,6 +173,10 @@ def _get_tracer_configurator() -> str | None:
171173
return environ.get(OTEL_PYTHON_TRACER_CONFIGURATOR, None)
172174

173175

176+
def _get_meter_configurator() -> str | None:
177+
return environ.get(OTEL_PYTHON_METER_CONFIGURATOR, None)
178+
179+
174180
def _get_exporter_entry_point(
175181
exporter_name: str, signal_type: Literal["traces", "metrics", "logs"]
176182
):
@@ -267,6 +273,7 @@ def _init_metrics(
267273
],
268274
resource: Resource | None = None,
269275
exporter_args_map: ExporterArgsMap | None = None,
276+
meter_configurator: _MeterConfiguratorT | None = None,
270277
):
271278
metric_readers = []
272279

@@ -282,7 +289,11 @@ def _init_metrics(
282289
)
283290
)
284291

285-
provider = MeterProvider(resource=resource, metric_readers=metric_readers)
292+
provider = MeterProvider(
293+
resource=resource,
294+
metric_readers=metric_readers,
295+
_meter_configurator=meter_configurator,
296+
)
286297
set_meter_provider(provider)
287298

288299

@@ -387,6 +398,27 @@ def _import_tracer_configurator(
387398
return tracer_configurator_impl
388399

389400

401+
def _import_meter_configurator(
402+
meter_configurator_name: str | None,
403+
) -> _MeterConfiguratorT | None:
404+
if not meter_configurator_name:
405+
return None
406+
407+
try:
408+
_, meter_configurator_impl = _import_config_components(
409+
[meter_configurator_name.strip()],
410+
"_opentelemetry_meter_configurator",
411+
)[0]
412+
except Exception as exc: # pylint: disable=broad-exception-caught
413+
_logger.warning(
414+
"Using default meter configurator. Failed to load meter configurator, %s: %s",
415+
meter_configurator_name,
416+
exc,
417+
)
418+
return None
419+
return meter_configurator_impl
420+
421+
390422
def _import_exporters(
391423
trace_exporter_names: Sequence[str],
392424
metric_exporter_names: Sequence[str],
@@ -507,6 +539,7 @@ def _initialize_components(
507539
export_log_record_processor: _ConfigurationExporterLogRecordProcessorT
508540
| None = None,
509541
tracer_configurator: _TracerConfiguratorT | None = None,
542+
meter_configurator: _MeterConfiguratorT | None = None,
510543
):
511544
# pylint: disable=too-many-locals
512545
if trace_exporter_names is None:
@@ -538,6 +571,11 @@ def _initialize_components(
538571
tracer_configurator = _import_tracer_configurator(
539572
tracer_configurator_name
540573
)
574+
if meter_configurator is None:
575+
meter_configurator_name = _get_meter_configurator()
576+
meter_configurator = _import_meter_configurator(
577+
meter_configurator_name
578+
)
541579

542580
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
543581
# from the env variable else defaults to "unknown_service"
@@ -554,7 +592,10 @@ def _initialize_components(
554592
tracer_configurator=tracer_configurator,
555593
)
556594
_init_metrics(
557-
metric_exporters, resource, exporter_args_map=exporter_args_map
595+
exporters_or_readers=metric_exporters,
596+
resource=resource,
597+
exporter_args_map=exporter_args_map,
598+
meter_configurator=meter_configurator,
558599
)
559600
if setup_logging_handler is None:
560601
setup_logging_handler = (

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,3 +814,15 @@ def channel_credential_provider() -> grpc.ChannelCredentials:
814814
This is an experimental environment variable and the name of this variable and its behavior can
815815
change in a non-backwards compatible way.
816816
"""
817+
818+
OTEL_PYTHON_METER_CONFIGURATOR = "OTEL_PYTHON_METER_CONFIGURATOR"
819+
"""
820+
.. envvar:: OTEL_PYTHON_METER_CONFIGURATOR
821+
822+
The :envvar:`OTEL_PYTHON_METER_CONFIGURATOR` environment variable allows users to set a
823+
custom Meter Configurator function.
824+
Default: opentelemetry.sdk.metrics._internal._default_meter_configurator
825+
826+
This is an experimental environment variable and the name of this variable and its behavior can
827+
change in a non-backwards compatible way.
828+
"""

0 commit comments

Comments
 (0)