OpenTelemetry
Bridge Risicare with OpenTelemetry for unified observability.
Risicare supports full OpenTelemetry interoperability for unified observability.
Python only
OTel Bridge
Export Risicare spans to OpenTelemetry:
import risicare
risicare.init(
api_key="rsk-...",
otel_bridge=True, # Enable OTel bridge
)With the bridge enabled, all Risicare spans are also exported to the configured OTel collector.
OTLP Exporter
Export directly to OTLP-compatible backends:
risicare.init(
api_key="rsk-...",
otel_bridge=True,
otlp_endpoint="http://localhost:4318/v1/traces",
otlp_headers={"Authorization": "Bearer token"},
)OTLP Ingestion
Risicare can receive spans from existing OTel instrumentation:
POST /v1/otlp/v1/traces
Content-Type: application/x-protobuf
Authorization: Bearer rsk-...
<OTLP trace data>
The double /v1/ is intentional — the first is the Risicare gateway route prefix, the second is the standard OTLP protocol path per the OpenTelemetry OTLP/HTTP specification.
This allows migrating existing OTel instrumentation to Risicare without code changes.
OTLPExporter Reference
For full control over OTLP export, create an OTLPExporter directly and pass it to init():
from risicare import OTLPExporter
exporter = OTLPExporter(
endpoint="http://localhost:4318/v1/traces",
headers={"Authorization": "Bearer token"},
timeout_seconds=10.0,
max_retries=3,
compress=True,
service_name="my-agent",
service_version="1.0.0",
environment="production",
)
risicare.init(
api_key="rsk-...",
exporters=[exporter],
)| Parameter | Type | Default | Description |
|---|---|---|---|
endpoint | str | "http://localhost:4318/v1/traces" | OTLP/HTTP traces endpoint URL |
headers | dict | None | Additional HTTP headers (e.g., auth tokens) |
timeout_seconds | float | 10.0 | HTTP request timeout |
max_retries | int | 3 | Maximum retry attempts with exponential backoff |
compress | bool | True | gzip-compress payloads |
service_name | str | None | Service name for OTLP resource attributes |
service_version | str | None | Service version for OTLP resource attributes |
environment | str | None | Deployment environment for OTLP resource attributes |
The exporter includes a circuit breaker (3 consecutive failures triggers a 30-second cooldown) and maps Risicare span attributes to gen_ai.* semantic conventions automatically.
Multiple Exporters
Export to multiple backends:
from risicare import OTLPExporter
from risicare.exporters.http import HttpExporter
from risicare.exporters.console import ConsoleExporter
risicare.init(
api_key="rsk-...",
exporters=[
HttpExporter(), # Risicare cloud
OTLPExporter( # Jaeger
endpoint="http://jaeger:4318/v1/traces"
),
ConsoleExporter(), # Debug output
],
)Semantic Conventions
Risicare follows OpenTelemetry semantic conventions for GenAI:
| Attribute | Description |
|---|---|
gen_ai.system | LLM provider (openai, anthropic, etc.) |
gen_ai.request.model | Requested model name |
gen_ai.response.model | Actual model used |
gen_ai.usage.prompt_tokens | Input token count |
gen_ai.usage.completion_tokens | Output token count |
gen_ai.request.temperature | Temperature setting |
gen_ai.request.max_tokens | Max tokens setting |
Context Propagation
W3C Trace Context is fully supported:
from risicare import inject_trace_context, extract_trace_context
# Inject into outgoing request
headers = {}
inject_trace_context(headers)
# headers now contains 'traceparent' and 'tracestate'
# Extract from incoming request
context = extract_trace_context(request.headers)Existing OTel SDK
If you already use the OpenTelemetry Python SDK:
import risicare
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from risicare.integrations.otel import RisicareSpanProcessor
# Initialize Risicare first (required for the processor to work)
risicare.init(
api_key="rsk-...",
)
# Add Risicare as a span processor (no constructor params needed)
provider = TracerProvider()
provider.add_span_processor(RisicareSpanProcessor())
trace.set_tracer_provider(provider)
# Existing OTel instrumentation now exports to Risicare