Skip to main content

Audit Logging

AxonFlow provides comprehensive audit logging for every AI interaction, capturing complete request/response data for compliance, debugging, and observability.

Community Examples

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

Gateway Context (Pre-Check)

Every policy pre-check creates a gateway_context record:

FieldDescription
context_idUnique identifier for correlation
user_idUser making the request
client_idApplication or service identifier
queryOriginal prompt (with optional PII redaction)
approvedWhether policy allowed the request
policies_appliedList of policies evaluated
policy_violationsAny violations detected
pii_detectedTypes of PII found (SSN, credit card, etc.)
created_atTimestamp
metadataCustom context (department, project, etc.)

LLM Call Audit

After LLM processing, an llm_call_audit record is created:

FieldDescription
context_idLinks to gateway_context
providerLLM provider (openai, anthropic, bedrock)
modelSpecific model used (gpt-4, claude-opus-4)
input_tokensToken count for prompt
output_tokensToken count for response
total_tokensCombined token usage
latency_msResponse time in milliseconds
response_summaryTruncated response (configurable)
cost_usdEstimated cost based on token pricing
created_atTimestamp

Agent Audit Logs

Policy enforcement events captured by the Agent (via audit_queue.go):

Entry TypeData Captured
violationSeverity (critical/high/medium/low), policy name, block reason
metricPerformance metrics, latency, throughput
auditGeneral audit trail entries
gateway_contextSDK pre-check context (synchronous write)
llm_call_auditSDK LLM call audit (synchronous write)

Orchestrator Audit Logs

All requests captured by the Orchestrator (via audit_logger.go):

FieldDescription
user_id, user_email, user_roleUser identity
client_id, tenant_idClient/tenant isolation
request_typeType of operation
query, query_hashRequest content (hashed for deduplication)
policy_decisionallowed, blocked, redacted, error
provider, modelLLM provider and model used
response_time_ms, tokens_used, costPerformance and billing
compliance_flagshipaa_relevant, gdpr_applicable, sox_relevant, pii_access
security_metricsrisk_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.

Added in v3.3.0

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:

PhaseWhat's CapturedExample
REQUESTSQL injection blocking, dangerous operation detectionQuery blocked due to DROP TABLE pattern
RESPONSEPII detection and redactionSSN and credit card fields redacted
EXFILTRATIONRow count and volume limit violationsQuery exceeded 10K row limit

Audit Fields

FieldDescription
audit_idUnique identifier (matches SDK PolicyInfo.audit_id)
tenant_id, client_id, user_idIdentity context
connector_nameMCP connector accessed
operationOperation type (query, execute, etc.)
statement_hashSHA256 hash of the query (privacy-preserving)
request_blockedWhether request was blocked before execution
request_block_reasonBlock reason (e.g., "SQL injection detected")
request_matched_policiesArray of policy IDs that matched
response_redactedWhether PII was redacted from response
response_redacted_fieldsJSONPath of redacted fields
exfil_rows_returnedNumber of rows returned
exfil_exceededWhether exfiltration limit was exceeded
exfil_limit_typeType of limit exceeded (row_count, byte_size)
duration_msTotal operation duration
successWhether operation completed successfully
created_atTimestamp

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.

Added in v3.4.0

Workflow audit logging was added in AxonFlow v3.4.0 as part of the Workflow Control Plane feature.

Workflow Operations Logged

Request TypeWhen LoggedData Captured
workflow_createdWorkflow registrationworkflow_id, workflow_name, source, total_steps, metadata
workflow_step_gateStep gate checkworkflow_id, step_id, step_name, step_type, decision, policies_evaluated, policies_matched
workflow_step_completedStep marked completeworkflow_id, step_id, output
workflow_completedWorkflow finishesworkflow_id, final_status
workflow_abortedWorkflow cancelledworkflow_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}")
// 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;

Media Audit Records

When media (images, documents) is submitted alongside a request, the audit trail captures media-specific metadata for traceability and compliance.

FieldDescriptionEdition
sha256_hashSHA-256 hash of the submitted fileCommunity
mime_typeDetected MIME type (e.g., image/png)Community
file_sizeFile size in bytesCommunity
has_pii / pii_typesWhether PII was detected, and which types, via OCR extractionCommunity
content_safeBoolean: whether the image passed content safety checksCommunity
warningsValidation warnings (format, dimensions)Community
has_facesWhether faces were detected in the imageEnterprise
has_biometric_dataWhether biometric indicators were foundEnterprise
nsfw_score / violence_scoreContent safety confidence scoresEnterprise
document_classificationDocument type label from classifierEnterprise
analyzer_detailsPer-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.

Added in v3.4.0

Plan audit logging was added in AxonFlow v3.4.0 to enhance observability for multi-agent workflows.

Plan Operations Logged

Request TypeWhen LoggedData Captured
plan_createdPlan storedplan_id, query, domain, step_count, tenant_id, client_id
plan_execution_startedExecution beginsplan_id, domain, step_count
plan_completedExecution succeedsplan_id, domain, final_status
plan_failedExecution failsplan_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:

FrameworkRequired RetentionAxonFlow Support
SEBI AI/ML5 years (1825 days) Enterprise
RBI FREE-AI7 years (2555 days) Enterprise
EU AI Act7 years (2555 days) for decision_chain Enterprise
HIPAA6 years (2190 days) Enterprise
CustomConfigurable 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 VariableDefaultDescription
AXONFLOW_AUDIT_RETENTION_GATEWAY365Days to retain gateway context logs
AXONFLOW_AUDIT_RETENTION_LLM365Days to retain LLM call audit logs
AXONFLOW_AUDIT_RETENTION_AGENT365Days to retain agent audit logs
AXONFLOW_AUDIT_RETENTION_ORCHESTRATOR365Days to retain orchestrator logs
AXONFLOW_AUDIT_RETENTION_MCP365Days to retain MCP query audit logs
AXONFLOW_AUDIT_CLEANUP_INTERVAL24hHow often the retention cleanup job runs
AXONFLOW_AUDIT_FALLBACK_PATH/var/log/axonflow/audit_fallback.jsonlPath for fallback JSONL file

Export Formats

Community Edition

FormatUse Case
JSONProgrammatic access, API responses
CSVSpreadsheet analysis, basic reporting

Enterprise Edition

FormatUse Case
JSONProgrammatic access, API responses
CSVSpreadsheet analysis, basic reporting
PDFCompliance reports, board presentations
XLSXAdvanced Excel analysis with formatting
XMLSEBI 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:

PlatformIntegration MethodStatus
CloudWatchNative (AWS deployments)Community + Enterprise
SplunkHTTP Event CollectorEnterprise
DatadogLog forwardingEnterprise
Elastic/ELKLogstash integrationEnterprise

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

MetricTypeDescription
axonflow_audit_logs_totalCounterTotal audit log entries
axonflow_audit_write_latency_msHistogramTime to write audit log
axonflow_audit_fallback_activeGauge1 if using fallback mode
axonflow_policy_violations_totalCounterTotal policy violations
axonflow_pii_detections_totalCounterPII 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

FeatureCommunityEnterprise
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"}'