Configuration
Everything you can tune.
Environment variables
The SDK reads these at beval.init() unless overridden by arguments.
| Variable | Default | Purpose |
|---|---|---|
BEVAL_API_KEY | — | Your project API key. If unset, the SDK is a no-op. |
BEVAL_API_URL | https://ai-gateway.bolder.services | Gateway base URL. Override for self-hosted. |
BEVAL_PROJECT_ID | — | Default project ID for all logs. |
BEVAL_DEFAULT_MODEL_ID | — | Fallback model_id when none is passed per-call. |
BEVAL_DEBUG | false | Verbose SDK logging. 1 / true / yes to enable. |
beval.init() arguments
Pass these to override environment variables:
beval.init(
api_key="bv_...",
api_url="https://ai-gateway.example.com",
project_id="...",
default_model_id="gpt-4o-mini",
debug=True,
redact=my_redact_fn,
# advanced
timeout_s=5.0,
max_queue_size=10_000,
batch_size=20,
flush_interval_s=1.0,
max_retries=3,
extra={"service": "payments-api", "env": "prod"},
)See the API Reference → Config for all fields.
extra on init
Merged into every log’s extra field. Useful for service-wide metadata that the dashboard can filter on:
beval.init(extra={"service": "api", "env": "prod", "version": "2024.11"})
beval.log(input="...", output="...")
# → extra = {"service": "api", "env": "prod", "version": "2024.11"}
beval.log(input="...", output="...", extra={"user_id": "u_42"})
# → extra = {"service": "api", "env": "prod", "version": "2024.11", "user_id": "u_42"}Per-call extra is shallow-merged over the init defaults.
Redaction
Strip PII before it leaves the process. Pass a function that takes a payload dict and returns a payload dict:
import re
def redact(payload: dict) -> dict:
for key in ("input", "output"):
if payload.get(key):
payload[key] = re.sub(r"\b[\w.+-]+@[\w.-]+\b", "[EMAIL]", payload[key])
payload[key] = re.sub(r"\b\d{3}-\d{2}-\d{4}\b", "[SSN]", payload[key])
return payload
beval.init(redact=redact)The hook runs on the background thread, just before the HTTP POST. Exceptions in the hook are caught and logged — they do not drop the log, but redaction may not have applied. Test your redact function independently.
Custom extras
The SDK runs your redact after init.extra is merged, so redaction applies to the init defaults too. If you want to pass sensitive service metadata that should not be redacted, keep it in extra and key off known-safe fields in your redactor:
REDACT_KEYS = {"input", "output", "thinking_trace", "error_message"}
def redact(payload: dict) -> dict:
for key, value in payload.items():
if key in REDACT_KEYS and isinstance(value, str):
payload[key] = scrub_pii(value)
return payloadQueue tuning
beval.init(
max_queue_size=50_000, # raise if you have high-throughput services
batch_size=50, # currently unused (batch ingest coming)
flush_interval_s=0.5, # how often the worker wakes to send
max_retries=5, # 408/429/5xx retries per log
timeout_s=10.0, # per-request HTTP timeout
)When to raise max_queue_size — if your service can produce >10k logs between flushes (e.g. during a 30-second gateway outage at 500 rps, you’d overflow). Bigger queue = more RAM when the gateway is slow.
When to raise max_retries — usually don’t. The SDK already drops-and-warns after retries, and at-least-once delivery over a flaky network is fine for observability.
Disabling the SDK
Don’t call beval.init(), or unset BEVAL_API_KEY. The module-level beval.log() becomes a no-op returning False. Existing code keeps running.
For tests:
# conftest.py
import os
os.environ.pop("BEVAL_API_KEY", None)Logging the SDK itself
The SDK uses the standard logging module under the name beval. Enable verbose output:
import logging
logging.getLogger("beval").setLevel(logging.DEBUG)Or via env var:
export BEVAL_DEBUG=1Debug logs include per-send events (sent log <uuid>), queue overflow warnings, and retry attempts.