Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Increment the:

## [Unreleased]

* [SDK] Add `MeterProvider::UpdateMeterConfigurator()` and example
[#4256](https://github.com/open-telemetry/opentelemetry-cpp/issues/4256)

* [BUILD] Add missing opentelemetry_proto dependency to otlp_recordable
pkg-config
[#4316](https://github.com/open-telemetry/opentelemetry-cpp/pull/4316)
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ add_subdirectory(multi_processor)
add_subdirectory(environment_carrier)
add_subdirectory(tracer_configurator)
add_subdirectory(logger_configurator)
add_subdirectory(meter_configurator)
add_subdirectory(explicit_parent)

if(WITH_EXAMPLES_HTTP)
Expand Down
20 changes: 20 additions & 0 deletions examples/meter_configurator/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

load("@rules_cc//cc:cc_test.bzl", "cc_test")

cc_test(
name = "example_meter_configurator",
srcs = [
"main.cc",
],
tags = [
"ostream",
"tested_example",
],
deps = [
"//api",
"//exporters/ostream:ostream_metric_exporter",
"//sdk/src/metrics",
],
)
13 changes: 13 additions & 0 deletions examples/meter_configurator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

add_executable(example_meter_configurator main.cc)
target_link_libraries(
example_meter_configurator
PRIVATE opentelemetry-cpp::metrics
opentelemetry-cpp::ostream_metrics_exporter)

if(BUILD_TESTING)
add_test(NAME examples.meter_configurator
COMMAND "$<TARGET_FILE:example_meter_configurator>")
endif()
249 changes: 249 additions & 0 deletions examples/meter_configurator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Meter Configurator Example

This example demonstrates how to set a `MeterConfigurator` on construction
of the `MeterProvider` and to update it at runtime using
`MeterProvider::UpdateMeterConfigurator` to enable or disable specific
meters without restarting the application or recreating the meters.

`MeterProvider::UpdateMeterConfigurator` recomputes and applies a new
`MeterConfig` to all existing meters, and the updated configurator is also
used for meters created afterwards. It is safe to call concurrently with
`MeterProvider::GetMeter` and with instrument creation and recording on
existing meters.

Three meters with unique instrumentation scope names are used to simulate
a user application:

- `my_application`: simulated user application
- `my_library`: simulated user library
- `external_library`: simulated external third-party library

The example walks through a simulated cost management and debugging
workflow in four stages:

- Stage 1: Startup. All meters are enabled and all three scopes report
metrics.
- Stage 2: Steady state. The noisy `external_library` metrics are not
needed, so its meter is disabled.
- Stage 3: A user reports unexpected behavior. Re-enable the
`external_library` meter to investigate.
- Stage 4: The investigation completes and the `external_library` meter is
disabled again.

A `Meter` that is disabled when an instrument is created returns a no-op
instrument, and that instrument stays no-op even if the meter is enabled
later. Create instruments while the meter is enabled, as the classes in
this example do at startup, and then toggle the meters to start and stop
collection.

Disabling a meter stops collection and export for that scope. Measurements
recorded through already-created instruments while the meter is disabled
are still accumulated by the aggregation, so with cumulative temporality
they are included in the total once the meter is enabled again. This is
why `external_library.requests` reports `3` in stage 3 rather than `2`.

## Build and run

```sh
~/build/examples/meter_configurator/example_meter_configurator
```

**Expected output:**

Metrics are exported to stdout via the `OStreamMetricExporter`. The example
uses a long export interval and calls `ForceFlush` at the end of each
stage, so each stage exports exactly once.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The long interval does not make ForceFlush() the only export trigger. OnInitialized() starts the worker, and DoBackgroundWork() calls CollectAndExportOnce() before its first wait. That startup collection races with Stage 1's recording and ForceFlush():

documented: 4 stage-triggered export batches
observed:   5 batches, with the extra batch's placement varying

Therefore the checked-in exact transcript is not deterministic. The CTest target only runs the executable, and Bazel uses a plain cc_test, so neither validates stdout.


```sh
Stage 1: startup, all meters enabled
my_application, my_library and external_library report metrics
{
scope name : my_application
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_application.work_items
description : Work items processed by the application
unit : {item}
type : SumPointData
value : 1
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : my_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_library.calls
description : Calls into the library
unit : {call}
type : SumPointData
value : 1
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : external_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : external_library.requests
description : Requests handled by the external library
unit : {request}
type : SumPointData
value : 1
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}

Stage 2: steady state, external_library meter disabled
only my_application and my_library report metrics
{
scope name : my_application
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_application.work_items
description : Work items processed by the application
unit : {item}
type : SumPointData
value : 2
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : my_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_library.calls
description : Calls into the library
unit : {call}
type : SumPointData
value : 2
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}

Stage 3: investigating, external_library meter re-enabled
all three scopes report metrics again
{
scope name : my_application
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_application.work_items
description : Work items processed by the application
unit : {item}
type : SumPointData
value : 3
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : my_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_library.calls
description : Calls into the library
unit : {call}
type : SumPointData
value : 3
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : external_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : external_library.requests
description : Requests handled by the external library
unit : {request}
type : SumPointData
value : 3
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}

Stage 4: investigation complete, external_library meter disabled again
only my_application and my_library report metrics
{
scope name : my_application
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_application.work_items
description : Work items processed by the application
unit : {item}
type : SumPointData
value : 4
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
{
scope name : my_library
schema url :
version :
start time : Mon Jul 27 09:32:35 2026
end time : Mon Jul 27 09:32:35 2026
instrument name : my_library.calls
description : Calls into the library
unit : {call}
type : SumPointData
value : 4
attributes :
resources :
service.name: meter_configurator_example
telemetry.sdk.language: cpp
telemetry.sdk.name: opentelemetry
telemetry.sdk.version: 1.29.0-dev
}
```
Loading
Loading