# 如何將 Laravel Octane HTTP 類型 Metrics 整合到 RoadRunner Metrics ###### tags: `Laravel`,`PHP`,`RoadRunner`,`Octane` RoadRunner 本身就有提供一些基本的 Metrics 供 Prometheus 之類的監控工具監控,例如:`rr_http_workers_ready`、`rr_http_workers_working`,RoadRunner 可以透過簡單的 `.rr.yaml` 設定端口輸出這些 Metrics 數據,供 Prometheus 抓取。 ```yaml metrics: address: 0.0.0.0:2112 # Prometheus metrics 端口 ``` 重啟 Server 後開啟 http://localhost:2112/metrics 會出現類似下面的畫面,RoadRunner 提供很多基本 Metrics 數據。 ![截圖 2025-10-22 下午3.26.40](https://hackmd.io/_uploads/ryHvvWU0ex.png) 實務上系統常需要監控 Reqeust 數量跟執行時間等等跟 HTTP Reqeust 相關的數據,RoadRunner 雖然有提供 [HTTP Metrics](https://docs.roadrunner.dev/docs/logging-and-observability/metrics#http-metrics) Middleware,可以監控 request 數量跟執行時間等等資訊。 但是如果使用 Laravel Octane 搭配 RoadRunner,RoadRunner 不會參與實際處理 HTTP Reqeust,而是把 Reqeust 轉交由 Laravel Octane 自己的 PHP 進程處理。由於跳過 RoadRunner HTTP Metrics Middleware,所以即使引用了 Middleware,Metrics 頁面並不會出現 `rr_http_request_total`、`rr_http_request_duration_seconds` 等數據。 那 Laravel Octane 要如何處理 HTTP Reqeust Metrics 呢?這有兩種做法: 1. 自行做統計,並另外新增 Metrics Port 和 Path(EX: http://localhost:80/metrics),輸出這些統計資料。 2. 透過 RoadRunner Metrics Plugin,當 Laravel App 層處理 HTTP Reqeust 時,經過 RPC 觸發 RoadRunner Application Metrics,這樣就可以在原本的 http://localhost:2112/metrics 頁面呈現客製化的 Metrics 數據。 接下來要介紹一下第二種做法 ## RoadRunner Application Metrics 如果希望沿用原本 RoadRunner Metrics 頁面(http://localhost:2112/metrics),那就要透過 RoadRunner Metrics Plugin 處理 Metrics 數據: ```mermaid graph LR A(Laravel 端) --> |RPC| B(RoadRunner Application Metrics) ``` ### RoadRunner 設定 首先在 RoadRunner `.rr.yaml` 的 `metrics.collect` 下設定客製化的 Metrics ```yaml metrics: address: 0.0.0.0:2112 # Prometheus Metrics 端口 collect: api_requests_total: type: counter help: "Total number of HTTP requests." labels: ["method", "path"] api_request_failures_total: type: counter help: "Total number of failed HTTP requests (non-2xx responses)." labels: ["method", "path"] api_request_duration_seconds: type: histogram help: "Request latency in seconds." labels: ["method", "path"] # 根據您的需求調整 buckets buckets: [0.1, 0.3, 0.5, 1, 2] ``` 以上例子新增三種客製化的 Application Metrics(`api_requests_total`、`api_request_failures_total`、`api_request_duration_seconds`),顧名思義就是 HTTP Requests 數目、非 200 Http Status Code Requests 數目 跟 API Request 執行時間。 - type:種類有四種:gauge、counter、summary、histogram,差異請參考 ChatGPT 整理表格 ![截圖 2025-10-22 下午4.17.50](https://hackmd.io/_uploads/S1iU7MURlx.png) 以上例子因為是作 Requests 數量統計跟執行時間(duration)分佈,所以使用 `counter` & `histogram` 兩種 Type - buckets:`histogram` Type 需設定的執行時間分佈區間,設定為 0.1s、0.3s、0.5s、1s、2s,假設有個 Request 執行 0.8s,0.1s、0.3s、0.5s 這三個 buckets 會 +1,如果 0.05s,那就沒有 buckets 會累計了,以此類推。 - labels:可以增加額外的 Metadata,適合拿來做分類統計或過濾,以上例子採用 HTTP Method & Request Path 做分類,也就是 Requests 數量統計跟執行時間(duration)分佈會依照不同 HTTP Method & Request Path 做分類。 ### Laravel 監聽事件 設定好 RoadRunner Application Metrics 後,接著要在 Laravel 端觸發 Application Metrics,這邊使用到一個套件 [spiral/roadrunner-metrics](https://github.com/roadrunner-php/metrics),它是一個 PHP 與 RoadRunner Metrics Plugin 介接的橋樑,通過這橋樑提供 RoadRunner Metrics 資料,例如某個 Metrics 統計數量加 1 / 減 1 等等。 - 在 App\Providers 的 AppServiceProvider 註冊 Metrics 實例 ```php $this->app->singleton(MetricsInterface::class, function () { // 從設定檔讀取 RPC 位址 $rpcAddress = config('octane.rpc'); // 透過 RPC 連線建立 RoadRunner Metrics Client 端 return new Metrics( RPC::create($rpcAddress) ); }); ``` - 在 App\Listeners 下新增 OctaneMetricsReporter 監聽物件,有三種 Metrics(`api_requests_total`、`api_request_failures_total`、`api_request_duration_seconds`)要觸發 ```php <?php namespace App\Listeners; use Spiral\RoadRunner\Metrics\MetricsInterface; class OctaneMetricsReporter { protected MetricsInterface $metrics; public function __construct(MetricsInterface $metrics) { $this->metrics = $metrics; } public function handle($event) { // 如果沒有 Response 物件,則直接返回 if (!$event->response) { return; } $method = $event->request->getMethod(); // 符合 Route 設定回傳 Route URI,不符合則一率為 unmatched $path = optional($event->request->route())->uri() ?? 'unmatched'; $labels = [$method, $path]; // 每次請求,將 api_requests_total 計數器加 1 $this->metrics->add('api_requests_total', 1, $labels); // 如果不是 2xx,則累加 api_request_failures_total $statusCode = $event->response->getStatusCode(); if ($statusCode < 200 || $statusCode >= 300) { $this->metrics->add('api_request_failures_total', 1, $labels); } // 計算請求執行期間並記錄 api_request_duration_seconds $startTime = $event->request->server('REQUEST_TIME_FLOAT'); if ($startTime) { $latencyInSeconds = (microtime(true) - $startTime); $this->metrics->observe('api_request_duration_seconds', $latencyInSeconds, $labels); } } } ``` - 最後在 config 的 octane.php 新增 RoadRunner RPC Endpoint(預設是 `tcp://127.0.0.1:6001`)及在 RequestTerminated 階段設定監聽事件 ```php return [ ... 'listeners' => [ ... RequestTerminated::class => [ // FlushUploadedFiles::class, App\Listeners\OctaneMetricsReporter::class, ], ], ... 'rpc' => env('ROADRUNNER_RPC', 'tcp://127.0.0.1:6001'), ] ``` 完成上述設定後,重啟 Laravel Octane Server,再呼叫一些 api,就能看到剛剛設定客製化 Metrics 了 ![截圖 2025-10-22 下午4.52.23](https://hackmd.io/_uploads/rJvJTzIRex.png)