Logging & debugging
The SDK uses Python's standard logging module — there's no custom logger
to wire up. Enable debug-level on the right loggers when you need to see
what's actually going on.
Quick: see SDK retry attempts
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("thrustlab").setLevel(logging.DEBUG)
The thrustlab logger emits exactly one kind of debug line — the retry
backoff, right before each time.sleep() between attempts:
DEBUG:thrustlab:thrustlab: retrying after 0.73s (attempt 1)
DEBUG:thrustlab:thrustlab: retrying after 1.86s (attempt 2)
There's no per-request method/path/status log line — the SDK doesn't log successful requests or the first attempt at all, only the sleep before a retry. For request/response detail (method, path, status), see full HTTP traces below.
See full HTTP traces
The SDK uses httpx under the hood. Its built-in logging gives you full
request/response bodies and headers:
import logging
logging.getLogger("httpx").setLevel(logging.DEBUG)
For even more verbose httpcore traces:
logging.getLogger("httpcore").setLevel(logging.DEBUG)
Caution:
httpxdebug logs print request bodies and headers, including theAuthorization: Bearer key_...header. Don't ship them to a log aggregator without redaction.
Capture request_id in your own logs
Every error response embeds a request_id in the JSON error envelope
(error.request_id); the SDK (0.3.2+) reads it straight off that envelope
and surfaces it as exc.request_id on every raised APIError. Responses
also carry an X-Request-ID response header once the backend rollout for
it is live, but the SDK doesn't need it — exc.request_id is already
populated from the body. Logging this id lets ThrustLab support trace your
specific call server-side.
import logging
from thrustlab import Client
from thrustlab.exceptions import APIError
log = logging.getLogger(__name__)
client = Client()
try:
sim = client.simulations.create(project_id="proj_xxx", ...)
except APIError as exc:
log.warning(
"thrustlab call failed",
extra={
"code": exc.code,
"type": exc.type,
"request_id": exc.request_id,
"http_status": exc.http_status,
},
)
raise
Successful calls return a plain dict, not a response object — there's no
request_id to capture on the happy path. You typically only need it when
something failed and you're filing a support ticket.
Inspect the User-Agent
Every request carries:
User-Agent: thrustlab-python/0.3.2 (Python/3.11.6; Linux)
Include this string in support tickets — it tells us which SDK version is calling.
Common debug recipes
"My retries aren't happening"
Confirm the failure is on the retry list (429 / 5xx / network error). 4xx other than 429 fails-fast by design — see retries & timeouts.
logging.getLogger("thrustlab").setLevel(logging.DEBUG)
# Reproduce. The log will show "retrying" lines if the SDK is retrying,
# or jump straight to the typed exception if it isn't.
"The webhook signature keeps failing"
Almost always: handler is verifying against re-encoded JSON instead of raw bytes. See webhook signature verification.
logging.getLogger("thrustlab").setLevel(logging.DEBUG)
# Inspect the bytes you're passing into Webhook.verify.
# If it differs by even one byte from what the server signed, verify fails.
"I'm getting ConfigurationError: no API key provided"
The Client constructor falls back to $THRUSTLAB_API_KEY only — not
THRUSTLAB_KEY or API_KEY. Confirm:
import os
print(os.environ.get("THRUSTLAB_API_KEY")) # should print key_...
If you're running under systemd / supervisord / Docker, the env var has to be set in the unit / container, not just your shell.
See also
- Configuration
- Errors — all attributes on raised exceptions
- Retries & timeouts