From 6a43838da2d4eea9aedf3ae6260ab10a80ec8e0c Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 16 Aug 2022 12:00:05 +0530 Subject: [PATCH 01/10] add metric instrumentation in falcon --- .../instrumentation/falcon/__init__.py | 29 ++++++- .../tests/test_falcon.py | 84 +++++++++++++++++++ 2 files changed, 110 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index cdf2c3553f..b29c45ab5f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -143,6 +143,7 @@ def response_hook(span, req, resp): from logging import getLogger from sys import exc_info +from timeit import default_timer from typing import Collection import falcon @@ -152,6 +153,7 @@ def response_hook(span, req, resp): from opentelemetry import context, trace from opentelemetry.instrumentation.falcon.package import _instruments from opentelemetry.instrumentation.falcon.version import __version__ +from opentelemetry.metrics import get_meter from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.propagators import ( FuncSetter, @@ -200,12 +202,26 @@ def __init__(self, *args, **kwargs): # inject trace middleware middlewares = kwargs.pop("middleware", []) tracer_provider = otel_opts.pop("tracer_provider", None) + meter_provider = otel_opts.pop("meter_provider", None) if not isinstance(middlewares, (list, tuple)): middlewares = [middlewares] self._otel_tracer = trace.get_tracer( __name__, __version__, tracer_provider ) + self._otel_meter = get_meter( + __name__, __version__, meter_provider + ) + self.duration_histogram = self._otel_meter.create_histogram( + name="http.server.duration", + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + self.active_requests_counter = self._otel_meter.create_up_down_counter( + name="http.server.active_requests", + unit="requests", + description="measures the number of concurrent HTTP requests that are currently in-flight", + ) trace_middleware = _TraceMiddleware( self._otel_tracer, @@ -254,7 +270,7 @@ def __call__(self, env, start_response): return super().__call__(env, start_response) start_time = _time_ns() - + start = default_timer() span, token = _start_internal_or_server_span( tracer=self._otel_tracer, span_name=otel_wsgi.get_default_span_name(env), @@ -262,9 +278,12 @@ def __call__(self, env, start_response): context_carrier=env, context_getter=otel_wsgi.wsgi_getter, ) + attributes = otel_wsgi.collect_request_attributes(env) + active_requests_count_attrs = otel_wsgi._parse_active_request_count_attrs(attributes) + duration_attrs = otel_wsgi._parse_duration_attrs(attributes) + self.active_requests_counter.add(1, active_requests_count_attrs) if span.is_recording(): - attributes = otel_wsgi.collect_request_attributes(env) for key, value in attributes.items(): span.set_attribute(key, value) if span.is_recording() and span.kind == trace.SpanKind.SERVER: @@ -299,7 +318,11 @@ def _start_response(status, response_headers, *args, **kwargs): if token is not None: context.detach(token) raise - + finally: + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + duration = max(round((default_timer() - start) * 1000), 0) + self.duration_histogram.record(duration, duration_attrs) + self.active_requests_counter.add(-1, active_requests_count_attrs) class _TraceMiddleware: # pylint:disable=R0201,W0613 diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 5098937b2a..64c9ac01ab 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from timeit import default_timer from unittest.mock import Mock, patch import pytest @@ -26,6 +27,14 @@ get_global_response_propagator, set_global_response_propagator, ) +from opentelemetry.instrumentation.wsgi import ( + _active_requests_count_attrs, + _duration_attrs, +) +from opentelemetry.sdk.metrics.export import ( + HistogramDataPoint, + NumberDataPoint, +) from opentelemetry.sdk.resources import Resource from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase @@ -38,6 +47,14 @@ from .app import make_app +_expected_metric_names = [ + "http.server.active_requests", + "http.server.duration", +] +_recommended_attrs = { + "http.server.active_requests": _active_requests_count_attrs, + "http.server.duration": _duration_attrs, +} class TestFalconBase(TestBase): def setUp(self): @@ -242,6 +259,73 @@ def test_traced_not_recording(self): self.assertFalse(mock_span.set_attribute.called) self.assertFalse(mock_span.set_status.called) + def test_falcon_metrics(self): + self.client().simulate_get("/hello/756") + self.client().simulate_get("/hello/756") + self.client().simulate_get("/hello/756") + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, _recommended_attrs[metric.name] + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_falcon_metric_values(self): + expected_duration_attributes = {'http.method': 'GET', 'http.host': 'falconframework.org', 'http.scheme': 'http', 'http.flavor': '1.1', 'http.server_name': 'falconframework.org', 'net.host.port': 80, 'http.status_code': 404} + expected_requests_count_attributes = {'http.method': 'GET', 'http.host': 'falconframework.org', 'http.scheme': 'http', 'http.flavor': '1.1', 'http.server_name': 'falconframework.org'} + start = default_timer() + self.client().simulate_get("/hello/756") + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertDictEqual( + expected_duration_attributes, + dict(point.attributes), + ) + self.assertEqual(point.count, 1) + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + if isinstance(point, NumberDataPoint): + self.assertDictEqual( + expected_requests_count_attributes, + dict(point.attributes), + ) + self.assertEqual(point.value, 0) + + def test_metric_uninstrument(self): + self.client().simulate_request(method="POST", path="/hello/756") + FalconInstrumentor().uninstrument() + self.app = make_app() + self.client().simulate_request(method="POST", path="/hello/756") + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) class TestFalconInstrumentationWithTracerProvider(TestBase): def setUp(self): From 53221ec38882a3f99ba99037adca261397d1be14 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 16 Aug 2022 12:05:44 +0530 Subject: [PATCH 02/10] fix lint --- .../instrumentation/falcon/__init__.py | 15 ++++++++----- .../tests/test_falcon.py | 22 ++++++++++++++++--- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index b29c45ab5f..3918479e69 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -153,7 +153,6 @@ def response_hook(span, req, resp): from opentelemetry import context, trace from opentelemetry.instrumentation.falcon.package import _instruments from opentelemetry.instrumentation.falcon.version import __version__ -from opentelemetry.metrics import get_meter from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.propagators import ( FuncSetter, @@ -164,6 +163,7 @@ def response_hook(span, req, resp): extract_attributes_from_object, http_status_to_status_code, ) +from opentelemetry.metrics import get_meter from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status from opentelemetry.util._time import _time_ns @@ -209,9 +209,7 @@ def __init__(self, *args, **kwargs): self._otel_tracer = trace.get_tracer( __name__, __version__, tracer_provider ) - self._otel_meter = get_meter( - __name__, __version__, meter_provider - ) + self._otel_meter = get_meter(__name__, __version__, meter_provider) self.duration_histogram = self._otel_meter.create_histogram( name="http.server.duration", unit="ms", @@ -279,7 +277,9 @@ def __call__(self, env, start_response): context_getter=otel_wsgi.wsgi_getter, ) attributes = otel_wsgi.collect_request_attributes(env) - active_requests_count_attrs = otel_wsgi._parse_active_request_count_attrs(attributes) + active_requests_count_attrs = ( + otel_wsgi._parse_active_request_count_attrs(attributes) + ) duration_attrs = otel_wsgi._parse_duration_attrs(attributes) self.active_requests_counter.add(1, active_requests_count_attrs) @@ -319,11 +319,14 @@ def _start_response(status, response_headers, *args, **kwargs): context.detach(token) raise finally: - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + duration_attrs[ + SpanAttributes.HTTP_STATUS_CODE + ] = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) duration = max(round((default_timer() - start) * 1000), 0) self.duration_histogram.record(duration, duration_attrs) self.active_requests_counter.add(-1, active_requests_count_attrs) + class _TraceMiddleware: # pylint:disable=R0201,W0613 diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 64c9ac01ab..3d458f5ff7 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -56,6 +56,7 @@ "http.server.duration": _duration_attrs, } + class TestFalconBase(TestBase): def setUp(self): super().setUp() @@ -286,10 +287,24 @@ def test_falcon_metrics(self): attr, _recommended_attrs[metric.name] ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) - + def test_falcon_metric_values(self): - expected_duration_attributes = {'http.method': 'GET', 'http.host': 'falconframework.org', 'http.scheme': 'http', 'http.flavor': '1.1', 'http.server_name': 'falconframework.org', 'net.host.port': 80, 'http.status_code': 404} - expected_requests_count_attributes = {'http.method': 'GET', 'http.host': 'falconframework.org', 'http.scheme': 'http', 'http.flavor': '1.1', 'http.server_name': 'falconframework.org'} + expected_duration_attributes = { + "http.method": "GET", + "http.host": "falconframework.org", + "http.scheme": "http", + "http.flavor": "1.1", + "http.server_name": "falconframework.org", + "net.host.port": 80, + "http.status_code": 404, + } + expected_requests_count_attributes = { + "http.method": "GET", + "http.host": "falconframework.org", + "http.scheme": "http", + "http.flavor": "1.1", + "http.server_name": "falconframework.org", + } start = default_timer() self.client().simulate_get("/hello/756") duration = max(round((default_timer() - start) * 1000), 0) @@ -327,6 +342,7 @@ def test_metric_uninstrument(self): if isinstance(point, HistogramDataPoint): self.assertEqual(point.count, 1) + class TestFalconInstrumentationWithTracerProvider(TestBase): def setUp(self): super().setUp() From 78147e94ef75ceebf0eb97bcf58106dcbdbc9116 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 16 Aug 2022 12:14:54 +0530 Subject: [PATCH 03/10] add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0197944f9..5abb41062f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1197](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1197)) - Add metric instumentation for flask ([#1186](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1186)) +- Add metric instrumentation in Falcon + ([#1230](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1230)) ## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-01 From beae96664cc20dab6da44d2b26f4f0dc0c0d4d67 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 16 Aug 2022 14:34:00 +0530 Subject: [PATCH 04/10] fix lint error --- .../src/opentelemetry/instrumentation/falcon/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 3918479e69..c9afb7fa59 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -264,6 +264,7 @@ def _handle_exception( def __call__(self, env, start_response): # pylint: disable=E1101 + # pylint: disable=too-many-locals if self._otel_excluded_urls.url_disabled(env.get("PATH_INFO", "/")): return super().__call__(env, start_response) From fd33567f92f33cb19488b235dc9f5c4699039c69 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Fri, 26 Aug 2022 10:51:20 +0530 Subject: [PATCH 05/10] fix generate --- .../src/opentelemetry/instrumentation/falcon/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index a203b25d06..7893951e08 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -143,8 +143,8 @@ def response_hook(span, req, resp): from logging import getLogger from sys import exc_info -from timeit import default_timer from time import time_ns +from timeit import default_timer from typing import Collection import falcon @@ -268,8 +268,9 @@ def __call__(self, env, start_response): if self._otel_excluded_urls.url_disabled(env.get("PATH_INFO", "/")): return super().__call__(env, start_response) - start_time = _time_ns() + start_time = time_ns() start = default_timer() + span, token = _start_internal_or_server_span( tracer=self._otel_tracer, span_name=otel_wsgi.get_default_span_name(env), From 330df271b9a6e8a82a5a48f176d7652d9ffa8b43 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Fri, 26 Aug 2022 16:03:32 +0530 Subject: [PATCH 06/10] fix changelog --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af080be044..00ccf93303 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add metric instrumentation in Falcon + ([#1230](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1230)) + ### Fixed - `opentelemetry-instrumentation-boto3sqs` Make propagation compatible with other SQS instrumentations, add 'messaging.url' span attribute, and fix missing package dependencies. @@ -34,8 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1197](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1197)) - Add metric instumentation for flask ([#1186](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1186)) -- Add metric instrumentation in Falcon - ([#1230](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1230)) ## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-01 From a12566b92e7c3f10d3a2886a01dffd61ef208063 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 6 Sep 2022 11:49:29 +0530 Subject: [PATCH 07/10] fix time position --- .../src/opentelemetry/instrumentation/falcon/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 7893951e08..4ddc1976d7 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -309,6 +309,7 @@ def _start_response(status, response_headers, *args, **kwargs): context.detach(token) return response + start = default_timer() try: return super().__call__(env, _start_response) except Exception as exc: From d14cd022712e9fdfb7e0006a6136ed5f5a8f3584 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Tue, 6 Sep 2022 19:16:04 +0530 Subject: [PATCH 08/10] add readme --- instrumentation/README.md | 2 +- .../src/opentelemetry/instrumentation/fastapi/package.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/instrumentation/README.md b/instrumentation/README.md index deeb3693f0..d7dd93c3a3 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -16,7 +16,7 @@ | [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No | [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | No -| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | No +| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0, < 3.0 | Yes | [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No | [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/package.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/package.py index cccaa51a8c..8df84fc931 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/package.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/package.py @@ -14,3 +14,5 @@ _instruments = ("fastapi ~= 0.58",) + +_supports_metrics = True From f6e317439d1246fa7f972ef15bd6e949200b56f6 Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Wed, 21 Sep 2022 13:51:15 +0530 Subject: [PATCH 09/10] fix uninstruent test --- .../opentelemetry-instrumentation-falcon/tests/test_falcon.py | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 2c61e9bf96..7e714342a7 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -344,7 +344,6 @@ def test_falcon_metric_values(self): def test_metric_uninstrument(self): self.client().simulate_request(method="POST", path="/hello/756") FalconInstrumentor().uninstrument() - self.app = make_app() self.client().simulate_request(method="POST", path="/hello/756") metrics_list = self.memory_metrics_reader.get_metrics_data() for resource_metric in metrics_list.resource_metrics: From d415b665beab8ca217c438a32b7a0793e39d28fc Mon Sep 17 00:00:00 2001 From: "anshul.asawa" Date: Thu, 22 Sep 2022 14:04:12 +0530 Subject: [PATCH 10/10] remove time initi twice --- .../src/opentelemetry/instrumentation/falcon/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 3c224f994e..8a21ca429e 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -283,7 +283,6 @@ def __call__(self, env, start_response): return super().__call__(env, start_response) start_time = time_ns() - start = default_timer() span, token = _start_internal_or_server_span( tracer=self._otel_tracer,