Event Loop Lag Metrics

Latest version: pecl install openswoole-26.2.0 | composer require openswoole/core:26.2.0

Since: OpenSwoole v26.2.0

Description

OpenSwoole 26.2.0 introduces real-time event loop lag monitoring via $server->stats(). These metrics help you detect blocking operations that stall the event loop, such as synchronous file I/O, CPU-intensive computations, or unhookable blocking calls.

Available Metrics

MetricDescription
event_loop_lag_msCurrent event loop lag in milliseconds
event_loop_lag_max_msMaximum event loop lag observed since server start
event_loop_lag_avg_msAverage event loop lag

These metrics are available per:

  • Worker processes
  • Task workers (when coroutine-enabled)
  • Reactor threads (process mode)

Example: Monitoring Event Loop Lag

<?php
use OpenSwoole\Http\Server;
use OpenSwoole\Http\Request;
use OpenSwoole\Http\Response;

$server = new Server("0.0.0.0", 9501);

$server->set([
    'worker_num' => 4,
]);

$server->on("request", function (Request $request, Response $response) use ($server) {
    if ($request->server['request_uri'] === '/metrics') {
        $stats = $server->stats();

        $response->header('Content-Type', 'application/json');
        $response->end(json_encode([
            'event_loop_lag_ms' => $stats['event_loop_lag_ms'],
            'event_loop_lag_max_ms' => $stats['event_loop_lag_max_ms'],
            'event_loop_lag_avg_ms' => $stats['event_loop_lag_avg_ms'],
        ]));
        return;
    }

    $response->end("Hello World\n");
});

$server->start();

Example: Alerting on High Event Loop Lag

<?php
use OpenSwoole\Http\Server;
use OpenSwoole\Http\Request;
use OpenSwoole\Http\Response;
use OpenSwoole\Timer;

$server = new Server("0.0.0.0", 9501);

$server->set([
    'worker_num' => 4,
]);

$server->on("workerStart", function (Server $server, int $workerId) {
    // Check event loop lag every 5 seconds
    Timer::tick(5000, function () use ($server) {
        $stats = $server->stats();
        $lagMs = $stats['event_loop_lag_ms'] ?? 0;

        if ($lagMs > 100) {
            // Log a warning if event loop lag exceeds 100ms
            error_log(sprintf(
                "[WARNING] High event loop lag: %.2fms (max: %.2fms, avg: %.2fms) worker_id=%d",
                $lagMs,
                $stats['event_loop_lag_max_ms'],
                $stats['event_loop_lag_avg_ms'],
                $server->getWorkerId()
            ));
        }
    });
});

$server->on("request", function (Request $request, Response $response) {
    $response->end("Hello World\n");
});

$server->start();

Example: Prometheus / OpenMetrics Endpoint

<?php
use OpenSwoole\Http\Server;
use OpenSwoole\Http\Request;
use OpenSwoole\Http\Response;

$server = new Server("0.0.0.0", 9501);

$server->on("request", function (Request $request, Response $response) use ($server) {
    if ($request->server['request_uri'] === '/metrics') {
        $stats = $server->stats(\OpenSwoole\Constant::STATS_OPENMETRICS);
        $response->header('Content-Type', 'text/plain; version=0.0.4');
        $response->end($stats);
        return;
    }

    $response->end("Hello World\n");
});

$server->start();

The OpenMetrics output includes event loop lag metrics:

# TYPE openswoole_event_loop_lag_ms gauge
openswoole_event_loop_lag_ms 0.052
# TYPE openswoole_event_loop_lag_max_ms gauge
openswoole_event_loop_lag_max_ms 1.203
# TYPE openswoole_event_loop_lag_avg_ms gauge
openswoole_event_loop_lag_avg_ms 0.087

Notes

  • A healthy event loop should show lag under 10ms for most workloads
  • High event loop lag usually indicates blocking operations that should be moved to task workers or converted to async operations
  • Use hook_flags to ensure all I/O operations are non-blocking
  • Event loop lag metrics are reset when a worker process restarts
Last updated on February 28, 2026