Mengkonfigurasi plugin logs RoadRunner dengan format dan level, menulis structured logs terpadu antara server Go dan worker PHP, memakai PSR-3 logger di worker, dan mengekspor observability ke OpenTelemetry atau file logs.

Setelah di episode 8 kita menyusun middleware, pada episode kali ini kita memastikan semua yang terjadi bisa diamati: logging dan observability. Di aplikasi long-running, kesalahan tidak datang sebagai satu request yang gagal — melainkan sebagai pola lambat yang tersebar di ribuan request yang dilayani banyak worker. Tanpa log dan telemetry yang baik, kalian buta.
Mengapa episode ini penting? Karena RoadRunner punya dua dunia yang harus dicatat: server Go (apa yang dilakukan server, restart worker, error pool) dan worker PHP (apa yang dilakukan aplikasi). Menyatukan keduanya dalam format log yang sama adalah kunci debugging lintas lapisan.
logs RoadRunnerRoadRunner memiliki plugin logging bawaan yang menangkap log dari server Go dan plugin-pluginnya. Konfigurasinya:
logs:
mode: production
level: info
encoding: json
output: stdout
err_output: stderr
channels:
server:
mode: production
level: info
encoding: json
http:
mode: production
level: debug
encoding: json| Key | Fungsi |
|---|---|
mode | production (JSON) atau development (human-readable) |
level | debug, info, warn, error, dpanic, panic, fatal |
encoding | json, console, atau zap |
output / err_output | Tujuan log normal dan error (stdout/stderr/file) |
channels | Override per-plugin (misal debug lebih detail untuk http) |
Untuk menulis ke file:
logs:
mode: production
level: info
encoding: json
output: /var/log/rr/server.log
err_output: /var/log/rr/server.err.logLog aplikasi PHP ditangani terpisah — memakai logger PSR-3 (Monolog). Kuncinya: format log PHP sebaiknya sejalan dengan format log Go agar bisa di-agregasi (misal ke Loki/ELK). Contoh worker dengan Monolog:
<?php
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\Formatter\JsonFormatter;
use Spiral\RoadRunner\Http\PSR7Worker;
use Spiral\RoadRunner\Worker;
require __DIR__ . '/vendor/autoload.php';
$log = new Logger('app');
$handler = new StreamHandler('php://stderr');
$handler->setFormatter(new JsonFormatter());
$log->pushHandler($handler);
$psr7 = new PSR7Worker(Worker::create(), $psr17, $psr17, $psr17);
while ($request = $psr7->waitRequest()) {
$start = microtime(true);
try {
// ... proses request ...
$log->info('request.ok', [
'method' => $request->getMethod(),
'path' => $request->getUri()->getPath(),
'duration' => round(microtime(true) - $start, 4),
]);
$psr7->respond($response);
} catch (\Throwable $e) {
$log->error('request.failed', [
'exception' => $e::class,
'message' => $e->getMessage(),
]);
$psr7->getWorker()->error((string) $e);
}
}Poin penting: log ke stderr — RoadRunner menyalurkan stderr worker ke log-nya sendiri dengan konteks worker, sehingga log aplikasi muncul menyatu dengan log server. Dan selalu sertakan konteks terstruktur (method, path, durasi, request id) — bukan string bebas.
Agar bisa menelusuri satu request lintas lapisan, buat request ID di middleware dan bawa ke seluruh log:
http:
middleware: ["requestid", "gzip"]
requestid:
header: X-Request-IdPlugin requestid (atau middleware kustom PHP) memberi tiap request ID unik; worker menambahkan ID ini ke semua log context. Dengan begitu kalian bisa grep "req-abc123" dan melihat perjalanan lengkap request — dari log server Go sampai log aplikasi.
| Mode | Keuntungan | Kerugian |
|---|---|---|
production (JSON) | Mudah di-parse tool (Loki, ELK, CloudWatch), konteks terstruktur | Sulit dibaca manusia langsung |
development (console) | Nyaman di terminal saat debugging | Tidak ideal untuk agregasi |
Gunakan development di lokal, production di staging/production. Kalian bisa memilih per-channel, jadi plugin tertentu boleh lebih verbose.
Untuk observability penuh, RoadRunner mendukung ekspor telemetry ke OpenTelemetry:
otel:
address: 127.0.0.1:4318
service_name: roadrunner-app
insecure: trueDengan otel aktif, server Go mengirim trace dan metrics ke OpenTelemetry Collector. Di sisi PHP, kalian memakai SDK OpenTelemetry PHP untuk instrumentasi aplikasi — span dari PHP dan span dari Go terhubung via konteks yang disebar antar lapisan. Ini pola observability yang sama dipakai bersama plugin metrics Prometheus (episode 12).
Tip
Mulai dari yang sederhana: pastikan JSON logs server + worker menyatu, lalu tambahkan request ID. OpenTelemetry adalah peningkatan berikutnya setelah pola dasar ini stabil — jangan langsung pasang semua sekaligus sebelum kalian nyaman membaca log.
Pada episode 9 ini, kalian telah membangun fondasi observability.
Inti yang harus dibawa pulang:
logs mengatur log server Go: mode, level, encoding, output, channel.production JSON untuk produksi, development untuk lokal.otel plugin) untuk trace dan metrics penuh.Di episode 10 selanjutnya, kita masuk ke data: KV plugin dengan driver Redis, Memory, dan File — menyimpan cache dan session, memakai TTL, dan memilih driver yang tepat untuk kebutuhan. Sampai jumpa di episode 10!