Skip to main content
The AuditRails Python SDK supports both synchronous and asynchronous Python applications. The synchronous client uses only the standard library (urllib) so it installs with zero additional dependencies. The async client adds httpx for non-blocking HTTP and is installed via an optional extra. Both clients are thread-safe, buffer events automatically, and flush on process exit so you never lose an audit record.

Installation

The synchronous client runs a background daemon thread and flushes via atexit. Requires Python 3.9+.

Initialization

Create an AuditRails instance with a Config object. The only required field is api_key. The client starts its background flush thread immediately on construction.
Instantiate the client once at module level (or in your application factory) and import it wherever you need it.

Configuration options

Logging events

audit.log() adds an AuditEvent to an in-memory buffer and returns immediately. The buffer is flushed in the background on the flush_interval schedule. This method never raises an exception.

Direct (immediate) logging

audit.log_direct() sends the event immediately and returns the API response. It raises AuditRailsError on failure.

Direct batch logging

Send multiple events in a single HTTP request, bypassing the buffer. Raises on error.

Manual flush

Framework integration

Django

Add AuditMiddleware to your MIDDLEWARE list in settings.py. The middleware logs every request after the response has been generated, capturing the final HTTP status code.

FastAPI

Use a lifespan context manager to start and close the async client alongside your application.

Error handling

log() never raises. For log_direct() and log_batch_direct(), catch AuditRailsError to inspect the failure details. AuditRailsTimeoutError is a subclass specifically for request timeouts.

Graceful shutdown

Sync: The background daemon thread is registered with Python’s atexit module. When your process exits normally, it automatically flushes any buffered events. You can also flush and shut down manually:
Async: The atexit hook is not available for async clients. You must call await audit.close() explicitly — for example, in your framework’s shutdown lifecycle hook (as shown in the FastAPI lifespan example above).
For async applications, always wire await audit.close() into your framework’s shutdown hook. If the event loop is torn down before close() is called, buffered events that have not yet been flushed will be lost.