在前端服務中如果要取得數據資料,勢必需要向後端服務發起 HTTP 請求,在 Grafana Scenes 中也是相同道理,而取得的資料即為 Datasource 的資料。在第三章中有說到,Datasource 的資料如果要提供給 Panel 使用需要透過 Query 和 Transform 的處理,然而在 Scenes 中不會讓開發者直接用 fetch 等 action 向 Grafana 後端請求,而是封裝了一些工具,讓開發者只需要設定相關的參數即可取得資料,這不僅更簡化了開發流程,也讓開發者可以更專注於數據的呈現和分析,而不必過多關注底層的資料獲取細節。
在 Scenes 中的 Scene Object 基本狀態有 $timeRange、$data、$variables 和 $behaviors,要讓 Scene Panel 取得資料可以依靠 $timeRange 和 $data 的設定,並調用特定的元件,元件會自行向 Grafana 後端請求,請求後也不需要做回傳資料的 setter,因為 Panel 或 Scene Object 會抓取本身的 $data 或是父層、祖先層的 $data 資料作為圖表呈現。而可以使用的元件有 $timeRange 的 SceneTimeRange 和 $data 的 SceneQueryRunner,以下逐一介紹:
const scene = new EmbeddedScene({
$data: ...,
$timeRange: new SceneTimeRange({ from: 'now-5m', to: 'now' }),
body: ...,
controls:[new SceneTimePicker({ isOnCanvas: true })]
})
Scene Object 中的 $timeRange 是管理所取資料時間範圍的屬性,而 SceneTimeRange 則是實現 $timeRange 功能的元件。還記得 Grafana 最初是將 time series 的資料作為視覺化工具,所以時間對於 Panel 而言是非常重要的設定。因此在介紹 SceneTimeRange 之前我們需要先了解在 Grafana 中 $timeRange 的資料格式。
$timeRange 接收的類型為 SceneTimeRangeLike,除了一些功能性的回調函數,最重要的是繼承了 SceneTimeRangeState 的類型,此類型也就是 timeRange 的格式,定義了時間範圍的具體屬性。其中包括了以下屬性:
from: 'now-5m', to: 'now'
,代表『從5分鐘前到現在的時間範圍』,因此每次資料查詢時範圍都會自動調整為最近的5分鐘。weekStart
會改變全域的日期區域設置,因此不支援同時有多個不同的 weekStart
值。了解了 $timeRange
的屬性後,我們同時也認識了 SceneTimeRange
可以設定的參數,並且元件回傳的值可以與 SceneQueryRunner
等 data 元件組合,重新進行資料查詢。
在 Dashboard 中,使用者也可以通過一些操作手動改變時間範圍或相關屬性。例如,在 controls
屬性中,可以設置 SceneTimePicker
元件。該元件是基於 @grafana/ui
的 TimeRangePicker
元件進行封裝,並在選擇或改變時間範圍時,調用 $timeRange
所提供的 onTimeRangeChange
、onTimeZoneChange
等回調函數來更新狀態。
Scene Object 中的 $data 則是代表了視覺化中所需的數據資料,為了管理和處理這些資料,Scenes 提供了一個關鍵元件:SceneQueryRunner 。
雖然取得資料後 Panel 可以自行應用這些數據,但我們可以粗淺了解一下 $data 的資料格式。除了相關的回調函數,$data 的屬性只有一個型別為 PanelData
的 data,顧名思義是為 Panel 所設計的格式。其中有三個重要的必有屬性 state、series 及 timeRange:
SceneQueryRunner 是負責執行查詢和獲取原始數據的元件。元件在得到參數的初始化除了會針對 timeRange 狀態的改變與否進行監聽,更重要的就是對 Grafana 後端做資料請求。最核心的功能是 runWithTimeRange 的函數,會先整理請求的參數後調用由 @grafana/runtime 提供的 API 工具 - getDataSourceSrv() 顯取得需要哪一種 DataSource API 實例,再使用 getRunRequest 取得專門請求的函數 - runRequest,最後依據相對應的 DataSource 及參數執行請求。
SceneQueryRunner 可以帶入的參數可以有 datasource、minInterval、maxDataPoints(限制回傳的最大資料點數量)、liveStreaming(是否啟用即時資料流)等功能,而最重要的參數是查詢參數 - queries,但每一種 Data source 都有自己的特定查詢語法,所以下方只以測試資料為範例。
而 datasource 屬性是告訴 SceneQueryRunner 以何種資料類型做查詢,可以傳入兩個參數:uid 和 type。
uid : 指定特定的資料源實例,可以在 Home > Connections > Data sources > 查詢的來源 中的 Name 取得。
type:該 Data source 所表示的類型,例如 testdata、prometheus、loki 等等。
queries 屬性會依據不同的 datasource 有不同的設定,但可以注意的是 queries 是一個陣列,所以可以針對第一層的 datasource 設定多種不同的 query 語法;同時也可以在同一個 Panel 中使用不同的 datasource 比較來自不同來源的數據或是複合查詢,Grafana 會分別處理每個查詢,再於前端將結果組合在一起。
範例一 - 同一 datasource 設定多種 query:
const multipleQueryRunner = new SceneQueryRunner({
datasource: {
uid: "gdev-testdata",
type: "testdata",
},
queries: [
{
refId: "A",
scenarioId: "random_walk",
seriesCount: 5,
alias: "__server_names",
min: 30,
max: 60,
},
{
refId: "B",
scenarioId: "random_walk",
seriesCount: 5,
alias: "__house_locations",
min: 30,
max: 60,
},
],
maxDataPoints: 100,
});
範例二 - 設定多種 datasource 的 query:
const multipleDsQueryRunner = new SceneQueryRunner({
queries: [
{
refId: "A",
datasource: {
type: "prometheus",
uid: "P1234",
},
expr: 'sum(rate(http_requests_total{job="api-server"}[5m]))',
// 其他 Prometheus 特定的查詢參數...
},
{
refId: "B",
datasource: {
type: "mysql",
uid: "M5678",
},
rawSql: "SELECT * FROM users WHERE created_at > NOW() - INTERVAL 1 DAY",
// 其他 MySQL 特定的查詢參數...
},
],
maxDataPoints: 100,
});
💡NOTICE
queries 中皆會有一個 refId 的屬性,作為 query 的唯一識別值,通常是字母(A, B, C...)可以作為 Panel 中引用特定 query 的結果,也可以依據這個屬性來做結果的後續處理,例如下方範例。另外在 Explore 頁面中每種 query 上方也會顯示 refId 方便使用者辨識。
{
refId: "C",
expression: "$A + $B",
type: "math",
// ...
}
筆者語錄
透過本文的介紹,我們已經了解在 Grafana Scenes 中如何有效使用$timeRange
和$data
來管理和取得資料,並透過SceneTimeRange
和SceneQueryRunner
元件簡化了開發流程,也帶讀者們認識這請求元件背後所執行的過程。這兩個功能的結合不僅提升開發效率,讓開發者專注於資料的視覺化與分析,減少在底層資料取得上的重複工作。當然還會有許多不同的請求情境與需求,因此 Scenes 也提供其他更複雜的資料請求工具,將會在後續的進階功能中向各位介紹!