Belajar Swoole - Monitoring, Logging & Debugging
Episode 19 of 26

Belajar Swoole - Monitoring, Logging & Debugging

Mengamati server Swoole dari luar: membaca stats dan status worker, event loop lag metrics, strategi logging yang benar, mode debugging dengan Xdebug di OpenSwoole, serta export metrik ke Prometheus dan OpenTelemetry.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 18 kita mengamankan lalu lintas dengan TLS — pada episode kali ini kita belajar mengamati. Server yang tidak terpantau adalah bom waktu: memory naik perlahan, koneksi membengkak, event loop mulai lambat — semua terjadi diam-diam sampai user yang komplain.

Mengapa episode ini penting? Karena Swoole adalah server long-running — ia bisa hidup berminggu-minggu tanpa restart, dan justru di situlah bahayanya. Kebocoran memory atau loop yang melambat menumpuk seiring waktu. Monitoring bukan pemanis: ia adalah deteksi dini sebelum server kalian kolaps di jam sibuk.

Server Stats: stats() dan status

Swoole menyediakan data statistik internal langsung dari proses Master:

Membaca stats server
$server->on('Request', function ($req, $res) use ($server) {
    $stats = $server->stats();
    $res->header('Content-Type', 'application/json');
    $res->end(json_encode($stats));
});

Contoh isi stats():

KunciArti
start_timeWaktu server mulai
connection_numKoneksi aktif saat ini
accept_countTotal koneksi diterima
request_countTotal request diproses
tasking_numTask sedang antre/diproses
worker_request_countRequest per worker

Perhatikan perbedaan connection_num (koneksi yang sedang hidup) vs accept_count (total sejak start) — keduanya menandakan gejala berbeda saat naik.

Tip

Lapisi stats() dengan endpoint /stats (dilindungi auth/network internal saja) — jangan pernah expose mentah ke internet. Ini sekaligus menjadi fondasi endpoint /metrics Prometheus di bagian akhir episode ini.

Status Worker dan Event Loop

Memantau kesehatan worker — bukan hanya jumlahnya:

Status worker
$workerStatus = $server->getWorkerStatus(); // array status per worker
foreach ($workerStatus as $id => $status) {
    echo "Worker $id: $status\n";
}

Event loop metrics adalah pengukur paling jujur: berapa lama event loop macet. OpenSwoole 26.2 memperkenalkan event loop lag metrics — angka yang menunjukkan delay aktual siklus event loop. Bila lag melewati ratusan milidetik, ada pekerjaan blocking di worker. Di Swoole klasik, pendekatan manual: ukur selisih waktu antara tick timer:

Deteksi event loop lag manual
use Swoole\Timer;
 
Timer::tick(1000, function () {
    static $last = 0;
    $now = microtime(true);
    if ($last > 0) {
        $drift = $now - $last - 1.0; // harusnya ~0
        if ($drift > 0.2) {
            error_log("Event loop lambat: +{$drift}s");
        }
    }
    $last = $now;
});

Drift mendadak > 0.2s menandakan ada CPU-bound work di worker — saatnya pindah ke task worker (episode 11).

Logging yang Benar

Logging di Swoole punya satu aturan emas: jangan blokir. echo/fwrite ke stderr bisa memperlambat worker saat beban tinggi. Strategi berlapis:

Logging async via task worker
$server->on('Request', function ($req, $res) use ($server) {
    $server->task(['log' => ['ts' => time(), 'path' => $req->server['request_uri'] ?? '/']]);
    $res->end('ok');
});
 
$server->on('Task', function ($server, $taskId, $workerId, $data) {
    file_put_contents(
        '/var/log/app/access.log',
        json_encode($data['log']) . "\n",
        FILE_APPEND
    );
    return true;
});

Format log terstruktur (JSON) lebih baik daripada teks bebas — karena bisa diparsing log pipeline (Loki, ELK) secara otomatis. Untuk proyek besar, gunakan PSR-3 logger (monolog) dengan handler async.

Debugging: Xdebug di Coroutine

Tantangan klasik debugging Swoole: kode berjalan di dalam coroutine, dan Xdebug tradisional tidak suka dengan context switching. Situasinya membaik di 2026:

  • OpenSwoole 26.2 mendukung Xdebug step debugging di dalam coroutine — kalian bisa breakpoint langsung di handler coroutine.
  • Swoole klasik: step debugging masih terbatas; pendekatan yang dipakai adalah log + var_dump ke stderr, karena error selalu dicetak ke terminal server.

Pola debugging praktis yang jalan di keduanya:

Debug via log terstruktur
$server->on('Request', function ($req, $res) {
    try {
        $result = $someService->process($req->get);
    } catch (Throwable $e) {
        error_log(json_encode([
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString(),
            'coroutine' => Swoole\Coroutine::getCid(),
        ]));
        $res->status(500);
        $res->end('Error');
        return;
    }
    $res->end($result);
});

Swoole\Coroutine::getCid() memberi ID coroutine — berguna untuk mencocokkan baris log dengan coroutine tertentu saat ada ratusan request bersamaan.

Export ke Prometheus / OpenTelemetry

Pola standar: Swoole menyediakan data, kita format menjadi metrik, lalu exporter menariknya.

Prometheus: Endpoint /metrics

Endpoint /metrics Prometheus
$server->on('Request', function ($req, $res) use ($server) {
    if (($req->server['request_uri'] ?? '/') !== '/metrics') {
        $res->end('ok');
        return;
    }
 
    $s = $server->stats();
    $body = "# HELP swoole_connections Koneksi aktif\n";
    $body .= "# TYPE swoole_connections gauge\n";
    $body .= "swoole_connections {$s['connection_num']}\n";
    $body .= "swoole_total_requests {$s['request_count']}\n";
    $body .= "swoole_tasking {$s['tasking_num']}\n";
 
    $res->header('Content-Type', 'text/plain; version=0.0.4');
    $res->end($body);
});

Lalu target Prometheus scrape_configs menunjuk ke endpoint ini.

OpenTelemetry

Untuk tracing distribusi, gunakan SDK OpenTelemetry PHP:

Instrumentasi OTel
use OpenTelemetry\API\Trace\TracerProviderInterface;
 
$server->on('Request', function ($req, $res) use ($tracer) {
    $span = $tracer->spanBuilder('http.request')->startSpan();
    try {
        $res->end(handle($req));
    } finally {
        $span->end();
    }
});

Tracing memberi kalian gambaran lintas service — request dari client → Swoole → DB → service lain, satu timeline utuh. Sangat membantu saat microservices (episode 16) mulai banyak.

Common Pitfalls

MasalahPenyebabSolusi
Metrik tidak pernah berubahServer lain yang dilirik (bukan Swoole)Pastikan scrape ke port/endpoint yang benar
Log hilang saat crashFILE_APPEND tanpa buffer flushGunakan logger dengan buffer + sink (Loki/ELK)
Drift event loop besar di jam sibukCPU-heavy di workerPindahkan ke task worker / naikkan worker_num
Xdebug step tidak jalanSwoole klasik tidak mendukungPakai log, atau OpenSwoole 26.2

Penutup

Pada episode 19 ini, kalian telah belajar mengamati server Swoole.

Inti yang harus dibawa pulang:

  • $server->stats() memberi data koneksi, request, dan task — lapisi di endpoint /stats internal.
  • Event loop lag (OpenSwoole 26.2) / drift tick mengukur kesehatan sebenarnya worker.
  • Logging harus async dan terstruktur (JSON) — jangan blokir worker.
  • Xdebug step debugging didukung OpenSwoole 26.2; untuk Swoole klasik gunakan log.
  • Export /metrics ke Prometheus dan tracing via OpenTelemetry.

Di episode 20 selanjutnya, kita memeras performa: Performance Tuning & Benchmark — worker_num, max_request, dispatch_mode, kernel settings, dan perbandingan Swoole vs Nginx+PHP-FPM vs Go. Sampai jumpa di episode 20!

Belajar Swoole - Monitoring, Logging & Debugging | Belajar Swoole