diff --git a/CHANGELOG.md b/CHANGELOG.md index ae22221e3f..4c19c1e855 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3447](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3447)) - `opentelemetry-instrumentation-botocore` Capture server attributes for botocore API calls ([#3448](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3448)) +- `opentelemetry-instrumentation-tornado` Fix server (request) duration metric calculation + ([#3486](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3486)) ## Version 1.32.0/0.53b0 (2025-04-10) diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index 9fbf88a74d..7608259f0b 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -199,6 +199,7 @@ def client_response_hook(span, future): _logger = getLogger(__name__) _TraceContext = namedtuple("TraceContext", ["activation", "span", "token"]) +_HANDLER_STATE_KEY = "_otel_state_key" _HANDLER_CONTEXT_KEY = "_otel_trace_context_key" _OTEL_PATCHED_KEY = "_otel_patched_key" @@ -379,7 +380,10 @@ def _wrap(cls, method_name, wrapper): def _prepare( tracer, server_histograms, request_hook, func, handler, args, kwargs ): - server_histograms[_START_TIME] = default_timer() + otel_handler_state = { + _START_TIME: default_timer() + } + setattr(handler, _HANDLER_STATE_KEY, otel_handler_state) request = handler.request if _excluded_urls.url_disabled(request.uri): @@ -593,8 +597,10 @@ def _record_prepare_metrics(server_histograms, handler): def _record_on_finish_metrics(server_histograms, handler, error=None): + otel_handler_state = getattr(handler, _HANDLER_STATE_KEY, None) or {} + start_time = otel_handler_state.get(_START_TIME, None) or default_timer() elapsed_time = round( - (default_timer() - server_histograms[_START_TIME]) * 1000 + (default_timer() - start_time) * 1000 ) response_size = int(handler._headers.get("Content-Length", 0))