Beispiel #1
0
    def client_response_hook(self, span, resp_data):
        """used to capture the response data
        this function is called twice, once during each resp_phase"""
        resp_phase = resp_data['type']
        if resp_phase == "http.response.start":
            status_code = resp_data["status"]
            set_status_code(span, status_code)
            headers = dict(Headers(raw=resp_data['headers']))
            should_capture_body = self._capture_headers(
                self._process_response_headers,
                self.HTTP_RESPONSE_HEADER_PREFIX, span, headers,
                self._process_response_body)
            span.set_attribute('hypertrace.capture', should_capture_body)

        elif resp_phase == 'http.response.body':
            should_capture = span.attributes.get('hypertrace.capture')
            if should_capture:
                body_data = resp_data['body']
                body_str = None
                if isinstance(body_data, bytes):
                    body_str = body_data.decode('UTF8', 'backslashreplace')
                else:
                    body_str = body_data

                resp_body_str = self.grab_first_n_bytes(body_str)
                span.set_attribute('http.response.body', resp_body_str)
 async def wrapped_receive():
     with self.tracer.start_as_current_span(
             span_name + " asgi." + scope["type"] +
             ".receive") as receive_span:
         message = await receive()
         if receive_span.is_recording():
             if message["type"] == "websocket.receive":
                 set_status_code(receive_span, 200)
             receive_span.set_attribute("type", message["type"])
     return message
Beispiel #3
0
 async def wrapped_receive():
     with self.tracer.start_as_current_span(" ".join(
         (span_name, scope["type"], "receive"))) as receive_span:
         if callable(self.client_request_hook):
             self.client_request_hook(receive_span, scope)
         message = await receive()
         if receive_span.is_recording():
             if message["type"] == "websocket.receive":
                 set_status_code(receive_span, 200)
             receive_span.set_attribute("type", message["type"])
     return message
Beispiel #4
0
 async def wrapped_send(message):
     send_span = span
     if callable(self.client_response_hook):
         self.client_response_hook(send_span, message)
     if send_span.is_recording():
         if message["type"] == "http.response.start":
             status_code = message["status"]
             set_status_code(span, status_code)
         elif message["type"] == "websocket.send":
             set_status_code(span, 200)
         elif message["type"] == 'http.response.body':
             pass
     await send(message)
    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
                async def wrapped_send(message):
                    with self.tracer.start_as_current_span(
                            span_name + " asgi." + scope["type"] +
                            ".send") as send_span:
                        if send_span.is_recording():
                            if message["type"] == "http.response.start":
                                status_code = message["status"]
                                set_status_code(send_span, status_code)
                                set_status_code(span, status_code)

                        elif message["type"] == "websocket.send":
                            set_status_code(send_span, 200)
                            set_status_code(span, 200)
                        send_span.set_attribute("type", message["type"])
                        await send(message)
Beispiel #7
0
async def replaced_ot_middleware_call(self, scope, receive, send):  # pylint:disable=R0914
    """The ASGI application

    Args:
        scope: A ASGI environment.
        receive: An awaitable callable yielding dictionaries
        send: An awaitable callable taking a single dictionary as argument.
    """
    if scope["type"] not in ("http", "websocket"):
        return await self.app(scope, receive, send)

    _, _, url = get_host_port_url_tuple(scope)
    if self.excluded_urls and self.excluded_urls.url_disabled(url):
        return await self.app(scope, receive, send)

    token = context.attach(extract(scope, getter=asgi_getter))
    span_name, additional_attributes = self.default_span_details(scope)

    request = Request(scope, receive=receive)
    body = await request.body()

    try:
        with self.tracer.start_as_current_span(
                span_name,
                kind=trace.SpanKind.SERVER,
        ) as span:
            if span.is_recording():
                attributes = collect_request_attributes(scope)
                attributes.update(additional_attributes)
                for key, value in attributes.items():
                    span.set_attribute(key, value)

            should_forward_to_handler = True
            if callable(self.server_request_hook):
                should_forward_to_handler = self.server_request_hook(
                    span, scope, body)

            @wraps(receive)
            async def wrapped_receive():
                with self.tracer.start_as_current_span(" ".join(
                    (span_name, scope["type"], "receive"))) as receive_span:
                    if callable(self.client_request_hook):
                        self.client_request_hook(receive_span, scope)
                    message = await receive()
                    if receive_span.is_recording():
                        if message["type"] == "websocket.receive":
                            set_status_code(receive_span, 200)
                        receive_span.set_attribute("type", message["type"])
                return message

            @wraps(send)
            async def wrapped_send(message):
                send_span = span
                if callable(self.client_response_hook):
                    self.client_response_hook(send_span, message)
                if send_span.is_recording():
                    if message["type"] == "http.response.start":
                        status_code = message["status"]
                        set_status_code(span, status_code)
                    elif message["type"] == "websocket.send":
                        set_status_code(span, 200)
                    elif message["type"] == 'http.response.body':
                        pass
                await send(message)

            if should_forward_to_handler:
                await self.app(scope, wrapped_receive, wrapped_send)
            else:
                set_status_code(span, 403)
                raise HypertraceException(status_code=403)
    finally:
        context.detach(token)
Beispiel #8
0
 def test_response_attributes_invalid_status_code(self):
     otel_asgi.set_status_code(self.span, "Invalid Status Code")
     self.assertEqual(self.span.set_status.call_count, 1)
Beispiel #9
0
 def test_response_attributes(self):
     otel_asgi.set_status_code(self.span, 404)
     expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404), )
     self.assertEqual(self.span.set_attribute.call_count, 1)
     self.assertEqual(self.span.set_attribute.call_count, 1)
     self.span.set_attribute.assert_has_calls(expected, any_order=True)
    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