Concord.AuditLog (Concord v1.1.0)

Copy Markdown View Source

Comprehensive audit logging for Concord operations.

Provides an immutable audit trail of all data-modifying operations for compliance, security, and debugging purposes. Audit logs are append-only and stored in structured JSON format.

Features

  • Immutable append-only log storage
  • Structured JSON format for easy parsing
  • Automatic log rotation and retention
  • Query and export API
  • Minimal performance impact (async writes)
  • Integration with authentication and telemetry

Configuration

config :concord,
  audit_log: [
    enabled: true,
    log_dir: "./audit_logs",
    rotation_size_mb: 100,      # Rotate at 100MB
    retention_days: 90,          # Keep logs for 90 days
    log_reads: false,            # Don't log read operations
    sensitive_keys: false        # Don't log actual key values
  ]

Audit Log Format

Each audit log entry is a JSON object with the following fields:

{
  "timestamp": "2025-10-23T08:30:45.123456Z",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "operation": "put",
  "key": "user:123",  # Only if sensitive_keys: true
  "key_hash": "sha256:abc123...",  # Always present
  "result": "ok",
  "user": "token:sk_concord_...",  # If authenticated
  "node": "node1@127.0.0.1",
  "metadata": {
    "has_ttl": true,
    "ttl_seconds": 3600,
    "compressed": false
  },
  "trace_id": "a1b2c3d4...",  # If tracing enabled
  "span_id": "e5f6g7h8..."
}

Usage

Audit logging is automatic for all operations when enabled. You can also manually log custom events:

Concord.AuditLog.log(%{
  operation: "custom_action",
  key: "resource:id",
  result: :ok,
  metadata: %{action: "import", count: 100}
})

Querying Logs

# Get recent audit logs
{:ok, logs} = Concord.AuditLog.query(limit: 100)

# Filter by operation
{:ok, logs} = Concord.AuditLog.query(operation: "put", limit: 50)

# Filter by time range
{:ok, logs} = Concord.AuditLog.query(
  from: ~U[2025-10-23 00:00:00Z],
  to: ~U[2025-10-23 23:59:59Z]
)

Compliance

Audit logs support compliance requirements including:

  • PCI-DSS: Tracking and monitoring all access to cardholder data
  • HIPAA: Audit controls for PHI access
  • GDPR: Data processing activity logs
  • SOC 2: Detailed audit trails for security events

Summary

Functions

Returns a specification to start this module under a supervisor.

Cleans up old audit logs based on retention policy.

Exports audit logs to a file.

Logs an audit event.

Queries audit logs with optional filters.

Manually triggers log rotation.

Starts the audit log GenServer.

Returns current audit log statistics.

Types

event()

@type event() :: %{
  timestamp: DateTime.t(),
  event_id: String.t(),
  operation: String.t(),
  key: String.t() | nil,
  key_hash: String.t(),
  result: atom() | String.t(),
  user: String.t() | nil,
  node: atom(),
  metadata: map(),
  trace_id: String.t() | nil,
  span_id: String.t() | nil
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

cleanup()

Cleans up old audit logs based on retention policy.

export(path, opts \\ [])

Exports audit logs to a file.

Examples

:ok = Concord.AuditLog.export("/tmp/audit_export.jsonl")

log(event)

Logs an audit event.

Examples

Concord.AuditLog.log(%{
  operation: "put",
  key: "user:123",
  result: :ok
})

query(opts \\ [])

Queries audit logs with optional filters.

Options

  • :limit - Maximum number of entries to return (default: 100)
  • :operation - Filter by operation type
  • :from - Start datetime (DateTime struct)
  • :to - End datetime (DateTime struct)
  • :user - Filter by user/token
  • :result - Filter by result (:ok, :error)

Examples

{:ok, logs} = Concord.AuditLog.query(operation: "put", limit: 50)

rotate()

Manually triggers log rotation.

start_link(opts \\ [])

Starts the audit log GenServer.

stats()

Returns current audit log statistics.

Examples

iex> Concord.AuditLog.stats()
%{
  current_log_size: 45678912,
  total_files: 5,
  oldest_log: ~U[2025-07-23 00:00:00Z],
  entries_today: 1234
}