Skip to content

Logging

Craft Easy API uses structlog for structured logging with automatic request context binding.

Configuration

Setting Default Description
LOG_LEVEL "INFO" Minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
LOG_FORMAT "console" Output format: "console" (human-readable) or "json" (machine-parseable)
LOG_SLOW_REQUEST_MS 1000 Threshold in ms for slow request warnings

Output Formats

Console Format (development)

Human-readable, colored output ideal for local development:

2026-04-06 12:34:56 [info     ] Request completed          method=GET path=/users status=200 duration_ms=45 request_id=abc-123

JSON Format (production)

Structured JSON for log aggregation systems (ELK, Datadog, Cloud Logging):

{
  "timestamp": "2026-04-06T12:34:56.789Z",
  "level": "info",
  "event": "Request completed",
  "method": "GET",
  "path": "/users",
  "status": 200,
  "duration_ms": 45,
  "request_id": "abc-123",
  "tenant_id": "t-456",
  "user_id": "u-789"
}

Request Context

Every log entry within a request automatically includes:

Field Source
request_id From X-Request-ID header or auto-generated UUID
tenant_id From authenticated user's tenant scope
user_id From authenticated user's identity

This context is bound via structlog's contextvars, so any log.info(...) call within the request lifecycle inherits it without explicit passing.

Slow Request Detection

Requests that exceed LOG_SLOW_REQUEST_MS (default: 1000ms) are logged with a warning:

2026-04-06 12:34:56 [warning  ] Slow request               method=GET path=/reports/revenue status=200 duration_ms=3200 request_id=abc-123

This helps identify performance bottlenecks without external monitoring.

Log Levels by Status

Response Status Log Level
2xx info
4xx info (client errors are normal)
5xx error
Slow (any status) warning

Silenced Loggers

Noisy third-party loggers are silenced to reduce log volume:

  • uvicorn.access — superseded by the structured logging middleware
  • motor — MongoDB async driver internals
  • pymongo — MongoDB driver internals

Usage

Get a logger for your module:

from craft_easy.core.logging import get_logger

log = get_logger(__name__)

async def process_payment(payment_id: str):
    log.info("Processing payment", payment_id=payment_id)
    # ...
    log.info("Payment completed", payment_id=payment_id, amount=100.0)

The logger automatically includes any bound request context.