Structured logging, correlation ID propagation, and monitoring standards for all Zidney services
All Zidney services must produce structured, machine-readable logs using Pino. This skill codifies the exact logging patterns, required fields, and monitoring standards.
Every log entry MUST include:
| Field | Required | Description |
|---|---|---|
timestamp | Always | ISO 8601 timestamp |
level | Always | Log level (info, warn, error, fatal) |
service | Always | Service name (api, worker, mmc, backoffice, frontoffice) |
correlation_id | Always | Request-scoped unique ID for tracing |
workspace_slug | If tenant-bound | Tenant identifier |
workspace_id |
| If tenant-bound |
| Tenant UUID |
user_id | If authenticated | User UUID |
attempt_id | If attempt-bound | Exam attempt UUID |
msg | Always | Human-readable log message |
console.log is forbidden — use the structured loggerimport { createLogger } from '@zidney/logger';
// Service-level logger
const logger = createLogger('api');
// Request-scoped child logger (in middleware)
const requestLogger = logger.child({
correlation_id: req.header('x-correlation-id') ?? generateId(),
workspace_slug: resolvedTenant.slug,
workspace_id: resolvedTenant.id,
user_id: authenticatedUser?.id,
});
The correlation ID must flow through:
Client Request (X-Correlation-Id header)
→ API middleware (extract or generate)
→ Domain function calls (passed via context)
→ Worker jobs (embedded in job payload)
→ Database queries (logged alongside query)
Rules:
| Level | When to Use |
|---|---|
fatal | Service cannot continue (DB connection lost, config invalid) |
error | Operation failed but service continues (failed request, bad input) |
warn | Degraded operation (cache miss fallback, retry attempt, rate limit hit) |
info | Business events (user login, exam started, submission received) |
debug | Development detail (query timings, cache hits, middleware execution) |
info level minimumdebug level alloweddebug level defaulttry {
await riskyOperation();
} catch (error) {
logger.error({
err: error,
operation: 'riskyOperation',
context: { relevant_id: '...' },
}, 'Operation failed: brief description');
// Re-throw or return error response
}
Always include:
Services must log at startup:
logger.info({
version: process.env.APP_VERSION,
environment: process.env.NODE_ENV,
port: config.port,
}, 'Service started');
When metrics collection is added, track:
http_request_duration_seconds — histogram by route and statusdb_query_duration_seconds — histogram by operation typeworker_job_duration_seconds — histogram by job typeactive_attempts — gauge per workspacesubmission_rate — counter per workspacecache_hit_ratio — gauge per cache domainVERDICT: PASS — all log statements include mandatory fields
VERDICT: BLOCKED — missing mandatory log fields or forbidden practice detected