How It Works
Each tool call the agent makes is appended to the audit log before the result returns to the user.Quick Start
1
Enable audit logging
2
Close on shutdown
What’s Logged
Each JSONL line records:timestamp,session_id,agent_nametool_name,tool_input,execution_time_ms- Optional
tool_output(wheninclude_output=True)
after_tool automatically when you call enable_audit_log().
When a tool call went through the gateway resolve boundary, the
approver field now carries the resolving principal (e.g. operator:alice) rather than the constant "gateway", so audit reports can answer “who approved this exec?”. See how resolver identity is captured.Log Rotation
Audit records keep landing on the live file after an external rotator moves or removes it — no user action, no descriptor leak (PR #4205). Each write compares the inode behind the open handle against the inode on the log path; when they differ (or the path is gone), the stale handle is closed and the path reopened at0o600 before the line is appended.
Secret Redaction
Sensitive values intool_input are replaced with ***REDACTED*** before the JSONL line is written — on by default, no configuration needed.
Key matching is case-insensitive and recurses through nested dicts, lists, and tuples. The built-in denylist (_DEFAULT_SENSITIVE_KEYS in praisonai/security/audit.py):
File permissions. The audit file is created with mode
0o600 (owner read/write only) regardless of umask. This is enforced on the first append even if the file already exists.Configuration
enable_audit_log() and enable_security() accept only log_path and include_output — they do not yet forward redactor or sensitive_keys. To customise redaction, instantiate AuditLogHook directly and register it with add_hook("after_tool", ...) (see below).Customising Redaction
InstantiateAuditLogHook directly for full control over redaction.
Pick the option that fits your situation:
sensitive_keys only affects the built-in redactor. A redactor= callable you supply is used exactly as given — the class does not merge it with the default.
Thread Safety (PR #2062)
- Uses
threading.Lockfor concurrent multi-agent writes - Rotation-safe: each write
stats the log path and reopens when the on-disk inode differs from the open handle (recovers fromlogrotate,mv, orrmmid-run) — added in PR #4205 - Each write calls
fsyncfor crash durability - Call
get_audit_log().close()on shutdown to flush and release the handle
Best Practices
Enable early in production
Enable early in production
Call
enable_audit_log() before creating agents so every tool invocation is captured from the first turn — retrofitting mid-session misses earlier calls.Close on shutdown
Close on shutdown
Call
get_audit_log().close() in your shutdown handler to flush the file handle. Long-running daemons that skip this may lose the last buffered line on crash.Keep output logging selective
Keep output logging selective
Leave
include_output=False unless you need forensic replay. When enabled, tune max_output_chars to avoid bloating the JSONL with large tool payloads. Redaction covers tool_input only — outputs are written verbatim.Verify redaction after enabling
Verify redaction after enabling
Grep your audit file for known-sensitive strings once, especially if your tools use exotic key names not in the default denylist. If you see leaks, extend
sensitive_keys or supply a custom redactor on a directly-instantiated AuditLogHook.Rotate and protect log files
Rotate and protect log files
Store logs outside web-served directories. The file is created
0o600 (owner-only) by default, and the audit path is protected — do not disable Protected Paths on production hosts. External rotators (logrotate, container log drivers, cron mv + HUP) are supported directly — the writer reopens the live file on the next write, so you never need to signal the process (PR #4205).Scope audit logging in multi-tenant hosts
Scope audit logging in multi-tenant hosts
enable_audit_log() registers on the shared praisonaiagents.hooks registry, so every Agent in the same Python process is audited under a single sink and single configuration. This is fine for single-tenant deployments; for multi-tenant servers (e.g. praisonai serve), keep the returned hook ID and call praisonaiagents.hooks.remove_hook(hook_id) at teardown, or instantiate AuditLogHook and add_hook("after_tool", ...) per-request for per-tenant sinks.Related
Security Overview
Enable audit log with other security features
Protected Paths
Audit log file is itself protected

