Skip to main content
GitHub

Configuration

Configure the Risicare SDK for your application.

Configure the Risicare SDK to connect to your project and customize tracing behavior.

JavaScript SDK?

For JavaScript/TypeScript configuration, see the JS Configuration guide.

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

OptionTypeDescription
api_keystrYour Risicare API key, from the dashboard. Paste it exactly as the dashboard shows it. Each key is scoped to one project.

With no API key the SDK sends nothing

With no key (also a key of only whitespace; the SDK trims the key) and no exporter of your own, tracing is off. The SDK sends nothing to Risicare, is_enabled() and flush() return False, and nothing is counted as exported. init() logs one WARNING that says so (none when you turned tracing off on purpose). RISICARE_TRACING=true and enable() cannot turn tracing on without a key. An empty api_key argument counts as not given, so RISICARE_API_KEY applies. An exporter that you name yourself (otlp_endpoint, exporters=[...]) still delivers without a key: then is_enabled() is True and flush() reports the delivery of that exporter, with no WARNING. In 0.5.1 and earlier, is_enabled() and flush() returned True with no key.

Optional

OptionTypeDefaultDescription
endpointstr"https://ingest.risicare.ai"Ingest gateway URL. The SDK sends spans to this host.
api_endpointstr"https://api.risicare.ai"API URL. The SDK sends scores to this host. If you pass endpoint (not the default ingest host) and no api_endpoint, scores go to endpoint, also when RISICARE_API_ENDPOINT is set.
project_idstrNoneDeprecated. Ignored by the gateway. See the warning above.
environmentstr"development"Environment name (development, staging, production)
service_namestrNoneService name for within-project organization
service_versionstrNoneService version for traces
enabledboolTrueEnable/disable tracing globally
trace_contentboolFalseCapture prompt/completion content. Off by default — pass trace_content=True (or set RISICARE_TRACE_CONTENT=true) to capture it
sample_ratefloat1.0Sampling rate (0.0-1.0, clamped)
batch_sizeint500Spans 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_msint1000Milliseconds between batch exports
auto_patchboolTruePatch ThreadPoolExecutor, ProcessPoolExecutor, and asyncio.create_task for automatic context propagation
debugboolFalseEcho every span to stdout via a console exporter. Prints span attributes as they are exported (after mask, if one is set), including prompt and completion text when content capture is on — see the warning below before enabling.
exporterslist[SpanExporter]NoneCustom span exporters. Import the base class with from risicare.exporters import SpanExporter, ExportResult, and implement export(self, spans) -> ExportResult. When you pass exporters, the SDK does not add its HTTP exporter (it logs a WARNING). Default: the HTTP exporter when api_key is provided
metadatadict{}Global metadata attached to all spans
otlp_endpointstrNoneOTLP/HTTP export endpoint
otlp_headersdictNoneOTLP export headers
otel_bridgeboolFalseEnable OpenTelemetry bridge
maskCallable[[str, Any], Any]NoneFunction mask(key, value) that returns the value to export. It runs on content-bearing fields before export. It has no environment variable. See Production & Failure Modes.
fix_runtimeboolFalseStart the fix runtime. It is off by default since 0.4.0. The route that the fix runtime reads is not reachable with an API key during the beta, so keep it off.

Content truncation

When trace_content=True, captured text is truncated. Provider integrations cut each prompt and completion field at 10,000 characters, with no marker (an Anthropic system prompt at 5,000). Framework integrations cut at a limit between 500 and 10,000 characters and append ... [truncated]. These limits are not configurable — they are hardcoded safety bounds to prevent oversized spans.

auto_patch does not control provider instrumentation

When tracing is enabled, init() installs the import hooks that patch LLM provider libraries (OpenAI, Anthropic, etc.), whatever the value of auto_patch. auto_patch controls only the ThreadPoolExecutor, ProcessPoolExecutor and asyncio.create_task patches. With auto_patch=False, providers are still instrumented.

What debug=True enables

  • Console exporter: Adds a ConsoleExporter that prints every span to stdout as it's exported — including span attributes. With no API key it still prints the spans, but they are not counted as exported and not delivered, and flush() returns False
  • Debug log messages: Messages about an LLM call with no parent span (each such call becomes its own trace — a common Tier 1 mistake) and about initialization go to the risicare logger at DEBUG level. You see them only if you set that logger to DEBUG
  • No startup line: The [risicare] Tracing active line is not printed when debug=True

debug=True prints prompt and completion content unredacted

The console exporter writes span attributes to stdout as they are exported (after mask, if one is set), including gen_ai.prompt and gen_ai.completion when content capture is on. 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 more about export failures

A failed span export logs a WARNING that names the endpoint and the HTTP status (or the error, when there is no answer). debug=True adds nothing on that path. To see each attempt, 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 logs a WARNING that names the endpoint and the HTTP status when spans stop arriving. To see each attempt, raise the SDK logger as shown above.

The OTLPExporter also opens after 5 failed calls and stays open for 60 seconds. After the cooldown it lets one call through; if that call fails, it opens again at once. It counts a 429 or a 503 as a failure — 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

You can set these options with environment variables:

export RISICARE_API_KEY="rsk-..."
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_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"
VariableMaps To
RISICARE_API_KEYapi_key
RISICARE_ENDPOINTendpoint
RISICARE_API_ENDPOINTapi_endpoint
RISICARE_PROJECT_IDproject_id (deprecated)
RISICARE_ENVIRONMENTenvironment
RISICARE_SERVICE_NAMEservice_name
RISICARE_SERVICE_VERSIONservice_version
RISICARE_TRACINGenabled
RISICARE_TRACE_CONTENTtrace_content
RISICARE_SAMPLE_RATEsample_rate
RISICARE_DEBUGdebug
RISICARE_OTLP_ENDPOINTotlp_endpoint
RISICARE_OTLP_HEADERSotlp_headers
RISICARE_OTEL_BRIDGEotel_bridge
RISICARE_FIX_RUNTIMEfix_runtime

risicare.init() reads these fifteen variables. The import hooks read one more, RISICARE_STRICT_INSTRUMENTATION — see Production & Failure Modes. batch_size, batch_timeout_ms, auto_patch, exporters, metadata and mask have no environment variable.

Boolean variables accept true, 1, yes and on, in upper or lower case. Any other value, including an empty value, means false. RISICARE_TRACING has its own rule: the value is trimmed and case is ignored; true, 1, yes and on turn tracing on; false, 0, no and off turn it off; an empty value is the same as no value; any other value turns tracing off and logs one WARNING.

Do not set RISICARE_ENDPOINT to the dashboard address

https://app.risicare.ai is the dashboard. It is not the ingest gateway. Leave both variables unset to use the defaults. The SDK finds the host for scores in this order: the api_endpoint option; the endpoint option, unless it is the default ingest host; RISICARE_API_ENDPOINT; RISICARE_ENDPOINT, when no endpoint option is given and it is not the default ingest host; https://api.risicare.ai. So a custom endpoint alone also receives the scores, and https://ingest.risicare.ai never does.

Single-Import Instrumentation

Add import risicare to your entrypoint and set RISICARE_API_KEY and RISICARE_TRACING=true to enable auto-instrumentation without calling init() or changing your agent logic. The import itself is required — these variables are read when the SDK is imported. This path uses the same defaults as init(): the environment development and no service name, when RISICARE_ENVIRONMENT and RISICARE_SERVICE_NAME are not set.

Advanced Configuration

Custom Endpoint

Override the default gateway endpoint (https://ingest.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",
)

endpoint sets where the SDK sends spans. If you do not also pass api_endpoint, the SDK sends scores to the same host as endpoint. To send scores to a different host, pass api_endpoint: when endpoint is passed as an option, RISICARE_API_ENDPOINT does not override it.

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 and api_endpoint retarget where the SDK sends its requests (a proxy or a non-default 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")

is_enabled() is False before init(), with tracing off, with no API key (and no exporter of your own), and after the SDK's own SIGTERM drain.

Flush Pending Spans

# Send the spans queued so far. The SDK stays usable afterwards.
risicare.flush(timeout_ms=5000)  # default: 5000ms

flush() returns a bool. True means that the gateway (in Python, also an exporter that you named) acknowledged every span and every score that the SDK accepted since the previous flush() returned, and that nothing is in the queue or in flight. This holds also in a signal handler and after shutdown().

A loss (a span dropped, rejected or not acknowledged, or a score that failed) makes the next flush() return False one time, and the one after it True again. flush() also returns False before init(), with tracing off, and with no API key (and no exporter of your own).

With more than one exporter, a batch counts as delivered when the first exporter that succeeds takes it, so True means that at least one exporter acknowledged each span; a failure of another exporter shows only in its own WARNING and in failed_exports. A span that you start after shutdown() has returned is not made, and nothing counts it.

When it is False, read risicare.get_metrics(): dropped_spans_by_reason, rejected_spans and failed_scores name the loss; a False at the deadline with none of them raised means that the spans are still in flight. See the flush() reference for every case.

metrics = risicare.get_metrics()
print(metrics["exported_spans"], metrics["failed_exports"], metrics["dropped_spans"])

See the Python SDK reference for every field.

Shutdown

# Graceful shutdown - flushes and closes connections
risicare.shutdown(timeout_ms=5000)  # default: 5000ms

shutdown() 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': 4, ...},
#  'anthropic': {'state': 'instrumented', 'hooks_landed': 2, ...}}
# A patched provider reports "instrumented"; "failed" if its patch raised;
# "pending" if the module that holds its patch points is not imported yet.
 
# Check a specific library: True when at least one hook landed.
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):

  1. Explicit init() parameters
  2. Environment variables
  3. Default values

Next Steps