Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4910](https://github.com/open-telemetry/opentelemetry-python/pull/4910))
- Add configurable `max_export_batch_size` to OTLP HTTP metrics exporter
([#4576](https://github.com/open-telemetry/opentelemetry-python/pull/4576))
- `opentelemetry-sdk`: Implement experimental Meter configurator
([#4966](https://github.com/open-telemetry/opentelemetry-python/pull/4966))
- `opentelemetry-exporter-otlp-proto-http`: use consistent protobuf for export request
([#5015](https://github.com/open-telemetry/opentelemetry-python/pull/5015))
- `opentelemetry-sdk`: cache TracerConfig into the tracer, this changes an internal interface. Only one Tracer with the same instrumentation scope will be created
Expand Down
47 changes: 47 additions & 0 deletions opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@
import pytest

from opentelemetry.sdk.metrics import Counter, MeterProvider
from opentelemetry.sdk.metrics._internal import (
_default_meter_configurator,
_disable_meter_configurator,
_MeterConfig,
_RuleBasedMeterConfigurator,
)
from opentelemetry.sdk.metrics.export import (
AggregationTemporality,
InMemoryMetricReader,
)
from opentelemetry.sdk.util.instrumentation import _scope_name_matches_glob

reader_cumulative = InMemoryMetricReader()
reader_delta = InMemoryMetricReader(
Expand Down Expand Up @@ -77,3 +84,43 @@ def benchmark_up_down_counter_add():
udcounter.add(1, labels)

benchmark(benchmark_up_down_counter_add)


@pytest.fixture(params=[None, 0, 1, 10, 50])
def num_meter_configurator_rules(request):
return request.param


# pylint: disable=protected-access,redefined-outer-name
def test_counter_add_with_meter_configurator_rules(
benchmark, num_meter_configurator_rules
):
def benchmark_counter_add():
counter_cumulative.add(1, {})

if num_meter_configurator_rules is None:
provider_reader_cumulative._set_meter_configurator(
meter_configurator=_disable_meter_configurator
)
else:

def meter_configurator(meter_scope):
return _RuleBasedMeterConfigurator(
rules=[
(
_scope_name_matches_glob(glob_pattern=str(i)),
_MeterConfig(is_enabled=True),
)
for i in range(num_meter_configurator_rules)
],
default_config=_MeterConfig(is_enabled=True),
)(meter_scope)

provider_reader_cumulative._set_meter_configurator(
meter_configurator=meter_configurator
)

benchmark(benchmark_counter_add)
provider_reader_cumulative._set_meter_configurator(
meter_configurator=_default_meter_configurator
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
TracerProvider,
_default_tracer_configurator,
_RuleBasedTracerConfigurator,
_scope_name_matches_glob,
_TracerConfig,
sampling,
)
from opentelemetry.sdk.util.instrumentation import _scope_name_matches_glob

tracer_provider = TracerProvider(
sampler=sampling.DEFAULT_ON,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
OTEL_EXPORTER_OTLP_PROTOCOL,
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
OTEL_PYTHON_METER_CONFIGURATOR,
OTEL_PYTHON_TRACER_CONFIGURATOR,
OTEL_TRACES_SAMPLER,
OTEL_TRACES_SAMPLER_ARG,
)
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics._internal import _MeterConfiguratorT
from opentelemetry.sdk.metrics.export import (
MetricExporter,
MetricReader,
Expand Down Expand Up @@ -171,6 +173,10 @@ def _get_tracer_configurator() -> str | None:
return environ.get(OTEL_PYTHON_TRACER_CONFIGURATOR, None)


def _get_meter_configurator() -> str | None:
return environ.get(OTEL_PYTHON_METER_CONFIGURATOR, None)


def _get_exporter_entry_point(
exporter_name: str, signal_type: Literal["traces", "metrics", "logs"]
):
Expand Down Expand Up @@ -267,6 +273,7 @@ def _init_metrics(
],
resource: Resource | None = None,
exporter_args_map: ExporterArgsMap | None = None,
meter_configurator: _MeterConfiguratorT | None = None,
):
metric_readers = []

Expand All @@ -282,7 +289,11 @@ def _init_metrics(
)
)

provider = MeterProvider(resource=resource, metric_readers=metric_readers)
provider = MeterProvider(
resource=resource,
metric_readers=metric_readers,
_meter_configurator=meter_configurator,
)
set_meter_provider(provider)


Expand Down Expand Up @@ -387,6 +398,27 @@ def _import_tracer_configurator(
return tracer_configurator_impl


def _import_meter_configurator(
meter_configurator_name: str | None,
) -> _MeterConfiguratorT | None:
if not meter_configurator_name:
return None

try:
_, meter_configurator_impl = _import_config_components(
[meter_configurator_name.strip()],
"_opentelemetry_meter_configurator",
)[0]
except Exception as exc: # pylint: disable=broad-exception-caught
_logger.warning(
"Using default meter configurator. Failed to load meter configurator, %s: %s",
meter_configurator_name,
exc,
)
return None
return meter_configurator_impl


def _import_exporters(
trace_exporter_names: Sequence[str],
metric_exporter_names: Sequence[str],
Expand Down Expand Up @@ -507,6 +539,7 @@ def _initialize_components(
export_log_record_processor: _ConfigurationExporterLogRecordProcessorT
| None = None,
tracer_configurator: _TracerConfiguratorT | None = None,
meter_configurator: _MeterConfiguratorT | None = None,
):
# pylint: disable=too-many-locals
if trace_exporter_names is None:
Expand Down Expand Up @@ -538,6 +571,11 @@ def _initialize_components(
tracer_configurator = _import_tracer_configurator(
tracer_configurator_name
)
if meter_configurator is None:
meter_configurator_name = _get_meter_configurator()
meter_configurator = _import_meter_configurator(
meter_configurator_name
)

# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
# from the env variable else defaults to "unknown_service"
Expand All @@ -554,7 +592,10 @@ def _initialize_components(
tracer_configurator=tracer_configurator,
)
_init_metrics(
metric_exporters, resource, exporter_args_map=exporter_args_map
exporters_or_readers=metric_exporters,
resource=resource,
exporter_args_map=exporter_args_map,
meter_configurator=meter_configurator,
)
if setup_logging_handler is None:
setup_logging_handler = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -814,3 +814,15 @@ def channel_credential_provider() -> grpc.ChannelCredentials:
This is an experimental environment variable and the name of this variable and its behavior can
change in a non-backwards compatible way.
"""

OTEL_PYTHON_METER_CONFIGURATOR = "OTEL_PYTHON_METER_CONFIGURATOR"
"""
.. envvar:: OTEL_PYTHON_METER_CONFIGURATOR

The :envvar:`OTEL_PYTHON_METER_CONFIGURATOR` environment variable allows users to set a
custom Meter Configurator function.
Default: opentelemetry.sdk.metrics._internal._default_meter_configurator

This is an experimental environment variable and the name of this variable and its behavior can
change in a non-backwards compatible way.
"""
Loading
Loading