<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Json-Schema on Tarragon</title><link>https://tarrragon.github.io/blog/tags/json-schema/</link><description>Recent content in Json-Schema on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/json-schema/index.xml" rel="self" type="application/rss+xml"/><item><title>event.schema.json 完整欄位解說</title><link>https://tarrragon.github.io/blog/monitoring/02-log-schema/event-schema-fields/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/02-log-schema/event-schema-fields/</guid><description>&lt;p>事件 schema 定義了每一筆監控事件的資料結構。統一的 schema 讓 SDK、collector、查詢工具使用同一個資料契約 — SDK 知道該送什麼欄位，collector 知道該驗證什麼，查詢工具知道該讀什麼。&lt;/p>
&lt;h2 id="核心欄位">核心欄位&lt;/h2>
&lt;h3 id="type必填">type（必填）&lt;/h3>
&lt;p>事件類型。對應四類事件分類（&lt;a href="https://tarrragon.github.io/blog/monitoring/01-mental-model/four-event-types/" data-link-title="四類事件的完整定義" data-link-desc="Event / Error / Metric / Lifecycle 四類事件各自的語意、觸發時機和典型用途 — 分類是監控體系的統一語言">模組一&lt;/a>）：&lt;code>event&lt;/code>、&lt;code>error&lt;/code>、&lt;code>metric&lt;/code>、&lt;code>lifecycle&lt;/code>。&lt;/p>
&lt;p>Collector 用 type 決定事件的處理路徑 — error 類型觸發告警規則，metric 類型進入數值聚合，event 類型進入行為分析。&lt;/p>
&lt;h3 id="name必填">name（必填）&lt;/h3>
&lt;p>事件名稱。使用 namespace.action 格式（&lt;a href="https://tarrragon.github.io/blog/monitoring/01-mental-model/event-naming-convention/" data-link-title="事件命名規範" data-link-desc="namespace.action 格式的事件命名、命名一致性的工程價值、和商業方案命名慣例的對應">事件命名規範&lt;/a>）。例如 &lt;code>terminal.connect.done&lt;/code>、&lt;code>auth.biometric.failed&lt;/code>。&lt;/p>
&lt;p>name 是查詢和統計的主要索引。&lt;code>grep &amp;quot;terminal.connect&amp;quot;&lt;/code> 找到所有連線事件；按 name 分群計數得到功能使用頻率。&lt;/p>
&lt;h3 id="timestamp必填">timestamp（必填）&lt;/h3>
&lt;p>事件發生的時間。ISO 8601 格式，包含時區偏移。&lt;code>2026-06-19T14:30:00.123+08:00&lt;/code>。&lt;/p>
&lt;p>Timestamp 由 SDK 在事件發生時記錄，不是 collector 收到時記錄。兩者可能有延遲（離線 buffer、網路延遲），以 SDK 端的時間為準。&lt;/p>
&lt;h3 id="source必填">source（必填）&lt;/h3>
&lt;p>事件來源的識別資訊。包含產生事件的 SDK、app 名稱、版本、平台、OS 版本。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;source&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;sdk&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;flutter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;app&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;app_tunnel&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.2.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;platform&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;ios&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl"> &lt;span class="nt">&amp;#34;os&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;17.4&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>sdk&lt;/code> 標明產生事件的 SDK 種類（&lt;code>js&lt;/code> / &lt;code>flutter&lt;/code> / &lt;code>python&lt;/code> / &lt;code>go&lt;/code>）。同一個平台可能有不同的 SDK——iOS 上可能是 Flutter SDK 或未來的 Swift 原生 SDK——sdk 欄位讓 collector 區分事件來自哪個 SDK 實作，platform 無法替代這個識別。&lt;code>sdk&lt;/code> 和 &lt;code>platform&lt;/code> 為必填，&lt;code>app&lt;/code>、&lt;code>version&lt;/code>、&lt;code>os&lt;/code> 為選填。&lt;/p>
&lt;p>Source 讓同一個 collector 接收多個 app 的事件時可以區分來源。也用於分析「哪個版本的 error 率最高」、「哪個 OS 版本有特定問題」。&lt;/p>
&lt;h4 id="platform-合法值與自動偵測">platform 合法值與自動偵測&lt;/h4>
&lt;p>&lt;code>platform&lt;/code> 由 SDK init 時自動偵測，開發者不需手動設定。各 SDK 的偵測來源和映射規則：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>SDK&lt;/th>
 &lt;th>偵測來源&lt;/th>
 &lt;th>映射規則&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Python&lt;/td>
 &lt;td>&lt;code>sys.platform&lt;/code>&lt;/td>
 &lt;td>&lt;code>darwin&lt;/code>→&lt;code>macos&lt;/code>、&lt;code>linux&lt;/code>→&lt;code>linux&lt;/code>、&lt;code>win32&lt;/code>→&lt;code>windows&lt;/code>、其他直接傳原值&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Flutter&lt;/td>
 &lt;td>&lt;code>Platform.operatingSystem&lt;/code>&lt;/td>
 &lt;td>回傳值（&lt;code>ios&lt;/code>/&lt;code>android&lt;/code>/&lt;code>macos&lt;/code>/&lt;code>linux&lt;/code>/&lt;code>windows&lt;/code>）即合法值，無需映射&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>JS&lt;/td>
 &lt;td>瀏覽器環境&lt;/td>
 &lt;td>固定為 &lt;code>web&lt;/code>；OS 偵測（如需要）從 &lt;code>navigator.userAgentData&lt;/code> 解析&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Go&lt;/td>
 &lt;td>&lt;code>runtime.GOOS&lt;/code>&lt;/td>
 &lt;td>&lt;code>darwin&lt;/code>→&lt;code>macos&lt;/code>、&lt;code>linux&lt;/code>→&lt;code>linux&lt;/code>、&lt;code>windows&lt;/code>→&lt;code>windows&lt;/code>、映射邏輯同 Python&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>以上映射是 SDK init 時的預設自動偵測行為。Python 和 Go 的 runtime 回傳系統內部名稱（&lt;code>darwin&lt;/code>、&lt;code>win32&lt;/code>），SDK 負責映射到 schema 定義的標準名稱。Flutter 的 &lt;code>dart:io Platform.operatingSystem&lt;/code> 恰好回傳合法值。JS SDK 在瀏覽器環境中無法可靠偵測 OS，platform 統一為 &lt;code>web&lt;/code>。&lt;/p>
&lt;p>自動偵測之外，SDK 也接受手動覆蓋 platform 值。短生命週期的命令列腳本（如 CI pipeline step、pre-commit hook）可手動將 platform 設為 &lt;code>script&lt;/code>，表示非互動式 OS session——這類場景中 OS 名稱不是有意義的區分維度，&lt;code>script&lt;/code> 讓查詢時能篩選出所有腳本來源的事件。&lt;/p>
&lt;p>SDK 不做映射的話，collector 會收到不一致的 platform 值——同是 macOS 的事件有些標 &lt;code>darwin&lt;/code> 有些標 &lt;code>macos&lt;/code>，查詢篩選會漏事件。各平台 SDK 的執行環境適配細節見&lt;a href="https://tarrragon.github.io/blog/monitoring/05-platform-adaptation/" data-link-title="模組五：平台適配" data-link-desc="JS CORS / Flutter isolate / Python GIL / Go graceful shutdown — 各平台的特殊考量">模組五：平台適配&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>事件 schema 定義了每一筆監控事件的資料結構。統一的 schema 讓 SDK、collector、查詢工具使用同一個資料契約 — SDK 知道該送什麼欄位，collector 知道該驗證什麼，查詢工具知道該讀什麼。</p>
<h2 id="核心欄位">核心欄位</h2>
<h3 id="type必填">type（必填）</h3>
<p>事件類型。對應四類事件分類（<a href="/blog/monitoring/01-mental-model/four-event-types/" data-link-title="四類事件的完整定義" data-link-desc="Event / Error / Metric / Lifecycle 四類事件各自的語意、觸發時機和典型用途 — 分類是監控體系的統一語言">模組一</a>）：<code>event</code>、<code>error</code>、<code>metric</code>、<code>lifecycle</code>。</p>
<p>Collector 用 type 決定事件的處理路徑 — error 類型觸發告警規則，metric 類型進入數值聚合，event 類型進入行為分析。</p>
<h3 id="name必填">name（必填）</h3>
<p>事件名稱。使用 namespace.action 格式（<a href="/blog/monitoring/01-mental-model/event-naming-convention/" data-link-title="事件命名規範" data-link-desc="namespace.action 格式的事件命名、命名一致性的工程價值、和商業方案命名慣例的對應">事件命名規範</a>）。例如 <code>terminal.connect.done</code>、<code>auth.biometric.failed</code>。</p>
<p>name 是查詢和統計的主要索引。<code>grep &quot;terminal.connect&quot;</code> 找到所有連線事件；按 name 分群計數得到功能使用頻率。</p>
<h3 id="timestamp必填">timestamp（必填）</h3>
<p>事件發生的時間。ISO 8601 格式，包含時區偏移。<code>2026-06-19T14:30:00.123+08:00</code>。</p>
<p>Timestamp 由 SDK 在事件發生時記錄，不是 collector 收到時記錄。兩者可能有延遲（離線 buffer、網路延遲），以 SDK 端的時間為準。</p>
<h3 id="source必填">source（必填）</h3>
<p>事件來源的識別資訊。包含產生事件的 SDK、app 名稱、版本、平台、OS 版本。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;sdk&#34;</span><span class="p">:</span> <span class="s2">&#34;flutter&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;app_tunnel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.2.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="s2">&#34;ios&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;17.4&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p><code>sdk</code> 標明產生事件的 SDK 種類（<code>js</code> / <code>flutter</code> / <code>python</code> / <code>go</code>）。同一個平台可能有不同的 SDK——iOS 上可能是 Flutter SDK 或未來的 Swift 原生 SDK——sdk 欄位讓 collector 區分事件來自哪個 SDK 實作，platform 無法替代這個識別。<code>sdk</code> 和 <code>platform</code> 為必填，<code>app</code>、<code>version</code>、<code>os</code> 為選填。</p>
<p>Source 讓同一個 collector 接收多個 app 的事件時可以區分來源。也用於分析「哪個版本的 error 率最高」、「哪個 OS 版本有特定問題」。</p>
<h4 id="platform-合法值與自動偵測">platform 合法值與自動偵測</h4>
<p><code>platform</code> 由 SDK init 時自動偵測，開發者不需手動設定。各 SDK 的偵測來源和映射規則：</p>
<table>
  <thead>
      <tr>
          <th>SDK</th>
          <th>偵測來源</th>
          <th>映射規則</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Python</td>
          <td><code>sys.platform</code></td>
          <td><code>darwin</code>→<code>macos</code>、<code>linux</code>→<code>linux</code>、<code>win32</code>→<code>windows</code>、其他直接傳原值</td>
      </tr>
      <tr>
          <td>Flutter</td>
          <td><code>Platform.operatingSystem</code></td>
          <td>回傳值（<code>ios</code>/<code>android</code>/<code>macos</code>/<code>linux</code>/<code>windows</code>）即合法值，無需映射</td>
      </tr>
      <tr>
          <td>JS</td>
          <td>瀏覽器環境</td>
          <td>固定為 <code>web</code>；OS 偵測（如需要）從 <code>navigator.userAgentData</code> 解析</td>
      </tr>
      <tr>
          <td>Go</td>
          <td><code>runtime.GOOS</code></td>
          <td><code>darwin</code>→<code>macos</code>、<code>linux</code>→<code>linux</code>、<code>windows</code>→<code>windows</code>、映射邏輯同 Python</td>
      </tr>
  </tbody>
</table>
<p>以上映射是 SDK init 時的預設自動偵測行為。Python 和 Go 的 runtime 回傳系統內部名稱（<code>darwin</code>、<code>win32</code>），SDK 負責映射到 schema 定義的標準名稱。Flutter 的 <code>dart:io Platform.operatingSystem</code> 恰好回傳合法值。JS SDK 在瀏覽器環境中無法可靠偵測 OS，platform 統一為 <code>web</code>。</p>
<p>自動偵測之外，SDK 也接受手動覆蓋 platform 值。短生命週期的命令列腳本（如 CI pipeline step、pre-commit hook）可手動將 platform 設為 <code>script</code>，表示非互動式 OS session——這類場景中 OS 名稱不是有意義的區分維度，<code>script</code> 讓查詢時能篩選出所有腳本來源的事件。</p>
<p>SDK 不做映射的話，collector 會收到不一致的 platform 值——同是 macOS 的事件有些標 <code>darwin</code> 有些標 <code>macos</code>，查詢篩選會漏事件。各平台 SDK 的執行環境適配細節見<a href="/blog/monitoring/05-platform-adaptation/" data-link-title="模組五：平台適配" data-link-desc="JS CORS / Flutter isolate / Python GIL / Go graceful shutdown — 各平台的特殊考量">模組五：平台適配</a>。</p>
<h3 id="session選填">session（選填）</h3>
<p>使用者 session 的識別資訊。Session ID（UUID）和 session 開始時間。</p>
<p>Session 用於關聯同一次使用中的多個事件。「使用者在這次 session 中做了什麼操作、遇到了什麼 error」的分析依賴 session ID。</p>
<p>去識別化要求：session ID 用 UUID 而非使用者帳號，不包含個人識別資訊（<a href="/blog/monitoring/07-security-privacy/" data-link-title="模組七：資安與隱私" data-link-desc="SDK redaction / transport 加密 / collector access control / 去識別化 — 蒐集的資料本身就是風險資產">模組七</a>）。</p>
<h3 id="data選填">data（選填）</h3>
<p>事件的附加資料。自由結構的 JSON object，內容依事件類型和名稱而定。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;wss://192.168.1.100:7681/ws&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;duration_ms&#34;</span><span class="p">:</span> <span class="mi">320</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nt">&#34;step&#34;</span><span class="p">:</span> <span class="s2">&#34;3/5&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Data 欄位是 schema 中唯一的自由結構區域。核心欄位（type、name、timestamp、source）有固定格式，data 的內容由事件定義者決定。</p>
<h3 id="v必填">v（必填）</h3>
<p>Schema 版本號。整數，從 1 開始遞增。</p>
<p>版本號讓 collector 知道用哪個版本的 schema 驗證這筆事件。Schema 演進時，舊版本的事件仍可被正確處理。</p>
<h2 id="collector-附加欄位底線前綴">Collector 附加欄位（底線前綴）</h2>
<p>Collector 在事件寫入 storage 時可以附加系統層的 metadata。這些欄位使用底線前綴（<code>_flags</code>、<code>_fingerprint</code>），和 SDK 端產生的業務欄位區隔。SDK 送出的事件中不包含這些欄位 — 它們由 collector pipeline 在處理過程中計算並附加。</p>
<h3 id="_flags選填collector-附加">_flags（選填，collector 附加）</h3>
<p>Collector 端的行為分析或規則引擎偵測到異常時，在事件中附加標記。Dashboard 查詢可用 <code>_flags</code> 過濾可疑事件。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;_flags&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nt">&#34;suspicious&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nt">&#34;reason&#34;</span><span class="p">:</span> <span class="s2">&#34;rate_anomaly&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p><code>suspicious</code> 標記的事件不被刪除 — 直接丟棄有誤殺正常流量的風險（行銷活動的真實流量暴增可能觸發異常偵測）。Dashboard 預設排除 <code>_flags.suspicious = true</code> 的事件，需要調查時可包含。</p>
<p>標記來源和 reason 值的定義見 <a href="/blog/monitoring/07-security-privacy/client-sdk-authentication/" data-link-title="Client-side SDK 認證的根本限制" data-link-desc="嵌在 client 端的 credential 必然可被提取 — 認清 architecture 天花板後的多層緩解策略，從 origin 驗證到 device attestation">Client-side SDK 認證</a> 的事後標記策略段。</p>
<h3 id="_fingerprint選填collector-附加">_fingerprint（選填，collector 附加）</h3>
<p>Error 事件的去重識別碼。Collector 從 error 的 type、normalized message、stack trace 計算 hash，用於把相同根因的 error 歸組。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;_fingerprint&#34;</span><span class="p">:</span> <span class="s2">&#34;a3f8c2e1b7d94f06&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Fingerprint 的計算邏輯和 error grouping 機制見 <a href="/blog/monitoring/04-collector/error-fingerprint/" data-link-title="Error Fingerprint 與去重分群" data-link-desc="把大量 error 事件歸組成可管理的 issue 列表 — fingerprint 演算法、message normalization、error_groups 表設計、自架方案的務實邊界">Error Fingerprint 與去重分群</a>。</p>
<h3 id="sdk-自監控指標">SDK 自監控指標</h3>
<p>監控系統自身的資料完整性需要獨立的指標追蹤 — SDK 用 metric 類事件回報自己的送出量和丟棄量，collector 用 endpoint 暴露處理量和拒絕量。SDK 端的指標每次 flush 成功後作為標準 schema 事件一起送出，name 以 <code>sdk.</code> 前綴標識。</p>
<table>
  <thead>
      <tr>
          <th>name</th>
          <th>含義</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>sdk.events.produced</code></td>
          <td>事件產生總數（取樣前）</td>
      </tr>
      <tr>
          <td><code>sdk.events.sampled</code></td>
          <td>取樣後保留的事件數</td>
      </tr>
      <tr>
          <td><code>sdk.events.sent</code></td>
          <td>成功送出的事件數（收到 200/207 的 accepted）</td>
      </tr>
      <tr>
          <td><code>sdk.events.dropped</code></td>
          <td>被 FIFO 丟棄或重試耗盡的事件數</td>
      </tr>
      <tr>
          <td><code>sdk.flush.failures</code></td>
          <td>flush 失敗次數（429 / 5xx / timeout）</td>
      </tr>
      <tr>
          <td><code>sdk.sampling.rate</code></td>
          <td>當前動態取樣率</td>
      </tr>
  </tbody>
</table>
<p>Collector 端對應暴露 <code>collector.events.received</code>、<code>collector.events.rejected</code>、<code>collector.events.stored</code>、<code>collector.events.backpressure</code> 等指標，透過 <code>/metrics</code> endpoint 或 health endpoint 的擴展欄位提供。</p>
<p>完整的指標定義、端到端比對方法和損失率閾值見 <a href="/blog/monitoring/04-collector/data-integrity/" data-link-title="端到端資料完整性" data-link-desc="從 SDK 到 storage 的資料損失地圖 — 每個環節的損失類型、控制策略、完整性指標、被自己 SDK DDoS 的防護">端到端資料完整性</a> 的監控損失段。</p>
<h2 id="完整-schema-範例">完整 schema 範例</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;v&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;error&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;terminal.connect.failed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;timestamp&#34;</span><span class="p">:</span> <span class="s2">&#34;2026-06-19T14:30:00.123+08:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="nt">&#34;sdk&#34;</span><span class="p">:</span> <span class="s2">&#34;flutter&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="nt">&#34;app&#34;</span><span class="p">:</span> <span class="s2">&#34;app_tunnel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.2.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="nt">&#34;platform&#34;</span><span class="p">:</span> <span class="s2">&#34;ios&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="nt">&#34;os&#34;</span><span class="p">:</span> <span class="s2">&#34;17.4&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">  <span class="nt">&#34;session&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;a1b2c3d4-e5f6-7890-abcd-ef1234567890&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="nt">&#34;started&#34;</span><span class="p">:</span> <span class="s2">&#34;2026-06-19T14:25:00.000+08:00&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="nt">&#34;step&#34;</span><span class="p">:</span> <span class="s2">&#34;ws_connect&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="nt">&#34;error&#34;</span><span class="p">:</span> <span class="s2">&#34;Connection refused&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;wss://192.168.1.100:7681/ws&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h2 id="下一步路由">下一步路由</h2>
<ul>
<li>欄位設計的原則 → <a href="/blog/monitoring/02-log-schema/field-design-principles/" data-link-title="欄位設計原則" data-link-desc="source 標明來源、data 自由欄位、v 版本演進 — 三個設計原則讓 schema 在不同階段都能使用">欄位設計原則</a></li>
<li>Schema 版本演進 → <a href="/blog/monitoring/02-log-schema/schema-versioning/" data-link-title="Schema 版本演進策略" data-link-desc="Backward compatible 的增量變更 — 新增欄位不改版、改名或改型別才改版、collector 同時支援多版本">Schema 版本演進策略</a></li>
<li>和 OpenTelemetry 的差異 → <a href="/blog/monitoring/02-log-schema/otel-comparison/" data-link-title="跟 OpenTelemetry 的 schema 差異對照" data-link-desc="自架 event schema 和 OTLP 的設計差異 — 為什麼 client-side 監控用簡化 schema、什麼時候切換到 OTLP">跟 OpenTelemetry 的 schema 差異對照</a></li>
<li>Log 點的設計方法 → <a href="/blog/testing/02-client-observability/" data-link-title="模組二：客戶端可觀測性" data-link-desc="連線生命週期 log、protocol 訊息 log、使用者行為 log — log 設計是功能規格的一部分">testing 模組二 客戶端可觀測性</a></li>
</ul>
]]></content:encoded></item></channel></rss>