Skip to content

OpenTelemetry Integration

OtelGuardrailHandler is a built-in GuardrailEventCallback that turns every guardrail check into an OpenTelemetry span, automatically nested under whatever span is active in your application.

Following OTel best practices — the library depends only on opentelemetry-api. Your application configures the SDK and chooses an exporter.


Install

pip install "mend-guardrails[observability]"

Quickstart

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.sdk.resources import Resource

# 1. Configure the OTel SDK once at application startup.
resource = Resource.create({"service.name": "my-guardrails-app"})
provider = TracerProvider(resource=resource)
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)

# 2. Attach the handler to any Guardrails client.
from mendguardrails import MendGuardrailsAsyncOpenAI
from mendguardrails.observability.otel import OtelGuardrailHandler

client = MendGuardrailsAsyncOpenAI(
    mend_key="...",
    on_guardrail_event=OtelGuardrailHandler(),
)

OTLP exporter (production)

Export spans to any OpenTelemetry Collector, Jaeger, Datadog, etc.:

from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

provider = TracerProvider(resource=Resource.create({"service.name": "my-app"}))
provider.add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True))
)
trace.set_tracer_provider(provider)

client = MendGuardrailsAsyncOpenAI(
    mend_key="...",
    on_guardrail_event=OtelGuardrailHandler(),
)

Span structure

Each span is named guardrail {guardrail_name}, kind INTERNAL, and automatically parented to whatever span is active on the calling thread — so guardrail spans appear nested inside your existing inference spans.

chat gpt-4o                       [CLIENT, 320 ms]
  guardrail PromptInjection        [INTERNAL, 4 ms]
    gen_ai.operation.name        = "guardrail.check"
    gen_ai.provider.name         = "mend"
    gen_ai.request.model         = "gpt-4o"
    gen_ai.guardrail.name        = "PromptInjection"
    gen_ai.guardrail.type        = "Prompt Injection"
    gen_ai.guardrail.action      = "block"
    gen_ai.guardrail.direction   = "input"
    gen_ai.guardrail.severity    = "high"
    gen_ai.guardrail.detection   = "Prompt injection detected"
    gen_ai.guardrail.stage       = "pre_flight"
    gen_ai.guardrail.enforcement = True
    gen_ai.guardrail.exec_failed = False
    gen_ai.usage.input_tokens    = 42   (when available)

Span status is ERROR only when the guardrail itself raised an unhandled exception (execution_failed=True). A block or alert is a successful security check — it does not mark the span as an error.


Prompt text capture (opt-in)

The evaluated prompt or response text is not attached to spans by default because many OTel backends are not PII-safe. Enable it explicitly when your backend is appropriately secured:

OtelGuardrailHandler(capture_prompt_text=True)

This sets the gen_ai.guardrail.checked_text attribute on the span.


Custom tracer

By default the handler obtains a tracer scoped to guardrails.observability.otel. Pass your own Tracer to override the instrumentation scope or use a non-global TracerProvider:

from opentelemetry import trace

app_tracer = trace.get_tracer("my-app")

OtelGuardrailHandler(tracer=app_tracer)

Compatible exporters

OtelGuardrailHandler works with the entire OTel ecosystem:

  • Backends: Jaeger, Zipkin, AWS X-Ray, Google Cloud Trace, Azure Monitor
  • Vendors: Datadog, New Relic, Honeycomb, Grafana Tempo, Lightstep
  • Collector: OpenTelemetry Collector (OTLP)

Combining with other sinks

Pass a list to on_guardrail_event to run OTel alongside a custom sink concurrently:

client = MendGuardrailsAsyncOpenAI(
    mend_key="...",
    on_guardrail_event=[OtelGuardrailHandler(), my_database_sink],
)

See Observability for the full on_guardrail_event callback reference.