Ejemplo n.º 1
0
        def _before_flask_request():
            environ = flask.request.environ
            span_name = (flask.request.endpoint
                         or otel_wsgi.get_default_span_name(environ))
            token = context.attach(
                propagators.extract(otel_wsgi.get_header_from_environ,
                                    environ))

            tracer = trace.get_tracer(__name__, __version__)

            attributes = otel_wsgi.collect_request_attributes(environ)
            if flask.request.url_rule:
                # For 404 that result from no route found, etc, we
                # don't have a url_rule.
                attributes["http.route"] = flask.request.url_rule.rule
            span = tracer.start_span(
                span_name,
                kind=trace.SpanKind.SERVER,
                attributes=attributes,
                start_time=environ.get(_ENVIRON_STARTTIME_KEY),
            )
            activation = tracer.use_span(span, end_on_exit=True)
            activation.__enter__()
            environ[_ENVIRON_ACTIVATION_KEY] = activation
            environ[_ENVIRON_SPAN_KEY] = span
            environ[_ENVIRON_TOKEN] = token
Ejemplo n.º 2
0
async def _opentracing_middleware(
    request: Request,
    handler: Callable[[Request], Awaitable[StreamResponse]],
) -> StreamResponse:
    tracer = get_tracer(__name__)
    attach(extract(_headers_getter, request))
    with tracer.start_as_current_span(
            request.path,
            kind=SpanKind.SERVER,
            attributes={
                "component": "http",
                "http.method": request.method,
                "http.scheme": request.scheme,
                "http.host": request.host,
            },
    ) as span:
        try:
            response = await handler(request)
        except HTTPException as e:
            code = _utils.status_to_canonical_code(e.status)
            span.set_status(Status(code))
            span.set_attribute("http.status_text", e.reason)
            raise
        else:
            code = _utils.status_to_canonical_code(response.status)
            span.set_status(Status(code))
            span.set_attribute("http.status_text", response.reason)
            return response
Ejemplo n.º 3
0
    def process_request(self, request):
        # request.META is a dictionary containing all available HTTP headers
        # Read more about request.META here:
        # https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META

        if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
            return

        environ = request.META

        token = attach(extract(get_header_from_environ, environ))

        tracer = get_tracer(__name__, __version__)

        attributes = collect_request_attributes(environ)
        for attr in self._traced_request_attrs:
            value = getattr(request, attr, None)
            if value is not None:
                attributes[attr] = str(value)

        span = tracer.start_span(
            self._get_span_name(request),
            kind=SpanKind.SERVER,
            attributes=attributes,
            start_time=environ.get(
                "opentelemetry-instrumentor-django.starttime_key"),
        )

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()

        request.META[self._environ_activation_key] = activation
        request.META[self._environ_span_key] = span
        request.META[self._environ_token] = token
Ejemplo n.º 4
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        parent_span = propagators.extract(get_header_from_environ, environ)
        span_name = get_default_span_name(environ)

        span = self.tracer.start_span(
            span_name,
            parent_span,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(environ),
        )

        try:
            with self.tracer.use_span(span):
                start_response = self._create_start_response(
                    span, start_response)
                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(iterable, span, self.tracer)
        except:  # noqa
            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)
            span.end()
            raise
Ejemplo n.º 5
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        tracer = trace.tracer()
        parent_span = propagators.extract(get_header_from_environ, environ)
        span_name = get_default_span_name(environ)

        span = tracer.start_span(
            span_name, parent_span, kind=trace.SpanKind.SERVER
        )

        try:
            with tracer.use_span(span):
                add_request_attributes(span, environ)
                start_response = self._create_start_response(
                    span, start_response
                )

                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(iterable, span, tracer)
        except:  # noqa
            span.end()
            raise
Ejemplo n.º 6
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        tracer = trace.tracer()
        path_info = environ["PATH_INFO"] or "/"
        parent_span = propagators.extract(get_header_from_environ, environ)

        with tracer.start_span(path_info,
                               parent_span,
                               kind=trace.SpanKind.SERVER) as span:
            self._add_request_attributes(span, environ)
            start_response = self._create_start_response(span, start_response)

            iterable = self.wsgi(environ, start_response)
            try:
                for yielded in iterable:
                    yield yielded
            finally:
                if hasattr(iterable, "close"):
                    iterable.close()
    def test_propagation(self):
        traceparent_value = "00-{trace_id}-{span_id}-00".format(
            trace_id=format(self.TRACE_ID, "032x"),
            span_id=format(self.SPAN_ID, "016x"),
        )
        tracestate_value = "foo=1,bar=2,baz=3"
        headers = {
            "otcorrelationcontext": ["key1=val1,key2=val2"],
            "traceparent": [traceparent_value],
            "tracestate": [tracestate_value],
        }
        ctx = extract(get_as_list, headers)
        correlations = correlationcontext.get_correlations(context=ctx)
        expected = {"key1": "val1", "key2": "val2"}
        self.assertEqual(correlations, expected)
        span_context = get_span_from_context(context=ctx).get_context()

        self.assertEqual(span_context.trace_id, self.TRACE_ID)
        self.assertEqual(span_context.span_id, self.SPAN_ID)

        span = trace.DefaultSpan(span_context)
        ctx = correlationcontext.set_correlation("key3", "val3")
        ctx = correlationcontext.set_correlation("key4", "val4", context=ctx)
        ctx = set_span_in_context(span, context=ctx)
        output = {}
        inject(dict.__setitem__, output, context=ctx)
        self.assertEqual(traceparent_value, output["traceparent"])
        self.assertIn("key3=val3", output["otcorrelationcontext"])
        self.assertIn("key4=val4", output["otcorrelationcontext"])
        self.assertIn("foo=1", output["tracestate"])
        self.assertIn("bar=2", output["tracestate"])
        self.assertIn("baz=3", output["tracestate"])
Ejemplo n.º 8
0
    def _before_request():
        if _excluded_urls.url_disabled(flask.request.url):
            return

        environ = flask.request.environ
        span_name = name_callback()
        token = context.attach(
            propagators.extract(otel_wsgi.carrier_getter, environ))

        tracer = trace.get_tracer(__name__, __version__)

        span = tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            start_time=environ.get(_ENVIRON_STARTTIME_KEY),
        )
        if span.is_recording():
            attributes = otel_wsgi.collect_request_attributes(environ)
            if flask.request.url_rule:
                # For 404 that result from no route found, etc, we
                # don't have a url_rule.
                attributes["http.route"] = flask.request.url_rule.rule
            for key, value in attributes.items():
                span.set_attribute(key, value)

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()
        environ[_ENVIRON_ACTIVATION_KEY] = activation
        environ[_ENVIRON_SPAN_KEY] = span
        environ[_ENVIRON_TOKEN] = token
Ejemplo n.º 9
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        token = context.attach(
            propagators.extract(get_header_from_environ, environ))
        span_name = self.name_callback(environ)

        span = self.tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(environ),
        )

        try:
            with self.tracer.use_span(span):
                start_response = self._create_start_response(
                    span, start_response)
                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(iterable, span, self.tracer,
                                                 token)
        except Exception as ex:
            span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))
            span.end()
            context.detach(token)
            raise
Ejemplo n.º 10
0
    def process_view(self, request, view_func, view_args, view_kwargs):  # pylint: disable=unused-argument
        # request.META is a dictionary containing all available HTTP headers
        # Read more about request.META here:
        # https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META

        # environ = {
        #     key.lower().replace('_', '-').replace("http-", "", 1): value
        #     for key, value in request.META.items()
        # }

        environ = request.META

        token = attach(extract(get_header_from_environ, environ))

        tracer = get_tracer(__name__, __version__)

        attributes = collect_request_attributes(environ)

        span = tracer.start_span(
            view_func.__name__,
            kind=SpanKind.SERVER,
            attributes=attributes,
            start_time=environ.get(
                "opentelemetry-instrumentor-django.starttime_key"),
        )

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()

        request.META[self._environ_activation_key] = activation
        request.META[self._environ_span_key] = span
        request.META[self._environ_token] = token
Ejemplo n.º 11
0
def server_request():
    with tracer.start_as_current_span(
            "server_request",
            context=propagators.extract(DictGetter(), request.headers),
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(request.environ)):
        print(request.args.get("param"))
        return "served"
def server_request():
    with tracer.start_as_current_span(
            "server_request",
            parent=propagators.extract(lambda dict_, key: dict_.get(key, []),
                                       request.headers)["current-span"],
    ):
        print(request.args.get("param"))
        return "served"
    async def __call__(self, scope, receive, send):
        """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(propagators.extract(carrier_getter, scope))
        span_name, additional_attributes = self.span_details_callback(scope)

        try:
            with self.tracer.start_as_current_span(
                    span_name + " asgi",
                    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)

                @wraps(receive)
                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

                @wraps(send)
                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)
                            elif message["type"] == "websocket.send":
                                set_status_code(send_span, 200)
                            send_span.set_attribute("type", message["type"])
                        await send(message)

                await self.app(scope, wrapped_receive, wrapped_send)
        finally:
            context.detach(token)
def server_request():
    with tracer.start_as_current_span(
            "server_request",
            parent=propagators.extract(lambda dict_, key: dict_.get(key, []),
                                       request.headers)["current-span"],
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(request.environ),
    ):
        print(request.args.get("param"))
        return "served"
Ejemplo n.º 15
0
def server_request():
    with tracer.start_as_current_span(
            "GET /backend",
            parent=propagators.extract(
                lambda request, key: request.headers.get_all(key),
                request)["current-span"],
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(request.environ),
    ) as foo:
        return "served"
Ejemplo n.º 16
0
    def link_from_headers(cls, headers):
        # type: (Dict[str, str]) -> None
        """
        Given a dictionary, extracts the context and links the context to the current tracer.

        :param headers: A key value pair dictionary
        :type headers: dict
        """
        ctx = extract(_get_headers_from_http_request_headers, headers)
        current_span = cls.get_current_span()
        current_span.links.append(Link(ctx))
    def link_from_headers(cls, headers, attributes=None):
        # type: (Dict[str, str], Attributes) -> None
        """
        Given a dictionary, extracts the context and links the context to the current tracer.

        :param headers: A key value pair dictionary
        :type headers: dict
        """
        ctx = extract(DictGetter(), headers)
        span_ctx = get_span_from_context(ctx).get_span_context()
        current_span = cls.get_current_span()
        current_span.links.append(Link(span_ctx, attributes))
Ejemplo n.º 18
0
 def _set_remote_context(self, servicer_context):
     metadata = servicer_context.invocation_metadata()
     if metadata:
         md_dict = {md.key: md.value for md in metadata}
         ctx = propagators.extract(self._carrier_getter, md_dict)
         token = attach(ctx)
         try:
             yield
         finally:
             detach(token)
     else:
         yield
Ejemplo n.º 19
0
    async def __call__(self, scope, receive, send):
        """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)

        token = context.attach(
            propagators.extract(get_header_from_scope, scope)
        )
        span_name, additional_attributes = self.span_details_callback(scope)
        attributes = collect_request_attributes(scope)
        attributes.update(additional_attributes)

        try:
            with self.tracer.start_as_current_span(
                span_name + " asgi",
                kind=trace.SpanKind.SERVER,
                attributes=attributes,
            ):

                @wraps(receive)
                async def wrapped_receive():
                    with self.tracer.start_as_current_span(
                        span_name + " asgi." + scope["type"] + ".receive"
                    ) as receive_span:
                        message = await receive()
                        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):
                    with self.tracer.start_as_current_span(
                        span_name + " asgi." + scope["type"] + ".send"
                    ) as send_span:
                        if message["type"] == "http.response.start":
                            status_code = message["status"]
                            set_status_code(send_span, status_code)
                        elif message["type"] == "websocket.send":
                            set_status_code(send_span, 200)
                        send_span.set_attribute("type", message["type"])
                        await send(message)

                await self.app(scope, wrapped_receive, wrapped_send)
        finally:
            context.detach(token)
Ejemplo n.º 20
0
    async def __call__(self, scope, receive, send):
        if scope["type"] not in ("http", "websocket"):
            return await self.app(scope, receive, send)
        if await self.is_filtered(scope):
            return await self.app(scope, receive, send)

        token = context.attach(propagators.extract(carrier_getter, scope))
        span_name, additional_attributes = self.span_details_callback(scope)

        try:
            with self.tracer.start_as_current_span(
                    span_name + " asgi",
                    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)

                @wraps(receive)
                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

                @wraps(send)
                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)

                await self.app(scope, wrapped_receive, wrapped_send)
        finally:
            context.detach(token)
Ejemplo n.º 21
0
async def _recv_request(event: RecvRequest) -> None:
    tracer = get_tracer(__name__)
    attach(extract(_metadata_getter, event.metadata))
    span_ctx = tracer.start_as_current_span(
        event.method_name,
        kind=SpanKind.SERVER,
        attributes={
            "component": "grpc",
            "grpc.method": event.method_name
        },
    )
    span_ctx.__enter__()
    _server_span_ctx.set(span_ctx)
 def poll(self, *args, **kwargs):
     self._self_release_context()
     msg = self._self_instance.poll(*args, **kwargs)
     if msg:
         ctx = propagators.extract(get_from_messge, msg)
         self._self_span = trace.get_tracer(__name__).start_span(
             name="confluent_kafka.poll",
             kind=trace.SpanKind.CONSUMER,
             parent=trace.get_current_span(ctx),
         )
         set_span_from_message(self._self_span, msg)
         msg = MessageProxy(msg)
         weakref.finalize(msg, self._self_release_context)
     return msg
def _before_traversal(event):
    request = event.request
    request_environ = request.environ
    span_name = otel_wsgi.get_default_span_name(request_environ)

    enabled = request_environ.get(_ENVIRON_ENABLED_KEY)
    if enabled is None:
        _logger.warning(
            "Opentelemetry pyramid tween 'opentelemetry.instrumentation.pyramid.trace_tween_factory'"
            "was not called. Make sure that the tween is included in 'pyramid.tweens' if"
            "the tween list was created manually")
        return

    if not enabled:
        # Tracing not enabled, return
        return

    start_time = request_environ.get(_ENVIRON_STARTTIME_KEY)

    token = context.attach(
        propagators.extract(otel_wsgi.carrier_getter, request_environ))
    tracer = trace.get_tracer(__name__, __version__)

    if request.matched_route:
        span_name = request.matched_route.pattern
    else:
        span_name = otel_wsgi.get_default_span_name(request_environ)

    span = tracer.start_span(
        span_name,
        kind=trace.SpanKind.SERVER,
        start_time=start_time,
    )

    if span.is_recording():
        attributes = otel_wsgi.collect_request_attributes(request_environ)
        if request.matched_route:
            attributes["http.route"] = request.matched_route.pattern
        for key, value in attributes.items():
            span.set_attribute(key, value)

    activation = tracer.use_span(span, end_on_exit=True)
    activation.__enter__()
    request_environ[_ENVIRON_ACTIVATION_KEY] = activation
    request_environ[_ENVIRON_SPAN_KEY] = span
    request_environ[_ENVIRON_TOKEN] = token
Ejemplo n.º 24
0
    async def __call__(self, scope:dict, receive:Coroutine, send:Coroutine) -> Coroutine:
        """The ASGI application

        Args:
            scope: The connection scope, a dictionary that contains at least a type key specifying the protocol that is incoming.
            receive: an awaitable callable that will yield a new event dictionary when one is available
            send: an awaitable callable taking a single event dictionary as a positional argument that will return once the send has been completed or the connection has been closed
        """

        parent_span = propagators.extract(get_header_from_scope, scope)
        span_name = self.name_callback(scope)
        
        with self.tracer.start_span(
            span_name + " (asgi_connection)",
            parent_span,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(scope)
        ):
            @wraps(receive)
            async def wrapped_receive():
                with self.tracer.start_as_current_span(
                    span_name + " (asgi.{type}.receive".format({"type":scope['type']})
                ) as receive_span:
                    payload = await receive()
                    if payload['type'] == 'websocket.receive':
                        set_status_code(receive_span, 200)
                        receive_span.set_attribute('http.status_text',payload['type'])
                return payload
            
            @wraps(send)
            async def wrapped_send(payload):
                with self.tracer.start_as_current_span(
                    span_name + " (asgi.{type}.end)".format({"type":scope['type']})
                ) as send_span:
                    t = payload['type']
                    if t =='http.response.start':
                        status_code = payload['sattus']
                        set_status_code(send_span, status_code)
                    elif t == "websocket.send":
                        set_status_code(send_span, 200)
                        send_span.set_attribute(
                            "http.status_text", payload['text']
                        )
                    send_span.set_attribute("type", t)
                    await send(payload)
        await self.app(scope, wrapped_receive, wrapped_send)
Ejemplo n.º 25
0
    def _set_remote_context(self, servicer_context):
        metadata = servicer_context.invocation_metadata()
        if metadata:
            md_dict = {md.key: md.value for md in metadata}

            def get_from_grpc_metadata(metadata, key) -> List[str]:
                return [md_dict[key]] if key in md_dict else []

            # Update the context with the traceparent from the RPC metadata.
            ctx = propagators.extract(get_from_grpc_metadata, metadata)
            token = attach(ctx)
            try:
                yield
            finally:
                detach(token)
        else:
            yield
    def process_request(self, request):
        # request.META is a dictionary containing all available HTTP headers
        # Read more about request.META here:
        # https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META

        if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
            return

        # pylint:disable=W0212
        request._otel_start_time = time()

        request_meta = request.META

        token = attach(extract(carrier_getter, request_meta))

        tracer = get_tracer(__name__, __version__)

        span = tracer.start_span(
            self._get_span_name(request),
            kind=SpanKind.SERVER,
            start_time=request_meta.get(
                "opentelemetry-instrumentor-django.starttime_key"
            ),
        )

        attributes = collect_request_attributes(request_meta)
        # pylint:disable=W0212
        request._otel_labels = self._get_metric_labels_from_attributes(
            attributes
        )

        if span.is_recording():
            attributes = extract_attributes_from_object(
                request, self._traced_request_attrs, attributes
            )
            for key, value in attributes.items():
                span.set_attribute(key, value)

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()

        request.META[self._environ_activation_key] = activation
        request.META[self._environ_span_key] = span
        request.META[self._environ_token] = token
    async def __call__(self, scope, receive, send):
        parent_span = propagators.extract(get_header_from_scope, scope)
        span_name = get_default_span_name(scope)

        span = self.tracer.start_span(
            span_name,
            parent_span,
            kind=trace.SpanKind.SERVER,
            attributes={}#collect_request_attributes(scope),
        )

        try:
            with self.tracer.use_span(span):
                await self.asgi(scope)(receive, send)
                span.end()
        except:  # noqa
            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)
            span.end()
            raise
    def _trace_prerun(self, *args, **kwargs):
        task = utils.retrieve_task(kwargs)
        task_id = utils.retrieve_task_id(kwargs)

        if task is None or task_id is None:
            return

        request = task.request
        tracectx = propagators.extract(carrier_getter, request) or None

        logger.debug("prerun signal start task_id=%s", task_id)

        operation_name = "{0}/{1}".format(_TASK_RUN, task.name)
        span = self._tracer.start_span(
            operation_name, context=tracectx, kind=trace.SpanKind.CONSUMER
        )

        activation = self._tracer.use_span(span, end_on_exit=True)
        activation.__enter__()
        utils.attach_span(task, task_id, (span, activation))
Ejemplo n.º 29
0
    def __call__(self, env, start_response):
        if _excluded_urls.url_disabled(env.get("PATH_INFO", "/")):
            return super().__call__(env, start_response)

        start_time = time_ns()

        token = context.attach(
            propagators.extract(otel_wsgi.carrier_getter, env))
        span = self._tracer.start_span(
            otel_wsgi.get_default_span_name(env),
            kind=trace.SpanKind.SERVER,
            start_time=start_time,
        )
        if span.is_recording():
            attributes = otel_wsgi.collect_request_attributes(env)
            for key, value in attributes.items():
                span.set_attribute(key, value)

        activation = self._tracer.use_span(span, end_on_exit=True)
        activation.__enter__()
        env[_ENVIRON_SPAN_KEY] = span
        env[_ENVIRON_ACTIVATION_KEY] = activation

        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

        try:
            return super().__call__(env, _start_response)
        except Exception as exc:
            activation.__exit__(
                type(exc),
                exc,
                getattr(exc, "__traceback__", None),
            )
            context.detach(token)
            raise
def _start_span(tracer, handler, start_time) -> _TraceContext:
    token = context.attach(
        propagators.extract(
            carrier_getter,
            handler.request.headers,
        ))

    span = tracer.start_span(
        _get_operation_name(handler, handler.request),
        kind=trace.SpanKind.SERVER,
        start_time=start_time,
    )
    if span.is_recording():
        attributes = _get_attributes_from_request(handler.request)
        for key, value in attributes.items():
            span.set_attribute(key, value)

    activation = tracer.use_span(span, end_on_exit=True)
    activation.__enter__()
    ctx = _TraceContext(activation, span, token)
    setattr(handler, _HANDLER_CONTEXT_KEY, ctx)
    return ctx