Skip to content

Commit 552d3fa

Browse files
committed
requests duration histogram stable semconv
Signed-off-by: emdneto <[email protected]>
1 parent c1578c2 commit 552d3fa

File tree

3 files changed

+67
-10
lines changed

3 files changed

+67
-10
lines changed

instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ def response_hook(span, request_obj, response):
5757
request_hook=request_hook, response_hook=response_hook
5858
)
5959
60+
Custom Duration Histogram Boundaries
61+
************************************
62+
To customize the duration histogram bucket boundaries used for HTTP client request duration metrics,
63+
you can provide a list of values when instrumenting:
64+
65+
.. code:: python
66+
67+
import requests
68+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
69+
70+
custom_boundaries = [0, 5, 10, 25, 50, 100, 250, 500, 1000]
71+
72+
RequestsInstrumentor().instrument(
73+
duration_histogram_boundaries=custom_boundaries
74+
)
75+
6076
Exclude lists
6177
*************
6278
To exclude certain URLs from being tracked, set the environment variable ``OTEL_PYTHON_REQUESTS_EXCLUDED_URLS``
@@ -87,7 +103,8 @@ def response_hook(span, request_obj, response):
87103
from requests.structures import CaseInsensitiveDict
88104

89105
from opentelemetry.instrumentation._semconv import (
90-
_DURATION_HISTOGRAM_NEW_EXPLICIT_BOUNDS,
106+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_NEW,
107+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_OLD,
91108
_client_duration_attrs_new,
92109
_client_duration_attrs_old,
93110
_filter_semconv_duration_attrs,
@@ -411,8 +428,8 @@ def _instrument(self, **kwargs: Any):
411428
``tracer_provider``: a TracerProvider, defaults to global
412429
``request_hook``: An optional callback that is invoked right after a span is created.
413430
``response_hook``: An optional callback which is invoked right before the span is finished processing a response.
414-
``excluded_urls``: A string containing a comma-delimited
415-
list of regexes used to exclude URLs from tracking
431+
``excluded_urls``: A string containing a comma-delimited list of regexes used to exclude URLs from tracking
432+
``duration_histogram_boundaries``: A list of float values representing the explicit bucket boundaries for the duration histogram.
416433
"""
417434
semconv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
418435
_OpenTelemetryStabilitySignalType.HTTP,
@@ -427,6 +444,9 @@ def _instrument(self, **kwargs: Any):
427444
)
428445
excluded_urls = kwargs.get("excluded_urls")
429446
meter_provider = kwargs.get("meter_provider")
447+
duration_histogram_boundaries = kwargs.get(
448+
"duration_histogram_boundaries"
449+
)
430450
meter = get_meter(
431451
__name__,
432452
__version__,
@@ -439,14 +459,17 @@ def _instrument(self, **kwargs: Any):
439459
name=MetricInstruments.HTTP_CLIENT_DURATION,
440460
unit="ms",
441461
description="measures the duration of the outbound HTTP request",
462+
explicit_bucket_boundaries_advisory=duration_histogram_boundaries
463+
or DURATION_HISTOGRAM_EXPLICIT_BOUNDS_OLD,
442464
)
443465
duration_histogram_new = None
444466
if _report_new(semconv_opt_in_mode):
445467
duration_histogram_new = meter.create_histogram(
446468
name=HTTP_CLIENT_REQUEST_DURATION,
447469
unit="s",
448470
description="Duration of HTTP client requests.",
449-
explicit_bucket_boundaries_advisory=_DURATION_HISTOGRAM_NEW_EXPLICIT_BOUNDS,
471+
explicit_bucket_boundaries_advisory=duration_histogram_boundaries
472+
or DURATION_HISTOGRAM_EXPLICIT_BOUNDS_NEW,
450473
)
451474
_instrument(
452475
tracer,

instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import opentelemetry.instrumentation.requests
2424
from opentelemetry import trace
2525
from opentelemetry.instrumentation._semconv import (
26-
_DURATION_HISTOGRAM_NEW_EXPLICIT_BOUNDS,
27-
_DURATION_HISTOGRAM_OLD_EXPLICIT_BOUNDS,
26+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_NEW,
27+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_OLD,
2828
OTEL_SEMCONV_STABILITY_OPT_IN,
2929
_OpenTelemetrySemanticConventionStability,
3030
)
@@ -125,6 +125,7 @@ def setUp(self):
125125
def tearDown(self):
126126
super().tearDown()
127127
self.env_patch.stop()
128+
_OpenTelemetrySemanticConventionStability._initialized = False
128129
RequestsInstrumentor().uninstrument()
129130
httpretty.disable()
130131

@@ -732,6 +733,7 @@ def setUp(self):
732733
def tearDown(self):
733734
super().tearDown()
734735
self.env_patch.stop()
736+
_OpenTelemetrySemanticConventionStability._initialized = False
735737
RequestsInstrumentor().uninstrument()
736738
httpretty.disable()
737739

@@ -766,7 +768,7 @@ def test_basic_metric_success(self):
766768
for data_point in metric.data.data_points:
767769
self.assertEqual(
768770
data_point.explicit_bounds,
769-
_DURATION_HISTOGRAM_OLD_EXPLICIT_BOUNDS,
771+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_OLD,
770772
)
771773
self.assertDictEqual(
772774
expected_attributes, dict(data_point.attributes)
@@ -796,7 +798,7 @@ def test_basic_metric_new_semconv(self):
796798
for data_point in metric.data.data_points:
797799
self.assertEqual(
798800
data_point.explicit_bounds,
799-
_DURATION_HISTOGRAM_NEW_EXPLICIT_BOUNDS,
801+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_NEW,
800802
)
801803
self.assertDictEqual(
802804
expected_attributes, dict(data_point.attributes)
@@ -843,6 +845,38 @@ def test_basic_metric_both_semconv(self):
843845
)
844846
self.assertEqual(data_point.count, 1)
845847

848+
def test_custom_histogram_boundaries(self):
849+
RequestsInstrumentor().uninstrument()
850+
custom_boundaries = (0, 1, 2, 5, 10, 20, 50, 100)
851+
meter_provider, memory_reader = self.create_meter_provider()
852+
RequestsInstrumentor().instrument(
853+
meter_provider=meter_provider,
854+
duration_histogram_boundaries=custom_boundaries,
855+
)
856+
857+
self.perform_request(self.URL)
858+
metrics = memory_reader.get_metrics_data().resource_metrics[0]
859+
self.assertEqual(len(metrics.scope_metrics), 1)
860+
data_point = metrics.scope_metrics[0].metrics[0].data.data_points[0]
861+
self.assertEqual(data_point.explicit_bounds, custom_boundaries)
862+
self.assertEqual(data_point.count, 1)
863+
864+
def test_custom_histogram_boundaries_new_semconv(self):
865+
RequestsInstrumentor().uninstrument()
866+
custom_boundaries = (0, 5, 10, 25, 50, 100, 250, 500, 1000)
867+
meter_provider, memory_reader = self.create_meter_provider()
868+
RequestsInstrumentor().instrument(
869+
meter_provider=meter_provider,
870+
duration_histogram_boundaries=custom_boundaries,
871+
)
872+
873+
self.perform_request(self.URL)
874+
metrics = memory_reader.get_metrics_data().resource_metrics[0]
875+
self.assertEqual(len(metrics.scope_metrics), 1)
876+
data_point = metrics.scope_metrics[0].metrics[0].data.data_points[0]
877+
self.assertEqual(data_point.explicit_bounds, custom_boundaries)
878+
self.assertEqual(data_point.count, 1)
879+
846880
def test_basic_metric_non_recording_span(self):
847881
expected_attributes = {
848882
SpanAttributes.HTTP_STATUS_CODE: 200,

opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from opentelemetry.trace.status import Status, StatusCode
4949

5050
# Values defined in milliseconds
51-
_DURATION_HISTOGRAM_OLD_EXPLICIT_BOUNDS = (
51+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_OLD = (
5252
0.0,
5353
5.0,
5454
10.0,
@@ -67,7 +67,7 @@
6767
)
6868

6969
# Values defined in seconds
70-
_DURATION_HISTOGRAM_NEW_EXPLICIT_BOUNDS = (
70+
DURATION_HISTOGRAM_EXPLICIT_BOUNDS_NEW = (
7171
0.005,
7272
0.01,
7373
0.025,

0 commit comments

Comments
 (0)