Skip to main content

Overview

All Respan instrumentation plugins implement a simple protocol with name, activate(), and deactivate(). This lets you build plugins for any vendor SDK and have them work with Respan().

Protocol

from respan import Instrumentation

class Instrumentation(Protocol):
    name: str

    def activate(self) -> None:
        """Start intercepting spans and injecting them into the OTEL pipeline."""
        ...

    def deactivate(self) -> None:
        """Stop intercepting spans and clean up resources."""
        ...
Attribute/MethodDescription
nameUnique identifier for the plugin (e.g. "openai-agents", "openai").
activate()Called by Respan.__init__(). Registers hooks/processors with the vendor SDK.
deactivate()Called by Respan.shutdown(). Cleans up hooks/processors.

Building a custom plugin

A plugin typically:
  1. Registers a hook or processor with the vendor SDK in activate().
  2. On each SDK event, converts it to a ReadableSpan using build_readable_span().
  3. Injects the span into the OTEL pipeline using inject_span().

Minimal example

from respan import Respan
from respan_tracing.utils.span_factory import build_readable_span, inject_span

class MySDKInstrumentor:
    name = "my-sdk"

    def activate(self) -> None:
        # Register a callback with the vendor SDK
        import my_sdk
        my_sdk.on_completion(self._on_completion)

    def deactivate(self) -> None:
        import my_sdk
        my_sdk.remove_callback(self._on_completion)

    def _on_completion(self, event):
        span = build_readable_span(
            name=f"my-sdk.completion",
            trace_id=event.trace_id,
            attributes={
                "llm.request.type": "chat",
                "gen_ai.request.model": event.model,
                "gen_ai.usage.prompt_tokens": event.input_tokens,
                "gen_ai.usage.completion_tokens": event.output_tokens,
                "traceloop.span.kind": "task",
                "traceloop.entity.name": "completion",
            },
        )
        inject_span(span)

# Use it
respan = Respan(
    api_key="your-api-key",
    instrumentations=[MySDKInstrumentor()],
)

Key functions

FunctionModuleDescription
build_readable_span()respan_tracing.utils.span_factoryCreates a ReadableSpan with proper trace/span IDs, timestamps, and attributes. Automatically reads propagated attributes from the current context.
inject_span()respan_tracing.utils.span_factoryInjects a ReadableSpan into the global OTEL processor chain for export.
read_propagated_attributes()respan_tracing.utils.span_factoryReads the current propagate_attributes() context. Useful if you need to inspect attributes before building the span.

Required attributes

For spans to be processed and displayed correctly by the Respan backend:
AttributeRequiredDescription
traceloop.span.kindYesOne of "workflow", "agent", "task", "tool".
traceloop.entity.nameYesHuman-readable span name.
llm.request.typeFor LLM spansSet to "chat" to trigger prompt/completion parsing.
gen_ai.request.modelFor LLM spansModel name.

Existing plugins

PluginPackageSDK
OpenAI Agents SDKrespan-instrumentation-openai-agentsopenai-agents
OpenAIrespan-instrumentation-openaiopenai