Skip to content

Commit 3e0ba7d

Browse files
GonzaloGuaschGonzaloGuasch
authored and
GonzaloGuasch
committed
add metric attribute
1 parent 0a231e5 commit 3e0ba7d

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
### Added
2424

25+
- `opentelemetry-instrumentation-flask` Add http route to metric attributes
26+
([#2506](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2506))
2527
- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the
2628
`opentelemetry_resource_detector` entry point
2729
([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382))

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

+23-3
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ def response_hook(span: Span, status: str, response_headers: List):
251251
import opentelemetry.instrumentation.wsgi as otel_wsgi
252252
from opentelemetry import context, trace
253253
from opentelemetry.instrumentation._semconv import (
254-
_METRIC_ATTRIBUTES_SERVER_DURATION_NAME,
255254
_get_schema_url,
256255
_HTTPStabilityMode,
257256
_OpenTelemetrySemanticConventionStability,
@@ -268,6 +267,9 @@ def response_hook(span: Span, status: str, response_headers: List):
268267
from opentelemetry.instrumentation.utils import _start_internal_or_server_span
269268
from opentelemetry.metrics import get_meter
270269
from opentelemetry.semconv.metrics import MetricInstruments
270+
from opentelemetry.semconv.metrics.http_metrics import (
271+
HTTP_SERVER_REQUEST_DURATION,
272+
)
271273
from opentelemetry.semconv.trace import SpanAttributes
272274
from opentelemetry.util.http import (
273275
get_excluded_urls,
@@ -282,6 +284,7 @@ def response_hook(span: Span, status: str, response_headers: List):
282284
_ENVIRON_ACTIVATION_KEY = "opentelemetry-flask.activation_key"
283285
_ENVIRON_REQCTX_REF_KEY = "opentelemetry-flask.reqctx_ref_key"
284286
_ENVIRON_TOKEN = "opentelemetry-flask.token"
287+
_ENVIRON_REQUEST_ROUTE_KEY = "request-route_key"
285288

286289
_excluded_urls_from_env = get_excluded_urls("FLASK")
287290

@@ -344,6 +347,11 @@ def _start_response(status, response_headers, *args, **kwargs):
344347
excluded_urls is None
345348
or not excluded_urls.url_disabled(flask.request.url)
346349
):
350+
if flask.request.url_rule:
351+
wrapped_app_environ[_ENVIRON_REQUEST_ROUTE_KEY] = str(
352+
flask.request.url_rule
353+
)
354+
347355
span = flask.request.environ.get(_ENVIRON_SPAN_KEY)
348356

349357
propagator = get_global_response_propagator()
@@ -386,13 +394,25 @@ def _start_response(status, response_headers, *args, **kwargs):
386394
duration_attrs_old = otel_wsgi._parse_duration_attrs(
387395
attributes, _HTTPStabilityMode.DEFAULT
388396
)
397+
398+
if wrapped_app_environ.get(_ENVIRON_REQUEST_ROUTE_KEY, None):
399+
duration_attrs_old[SpanAttributes.HTTP_ROUTE] = (
400+
wrapped_app_environ.get(_ENVIRON_REQUEST_ROUTE_KEY)
401+
)
402+
389403
duration_histogram_old.record(
390404
max(round(duration_s * 1000), 0), duration_attrs_old
391405
)
392406
if duration_histogram_new:
393407
duration_attrs_new = otel_wsgi._parse_duration_attrs(
394408
attributes, _HTTPStabilityMode.HTTP
395409
)
410+
411+
if wrapped_app_environ.get(_ENVIRON_REQUEST_ROUTE_KEY, None):
412+
duration_attrs_new[SpanAttributes.HTTP_ROUTE] = (
413+
wrapped_app_environ.get(_ENVIRON_REQUEST_ROUTE_KEY)
414+
)
415+
396416
duration_histogram_new.record(
397417
max(duration_s, 0), duration_attrs_new
398418
)
@@ -553,7 +573,7 @@ def __init__(self, *args, **kwargs):
553573
duration_histogram_new = None
554574
if _report_new(_InstrumentedFlask._sem_conv_opt_in_mode):
555575
duration_histogram_new = meter.create_histogram(
556-
name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME,
576+
name=HTTP_SERVER_REQUEST_DURATION,
557577
unit="s",
558578
description="measures the duration of the inbound HTTP request",
559579
)
@@ -684,7 +704,7 @@ def instrument_app(
684704
duration_histogram_new = None
685705
if _report_new(sem_conv_opt_in_mode):
686706
duration_histogram_new = meter.create_histogram(
687-
name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME,
707+
name=HTTP_SERVER_REQUEST_DURATION,
688708
unit="s",
689709
description="measures the duration of the inbound HTTP request",
690710
)

instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
from opentelemetry import trace
2222
from opentelemetry.instrumentation._semconv import (
23-
_SPAN_ATTRIBUTES_ERROR_TYPE,
2423
OTEL_SEMCONV_STABILITY_OPT_IN,
2524
_OpenTelemetrySemanticConventionStability,
2625
_server_active_requests_count_attrs_new,
@@ -40,6 +39,7 @@
4039
NumberDataPoint,
4140
)
4241
from opentelemetry.sdk.resources import Resource
42+
from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
4343
from opentelemetry.semconv.trace import SpanAttributes
4444
from opentelemetry.test.wsgitestutil import WsgiTestBase
4545
from opentelemetry.util.http import (
@@ -379,7 +379,7 @@ def test_internal_error_new_semconv(self):
379379
SpanAttributes.URL_PATH: "/hello/500",
380380
SpanAttributes.HTTP_ROUTE: "/hello/<int:helloid>",
381381
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500,
382-
_SPAN_ATTRIBUTES_ERROR_TYPE: "500",
382+
ERROR_TYPE: "500",
383383
SpanAttributes.URL_SCHEME: "http",
384384
}
385385
)
@@ -405,7 +405,7 @@ def test_internal_error_both_semconv(self):
405405
{
406406
SpanAttributes.URL_PATH: "/hello/500",
407407
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500,
408-
_SPAN_ATTRIBUTES_ERROR_TYPE: "500",
408+
ERROR_TYPE: "500",
409409
SpanAttributes.URL_SCHEME: "http",
410410
}
411411
)
@@ -459,6 +459,7 @@ def test_exclude_lists_from_explicit(self):
459459
self.assertEqual(len(span_list), 1)
460460

461461
def test_flask_metrics(self):
462+
_server_duration_attrs_old.append("http.route")
462463
start = default_timer()
463464
self.client.get("/hello/123")
464465
self.client.get("/hello/321")
@@ -570,6 +571,7 @@ def test_basic_metric_success(self):
570571
self.client.get("/hello/756")
571572
expected_duration_attributes = {
572573
"http.method": "GET",
574+
"http.route": "/hello/<int:helloid>",
573575
"http.host": "localhost",
574576
"http.scheme": "http",
575577
"http.flavor": "1.1",
@@ -597,6 +599,7 @@ def test_basic_metric_success_new_semconv(self):
597599
expected_duration_attributes = {
598600
"http.request.method": "GET",
599601
"url.scheme": "http",
602+
"http.route": "/hello/<int:helloid>",
600603
"network.protocol.version": "1.1",
601604
"http.response.status_code": 200,
602605
}

0 commit comments

Comments
 (0)