事件 schema 定義了每一筆監控事件的資料結構。統一的 schema 讓 SDK、collector、查詢工具使用同一個資料契約 — SDK 知道該送什麼欄位,collector 知道該驗證什麼,查詢工具知道該讀什麼。

核心欄位

type(必填)

事件類型。對應四類事件分類(模組一):eventerrormetriclifecycle

Collector 用 type 決定事件的處理路徑 — error 類型觸發告警規則,metric 類型進入數值聚合,event 類型進入行為分析。

name(必填)

事件名稱。使用 namespace.action 格式(事件命名規範)。例如 terminal.connect.doneauth.biometric.failed

name 是查詢和統計的主要索引。grep "terminal.connect" 找到所有連線事件;按 name 分群計數得到功能使用頻率。

timestamp(必填)

事件發生的時間。ISO 8601 格式,包含時區偏移。2026-06-19T14:30:00.123+08:00

Timestamp 由 SDK 在事件發生時記錄,不是 collector 收到時記錄。兩者可能有延遲(離線 buffer、網路延遲),以 SDK 端的時間為準。

source(必填)

事件來源的識別資訊。包含產生事件的 SDK、app 名稱、版本、平台、OS 版本。

1{
2  "source": {
3    "sdk": "flutter",
4    "app": "app_tunnel",
5    "version": "1.2.0",
6    "platform": "ios",
7    "os": "17.4"
8  }
9}

sdk 標明產生事件的 SDK 種類(js / flutter / python / go)。同一個平台可能有不同的 SDK——iOS 上可能是 Flutter SDK 或未來的 Swift 原生 SDK——sdk 欄位讓 collector 區分事件來自哪個 SDK 實作,platform 無法替代這個識別。sdkplatform 為必填,appversionos 為選填。

Source 讓同一個 collector 接收多個 app 的事件時可以區分來源。也用於分析「哪個版本的 error 率最高」、「哪個 OS 版本有特定問題」。

platform 合法值與自動偵測

platform 由 SDK init 時自動偵測,開發者不需手動設定。各 SDK 的偵測來源和映射規則:

SDK偵測來源映射規則
Pythonsys.platformdarwinmacoslinuxlinuxwin32windows、其他直接傳原值
FlutterPlatform.operatingSystem回傳值(ios/android/macos/linux/windows)即合法值,無需映射
JS瀏覽器環境固定為 web;OS 偵測(如需要)從 navigator.userAgentData 解析
Goruntime.GOOSdarwinmacoslinuxlinuxwindowswindows、映射邏輯同 Python

以上映射是 SDK init 時的預設自動偵測行為。Python 和 Go 的 runtime 回傳系統內部名稱(darwinwin32),SDK 負責映射到 schema 定義的標準名稱。Flutter 的 dart:io Platform.operatingSystem 恰好回傳合法值。JS SDK 在瀏覽器環境中無法可靠偵測 OS,platform 統一為 web

自動偵測之外,SDK 也接受手動覆蓋 platform 值。短生命週期的命令列腳本(如 CI pipeline step、pre-commit hook)可手動將 platform 設為 script,表示非互動式 OS session——這類場景中 OS 名稱不是有意義的區分維度,script 讓查詢時能篩選出所有腳本來源的事件。

SDK 不做映射的話,collector 會收到不一致的 platform 值——同是 macOS 的事件有些標 darwin 有些標 macos,查詢篩選會漏事件。各平台 SDK 的執行環境適配細節見模組五:平台適配

session(選填)

使用者 session 的識別資訊。Session ID(UUID)和 session 開始時間。

Session 用於關聯同一次使用中的多個事件。「使用者在這次 session 中做了什麼操作、遇到了什麼 error」的分析依賴 session ID。

去識別化要求:session ID 用 UUID 而非使用者帳號,不包含個人識別資訊(模組七)。

data(選填)

事件的附加資料。自由結構的 JSON object,內容依事件類型和名稱而定。

1{
2  "data": {
3    "url": "wss://192.168.1.100:7681/ws",
4    "duration_ms": 320,
5    "step": "3/5"
6  }
7}

Data 欄位是 schema 中唯一的自由結構區域。核心欄位(type、name、timestamp、source)有固定格式,data 的內容由事件定義者決定。

v(必填)

Schema 版本號。整數,從 1 開始遞增。

版本號讓 collector 知道用哪個版本的 schema 驗證這筆事件。Schema 演進時,舊版本的事件仍可被正確處理。

Collector 附加欄位(底線前綴)

Collector 在事件寫入 storage 時可以附加系統層的 metadata。這些欄位使用底線前綴(_flags_fingerprint),和 SDK 端產生的業務欄位區隔。SDK 送出的事件中不包含這些欄位 — 它們由 collector pipeline 在處理過程中計算並附加。

_flags(選填,collector 附加)

Collector 端的行為分析或規則引擎偵測到異常時,在事件中附加標記。Dashboard 查詢可用 _flags 過濾可疑事件。

1{
2  "_flags": {
3    "suspicious": true,
4    "reason": "rate_anomaly"
5  }
6}

suspicious 標記的事件不被刪除 — 直接丟棄有誤殺正常流量的風險(行銷活動的真實流量暴增可能觸發異常偵測)。Dashboard 預設排除 _flags.suspicious = true 的事件,需要調查時可包含。

標記來源和 reason 值的定義見 Client-side SDK 認證 的事後標記策略段。

_fingerprint(選填,collector 附加)

Error 事件的去重識別碼。Collector 從 error 的 type、normalized message、stack trace 計算 hash,用於把相同根因的 error 歸組。

1{
2  "_fingerprint": "a3f8c2e1b7d94f06"
3}

Fingerprint 的計算邏輯和 error grouping 機制見 Error Fingerprint 與去重分群

SDK 自監控指標

監控系統自身的資料完整性需要獨立的指標追蹤 — SDK 用 metric 類事件回報自己的送出量和丟棄量,collector 用 endpoint 暴露處理量和拒絕量。SDK 端的指標每次 flush 成功後作為標準 schema 事件一起送出,name 以 sdk. 前綴標識。

name含義
sdk.events.produced事件產生總數(取樣前)
sdk.events.sampled取樣後保留的事件數
sdk.events.sent成功送出的事件數(收到 200/207 的 accepted)
sdk.events.dropped被 FIFO 丟棄或重試耗盡的事件數
sdk.flush.failuresflush 失敗次數(429 / 5xx / timeout)
sdk.sampling.rate當前動態取樣率

Collector 端對應暴露 collector.events.receivedcollector.events.rejectedcollector.events.storedcollector.events.backpressure 等指標,透過 /metrics endpoint 或 health endpoint 的擴展欄位提供。

完整的指標定義、端到端比對方法和損失率閾值見 端到端資料完整性 的監控損失段。

完整 schema 範例

 1{
 2  "v": 1,
 3  "type": "error",
 4  "name": "terminal.connect.failed",
 5  "timestamp": "2026-06-19T14:30:00.123+08:00",
 6  "source": {
 7    "sdk": "flutter",
 8    "app": "app_tunnel",
 9    "version": "1.2.0",
10    "platform": "ios",
11    "os": "17.4"
12  },
13  "session": {
14    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
15    "started": "2026-06-19T14:25:00.000+08:00"
16  },
17  "data": {
18    "step": "ws_connect",
19    "error": "Connection refused",
20    "url": "wss://192.168.1.100:7681/ws"
21  }
22}

下一步路由