Skip to content

Commit 71fae42

Browse files
committed
Add support for OTEL_TRACES_SAMPLER
1 parent 1ee7046 commit 71fae42

File tree

5 files changed

+327
-5
lines changed

5 files changed

+327
-5
lines changed

sdk/monitor/azure-monitor-opentelemetry/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ You can configure further with [OpenTelemetry environment variables][ot_env_vars
8080
| `OTEL_TRACES_EXPORTER` | If set to `None`, disables collection and export of distributed tracing telemetry. |
8181
| `OTEL_BLRP_SCHEDULE_DELAY` | Specifies the logging export interval in milliseconds. Defaults to 5000. |
8282
| `OTEL_BSP_SCHEDULE_DELAY` | Specifies the distributed tracing export interval in milliseconds. Defaults to 5000. |
83-
| `OTEL_TRACES_SAMPLER` | Specifies the sampler to be used for traces. Supports both [application_insights_sampling] and [rate_limited_sampling]. Use `microsoft.fixed.percentage` for the Application Insights sampler or `microsoft.rate_limited` for the Rate Limited sampler. |
83+
| `OTEL_TRACES_SAMPLER` | Specifies the sampler to be used for traces. Supports [`always_on`, `always_off`, `trace_id_ratio`, `parentbased_always_on`, `parentbased_always_off`, `parentbased_trace_id_ratio`], [application_insights_sampling] and [rate_limited_sampling]. Use `microsoft.fixed.percentage` for the Application Insights sampler or `microsoft.rate_limited` for the Rate Limited sampler. |
8484
| `OTEL_TRACES_SAMPLER_ARG` | Specifies the sampling parameter for the configured sampler. For the Application Insights sampler, this sets the ratio of distributed tracing telemetry to be [sampled][application_insights_sampling] with accepted values in the range [0,1]. Defaults to 1.0 (no sampling). For the Rate Limited sampler, this sets the maximum traces per second to be [sampled][rate_limited_sampler]. For example, 0.5 means one trace every two seconds, while 5.0 means five traces per second. |
8585
| `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS` | Specifies which of the supported instrumentations to disable. Disabled instrumentations will not be instrumented as part of `configure_azure_monitor`. However, they can still be manually instrumented with `instrument()` directly. Accepts a comma-separated list of lowercase [Library Names](#officially-supported-instrumentations). For example, set to `"psycopg2,fastapi"` to disable the Psycopg2 and FastAPI instrumentations. Defaults to an empty list, enabling all supported instrumentations. |
8686
| `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` | An experimental OpenTelemetry environment variable used to specify Resource Detectors to be used to generate Resource Attributes. This is an experimental feature and the name of this variable and its behavior can change in a non-backwards compatible way. Defaults to "azure_app_service,azure_vm" to enable the [Azure Resource Detectors][ot_resource_detector_azure] for Azure App Service and Azure VM. To add or remove specific resource detectors, set the environment variable accordingly. See the [OpenTelemetry Python Resource Detector Documentation][ot_python_resource_detectors] for more. |
@@ -221,6 +221,7 @@ contact [[email protected]](mailto:[email protected]) with any additio
221221
[application_insights_namespace]: https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview
222222
[application_insights_sampling]: https://learn.microsoft.com/azure/azure-monitor/app/sampling
223223
[rate_limited_sampling]: https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-configuration
224+
[always_on]: https://opentelemetry.io/docs/languages/sdk-configuration/general/#otel_traces_sampler
224225
[connection_string_doc]: https://learn.microsoft.com/azure/azure-monitor/app/sdk-connection-string
225226
[distro_feature_request]: https://github.com/Azure/azure-sdk-for-python/issues/new
226227
[exporter_configuration_docs]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry-exporter#configuration

sdk/monitor/azure-monitor-opentelemetry/azure/monitor/opentelemetry/_configure.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
SPAN_PROCESSORS_ARG,
4141
VIEWS_ARG,
4242
ENABLE_TRACE_BASED_SAMPLING_ARG,
43+
SAMPLING_ARG,
44+
SAMPLER_TYPE,
4345
)
4446
from azure.monitor.opentelemetry._types import ConfigurationValue
4547
from azure.monitor.opentelemetry.exporter._quickpulse import ( # pylint: disable=import-error,no-name-in-module
@@ -73,6 +75,7 @@
7375
from azure.monitor.opentelemetry._utils.configurations import (
7476
_get_configurations,
7577
_is_instrumentation_enabled,
78+
_get_sampler_from_name,
7679
)
7780
from azure.monitor.opentelemetry._utils.instrumentation import (
7881
get_dist_dependency_conflicts,
@@ -149,7 +152,12 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
149152
def _setup_tracing(configurations: Dict[str, ConfigurationValue]):
150153
resource: Resource = configurations[RESOURCE_ARG] # type: ignore
151154
enable_performance_counters_config = configurations[ENABLE_PERFORMANCE_COUNTERS_ARG]
152-
if SAMPLING_TRACES_PER_SECOND_ARG in configurations:
155+
if SAMPLING_ARG in configurations:
156+
sampler_arg = configurations[SAMPLING_ARG]
157+
sampler_type = configurations[SAMPLER_TYPE]
158+
sampler = _get_sampler_from_name(sampler_type, sampler_arg)
159+
tracer_provider = TracerProvider(sampler=sampler, resource=resource)
160+
elif SAMPLING_TRACES_PER_SECOND_ARG in configurations:
153161
traces_per_second = configurations[SAMPLING_TRACES_PER_SECOND_ARG]
154162
tracer_provider = TracerProvider(
155163
sampler=RateLimitedSampler(target_spans_per_second_limit=cast(float, traces_per_second)), resource=resource

sdk/monitor/azure-monitor-opentelemetry/azure/monitor/opentelemetry/_constants.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@
2929
FIXED_PERCENTAGE_SAMPLER = "microsoft.fixed.percentage"
3030
SAMPLING_TRACES_PER_SECOND_ARG = "traces_per_second"
3131
ENABLE_TRACE_BASED_SAMPLING_ARG = "enable_trace_based_sampling_for_logs"
32+
SAMPLER_TYPE = "sampler_type"
33+
SAMPLING_ARG = "sampling_arg"
34+
ALWAYS_ON_SAMPLER = "always_on"
35+
ALWAYS_OFF_SAMPLER = "always_off"
36+
TRACE_ID_RATIO_SAMPLER = "trace_id_ratio"
37+
PARENT_BASED_ALWAYS_ON_SAMPLER = "parentbased_always_on"
38+
PARENT_BASED_ALWAYS_OFF_SAMPLER = "parentbased_always_off"
39+
PARENT_BASED_TRACE_ID_RATIO_SAMPLER = "parentbased_trace_id_ratio"
40+
SUPPORTED_OTEL_SAMPLERS = (
41+
RATE_LIMITED_SAMPLER,
42+
FIXED_PERCENTAGE_SAMPLER,
43+
ALWAYS_ON_SAMPLER,
44+
ALWAYS_OFF_SAMPLER,
45+
TRACE_ID_RATIO_SAMPLER,
46+
PARENT_BASED_ALWAYS_ON_SAMPLER,
47+
PARENT_BASED_ALWAYS_OFF_SAMPLER,
48+
PARENT_BASED_TRACE_ID_RATIO_SAMPLER,
49+
)
3250

3351
# --------------------Autoinstrumentation Configuration------------------------------------------
3452

sdk/monitor/azure-monitor-opentelemetry/azure/monitor/opentelemetry/_utils/configurations.py

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
)
2424
from opentelemetry.sdk.resources import Resource
2525

26+
from opentelemetry.sdk.trace.sampling import (
27+
TraceIdRatioBased,
28+
ALWAYS_OFF,
29+
ALWAYS_ON,
30+
ParentBased,
31+
)
32+
2633
from azure.monitor.opentelemetry._constants import (
2734
_AZURE_APP_SERVICE_RESOURCE_DETECTOR_NAME,
2835
_AZURE_VM_RESOURCE_DETECTOR_NAME,
@@ -47,6 +54,15 @@
4754
RATE_LIMITED_SAMPLER,
4855
FIXED_PERCENTAGE_SAMPLER,
4956
ENABLE_TRACE_BASED_SAMPLING_ARG,
57+
SUPPORTED_OTEL_SAMPLERS,
58+
ALWAYS_OFF_SAMPLER,
59+
ALWAYS_ON_SAMPLER,
60+
TRACE_ID_RATIO_SAMPLER,
61+
PARENT_BASED_ALWAYS_ON_SAMPLER,
62+
PARENT_BASED_ALWAYS_OFF_SAMPLER,
63+
PARENT_BASED_TRACE_ID_RATIO_SAMPLER,
64+
SAMPLING_ARG,
65+
SAMPLER_TYPE,
5066
)
5167
from azure.monitor.opentelemetry._types import ConfigurationValue
5268
from azure.monitor.opentelemetry._version import VERSION
@@ -145,6 +161,7 @@ def _default_resource(configurations):
145161
configurations[RESOURCE_ARG] = Resource.create(configurations[RESOURCE_ARG].attributes)
146162

147163

164+
# pylint: disable=too-many-statements, disable=too-many-branches
148165
def _default_sampling_ratio(configurations):
149166
default_value = 1.0
150167
sampler_type = environ.get(OTEL_TRACES_SAMPLER)
@@ -188,16 +205,75 @@ def _default_sampling_ratio(configurations):
188205
)
189206
configurations[SAMPLING_RATIO_ARG] = default_value
190207

208+
# Handle always_on sampler
209+
elif sampler_type == ALWAYS_ON_SAMPLER:
210+
configurations[SAMPLING_ARG] = 1.0
211+
configurations[SAMPLER_TYPE] = ALWAYS_ON_SAMPLER
212+
213+
# Handle always_off sampler
214+
elif sampler_type == ALWAYS_OFF_SAMPLER:
215+
configurations[SAMPLING_ARG] = 0.0
216+
configurations[SAMPLER_TYPE] = ALWAYS_OFF_SAMPLER
217+
218+
# Handle trace_id_ratio sampler
219+
elif sampler_type == TRACE_ID_RATIO_SAMPLER:
220+
try:
221+
sampler_value = float(sampler_arg) if sampler_arg is not None else default_value
222+
if sampler_value < 0 or sampler_value > 1:
223+
_logger.error("Invalid value for OTEL_TRACES_SAMPLER_ARG. It should be a value between 0 and 1.")
224+
sampler_value = default_value
225+
else:
226+
_logger.info("Using sampling value: %s", sampler_value)
227+
configurations[SAMPLING_ARG] = sampler_value
228+
except ValueError as e:
229+
_logger.error( # pylint: disable=C
230+
_INVALID_FLOAT_MESSAGE,
231+
OTEL_TRACES_SAMPLER_ARG,
232+
default_value,
233+
e,
234+
)
235+
configurations[SAMPLING_ARG] = sampler_value
236+
configurations[SAMPLER_TYPE] = TRACE_ID_RATIO_SAMPLER
237+
238+
# Handle parentbased_always_on sampler
239+
elif sampler_type == PARENT_BASED_ALWAYS_ON_SAMPLER:
240+
configurations[SAMPLING_ARG] = 1.0
241+
configurations[SAMPLER_TYPE] = PARENT_BASED_ALWAYS_ON_SAMPLER
242+
243+
# Handle parentbased_always_off sampler
244+
elif sampler_type == PARENT_BASED_ALWAYS_OFF_SAMPLER:
245+
configurations[SAMPLING_ARG] = 0.0
246+
configurations[SAMPLER_TYPE] = PARENT_BASED_ALWAYS_OFF_SAMPLER
247+
248+
# Handle parentbased_traceidratio sampler
249+
elif sampler_type == PARENT_BASED_TRACE_ID_RATIO_SAMPLER:
250+
try:
251+
sampler_value = float(sampler_arg) if sampler_arg is not None else default_value
252+
if sampler_value < 0 or sampler_value > 1:
253+
_logger.error("Invalid value for OTEL_TRACES_SAMPLER_ARG. It should be a value between 0 and 1.")
254+
sampler_value = default_value
255+
else:
256+
_logger.info("Using sampling value: %s", sampler_value)
257+
configurations[SAMPLING_ARG] = sampler_value
258+
except ValueError as e:
259+
_logger.error( # pylint: disable=C
260+
_INVALID_FLOAT_MESSAGE,
261+
OTEL_TRACES_SAMPLER_ARG,
262+
default_value,
263+
e,
264+
)
265+
configurations[SAMPLING_ARG] = sampler_value
266+
configurations[SAMPLER_TYPE] = PARENT_BASED_TRACE_ID_RATIO_SAMPLER
267+
191268
# Handle all other cases (no sampler type specified or unsupported sampler type)
192269
else:
193270
if configurations.get(SAMPLING_RATIO_ARG) is None:
194271
configurations[SAMPLING_RATIO_ARG] = default_value
195272
if sampler_type is not None:
196273
_logger.error( # pylint: disable=C
197274
"Invalid argument for the sampler to be used for tracing. "
198-
"Supported values are %s and %s. Defaulting to %s: %s",
199-
RATE_LIMITED_SAMPLER,
200-
FIXED_PERCENTAGE_SAMPLER,
275+
"Supported values are %s. Defaulting to %s: %s",
276+
SUPPORTED_OTEL_SAMPLERS,
201277
FIXED_PERCENTAGE_SAMPLER,
202278
configurations[SAMPLING_RATIO_ARG],
203279
)
@@ -259,3 +335,19 @@ def _is_instrumentation_enabled(configurations, lib_name):
259335

260336
def _default_enable_trace_based_sampling(configurations):
261337
configurations.setdefault(ENABLE_TRACE_BASED_SAMPLING_ARG, False)
338+
339+
340+
def _get_sampler_from_name(sampler_type, sampler_arg):
341+
if sampler_type == ALWAYS_ON_SAMPLER:
342+
return ALWAYS_ON
343+
if sampler_type == ALWAYS_OFF_SAMPLER:
344+
return ALWAYS_OFF
345+
if sampler_type == TRACE_ID_RATIO_SAMPLER:
346+
ratio = float(sampler_arg) if sampler_arg is not None else 1.0
347+
return TraceIdRatioBased(ratio)
348+
if sampler_type == PARENT_BASED_ALWAYS_OFF_SAMPLER:
349+
return ParentBased(ALWAYS_OFF)
350+
if sampler_type == PARENT_BASED_TRACE_ID_RATIO_SAMPLER:
351+
ratio = float(sampler_arg) if sampler_arg is not None else 1.0
352+
return ParentBased(TraceIdRatioBased(ratio))
353+
return ParentBased(ALWAYS_ON)

0 commit comments

Comments
 (0)