Skip to main content
Every tool call can be recorded to an append-only JSONL audit log — thread-safe for concurrent multi-agent writes.
The user enables audit logging; each tool invocation is appended to JSONL safely even when many agents run in parallel.

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_name
  • tool_name, tool_input, execution_time_ms
  • Optional tool_output (when include_output=True)
The hook registers on after_tool automatically when you call enable_audit_log().

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 at 0o600 before the line is appended.

Secret Redaction

Sensitive values in tool_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):
Before / after on disk:
Redaction runs on tool_input only. When include_output=True, tool outputs are written verbatim (truncated at max_output_chars) with no redaction — keep secrets out of tool return values.
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

Instantiate AuditLogHook 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.Lock for 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 from logrotate, mv, or rm mid-run) — added in PR #4205
  • Each write calls fsync for crash durability
  • Call get_audit_log().close() on shutdown to flush and release the handle

Best Practices

Call enable_audit_log() before creating agents so every tool invocation is captured from the first turn — retrofitting mid-session misses earlier calls.
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.
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.
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.
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).

Security Overview

Enable audit log with other security features

Protected Paths

Audit log file is itself protected