From 01d2f5bcadda931437abaa076054dc7fd25b4c0e Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Wed, 10 Apr 2024 16:24:40 -0700 Subject: [PATCH] wsgi resp --- .../instrumentation/requests/__init__.py | 4 +- .../instrumentation/wsgi/__init__.py | 64 ++++++++++--------- .../opentelemetry/instrumentation/_semconv.py | 37 ++++++++++- 3 files changed, 70 insertions(+), 35 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index 96d7a5f928..54b718f678 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -74,7 +74,7 @@ _report_old, _set_http_host, _set_http_method, - _set_http_net_peer_name, + _set_http_net_peer_name_client, _set_http_network_protocol_version, _set_http_peer_port_client, _set_http_scheme, @@ -179,7 +179,7 @@ def get_or_create_headers(): _set_http_host( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) - _set_http_net_peer_name( + _set_http_net_peer_name_client( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) if _report_new(sem_conv_opt_in_mode): diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index 386e157e11..5e55fb40d1 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -230,15 +230,16 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he _set_http_method, _set_http_net_host, _set_http_net_host_port, + _set_http_net_peer_name_server, _set_http_peer_ip, - _set_http_peer_port_client_server, + _set_http_peer_port_server, _set_http_scheme, _set_http_target, _set_http_user_agent, + _set_status, ) from opentelemetry.instrumentation.utils import ( _start_internal_or_server_span, - http_status_to_status_code, ) from opentelemetry.instrumentation.wsgi.version import __version__ from opentelemetry.metrics import get_meter @@ -379,11 +380,11 @@ def collect_request_attributes( peer_port = environ.get("REMOTE_PORT") if peer_port: - _set_http_peer_port_client_server(result, peer_port, sem_conv_opt_in_mode) + _set_http_peer_port_server(result, peer_port, sem_conv_opt_in_mode) remote_host = environ.get("REMOTE_HOST") if remote_host and remote_host != remote_addr: - result[SpanAttributes.NET_PEER_NAME] = remote_host + _set_http_net_peer_name_server(result, remote_host, sem_conv_opt_in_mode) user_agent = environ.get("HTTP_USER_AGENT") if user_agent is not None and len(user_agent) > 0: @@ -491,23 +492,17 @@ def add_response_attributes( """ if not span.is_recording(): return - status_code, _ = start_response_status.split(" ", 1) + status_code_str, _ = start_response_status.split(" ", 1) + status_code = 0 try: - status_code = int(status_code) + status_code = int(status_code_str) except ValueError: - span.set_status( - Status( - StatusCode.ERROR, - "Non-integer HTTP status: " + repr(status_code), - ) - ) - else: - span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - span.set_status( - Status(http_status_to_status_code(status_code, server_span=True)) - ) - + status_code = -1 + if duration_attrs is None: + duration_attrs = {} + _set_status(span, duration_attrs, status_code_str, status_code, sem_conv_opt_in_mode) + def get_default_span_name(environ): """ @@ -591,17 +586,15 @@ def __init__( ) self.request_hook = request_hook self.response_hook = response_hook + self._sem_conv_opt_in_mode = sem_conv_opt_in_mode @staticmethod def _create_start_response( - span, start_response, response_hook, duration_attrs + span, start_response, response_hook, duration_attrs, sem_conv_opt_in_mode, ): @functools.wraps(start_response) def _start_response(status, response_headers, *args, **kwargs): - add_response_attributes(span, status, response_headers) - status_code = _parse_status_code(status) - if status_code is not None: - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = status_code + add_response_attributes(span, status, response_headers, duration_attrs, sem_conv_opt_in_mode) if span.is_recording() and span.kind == trace.SpanKind.SERVER: custom_attributes = collect_custom_response_headers_attributes( response_headers @@ -622,11 +615,11 @@ def __call__(self, environ, start_response): environ: A WSGI environment. start_response: The WSGI start_response callable. """ - req_attrs = collect_request_attributes(environ) + req_attrs = collect_request_attributes(environ, self._sem_conv_opt_in_mode) active_requests_count_attrs = _parse_active_request_count_attrs( - req_attrs + req_attrs, + self._sem_conv_opt_in_mode, ) - duration_attrs = _parse_duration_attrs(req_attrs) span, token = _start_internal_or_server_span( tracer=self.tracer, @@ -655,20 +648,31 @@ def __call__(self, environ, start_response): try: with trace.use_span(span): start_response = self._create_start_response( - span, start_response, response_hook, duration_attrs + span, + start_response, + response_hook, + req_attrs, + self._sem_conv_opt_in_mode, ) iterable = self.wsgi(environ, start_response) return _end_span_after_iterating(iterable, span, token) except Exception as ex: if span.is_recording(): - span.set_status(Status(StatusCode.ERROR, str(ex))) + if _report_new(self._sem_conv_opt_in_mode): + span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, type(ex).__qualname__ ) + span.set_status(Status(StatusCode.ERROR, str(ex))) span.end() if token is not None: context.detach(token) raise finally: - duration = max(round((default_timer() - start) * 1000), 0) - self.duration_histogram.record(duration, duration_attrs) + duration_s = default_timer() - start + if self.duration_histogram_old: + duration_attrs_old = _parse_duration_attrs(req_attrs, _OpenTelemetryStabilityMode.DEFAULT) + self.duration_histogram_old.record(max(round(duration_s * 1000), 0), duration_attrs_old) + if self.duration_histogram_new: + duration_attrs_new = _parse_duration_attrs(req_attrs, _OpenTelemetryStabilityMode.HTTP) + self.duration_histogram_new.record(max(round(duration_s * 1000), 0), duration_attrs_new) self.active_requests_counter.add(-1, active_requests_count_attrs) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index 0441319be1..c6f6ce25cf 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -16,6 +16,10 @@ import threading from enum import Enum +from opentelemetry.instrumentation.utils import ( + http_status_to_status_code, +) +from opentelemetry.trace.status import Status, StatusCode from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.util.http import _parse_url_query @@ -246,7 +250,7 @@ def _set_http_host(result, host, sem_conv_opt_in_mode): # Client -def _set_http_net_peer_name(result, peer_name, sem_conv_opt_in_mode): +def _set_http_net_peer_name_client(result, peer_name, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.NET_PEER_NAME, peer_name) if _report_new(sem_conv_opt_in_mode): @@ -306,7 +310,7 @@ def _set_http_peer_ip(result, ip, sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.CLIENT_ADDRESS, ip) -def _set_http_peer_port_client_server(result, port, sem_conv_opt_in_mode): +def _set_http_peer_port_server(result, port, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_int_attribute(result, SpanAttributes.NET_PEER_PORT, port) if _report_new(sem_conv_opt_in_mode): @@ -320,7 +324,7 @@ def _set_http_user_agent(result, user_agent, sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.USER_AGENT_ORIGINAL, user_agent) -def _set_http_net_peer_name(result, name, sem_conv_opt_in_mode): +def _set_http_net_peer_name_server(result, name, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.NET_PEER_NAME, name) if _report_new(sem_conv_opt_in_mode): @@ -334,6 +338,33 @@ def _set_http_flavor_version(result, version, sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.NETWORK_PROTOCOL_VERSION, version) +def _set_status(span, metrics_attributes, status_code_str, status_code, sem_conv_opt_in_mode): + if (status_code < 0): + if _report_new(sem_conv_opt_in_mode): + span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str) + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = status_code_str + + span.set_status( + Status( + StatusCode.ERROR, + "Non-integer HTTP status: " + status_code_str, + ) + ) + else: + status = http_status_to_status_code(status_code, server_span=True) + + if _report_old(sem_conv_opt_in_mode): + span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) + metrics_attributes[SpanAttributes.HTTP_STATUS_CODE] = status_code + if _report_new(sem_conv_opt_in_mode): + span.set_attribute(SpanAttributes.HTTP_RESPONSE_STATUS_CODE, status_code) + metrics_attributes[SpanAttributes.HTTP_RESPONSE_STATUS_CODE] = status_code + if status == StatusCode.ERROR: + span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str) + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = status_code_str + span.set_status(Status(status)) + + # Get schema version based off of opt-in mode def _get_schema_url(mode: _OpenTelemetryStabilityMode) -> str: if mode is _OpenTelemetryStabilityMode.DEFAULT: