Configuration
Configure the Risicare SDK for your application.
Configure the Risicare SDK to connect to your project and customize tracing behavior.
JavaScript SDK?
Basic Setup
import risicare
risicare.init(
api_key="rsk-...", # Or use RISICARE_API_KEY env var
service_name="my-agent", # Identify your service
environment="production", # Environment name
)API Key = Project
Your API key is scoped to the project it was created under (visible in Settings → General). No separate project_id is needed — the gateway resolves it from your key.
project_id is deprecated
Passing project_id to init() emits a DeprecationWarning in Python (or console.warn in JavaScript). The parameter is ignored by the gateway and will be removed in v1.0. Use service_name and environment for within-project organization instead.
Configuration Options
Required
| Option | Type | Description |
|---|---|---|
api_key | str | Your Risicare API key. Starts with rsk-. Each key is scoped to one project. |
Optional
| Option | Type | Default | Description |
|---|---|---|---|
endpoint | str | "https://app.risicare.ai" | Gateway endpoint URL |
environment | str | "development" | Environment name (development, staging, production) |
service_name | str | None | Service name for within-project organization |
service_version | str | None | Service version for traces |
enabled | bool | True | Enable/disable tracing globally |
trace_content | bool | True | Capture prompt/completion content |
sample_rate | float | 1.0 | Sampling rate (0.0-1.0, clamped) |
batch_size | int | 100 | Spans per batch export. Values outside [1, 10000] are clamped and a WARNING risicare.exporters.batch log line is emitted on each init() call that triggers a clamp. |
batch_timeout_ms | int | 1000 | Milliseconds between batch exports |
auto_patch | bool | True | Patch ThreadPoolExecutor, ProcessPoolExecutor, and asyncio.create_task for automatic context propagation |
debug | bool | False | Echo every span to stdout via a console exporter. Prints prompt/completion content unredacted — see the warning below before enabling. |
exporters | list[SpanExporter] | None | Custom span exporters (default: HTTP exporter when api_key is provided) |
metadata | dict | {} | Global metadata attached to all spans |
otlp_endpoint | str | None | OTLP/HTTP export endpoint |
otlp_headers | dict | None | OTLP export headers |
otel_bridge | bool | False | Enable OpenTelemetry bridge |
Content truncation
When trace_content=True, captured prompt and completion text is truncated to 10,000 characters per field. Content exceeding this limit is cut with a "... [truncated]" marker. This limit is not configurable — it's a hardcoded safety bound to prevent oversized spans.
auto_patch monkey-patches at import time
When auto_patch=True (default), init() monkey-patches all detected LLM provider libraries (OpenAI, Anthropic, etc.) via import hooks. For precise control over which providers are instrumented, set auto_patch=False and call instrument_already_imported() or install_import_hooks() selectively.
What debug=True enables
- Console exporter: Adds a
ConsoleExporterthat prints every span to stdout as it's exported — including span attributes - Orphan trace warnings: Logs a warning when an LLM call has no parent span (each call becomes its own trace — a common Tier 1 mistake)
- Initialization logging: Reports patching status (ThreadPoolExecutor, asyncio.create_task), endpoint, and service name on startup
debug=True prints prompt and completion content unredacted
The console exporter writes span attributes to stdout verbatim, including
gen_ai.prompt and gen_ai.completion. Any customer data in a prompt is
printed to your terminal and container logs. Attribute values are truncated at
~80 characters, which is not redaction — a value that begins with an SSN
or card number is printed in full.
Do not enable it against production traffic. init() also accepts a mask
callable for redacting attribute values before export.
debug=True does not show export failures
debug=True does not print the HTTP status of a failed span export — it
adds nothing on that path. If spans are not arriving, the SDK already emits a
one-line warning naming the endpoint; to get the underlying HTTP status and
error, raise the SDK logger:
import logging
logging.getLogger("risicare").setLevel(logging.DEBUG)Span Delivery
When you pass an api_key, init() installs the HTTP exporter. This is the
default path — if you have not configured exporters or an OTLP endpoint, this
is what is sending your spans.
The exporter has a circuit breaker
After 5 consecutive export failures the exporter opens a circuit and stops attempting exports for a 60-second cooldown. Spans created during that window are dropped. This bounds the damage a gateway outage does to your application's latency, but it means a brief outage costs you more than the outage itself — delivery does not resume the moment the gateway returns.
Tracing never raises: an export failure is logged, not thrown. The SDK emits a rate-limited warning naming the endpoint when spans stop arriving. To see the underlying HTTP status, raise the SDK logger as shown above.
The OTLPExporter applies the same 5-failure / 60-second policy — see
OpenTelemetry.
For the measured behaviour — how the threshold counts, which spans survive, and how long delivery really stays stopped — see Production & Failure Modes.
Environment Variables
All configuration can be set via environment variables:
export RISICARE_API_KEY="rsk-..."
export RISICARE_ENDPOINT="https://app.risicare.ai"
export RISICARE_ENVIRONMENT="production"
export RISICARE_SERVICE_NAME="my-agent"
export RISICARE_TRACING="true"
export RISICARE_TRACE_CONTENT="true"
export RISICARE_SAMPLE_RATE="1.0"
export RISICARE_SERVICE_NAME="my-service"
export RISICARE_SERVICE_VERSION="1.0.0"
export RISICARE_DEBUG="false"
export RISICARE_OTLP_ENDPOINT="https://otel-collector:4318"
export RISICARE_OTLP_HEADERS="key1=value1,key2=value2"
export RISICARE_OTEL_BRIDGE="false"| Variable | Maps To |
|---|---|
RISICARE_API_KEY | api_key |
RISICARE_ENDPOINT | endpoint |
RISICARE_ENVIRONMENT | environment |
RISICARE_SERVICE_NAME | service_name |
RISICARE_SERVICE_VERSION | service_version |
RISICARE_TRACING | enabled |
RISICARE_TRACE_CONTENT | trace_content |
RISICARE_SAMPLE_RATE | sample_rate |
RISICARE_DEBUG | debug |
RISICARE_OTLP_ENDPOINT | otlp_endpoint |
RISICARE_OTLP_HEADERS | otlp_headers |
RISICARE_OTEL_BRIDGE | otel_bridge |
Zero-Code Instrumentation
Set RISICARE_TRACING=true to enable auto-instrumentation without any code changes.
Advanced Configuration
Custom Endpoint
Override the default gateway endpoint (https://app.risicare.ai) — for example, to send
spans through an outbound proxy your network requires:
risicare.init(
api_key="rsk-...",
endpoint="https://llm-egress-proxy.internal.example.com",
)Risicare is a hosted service
Risicare runs as a managed service. There is no self-hosted or on-premise Risicare
instance to point this at — endpoint retargets where the SDK sends spans (a proxy or
a non-default gateway host), not where Risicare itself runs.
Sampling
Control trace sampling rate:
risicare.init(
api_key="rsk-...",
sample_rate=0.1, # Sample 10% of traces
)Programmatic Control
Check Status
if risicare.is_enabled():
print("Tracing is active")Flush Pending Spans
# Force export all pending spans
client = risicare.get_client()
client.flush()Shutdown
# Graceful shutdown - flushes and closes connections
risicare.shutdown(timeout_ms=5000) # default: 5000msshutdown() waits up to timeout_ms for the batch processor thread to drain, then performs a final flush and closes HTTP connections. An atexit handler calls shutdown() automatically on normal exit — explicit calls are only needed when you want to flush mid-process (e.g., serverless functions, before a long non-tracing phase).
Shutdown may block on network issues
If the exporter is mid-request when shutdown() runs, the thread join blocks for up to timeout_ms. In latency-sensitive paths, reduce the timeout: risicare.shutdown(timeout_ms=1000).
Auto-Instrumentation Management
Control which libraries are automatically instrumented:
from risicare import (
install_import_hooks,
remove_import_hooks,
instrument_already_imported,
is_instrumented,
get_instrumented_modules,
get_supported_modules,
)
# See which libraries can be auto-instrumented
get_supported_modules()
# {'openai', 'anthropic', 'cohere', 'google.generativeai', 'mistralai', ...}
# Check what's currently instrumented — returns a per-module state record
get_instrumented_modules()
# {'openai': {'state': 'instrumented', 'hooks_landed': 2, ...},
# 'anthropic': {'state': 'instrumented', 'hooks_landed': 2, ...}}
# Gate health checks on state == "instrumented" (the only value that means
# the integration is actually on a live call path).
# Check a specific library. NOTE: is_instrumented() is attempt-based — it
# returns True once instrumentation was attempted, even if the wrapper landed
# inert. For a real liveness check use get_instrumented_modules()[name]["state"].
is_instrumented("openai") # True
# Instrument libraries that were imported before risicare.init()
count = instrument_already_imported()
# Returns number of newly instrumented modules
# Remove all import hooks (stops future auto-instrumentation)
remove_import_hooks()
# Re-install import hooks
install_import_hooks()Configuration Precedence
Configuration is resolved in this order (highest to lowest priority):
- Explicit
init()parameters - Environment variables
- Default values