Why Vapor is different
Each request runs in a Lambda function. Two meaningful consequences for monitoring:
- No persistent process. Agents that buffer telemetry in-process and flush via a background thread fit PHP-FPM / Octane, not Lambda. Lambda's execution model assumes the function returns, memory evaporates, next invocation starts fresh (or reuses a warm container).
- Cold starts dominate p95. Lambda cold starts on PHP add 500-2000ms depending on layer size. A route that looks slow at p95 might be 95% fast + 5% cold-starting — a very different bug than being uniformly slow.
- CloudWatch is the default. All stdout/stderr ends up in CloudWatch Logs. Powerful but expensive at scale; queries (CloudWatch Insights) cost per GB scanned.
Tracking cold starts
Detect cold starts by checking whether a Lambda invocation is handling its first request. Record alongside route and duration:
app/Http/Middleware/TrackColdStart.php
use Closure;
use Illuminate\Http\Request;
class TrackColdStart
{
private static bool $invoked = false;
public function handle(Request $request, Closure $next)
{
$isColdStart = !self::$invoked;
self::$invoked = true;
$request->attributes->set('is_cold_start', $isColdStart);
return $next($request);
}
}
Push is_cold_start to your telemetry. Split p95 by cold vs warm — a slow cold-path is a bundle-size problem (reduce Vapor package), a slow warm-path is an actual code/DB problem.
CloudWatch → log aggregator
Raw CloudWatch gets expensive for search. Stream logs out via a subscription:
Lambda logs
↓
CloudWatch Logs
↓ (subscription filter)
Kinesis Data Firehose / Lambda forwarder
↓
Axiom / Loki / Papertrail / S3 + AthenaBetter Stack, Axiom, and Papertrail all have AWS CloudWatch integrations. For self-hosted: a small Lambda forwarder that ships logs to your Loki or OpenSearch.
Queue monitoring
Vapor queues are SQS + Lambda consumers. Key metrics:
- ApproximateAgeOfOldestMessage — SQS metric, surfaces queue lag
- ApproximateNumberOfMessagesVisible — queue depth
- Lambda Errors / Throttles — job failures / concurrency limit hit
- Lambda Duration — per-job runtime
All visible in CloudWatch metrics. Alert on rising age-of-oldest or throttle rate.
Scheduled tasks
Vapor's scheduler runs via EventBridge Rule → Lambda. Each invocation logs to CloudWatch. For structured tracking:
app/Console/Kernel.php
$schedule->command('reports:send')
->daily()
->onSuccess(fn() => /* push metric */)
->onFailure(fn() => /* push metric + alert */);Vapor-compatible APM options
- Laravel Nightwatch Cloud — first-party Laravel APM, designed with Vapor as a first-class target
- Sentry — HTTP-based SDK, Lambda-safe. Tracks errors + performance spans
- AppSignal — also HTTP-based, Lambda-safe
- Datadog APM — Lambda Extension handles the agent-process problem
NightOwl currently assumes a persistent agent process and doesn't fit Lambda. If you're committed to Vapor, pick from the options above.