def _start_response(status, response_headers, *args, **kwargs): if flask.request and ( excluded_urls is None or not excluded_urls.url_disabled(flask.request.url)): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) propagator = get_global_response_propagator() if propagator: propagator.inject( response_headers, setter=otel_wsgi.default_response_propagation_setter, ) if span: otel_wsgi.add_response_attributes(span, status, response_headers) else: _logger.warning( "Flask environ's OpenTelemetry span " "missing at _start_response(%s)", status, ) if response_hook is not None: response_hook(span, status, response_headers) return start_response(status, response_headers, *args, **kwargs)
def _start_response(status, response_headers, *args, **kwargs): otel_wsgi.add_response_attributes(span, status, response_headers) response = start_response(status, response_headers, *args, **kwargs) activation.__exit__(None, None, None) context.detach(token) return response
def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response if (self._environ_activation_key in request.META.keys() and self._environ_span_key in request.META.keys()): add_response_attributes( request.META[self._environ_span_key], "{} {}".format(response.status_code, response.reason_phrase), response, ) request.META.pop(self._environ_span_key) exception = request.META.pop(self._environ_exception_key, None) if exception: request.META[self._environ_activation_key].__exit__( type(exception), exception, getattr(exception, "__traceback__", None), ) else: request.META[self._environ_activation_key].__exit__( None, None, None) request.META.pop(self._environ_activation_key) if self._environ_token in request.META.keys(): detach(request.environ.get(self._environ_token)) request.META.pop(self._environ_token) return response
def _start_response(status, response_headers, *args, **kwargs): if flask.request and ( excluded_urls is None or not excluded_urls.url_disabled(flask.request.url)): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) propagator = get_global_response_propagator() if propagator: propagator.inject( response_headers, setter=otel_wsgi.default_response_propagation_setter, ) if span: otel_wsgi.add_response_attributes(span, status, response_headers) status_code = otel_wsgi._parse_status_code(status) if status_code is not None: duration_attrs[ SpanAttributes.HTTP_STATUS_CODE] = status_code if (span.is_recording() and span.kind == trace.SpanKind.SERVER): custom_attributes = otel_wsgi.collect_custom_response_headers_attributes( response_headers) if len(custom_attributes) > 0: span.set_attributes(custom_attributes) else: _logger.warning( "Flask environ's OpenTelemetry span " "missing at _start_response(%s)", status, ) if response_hook is not None: response_hook(span, status, response_headers) return start_response(status, response_headers, *args, **kwargs)
def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response activation = request.META.pop(self._environ_activation_key, None) span = request.META.pop(self._environ_span_key, None) if activation and span: add_response_attributes( span, "{} {}".format(response.status_code, response.reason_phrase), response, ) exception = request.META.pop(self._environ_exception_key, None) if _DjangoMiddleware._otel_response_hook: _DjangoMiddleware._otel_response_hook( # pylint: disable=not-callable span, request, response ) if exception: activation.__exit__( type(exception), exception, getattr(exception, "__traceback__", None), ) else: activation.__exit__(None, None, None) if self._environ_token in request.META.keys(): detach(request.environ.get(self._environ_token)) request.META.pop(self._environ_token) return response
def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response if (self._environ_activation_key in request.META.keys() and self._environ_span_key in request.META.keys()): add_response_attributes( request.META[self._environ_span_key], "{} {}".format(response.status_code, response.reason_phrase), response, ) # pylint:disable=W0212 request._otel_labels["http.status_code"] = str( response.status_code) request.META.pop(self._environ_span_key) request.META[self._environ_activation_key].__exit__( None, None, None) request.META.pop(self._environ_activation_key) if self._environ_token in request.META.keys(): detach(request.environ.get(self._environ_token)) request.META.pop(self._environ_token) try: metric_recorder = getattr(settings, "OTEL_METRIC_RECORDER", None) if metric_recorder is not None: # pylint:disable=W0212 metric_recorder.record_server_duration_range( request._otel_start_time, time.time(), request._otel_labels) except Exception as ex: # pylint: disable=W0703 _logger.warning("Error recording duration metrics: %s", ex) return response
def test_response_attributes(self): otel_wsgi.add_response_attributes(self.span, "404 Not Found", {}) expected = ( mock.call("http.status_code", 404), mock.call("http.status_text", "Not Found"), ) self.assertEqual(self.span.set_attribute.call_count, len(expected)) self.span.set_attribute.assert_has_calls(expected, any_order=True)
def trace_tween(request): # pylint: disable=E1101 if _excluded_urls.url_disabled(request.url): request.environ[_ENVIRON_ENABLED_KEY] = False # short-circuit when we don't want to trace anything return handler(request) request.environ[_ENVIRON_ENABLED_KEY] = True request.environ[_ENVIRON_STARTTIME_KEY] = _time_ns() try: response = handler(request) response_or_exception = response except HTTPException as exc: # If the exception is a pyramid HTTPException, # that's still valuable information that isn't necessarily # a 500. For instance, HTTPFound is a 302. # As described in docs, Pyramid exceptions are all valid # response types response_or_exception = exc raise finally: span = request.environ.get(_ENVIRON_SPAN_KEY) enabled = request.environ.get(_ENVIRON_ENABLED_KEY) if not span and enabled: _logger.warning( "Pyramid environ's OpenTelemetry span missing." "If the OpenTelemetry tween was added manually, make sure" "PyramidInstrumentor().instrument_config(config) is called" ) elif enabled: otel_wsgi.add_response_attributes( span, response_or_exception.status, response_or_exception.headers, ) propagator = get_global_response_propagator() if propagator: propagator.inject(response.headers) activation = request.environ.get(_ENVIRON_ACTIVATION_KEY) if isinstance(response_or_exception, HTTPException): activation.__exit__( type(response_or_exception), response_or_exception, getattr(response_or_exception, "__traceback__", None), ) else: activation.__exit__(None, None, None) context.detach(request.environ.get(_ENVIRON_TOKEN)) return response
def _start_response(status, response_headers, *args, **kwargs): if not _excluded_urls.url_disabled(flask.request.url): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) if span: otel_wsgi.add_response_attributes(span, status, response_headers) else: _logger.warning( "Flask environ's OpenTelemetry span " "missing at _start_response(%s)", status, ) return start_response(status, response_headers, *args, **kwargs)
def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response is_asgi_request = _is_asgi_request(request) if not _is_asgi_supported and is_asgi_request: return response activation = request.META.pop(self._environ_activation_key, None) span = request.META.pop(self._environ_span_key, None) if activation and span: if is_asgi_request: set_status_code(span, response.status_code) else: add_response_attributes( span, f"{response.status_code} {response.reason_phrase}", response, ) propagator = get_global_response_propagator() if propagator: propagator.inject(response) # record any exceptions raised while processing the request exception = request.META.pop(self._environ_exception_key, None) if _DjangoMiddleware._otel_response_hook: _DjangoMiddleware._otel_response_hook( # pylint: disable=not-callable span, request, response ) if exception: activation.__exit__( type(exception), exception, getattr(exception, "__traceback__", None), ) else: activation.__exit__(None, None, None) if request.META.get(self._environ_token, None) is not None: detach(request.META.get(self._environ_token)) request.META.pop(self._environ_token) return response
def test_response_attributes_invalid_status_code(self): otel_wsgi.add_response_attributes(self.span, "Invalid Status Code", {}) self.assertEqual(self.span.set_attribute.call_count, 1) self.span.set_attribute.assert_called_with( "http.status_text", "Status Code" )
def test_response_attributes(self): otel_wsgi.add_response_attributes(self.span, "404 Not Found", {}) expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),) self.assertEqual(self.span.set_attribute.call_count, len(expected)) self.span.set_attribute.assert_has_calls(expected, any_order=True)
def trace_tween(request): # pylint: disable=E1101 if _excluded_urls.url_disabled(request.url): request.environ[_ENVIRON_ENABLED_KEY] = False # short-circuit when we don't want to trace anything return handler(request) request.environ[_ENVIRON_ENABLED_KEY] = True request.environ[_ENVIRON_STARTTIME_KEY] = _time_ns() response = None status = None try: response = handler(request) except HTTPException as exc: # If the exception is a pyramid HTTPException, # that's still valuable information that isn't necessarily # a 500. For instance, HTTPFound is a 302. # As described in docs, Pyramid exceptions are all valid # response types response = exc raise except BaseException: # In the case that a non-HTTPException is bubbled up we # should infer a internal server error and raise status = "500 InternalServerError" raise finally: span = request.environ.get(_ENVIRON_SPAN_KEY) enabled = request.environ.get(_ENVIRON_ENABLED_KEY) if not span and enabled: _logger.warning( "Pyramid environ's OpenTelemetry span missing." "If the OpenTelemetry tween was added manually, make sure" "PyramidInstrumentor().instrument_config(config) is called" ) elif enabled: status = getattr(response, "status", status) if status is not None: otel_wsgi.add_response_attributes( span, status, getattr(response, "headerlist", None), ) if span.is_recording() and span.kind == trace.SpanKind.SERVER: custom_attributes = ( otel_wsgi.collect_custom_response_headers_attributes( getattr(response, "headerlist", None))) if len(custom_attributes) > 0: span.set_attributes(custom_attributes) propagator = get_global_response_propagator() if propagator and hasattr(response, "headers"): propagator.inject(response.headers) activation = request.environ.get(_ENVIRON_ACTIVATION_KEY) # Only considering HTTPServerError # to make sure 200, 300 and 400 exceptions are not reported as error if isinstance(response, HTTPServerError): activation.__exit__( type(response), response, getattr(response, "__traceback__", None), ) else: activation.__exit__(None, None, None) env_token = request.environ.get(_ENVIRON_TOKEN, None) if env_token is not None: context.detach(env_token) return response
def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response is_asgi_request = _is_asgi_request(request) if not _is_asgi_supported and is_asgi_request: return response activation = request.META.pop(self._environ_activation_key, None) span = request.META.pop(self._environ_span_key, None) active_requests_count_attrs = request.META.pop( self._environ_active_request_attr_key, None ) duration_attrs = request.META.pop( self._environ_duration_attr_key, None ) if duration_attrs: duration_attrs[ SpanAttributes.HTTP_STATUS_CODE ] = response.status_code request_start_time = request.META.pop(self._environ_timer_key, None) if activation and span: if is_asgi_request: set_status_code(span, response.status_code) if span.is_recording() and span.kind == SpanKind.SERVER: custom_headers = {} for key, value in response.items(): asgi_setter.set(custom_headers, key, value) custom_res_attributes = ( asgi_collect_custom_response_attributes(custom_headers) ) for key, value in custom_res_attributes.items(): span.set_attribute(key, value) else: add_response_attributes( span, f"{response.status_code} {response.reason_phrase}", response.items(), ) if span.is_recording() and span.kind == SpanKind.SERVER: custom_attributes = ( wsgi_collect_custom_response_headers_attributes( response.items() ) ) if len(custom_attributes) > 0: span.set_attributes(custom_attributes) propagator = get_global_response_propagator() if propagator: propagator.inject(response) # record any exceptions raised while processing the request exception = request.META.pop(self._environ_exception_key, None) if _DjangoMiddleware._otel_response_hook: _DjangoMiddleware._otel_response_hook( # pylint: disable=not-callable span, request, response ) if exception: activation.__exit__( type(exception), exception, getattr(exception, "__traceback__", None), ) else: activation.__exit__(None, None, None) if request_start_time is not None: duration = max( round((default_timer() - request_start_time) * 1000), 0 ) self._duration_histogram.record(duration, duration_attrs) self._active_request_counter.add(-1, active_requests_count_attrs) if request.META.get(self._environ_token, None) is not None: detach(request.META.get(self._environ_token)) request.META.pop(self._environ_token) return response