Skip to main content

Structured Logging Contract

All server-side code uses log/slog. Never log.Printf, fmt.Printf (for logs), or third-party loggers.

Log Levels

LevelWhen to use
slog.DebugDetailed diagnostic info (request bodies, SQL queries, plugin calls)
slog.InfoNormal operations (server started, realm created, plugin loaded)
slog.WarnRecoverable issues (plugin health check failed, deprecated API used)
slog.ErrorUnrecoverable issues (database unreachable, encryption failed, plugin crashed)

log.Fatalf is reserved for fatal startup errors only (slog has no Fatal).

Standard Field Names

Every request-scoped log entry should include applicable fields from this list:

// Request context (set by middleware, present on all request-scoped logs)
"request_id" // string — from X-Request-Id header or generated
"method" // string — HTTP method (GET, POST, etc.)
"path" // string — URL path
"user_id" // string — authenticated user UUID
"realm" // string — realm slug (after resolution)
"status" // int — HTTP response status code
"duration_ms" // int64 — request duration in milliseconds

// Domain-specific (included when relevant)
"engine" // string — engine name
"plugin" // string — plugin name (if request touches a plugin)
"lease_id" // string — lease UUID
"policy_id" // string — policy/role UUID
"secret_key" // string — secret key name (NEVER the value)

// Error context
"error" // string — error message
"error_type" // string — category: "validation", "auth", "store", "plugin", "external", "internal"

// Plugin context
"plugin_name" // string — plugin binary name
"plugin_version" // string — plugin version
"host_function" // string — host function called (sql, http, store, audit)

Log Sanitization

NEVER log:

  • Secret values, passwords, tokens, API keys
  • Master key material or derived keys
  • Full request/response bodies in production (Debug level only)
  • User personal information beyond user_id

Handler Configuration

// Standalone: slog.TextHandler by default (human-readable to stderr)
// Multi-node: slog.JSONHandler (machine-parseable to stderr, queryable)
// Override with: ARCAN_LOG_FORMAT=json or ARCAN_LOG_FORMAT=text