在上一篇文章中,我們了前端監控與可觀測性的重要性,並介紹了可觀測性的三個要素 Trace、Metric 和 Logs。延續了 OpenTelemetry 的觀念,這篇文章要深入探討 Grafana Faro,是一個 Grafana 專為前端應用程式設計的開源監控解決方案。因此接下來會對 Faro 的架構、提供的 instrumentation、實現原理、與 React 的整合進行深入的介紹,希望可以透過這篇文章讓各位讀者陷入 Faro 的魅力之中。
Grafana Faro 是一個專為前端應用程式可觀察性設計的專案,包含一個可高度設置的 Web SDK,用於實際使用者監控 (RUM)。而 Faro SDK 可以幫助開發者在瀏覽器前端應用程式中植入工具,以捕捉各種可觀測性的訊號。前端的遙測數據可以與後端和基礎設施數據相關聯,實現無縫的全端可觀察性。
以上是官方文件對於 Grafana Faro 的介紹。在上一篇文章中所提及可觀測性工具的功能,在 Faro 中都可以幫我們實現。在 2022 年時,Grafana 開啟了 Faro 這個開源專案,同時作為一個 RUM 的工具,只需在 Web 應用程式中嵌入 SDK 的程式碼,即可收集各種使用者遙測數據。Faro SDK 是基於 OpenTelemetry 的 API 設計,因此收集的資料可以透過 Grafana 提供的 Collector Agent 無痛傳送至後端服務 —— Grafana Labs LGTM 堆疊,最終在 Grafana 的 Dashboard 上將數據進行視覺化呈現。基於以上的內容整理出 Faro 的幾個特點:
想像一下,在 Faro 中取得的資料需要經過一些處理,才能夠在 Grafana 中顯示。然而這一切的流程都可以透過 Grafana 的內部運作進行處理,比對上圖可以了解資料的流向:
💡TIP:
OpenTelemetry Protocol 是一種開放標準的遙測數據傳輸協議,他定義了遙測數據來源、接收器與遙測後端之間的數據 encoding、傳輸與發送機制。因此 Alloy 所收集的數據也可以傳送到其他符合 OpenTelemetry Protocol 的服務中,例如說 Jaeger、Prometheus 等。
Faro 是藉由在需監控的網頁中嵌入 SDK 的方式來收集遙測數據,這樣的行為稱為 Instrumentation。而截至 2024 年 9 月,在 Faro 中提供了以下幾種 Instrumentation :
在前端開發時,經常會使用 console.log
的方式來 debug,但這樣的行為基本上只能在開發環境中使用,正式上線後瀏覽器中可能會造成效能、敏感資訊洩漏、開發者工具混亂等問題。使用 Faro 的 console instrumentation 可以代替瀏覽器的控制台,例如調用 console.error
的行為,Faro 會將這些數據作為 log 收集。因此可以協助開發者在確認錯誤上下文、捕捉應用程式或第三方套件所發出的訊息。
💡NOTICE:
由於 console log 非常實用於錯誤排查,建議保持此功能啟用。不過,應謹慎啟用所有 log 等級,因為這會產生大量數據並增加成本。預設情況下,console.debug、console.trace 和 console.log 是停用的,僅在需要時再啟用。
應用程式在運行時,難免會遇到未處理的錯誤,這些錯誤通常是透過 try/catch
捕捉不到的,因此開發者不會即時察覺到問題,而使用者也不一定會回報。使用 Faro 會訂閱 window.onerror 和 onunhandledrejection 事件,自動收集錯誤並提取追蹤紀錄,最後使用 faro.api.pushError()
將錯誤回報至 Grafana Faro Web SDK。
💡NOTICE:
如果在 try/catch 中捕捉到的錯誤,Faro 不會再次捕捉,因此需要開發者自行將錯誤推送到 Faro 中。
const buggyFn = () => {
throw new Error("Buggy function");
};
try {
buggyFn();
} catch (err) {
// Re-throw the error so it can be caught by the instrumentation
throw err;
// Alternatively, report it manually
faro.api.pushError(err);
}
在 20、21 天的文章中,我們有深入了解過 Web Vitals 的指標,而 Web Vitals instrumentation 可以幫助我們收集這些指標的數據,並在 Grafana 的 Dashboard 上進行視覺化呈現。他所使用的測量方式是 web-vitals.js 套件,包括 CLS、FCP、FID、LCP、INP、TTFB 等。數據收集後再調用 faro 提拱的 api pushMeasurement
註冊為 Metrics 後,將數據推送到 Grafana Loki 中。
所謂的 user session 指的是特定的使用者在網頁上操作從開始到結束或 session 過期的生命週期,而 session tracking instrumentation 可以收集單一 session 期間發生的錯誤、Logs 和事件,並將他們關聯起來。
Faro 會在使用者造訪網頁時自動建立新的 session,或根據追蹤模式選擇使用者上一次的 session。在 Faro 中最長的 session 持續時間可以為 4 小時,然而預設為 45 分鐘;另外當非活躍時間達 15 分鐘後,session 會過期。而一旦過期後 Faro 會自動建立一個新的 session,並更新其中的 metadata,內容會包含新的 session ID 和舊的 session ID。
另外 session 檢查的機制是透過 onSessionChange
方法,會將新與舊的 session meta(oldSession and newSession)作為參數傳入,檢查有效性,如果 oldSession meta 是 null 則被丟棄。另外,會將 x-faro-session-id
的 header 加到每個 HTTP 請求中,作為後段追蹤 session 的依據。
Faro 提供兩種 session 追蹤模式,並使用 persistent
屬性來設定:
在大流量的網站中,如果每個 session 都進行追蹤,會產生大量的數據,可能會造成應用程式的效能或成本問題,因此 Faro 提供了取樣率的功能,可以控制數據的收集量,並基於效能、統計學的有效性、成本和使用者影響的考量,選擇合適的取樣率。
而有被 Faro 取樣的 session 才會被收集並傳送到後端服務,未被取樣的 session 數據會被捨棄。在 Faro 中,取樣率可以透過 samplingRate
屬性來設定,數值為 0~1,預設為 1,也就是所有 session 都會被取樣。而選擇取樣的時機在於:
setSession(...)
時。如果在前端應用程式中設定取樣率,而後端服務中也自行設定取樣率,會讓資料變得很雜碎或是分析結果偏差,甚至是追蹤困難,所以為了保持前後端資料的一致性,Faro 建議在後端服務中使用 parent based sampling 的取樣策略,而前端進行追蹤時會告知底層追蹤系統取樣結果,並設定 W3C 的 sampled
標誌來通知後續工具記錄 span。若後端使用 OpenTelemetry 進行 Instrumentation,則建議設置 parent-based
,以保持前後端資料的一致性。
💡TIP:
Parent-based sampling 是在分散式追蹤系統中,使用父 span 的取樣決策來決定子 span 的取樣決策,這樣可以保持前後端資料甚至整個請求鍊的一致性。
View tracking instrumentation 的核心作用是將 view meta 的變化作為事件進行回報,使得開發者能夠精確地追蹤應用程式中每個 view 的變更時刻。這一功能主要解決了 SPA 在切換路由時不會觸發頁面重新載入的問題,確保即使在無刷新的情況下也能捕捉到 view 的變化。
而 View instrumentation 深入了解使用者在不同 view 中的行為和可能遇到的問題,並與 Logs 和其他事件進行關聯分析,從而提供更全面的使用者體驗洞察,適合於 RUM 資料的收集與分析。
Faro 提供了靈活的 API,調用 setView
方法為不同的頁面或組件定自定義的 view。例如:
是基於 Web 的 Performance API 實現的,會針對 PerformanceNavigationTiming
和 PerformanceResourceTiming
進行監控,當頁面進行導覽(頁面加載或選染)或資源載入(如圖片、JavaScript、CSS 等)時,會自動收集相關效能數據。
在調用 Web API 後會再進行一系列的計算或加強後以 faro.performance.navigation 和 faro.performance.resource 的事件回報,而每個事件都會有建立唯一的 ID:faroResourceId 和 faroNavigationId,用以將資源與導覽事件關聯起來,才能在 session 中排列順序。
以下是關於兩個 API 分別會收集的數據:
上述的幾個 Instrumentation 都是屬於 logs 或 metrics 的數據,分類於 Web Instrumentation 中,而 tracing instrumentation 是屬於 trace 的數據,主要收集使用者每次與網頁互動的資訊,而為了將前端的追蹤與 API 的追蹤串聯起來,會依賴追蹤 propagator 的機制,預設使用 W3CTraceContextPropagator,將 traceparent
的 HTTP 的 header 添加到所有 API 使用的 fetch 請求中。而預設情況下,Tracing 使用以下 OpenTelemetry 工具:
NOTICE:
由於 OpenTelemetry 的關係,traceparent 只會發送至與當前視窗相同來源的請求中。
最後再由 faro.api.pushTraces()
函數將數據推送到 Tempo 中,預設包含的 Tracing instrumentation 有:
若有一個前端會呼叫 API 並將數據儲存在資料庫中的應用程式,可以利用 Tracing instrumentation 來:
Grafana 專案的前端本身是以 React 為基礎,因此 Grafana Faro 提供了與 React 的高度整合,其中為此開發了 faro-react 的套件,簡化整合流程,並提供以下功能::
💡NOTICE:
使用 profiler 可能會影響應用程式的效能,因此不建議在正式環境中使用。
在 Grafana Faro 出世之前已經有其他相對成熟的前端監控 SaaS 服務(如 New Relic, Sentry 等),但比起其他前端監控服務,Grafana Faro 有以下特點:
筆者語錄:
總和以上的介紹,Grafana Faro 為前端開發者提供了一個強大、靈活且經濟實惠的監控解決方案。雖然功能尚未非常完善,但依據目前所提供的功能已經可以滿足大部分的監控需求。再加上 Grafana 的生態系統,可以與其他工具如 Loki、Tempo 等整合,提供完整的開源可觀察性解決方案。另外,以其開源的特性,未來的發展性非常高,值得持續關注。
https://grafana.com/docs/grafana-cloud/monitor-applications/frontend-observability/
https://blog.mayflower.de/15107-grafana-faro-frontend-observability.html