Enterprise Features

Logging

PSR-3-compatible JSON logger:

$logger = new Logger(
    logDir: 'storage/logs',
    minLevel: 'info',  // Ignores debug messages
);

$logger->info('User logged in', ['user_id' => 42, 'ip' => '1.2.3.4']);
$logger->warning('Rate limit approaching', ['remaining' => 5]);
$logger->error('Payment failed', ['order_id' => 99, 'reason' => 'declined']);

// Message interpolation
$logger->info('User {user_id} performed {action}', ['user_id' => 42, 'action' => 'login']);
// Logs: "User 42 performed login"

Each log entry is a single JSON line in storage/logs/app.log:

{"timestamp":"2026-02-27T14:30:00+00:00","level":"info","message":"User 42 performed login","context":{"user_id":42,"action":"login"}}

Log levels (in order of severity): debug, info, notice, warning, error, critical, alert, emergency. Setting minLevel filters out lower-severity messages.

Health Checks

Monitor your application’s dependencies:

$health = new HealthCheck();

$health->addCheck('database', function () use ($db) {
    try {
        $db->fetchOne('SELECT 1');
        return ['status' => 'ok', 'message' => 'Connected'];
    } catch (\Throwable $e) {
        return ['status' => 'error', 'message' => $e->getMessage()];
    }
});

$health->addCheck('redis', function () use ($redis) {
    try {
        $redis->set('health', '1', ttl: 5);
        return ['status' => 'ok', 'message' => 'Connected'];
    } catch (\Throwable $e) {
        return ['status' => 'error', 'message' => $e->getMessage()];
    }
});

// Register as route
$router->get('/health', function () use ($health) {
    return $health->toResponse();
    // Returns 200 if all checks pass, 503 if any fail
});

Response format:

{
  "status": "healthy",
  "checks": {
    "database": { "status": "ok", "message": "Connected", "latency_ms": 1.23 },
    "redis": { "status": "ok", "message": "Connected", "latency_ms": 0.45 }
  },
  "timestamp": "2026-02-27T14:30:00+00:00"
}

OpenAPI Spec Generation

Auto-generate OpenAPI 3.0 documentation from your routes:

$generator = new OpenApiGenerator(
    router: $app->router(),
    title: 'My API',
    version: '1.0.0',
    description: 'API documentation',
);

$router->get('/api/docs', function () use ($generator) {
    return Response::json($generator->generate());
});

// Or export as JSON string
file_put_contents('openapi.json', $generator->toJson());

Route parameters like {id} are automatically extracted as OpenAPI path parameters.