-
Notifications
You must be signed in to change notification settings - Fork 2
systems audit trail
Active contributors: Magnus Hedemark
Durable query audit trail that records every search query and its dispatch results in a Valkey stream. Used for operational analysis, debugging, capacity planning, and understanding which queries hit which engines.
| Type | File | Description |
|---|---|---|
QueryAuditLogger |
slopsearx/audit.py |
Fire-and-forget audit writer. Each call to record_query() writes a field-value entry to a daily Valkey stream keyed by date. Valkey failure is a silent no-op. |
_AUDIT_STREAM_MAXLEN |
slopsearx/audit.py |
Stream cap constant (10,000 entries). Older entries are trimmed when the stream exceeds this length. |
_AUDIT_TTL |
slopsearx/audit.py |
Stream TTL constant (90 days / 7,776,000 seconds). Streams auto-expire after this period. |
Each audit entry is a set of field-value pairs written to a daily Valkey stream:
query_audit:{YYYY-MM-DD} → XADD MAXLEN ~10000 * field1 value1 field2 value2 ...
Entry fields:
| Field | Value |
|---|---|
query |
Raw search query string |
client_ip |
Requesting client IP address |
timestamp |
ISO 8601 timestamp with milliseconds |
engines |
Comma-separated list of dispatched engine names |
engines_ok |
Count of engines that returned successful results |
engines_error |
Count of engines that errored or were blocked |
engines_timeout |
Count of engines that timed out |
total_results |
Total results returned across all engines |
latency_ms |
Total request latency in milliseconds |
- After a search request completes (success or failure), the server calls
_audit_logger.record_query()as a fire-and-forget background task -
record_query()derives aggregate statistics from the per-engineAdapterResponseobjects: ok count, error count, timeout count, total results - The entry is written to the daily stream via
XADD stream_key MAXLEN ~10000 *withEXPIRE stream_key 7776000 - The write is wrapped in a try/except — Valkey unavailability is logged at DEBUG level and ignored
Each daily stream is capped at ~10,000 entries via Valkey's MAXLEN directive (approximate, using ~). Streams auto-expire after 90 days. At ~10K queries/day, this is roughly 90 streams of ~10K entries each, keeping total memory footprint predictable and bounded.
If Valkey is unavailable, QueryAuditLogger silently skips the write. The audit trail is an observability convenience, not a correctness requirement. No search request is blocked or delayed by audit failures.
-
Server startup:
QueryAuditLoggeris instantiated instartup()and stored in the module-level_audit_loggerglobal. It receives a reference toSearchCachefor access to the Valkey connection. -
Server search handler: After building the response, the server spawns a background
asyncio.create_task()calling_audit_logger.record_query()with the query, client IP, per-engine results, and total latency. -
Valkey connection: Shared with
SearchCache— no separate Valkey connection is opened for audit purposes.
- Adding fields to audit entries: modify
record_query()to derive and write new field-value pairs - Changing stream cap: modify
_AUDIT_STREAM_MAXLENconstant - Changing retention: modify
_AUDIT_TTLconstant - Changing key format: modify
_stream_key()method
| File | Description |
|---|---|
slopsearx/audit.py |
QueryAuditLogger class, stream key construction, ISO timestamp helper |
slopsearx/server.py |
_audit_logger initialization and record_query() call site |