def prepare_to_exit_span(
        self,
        id_: str,
        instance: Optional[Any] = None,
        result: Optional[Any] = None,
        **kwargs,
    ) -> SpanHolder:
        """Logic for preparing to drop a span."""
        span_holder = self.open_spans[id_]
        # I know it's messy, but the typing of result is messy and couldn't find a better way
        # to get a dictionary I can then use to remove keys
        try:
            serialized_output = json.dumps(result, cls=JSONEncoder)
            # we need to remove some keys like source_nodes as they can be very large
            output = json.loads(serialized_output)
            if "source_nodes" in output:
                del output["source_nodes"]
            if should_send_prompts():
                span_holder.otel_span.set_attribute(
                    SpanAttributes.TRACELOOP_ENTITY_OUTPUT,
                    json.dumps(output, cls=JSONEncoder),
                )
        except Exception:
            pass

        if isinstance(result, (Generator, AsyncGenerator, StreamingResponse)):
            # This is a streaming response, we want to wait for the streaming end event before ending the span
            span_holder.waiting_for_streaming = True
            with self.lock:
                self.waiting_for_streaming_spans[id_] = span_holder
            return span_holder
        else:
            should_detach_context = not isinstance(instance, Workflow)
            span_holder.end(should_detach_context)
            return span_holder
Logic for preparing to drop a span.
packages/opentelemetry-instrumentation-llamaindex/opentelemetry/instrumentation/llamaindex/dispatcher_wrapper.py