Audit Logging
AxonFlow provides comprehensive audit logging for every AI interaction, capturing complete request/response data for compliance, debugging, and observability.
Audit logging is one of the reasons AxonFlow remains useful even after a team already has provider logs, application logs, and APM traces. Those systems tell you pieces of the story. AxonFlow is the layer that ties policy decisions, governed request flow, workflow activity, and connector behavior into one governance-oriented record.
For most production teams, that matters when they need to answer questions like:
- Which policy blocked or redacted this request?
- Which user, tenant, agent, or workflow triggered the event?
- Did the risky behavior happen before execution, during execution, or in the response?
- Can we reconstruct what happened without scraping several unrelated systems?
That same property is what makes AxonFlow useful during evaluation. Teams in regulated environments often read audit logging before they decide whether the platform is even safe to test. If that is your situation, pair this page with Evaluating AxonFlow in Regulated Environments.
See complete working examples in the AxonFlow examples repository.
Architecture Overview
AxonFlow implements a multi-layer logging architecture:
Request Flow:
┌─────────────────────────────────────────────────────────────────┐
│ Your Application │
└─────────────────┬───────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AxonFlow Agent │
│ ┌─────────────────┐ ┌─────────────────────────────────────┐ │
│ │ Policy Engine │───▶│ Agent Audit Queue │ │
│ │ (Gateway Mode) │ │ - Pre-check decisions │ │
│ └─────────────────┘ │ - Policy violations │ │
│ │ - PII detections │ │
│ ┌─────────────────┐ │ │ │
│ │ MCP Handler │───▶│ - MCP query audits (NEW) │ │
│ │ │ │ - Connector access logs │ │
│ └─────────────────┘ └─────────────────────────────────────┘ │
└─────────────────┬───────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AxonFlow Orchestrator │
│ ┌─────────────────┐ ┌─────────────────────────────────────┐ │
│ │ LLM Routing │───▶│ Orchestrator Audit Logger │ │
│ │ MAP Planning │ │ - LLM call details │ │
│ └─────────────────┘ │ - Token usage & cost │ │
│ │ - Response metadata │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
What Gets Logged
The most useful way to think about AxonFlow audit logging is by execution surface:
- governed request traffic through the Agent
- provider and routing activity in the Orchestrator
- MCP and connector usage
- workflow-control and approval events
That separation helps operators decide which records they need for debugging, and it helps reviewers understand whether a problem was a content decision, a tool decision, or a workflow decision.
Gateway Context (Pre-Check)
Every policy pre-check creates a gateway_context record:
| Field | Description |
|---|---|
context_id | Unique identifier for correlation |
user_id | User making the request |
client_id | Application or service identifier |
query | Original prompt (with optional PII redaction) |
approved | Whether policy allowed the request |
policies_applied | List of policies evaluated |
policy_violations | Any violations detected |
pii_detected | Types of PII found (SSN, credit card, etc.) |
created_at | Timestamp |
metadata | Custom context (department, project, etc.) |
LLM Call Audit
After LLM processing, an llm_call_audit record is created:
| Field | Description |
|---|---|
context_id | Links to gateway_context |
provider | LLM provider (openai, anthropic, bedrock) |
model | Specific model used (gpt-4, claude-opus-4) |
input_tokens | Token count for prompt |
output_tokens | Token count for response |
total_tokens | Combined token usage |
latency_ms | Response time in milliseconds |
response_summary | Truncated response (configurable) |
cost_usd | Estimated cost based on token pricing |
created_at | Timestamp |
Agent Audit Logs
Policy enforcement events captured by the Agent (via audit_queue.go):
| Entry Type | Data Captured |
|---|---|
violation | Severity (critical/high/medium/low), policy name, block reason |
metric | Performance metrics, latency, throughput |
audit | General audit trail entries |
gateway_context | SDK pre-check context (synchronous write) |
llm_call_audit | SDK LLM call audit (synchronous write) |
Orchestrator Audit Logs
All requests captured by the Orchestrator (via audit_logger.go):
| Field | Description |
|---|---|
user_id, user_email, user_role | User identity |
client_id, tenant_id | Client/tenant isolation |
request_type | Type of operation |
query, query_hash | Request content (hashed for deduplication) |
policy_decision | allowed, blocked, redacted, error |
provider, model | LLM provider and model used |
response_time_ms, tokens_used, cost | Performance and billing |
compliance_flags | hipaa_relevant, gdpr_applicable, sox_relevant, pii_access |
security_metrics | risk_score, query_complexity (low/medium/high) |
MCP Query Audits
All MCP connector operations are logged in the mcp_query_audits table with complete policy evaluation results. This applies to both Gateway and Proxy mode operations.
MCP audit logging was added in AxonFlow v3.3.0 to provide a complete audit trail for connector access.
Three-Phase Policy Evaluation
MCP audit logging captures results from three policy evaluation phases:
| Phase | What's Captured | Example |
|---|---|---|
| REQUEST | SQL injection blocking, dangerous operation detection | Query blocked due to DROP TABLE pattern |
| RESPONSE | PII detection and redaction | SSN and credit card fields redacted |
| EXFILTRATION | Row count and volume limit violations | Query exceeded 10K row limit |
Audit Fields
| Field | Description |
|---|---|
audit_id | Unique identifier (matches SDK PolicyInfo.audit_id) |
tenant_id, client_id, user_id | Identity context |
connector_name | MCP connector accessed |
operation | Operation type (query, execute, etc.) |
statement_hash | SHA256 hash of the query (privacy-preserving) |
request_blocked | Whether request was blocked before execution |
request_block_reason | Block reason (e.g., "SQL injection detected") |
request_matched_policies | Array of policy IDs that matched |
response_redacted | Whether PII was redacted from response |
response_redacted_fields | JSONPath of redacted fields |
exfil_rows_returned | Number of rows returned |
exfil_exceeded | Whether exfiltration limit was exceeded |
exfil_limit_type | Type of limit exceeded (row_count, byte_size) |
duration_ms | Total operation duration |
success | Whether operation completed successfully |
created_at | Timestamp |
Privacy by Design
MCP audit logs protect sensitive data:
- Statement hashing: Only SHA256 hash of SQL stored, not the raw query
- No response data: Only metadata captured, not actual query results
- Field paths only: Redacted field paths logged, not the original values
SDK Correlation
The audit_id field in PolicyInfo correlates SDK responses with audit entries:
// Go SDK
resp, _ := client.MCPQuery(ctx, req)
if resp.PolicyInfo != nil {
// audit_id can be used to look up the mcp_query_audits record
fmt.Printf("Audit ID: %s\n", resp.PolicyInfo.AuditID)
}
Example Queries
Daily MCP operations summary:
SELECT
DATE_TRUNC('day', created_at) AS date,
connector_name,
COUNT(*) AS total_queries,
COUNT(*) FILTER (WHERE request_blocked = true) AS blocked,
COUNT(*) FILTER (WHERE response_redacted = true) AS redacted,
COUNT(*) FILTER (WHERE exfil_exceeded = true) AS exfil_violations
FROM mcp_query_audits
WHERE tenant_id = 'your-tenant'
GROUP BY 1, 2
ORDER BY date DESC;
Security incident investigation (blocked SQLi attempts):
SELECT created_at, client_id, request_block_reason, statement_hash
FROM mcp_query_audits
WHERE request_blocked = true
AND request_block_reason LIKE '%SQL injection%'
ORDER BY created_at DESC
LIMIT 100;
PII redaction report:
SELECT
connector_name,
UNNEST(response_redacted_fields) AS redacted_field,
COUNT(*) AS redaction_count
FROM mcp_query_audits
WHERE response_redacted = true
GROUP BY 1, 2
ORDER BY redaction_count DESC;
Workflow Audit Logs
Workflow Control Plane (WCP) operations are logged to provide a complete audit trail for external orchestrators (LangChain, LangGraph, CrewAI). Every workflow lifecycle event is recorded in the audit_logs table.
Workflow audit logging was added in AxonFlow v3.4.0 as part of the Workflow Control Plane feature.
Workflow Operations Logged
| Request Type | When Logged | Data Captured |
|---|---|---|
workflow_created | Workflow registration | workflow_id, workflow_name, source, total_steps, metadata |
workflow_step_gate | Step gate check | workflow_id, step_id, step_name, step_type, decision, policies_evaluated, policies_matched |
workflow_step_completed | Step marked complete | workflow_id, step_id, output |
workflow_completed | Workflow finishes | workflow_id, final_status |
workflow_aborted | Workflow cancelled | workflow_id, reason |
SDK Correlation
Use SDK audit search methods to query workflow audit logs:
# Python SDK
from datetime import datetime, timedelta, timezone
from axonflow.types import AuditSearchRequest, AuditQueryOptions
# Search for workflow audit logs from the last hour
response = await client.search_audit_logs(
AuditSearchRequest(
start_time=datetime.now(timezone.utc) - timedelta(hours=1),
limit=100,
)
)
# Filter for specific workflow
workflow_id = "wf_abc123"
for entry in response.entries:
if entry.request_id == workflow_id:
print(f"{entry.request_type}: {entry.query_summary}")
What A Good Audit Trail Enables
Strong audit logging is not just about retention. It enables three concrete operating workflows:
1. Incident Investigation
When a workflow is blocked, redacted, or rejected, teams can correlate:
- the original governed request
- policy decisions and matched rules
- workflow step state
- connector access
- approval outcomes where applicable
2. Production Readiness Reviews
Before a pilot moves to wider usage, platform and security teams often want proof that:
- requests are actually being governed
- risky connector operations are visible
- budget and policy decisions are inspectable
- human approvals are reconstructable
3. External Or Internal Assurance
Security, compliance, and procurement teams rarely want raw database access during an evaluation. They want evidence that the platform has a coherent audit model. The audit layer is one of the strongest signals that AxonFlow is designed for governed production usage rather than isolated experimentation.
// Go SDK
auditLogs, err := client.SearchAuditLogs(ctx, &axonflow.AuditSearchRequest{
StartTime: &startTime,
Limit: 100,
})
for _, entry := range auditLogs.Entries {
if entry.RequestID == workflowID {
fmt.Printf("%s: %s\n", entry.RequestType, entry.QuerySummary)
}
}
// TypeScript SDK
const response = await client.searchAuditLogs({
clientId: "workflow-service",
limit: 100,
});
for (const entry of response.entries) {
if (entry.requestId === workflowId) {
console.log(`${entry.requestType}: ${entry.querySummary}`);
}
}
// Java SDK
AuditSearchResponse response = client.searchAuditLogs(
AuditSearchRequest.builder()
.clientId("workflow-service")
.limit(100)
.build()
);
for (AuditLogEntry entry : response.getEntries()) {
if (workflowId.equals(entry.getRequestId())) {
System.out.println(entry.getRequestType() + ": " + entry.getQuerySummary());
}
}
# Python SDK - tenant scoped query
tenant_logs = await client.get_audit_logs_by_tenant(
"workflow-service",
AuditQueryOptions(limit=25, offset=0),
)
print(f"Tenant entries: {len(tenant_logs.entries)}")
// TypeScript SDK - tenant scoped query
const tenantLogs = await client.getAuditLogsByTenant("workflow-service", {
limit: 25,
offset: 0,
});
console.log(`Tenant entries: ${tenantLogs.entries.length}`);
// Java SDK - tenant scoped query
AuditSearchResponse tenantLogs = client.getAuditLogsByTenant(
"workflow-service",
AuditQueryOptions.builder().limit(25).offset(0).build()
);
System.out.println("Tenant entries: " + tenantLogs.getEntries().size());
Example Queries
Daily workflow operations summary:
SELECT
DATE_TRUNC('day', timestamp) AS date,
request_type,
COUNT(*) AS count
FROM audit_logs
WHERE request_type LIKE 'workflow_%'
GROUP BY 1, 2
ORDER BY date DESC, count DESC;
Blocked workflow steps (policy violations):
SELECT timestamp, request_id, query_summary, metadata->>'reason' AS reason
FROM audit_logs
WHERE request_type = 'workflow_step_gate'
AND metadata->>'decision' = 'block'
ORDER BY timestamp DESC
LIMIT 100;
Related Documentation
- Governance Overview for the broader governance model
- Evidence Export Pack for packaging records for review
- Human-in-the-Loop for approval-driven audit trails
- MCP Policy Enforcement for connector request, response, and exfiltration controls
Media Audit Records
When media (images, documents) is submitted alongside a request, the audit trail captures media-specific metadata for traceability and compliance.
| Field | Description | Edition |
|---|---|---|
sha256_hash | SHA-256 hash of the submitted file | Community |
mime_type | Detected MIME type (e.g., image/png) | Community |
file_size | File size in bytes | Community |
has_pii / pii_types | Whether PII was detected, and which types, via OCR extraction | Community |
content_safe | Boolean: whether the image passed content safety checks | Community |
warnings | Validation warnings (format, dimensions) | Community |
has_faces | Whether faces were detected in the image | Enterprise |
has_biometric_data | Whether biometric indicators were found | Enterprise |
nsfw_score / violence_score | Content safety confidence scores | Enterprise |
document_classification | Document type label from classifier | Enterprise |
analyzer_details | Per-analyzer results (Rekognition, Vision, etc.) | Enterprise |
Community records cover validation, OCR-based PII, and SHA-256 hashing. Enterprise records add cloud analyzer results, biometric detection, and content safety scores. See Media Governance for configuration details.
Plan (MAP) Audit Logs
Multi-Agent Planning (MAP) operations are logged to provide visibility into plan creation, execution, and completion. All plan lifecycle events are recorded in the audit_logs table.
Plan audit logging was added in AxonFlow v3.4.0 to enhance observability for multi-agent workflows.
Plan Operations Logged
| Request Type | When Logged | Data Captured |
|---|---|---|
plan_created | Plan stored | plan_id, query, domain, step_count, tenant_id, client_id |
plan_execution_started | Execution begins | plan_id, domain, step_count |
plan_completed | Execution succeeds | plan_id, domain, final_status |
plan_failed | Execution fails | plan_id, domain, error_message |
Example Queries
Plan execution success rate:
SELECT
DATE_TRUNC('day', timestamp) AS date,
COUNT(*) FILTER (WHERE request_type = 'plan_completed') AS succeeded,
COUNT(*) FILTER (WHERE request_type = 'plan_failed') AS failed,
ROUND(
100.0 * COUNT(*) FILTER (WHERE request_type = 'plan_completed') /
NULLIF(COUNT(*) FILTER (WHERE request_type IN ('plan_completed', 'plan_failed')), 0),
2
) AS success_rate
FROM audit_logs
WHERE request_type IN ('plan_completed', 'plan_failed')
GROUP BY 1
ORDER BY date DESC;
Recent failed plans with error details:
SELECT timestamp, request_id AS plan_id, metadata->>'error' AS error
FROM audit_logs
WHERE request_type = 'plan_failed'
ORDER BY timestamp DESC
LIMIT 20;
Query Examples
Common audit log queries for day-to-day operations:
Search by date range and user:
curl -X POST http://localhost:8080/audit/search \
-H "Content-Type: application/json" \
-d '{
"user_email": "[email protected]",
"start_time": "2026-01-01T00:00:00Z",
"end_time": "2026-01-31T23:59:59Z",
"limit": 50
}'
Search by policy action (all blocked requests):
curl -X POST http://localhost:8080/audit/search \
-H "Content-Type: application/json" \
-d '{
"request_type": "policy_violation",
"start_time": "2026-02-01T00:00:00Z",
"end_time": "2026-02-07T23:59:59Z",
"limit": 100
}'
Search by client ID (specific application):
curl -X POST http://localhost:8080/audit/search \
-H "Content-Type: application/json" \
-d '{
"client_id": "customer-support-agent",
"limit": 25
}'
SQL: Top users by blocked requests in the last 7 days:
SELECT user_email, COUNT(*) AS blocked_count
FROM audit_logs
WHERE policy_decision = 'blocked'
AND timestamp >= NOW() - INTERVAL '7 days'
GROUP BY user_email
ORDER BY blocked_count DESC
LIMIT 20;
Retention Policies
AxonFlow supports configurable retention periods to meet regulatory requirements:
| Framework | Required Retention | AxonFlow Support |
|---|---|---|
| SEBI AI/ML | 5 years (1825 days) | ✅ Enterprise |
| RBI FREE-AI | 7 years (2555 days) | ✅ Enterprise |
| EU AI Act | 7 years (2555 days) for decision_chain | ✅ Enterprise |
| HIPAA | 6 years (2190 days) | ✅ Enterprise |
| Custom | Configurable | ✅ All editions |
Configuration
Retention is configured per-log-type via YAML config or environment variables:
# axonflow-config.yaml
audit:
retention:
gateway_contexts: 365 # Days to retain pre-check logs
llm_call_audits: 365 # Days to retain LLM call logs
agent_audit_logs: 2555 # 7 years for RBI compliance
orchestrator_logs: 1825 # 5 years for SEBI compliance
Environment variable equivalents:
| Environment Variable | Default | Description |
|---|---|---|
AXONFLOW_AUDIT_RETENTION_GATEWAY | 365 | Days to retain gateway context logs |
AXONFLOW_AUDIT_RETENTION_LLM | 365 | Days to retain LLM call audit logs |
AXONFLOW_AUDIT_RETENTION_AGENT | 365 | Days to retain agent audit logs |
AXONFLOW_AUDIT_RETENTION_ORCHESTRATOR | 365 | Days to retain orchestrator logs |
AXONFLOW_AUDIT_RETENTION_MCP | 365 | Days to retain MCP query audit logs |
AXONFLOW_AUDIT_CLEANUP_INTERVAL | 24h | How often the retention cleanup job runs |
AXONFLOW_AUDIT_FALLBACK_PATH | /var/log/axonflow/audit_fallback.jsonl | Path for fallback JSONL file |
Export Formats
Community Edition
| Format | Use Case |
|---|---|
| JSON | Programmatic access, API responses |
| CSV | Spreadsheet analysis, basic reporting |
Enterprise Edition
| Format | Use Case |
|---|---|
| JSON | Programmatic access, API responses |
| CSV | Spreadsheet analysis, basic reporting |
| Compliance reports, board presentations | |
| XLSX | Advanced Excel analysis with formatting |
| XML | SEBI regulatory submission format |
Export API
# Export last 30 days of audit logs (JSON)
curl -X GET "http://localhost:8080/api/audit/export?days=30&format=json" \
-H "Authorization: Bearer $AXONFLOW_API_KEY"
# Export for SEBI compliance (Enterprise)
curl -X GET "http://localhost:8080/api/v1/sebi/audit-export?start=2024-01-01&end=2024-12-31" \
-H "Authorization: Bearer $AXONFLOW_LICENSE_KEY"
Fallback Mechanism
If the database is temporarily unavailable, audit logs are written to a local JSONL file:
/var/log/axonflow/audit_fallback.jsonl
On service restart, RecoverFromFallback() automatically replays entries back to the database:
- Reads JSONL file line-by-line
- Retries failed entries with exponential backoff
- Truncates fallback file when recovery succeeds
SIEM Integration
AxonFlow integrates with enterprise security information and event management (SIEM) systems:
| Platform | Integration Method | Status |
|---|---|---|
| CloudWatch | Native (AWS deployments) | Community + Enterprise |
| Splunk | HTTP Event Collector | Enterprise |
| Datadog | Log forwarding | Enterprise |
| Elastic/ELK | Logstash integration | Enterprise |
CloudWatch Integration (AWS)
Audit logs are automatically forwarded to CloudWatch when deployed in AWS:
# View audit logs in CloudWatch
aws logs filter-log-events \
--log-group-name "/ecs/axonflow-agent" \
--filter-pattern '"audit"'
Prometheus Metrics
AxonFlow exposes 80+ Prometheus metrics for audit observability:
Key Audit Metrics
| Metric | Type | Description |
|---|---|---|
axonflow_audit_logs_total | Counter | Total audit log entries |
axonflow_audit_write_latency_ms | Histogram | Time to write audit log |
axonflow_audit_fallback_active | Gauge | 1 if using fallback mode |
axonflow_policy_violations_total | Counter | Total policy violations |
axonflow_pii_detections_total | Counter | PII detections by type |
Example PromQL Queries
# Audit write latency P95
histogram_quantile(0.95, rate(axonflow_audit_write_latency_ms_bucket[5m]))
# Policy violations per minute
rate(axonflow_policy_violations_total[1m])
# PII detections by type
sum by (pii_type) (increase(axonflow_pii_detections_total[1h]))
API Reference
Query Audit Logs
# Search audit logs (POST with criteria)
POST /audit/search
{
"user_email": "[email protected]",
"client_id": "client-123",
"start_time": "2024-01-01T00:00:00Z",
"end_time": "2024-01-31T23:59:59Z",
"request_type": "llm_call",
"limit": 100
}
# Get tenant-specific audit logs
GET /audit/tenant/{tenant_id}
Response Example
{
"logs": [
{
"id": "audit_abc123",
"context_id": "ctx_xyz789",
"user_id": "user-123",
"event_type": "policy_violation",
"policy_name": "pii_ssn_detection",
"query_hash": "sha256:abc...",
"pii_types": ["ssn"],
"blocked": true,
"created_at": "2024-01-15T10:30:00Z"
}
],
"total": 1523,
"limit": 100,
"offset": 0
}
Community vs Enterprise
| Feature | Community | Enterprise |
|---|---|---|
| Basic audit logging | ✅ | ✅ |
| Gateway context capture | ✅ | ✅ |
| LLM call auditing | ✅ | ✅ |
| MCP query auditing | ✅ | ✅ |
| Workflow audit logging | ✅ | ✅ |
| Plan (MAP) audit logging | ✅ | ✅ |
| Media audit records (hash, MIME, PII, safety) | ✅ | ✅ |
| Media audit records (face, biometric, NSFW, classifiers) | ✅ | |
| JSON/CSV export | ✅ | ✅ |
| JSONL fallback | ✅ | ✅ |
| CloudWatch integration | ✅ | ✅ |
| Prometheus metrics | ✅ | ✅ |
| Custom retention policies | ✅ | |
| PDF/XLSX/XML export | ✅ | |
| SEBI audit export | ✅ | |
| RBI audit export | ✅ | |
| Splunk/Datadog SIEM | ✅ | |
| Compliance dashboards | ✅ |
Best Practices
1. Enable Correlation IDs
Always pass context_id through your application flow for end-to-end tracing:
# Python SDK
ctx = await client.get_policy_approved_context(
user_id="user-123",
query="...",
metadata={"request_id": "your-trace-id"}
)
# Use ctx.context_id for downstream correlation
2. Set Appropriate Retention
Match retention to your compliance requirements:
- Minimum 5 years for financial services (SEBI)
- Minimum 7 years for Indian banking (RBI FREE-AI)
- Minimum 7 years for EU AI Act decision_chain records
3. Monitor Audit Queue Depth
Set alerts on audit queue metrics to catch database issues early:
# Prometheus alert rule
groups:
- name: axonflow-audit
rules:
- alert: AuditFallbackActive
expr: axonflow_audit_fallback_active == 1
for: 5m
labels:
severity: warning
annotations:
summary: "AxonFlow audit using fallback storage"
4. Regular Export for Compliance
Schedule regular exports for compliance archives:
# Weekly SEBI compliance export (cron)
0 0 * * 0 curl -X POST "http://localhost:8080/api/v1/sebi/audit-export" \
-H "Authorization: Bearer $LICENSE_KEY" \
-d '{"format": "xml", "period": "last_week"}'
Related Documentation
- MCP Policy Enforcement - MCP connector security policies
- Monitoring Overview - Prometheus metrics and dashboards
- Security Best Practices - PII detection configuration
- Compliance Overview - Regulatory framework support
- API Reference - Full API documentation
