<?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>Event on Tarragon</title><link>https://tarrragon.github.io/blog/tags/event/</link><description>Recent content in Event 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/event/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><item><title>四類事件的完整定義</title><link>https://tarrragon.github.io/blog/monitoring/01-mental-model/four-event-types/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/01-mental-model/four-event-types/</guid><description>&lt;p>監控資料由四類事件構成。每類事件回答不同的問題，觸發時機不同，消費方式不同。分類的目的是讓「我要收集什麼」有結構化的答案，而非在每個功能上各自決定要不要加 log。&lt;/p>
&lt;h2 id="event使用者做了什麼">Event：使用者做了什麼&lt;/h2>
&lt;p>Event 記錄使用者主動發起的操作。按鈕點擊、頁面瀏覽、表單提交、搜尋查詢 — 每個 event 代表使用者的一個意圖表達。&lt;/p>
&lt;p>Event 的觸發時機是使用者操作發生時。程式碼中的位置通常是 UI 事件處理器（onClick、onSubmit、onNavigate）。&lt;/p>
&lt;p>Event 的消費方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Debug context&lt;/strong>：問題發生前使用者做了哪些操作。和 error 事件搭配使用，還原問題的操作路徑。&lt;/li>
&lt;li>&lt;strong>行為分析&lt;/strong>：使用者做了哪些操作、操作順序是什麼、在哪一步停止。&lt;a href="https://tarrragon.github.io/blog/monitoring/knowledge-cards/funnel-analysis/" data-link-title="Funnel Analysis" data-link-desc="說明追蹤使用者在多步驟流程中每一步的轉換率和流失率的分析方法">Funnel analysis&lt;/a> 的原料（&lt;a href="https://tarrragon.github.io/blog/monitoring/08-business-analytics/" data-link-title="模組八：行為資料的商業利用" data-link-desc="Funnel / Cohort / Attribution / A/B test / 推薦系統 / RFM — 從 debug 工具到商業資產的翻轉">模組八&lt;/a>）。&lt;/li>
&lt;li>&lt;strong>功能使用率&lt;/strong>：哪些功能被頻繁使用、哪些很少被觸發。功能優先順序的決策依據。&lt;/li>
&lt;/ul>
&lt;h2 id="error什麼出了問題">Error：什麼出了問題&lt;/h2>
&lt;p>Error 記錄程式碼執行中的非預期狀態。例外拋出、assertion 失敗、非預期的 API 回應、資源存取失敗。&lt;/p>
&lt;p>Error 的觸發時機是非預期狀態被偵測到時。來源包括：語言層級的 try/catch 捕獲、框架的全域錯誤處理器（Flutter 的 &lt;code>FlutterError.onError&lt;/code>、JavaScript 的 &lt;code>window.onerror&lt;/code>）、自訂的錯誤檢查邏輯。&lt;/p>
&lt;p>Error 的消費方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>即時告警&lt;/strong>：特定類型的 error 或 error 數量超過閾值時通知開發者。&lt;/li>
&lt;li>&lt;strong>趨勢分析&lt;/strong>：error 數量隨時間的變化。新版本部署後 error 是否增加。&lt;/li>
&lt;li>&lt;strong>根因分析&lt;/strong>：error 的 stack trace、觸發條件、影響範圍。和 event 搭配還原「使用者做了什麼導致 error」。&lt;/li>
&lt;/ul>
&lt;h2 id="metric系統狀態的數值快照">Metric：系統狀態的數值快照&lt;/h2>
&lt;p>Metric 記錄系統狀態的可量化指標。回應時間、記憶體使用量、佇列長度、連線數、frame rate。&lt;/p>
&lt;p>Metric 的觸發時機是定期取樣或特定事件發生時。定期取樣適合持續變化的指標（記憶體使用量每 30 秒取一次），事件觸發適合離散的測量（每次 API 回應記錄回應時間）。&lt;/p>
&lt;p>Metric 的消費方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>效能監控&lt;/strong>：回應時間的 P50 / P95 / P99 分佈。記憶體使用量的趨勢。&lt;/li>
&lt;li>&lt;strong>容量規劃&lt;/strong>：佇列長度接近上限、連線數接近 pool 上限 — 需要擴容的訊號。&lt;/li>
&lt;li>&lt;strong>SLA 追蹤&lt;/strong>：服務可用性、回應時間是否在承諾範圍內。&lt;/li>
&lt;/ul>
&lt;h2 id="lifecycle系統經歷了什麼階段">Lifecycle：系統經歷了什麼階段&lt;/h2>
&lt;p>Lifecycle 記錄系統本身的狀態轉換。App 啟動、前景/背景切換、連線建立/斷開、版本更新、設定變更。&lt;/p>
&lt;p>Lifecycle 的觸發時機是系統狀態轉換發生時。來源包括：app 生命週期回呼（onCreate、onResume、onPause）、連線狀態變化事件、部署和設定變更鉤子。&lt;/p>
&lt;p>Lifecycle 的消費方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Session 分析&lt;/strong>：使用者一次使用多久、啟動頻率、前後景切換頻率。&lt;/li>
&lt;li>&lt;strong>環境資訊&lt;/strong>：Error 發生時的系統狀態（app 版本、OS 版本、網路狀態）。&lt;/li>
&lt;li>&lt;strong>連線品質&lt;/strong>：連線建立成功率、斷線頻率、重連次數（&lt;a href="https://tarrragon.github.io/blog/testing/02-client-observability/three-layer-log-design/" data-link-title="三層 log 設計" data-link-desc="連線生命週期 log、protocol 訊息 log、使用者行為 log — 三層各自的職責、詳細程度和啟停控制">testing 模組二 三層 log&lt;/a>）。&lt;/li>
&lt;/ul>
&lt;h2 id="四類事件的區別">四類事件的區別&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>Event&lt;/th>
 &lt;th>Error&lt;/th>
 &lt;th>Metric&lt;/th>
 &lt;th>Lifecycle&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>觸發者&lt;/td>
 &lt;td>使用者操作&lt;/td>
 &lt;td>系統非預期狀態&lt;/td>
 &lt;td>定期取樣或事件觸發&lt;/td>
 &lt;td>系統狀態轉換&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>回答&lt;/td>
 &lt;td>使用者做了什麼&lt;/td>
 &lt;td>什麼出了問題&lt;/td>
 &lt;td>系統現在怎麼樣&lt;/td>
 &lt;td>系統經歷了什麼&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>頻率&lt;/td>
 &lt;td>依使用者行為&lt;/td>
 &lt;td>低（理想狀態）&lt;/td>
 &lt;td>固定間隔或事件驅動&lt;/td>
 &lt;td>低（狀態轉換才有）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>消費&lt;/td>
 &lt;td>行為分析、funnel&lt;/td>
 &lt;td>告警、根因分析&lt;/td>
 &lt;td>效能監控、容量規劃&lt;/td>
 &lt;td>session、環境資訊&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>事件命名規範 → &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;/li>
&lt;li>從需求推導收集策略 → &lt;a href="https://tarrragon.github.io/blog/monitoring/01-mental-model/derive-collection-from-requirements/" data-link-title="從需求推導「該收集哪些事件」" data-link-desc="從 debug 需求、行為分析需求、效能需求、合規需求四個方向推導事件收集策略 — 避免「什麼都收」和「什麼都不收」">從需求推導「該收集哪些事件」&lt;/a>&lt;/li>
&lt;li>Event 類事件在商業分析中的用途 → &lt;a href="https://tarrragon.github.io/blog/monitoring/08-business-analytics/" data-link-title="模組八：行為資料的商業利用" data-link-desc="Funnel / Cohort / Attribution / A/B test / 推薦系統 / RFM — 從 debug 工具到商業資產的翻轉">模組八 行為資料的商業利用&lt;/a>&lt;/li>
&lt;li>Log 點的設計方法 → &lt;a href="https://tarrragon.github.io/blog/testing/02-client-observability/" data-link-title="模組二：客戶端可觀測性" data-link-desc="連線生命週期 log、protocol 訊息 log、使用者行為 log — log 設計是功能規格的一部分">testing 模組二 客戶端可觀測性&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>監控資料由四類事件構成。每類事件回答不同的問題，觸發時機不同，消費方式不同。分類的目的是讓「我要收集什麼」有結構化的答案，而非在每個功能上各自決定要不要加 log。</p>
<h2 id="event使用者做了什麼">Event：使用者做了什麼</h2>
<p>Event 記錄使用者主動發起的操作。按鈕點擊、頁面瀏覽、表單提交、搜尋查詢 — 每個 event 代表使用者的一個意圖表達。</p>
<p>Event 的觸發時機是使用者操作發生時。程式碼中的位置通常是 UI 事件處理器（onClick、onSubmit、onNavigate）。</p>
<p>Event 的消費方式：</p>
<ul>
<li><strong>Debug context</strong>：問題發生前使用者做了哪些操作。和 error 事件搭配使用，還原問題的操作路徑。</li>
<li><strong>行為分析</strong>：使用者做了哪些操作、操作順序是什麼、在哪一步停止。<a href="/blog/monitoring/knowledge-cards/funnel-analysis/" data-link-title="Funnel Analysis" data-link-desc="說明追蹤使用者在多步驟流程中每一步的轉換率和流失率的分析方法">Funnel analysis</a> 的原料（<a href="/blog/monitoring/08-business-analytics/" data-link-title="模組八：行為資料的商業利用" data-link-desc="Funnel / Cohort / Attribution / A/B test / 推薦系統 / RFM — 從 debug 工具到商業資產的翻轉">模組八</a>）。</li>
<li><strong>功能使用率</strong>：哪些功能被頻繁使用、哪些很少被觸發。功能優先順序的決策依據。</li>
</ul>
<h2 id="error什麼出了問題">Error：什麼出了問題</h2>
<p>Error 記錄程式碼執行中的非預期狀態。例外拋出、assertion 失敗、非預期的 API 回應、資源存取失敗。</p>
<p>Error 的觸發時機是非預期狀態被偵測到時。來源包括：語言層級的 try/catch 捕獲、框架的全域錯誤處理器（Flutter 的 <code>FlutterError.onError</code>、JavaScript 的 <code>window.onerror</code>）、自訂的錯誤檢查邏輯。</p>
<p>Error 的消費方式：</p>
<ul>
<li><strong>即時告警</strong>：特定類型的 error 或 error 數量超過閾值時通知開發者。</li>
<li><strong>趨勢分析</strong>：error 數量隨時間的變化。新版本部署後 error 是否增加。</li>
<li><strong>根因分析</strong>：error 的 stack trace、觸發條件、影響範圍。和 event 搭配還原「使用者做了什麼導致 error」。</li>
</ul>
<h2 id="metric系統狀態的數值快照">Metric：系統狀態的數值快照</h2>
<p>Metric 記錄系統狀態的可量化指標。回應時間、記憶體使用量、佇列長度、連線數、frame rate。</p>
<p>Metric 的觸發時機是定期取樣或特定事件發生時。定期取樣適合持續變化的指標（記憶體使用量每 30 秒取一次），事件觸發適合離散的測量（每次 API 回應記錄回應時間）。</p>
<p>Metric 的消費方式：</p>
<ul>
<li><strong>效能監控</strong>：回應時間的 P50 / P95 / P99 分佈。記憶體使用量的趨勢。</li>
<li><strong>容量規劃</strong>：佇列長度接近上限、連線數接近 pool 上限 — 需要擴容的訊號。</li>
<li><strong>SLA 追蹤</strong>：服務可用性、回應時間是否在承諾範圍內。</li>
</ul>
<h2 id="lifecycle系統經歷了什麼階段">Lifecycle：系統經歷了什麼階段</h2>
<p>Lifecycle 記錄系統本身的狀態轉換。App 啟動、前景/背景切換、連線建立/斷開、版本更新、設定變更。</p>
<p>Lifecycle 的觸發時機是系統狀態轉換發生時。來源包括：app 生命週期回呼（onCreate、onResume、onPause）、連線狀態變化事件、部署和設定變更鉤子。</p>
<p>Lifecycle 的消費方式：</p>
<ul>
<li><strong>Session 分析</strong>：使用者一次使用多久、啟動頻率、前後景切換頻率。</li>
<li><strong>環境資訊</strong>：Error 發生時的系統狀態（app 版本、OS 版本、網路狀態）。</li>
<li><strong>連線品質</strong>：連線建立成功率、斷線頻率、重連次數（<a href="/blog/testing/02-client-observability/three-layer-log-design/" data-link-title="三層 log 設計" data-link-desc="連線生命週期 log、protocol 訊息 log、使用者行為 log — 三層各自的職責、詳細程度和啟停控制">testing 模組二 三層 log</a>）。</li>
</ul>
<h2 id="四類事件的區別">四類事件的區別</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Event</th>
          <th>Error</th>
          <th>Metric</th>
          <th>Lifecycle</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>觸發者</td>
          <td>使用者操作</td>
          <td>系統非預期狀態</td>
          <td>定期取樣或事件觸發</td>
          <td>系統狀態轉換</td>
      </tr>
      <tr>
          <td>回答</td>
          <td>使用者做了什麼</td>
          <td>什麼出了問題</td>
          <td>系統現在怎麼樣</td>
          <td>系統經歷了什麼</td>
      </tr>
      <tr>
          <td>頻率</td>
          <td>依使用者行為</td>
          <td>低（理想狀態）</td>
          <td>固定間隔或事件驅動</td>
          <td>低（狀態轉換才有）</td>
      </tr>
      <tr>
          <td>消費</td>
          <td>行為分析、funnel</td>
          <td>告警、根因分析</td>
          <td>效能監控、容量規劃</td>
          <td>session、環境資訊</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>事件命名規範 → <a href="/blog/monitoring/01-mental-model/event-naming-convention/" data-link-title="事件命名規範" data-link-desc="namespace.action 格式的事件命名、命名一致性的工程價值、和商業方案命名慣例的對應">事件命名規範</a></li>
<li>從需求推導收集策略 → <a href="/blog/monitoring/01-mental-model/derive-collection-from-requirements/" data-link-title="從需求推導「該收集哪些事件」" data-link-desc="從 debug 需求、行為分析需求、效能需求、合規需求四個方向推導事件收集策略 — 避免「什麼都收」和「什麼都不收」">從需求推導「該收集哪些事件」</a></li>
<li>Event 類事件在商業分析中的用途 → <a href="/blog/monitoring/08-business-analytics/" data-link-title="模組八：行為資料的商業利用" data-link-desc="Funnel / Cohort / Attribution / A/B test / 推薦系統 / RFM — 從 debug 工具到商業資產的翻轉">模組八 行為資料的商業利用</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><item><title>事件命名規範</title><link>https://tarrragon.github.io/blog/monitoring/01-mental-model/event-naming-convention/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/01-mental-model/event-naming-convention/</guid><description>&lt;p>事件命名的目的是讓事件可以被 grep、過濾和統計。統一的命名規範讓不同時期、不同開發者加入的事件能在同一個查詢框架中使用。&lt;/p>
&lt;h2 id="namespaceaction-格式">namespace.action 格式&lt;/h2>
&lt;p>每個事件名稱由兩部分組成：namespace（事件發生的模組或功能區域）和 action（發生了什麼）。用 &lt;code>.&lt;/code> 分隔。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">terminal.connect.start ← namespace: terminal.connect, action: start
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">terminal.connect.done ← namespace: terminal.connect, action: &lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">terminal.input.submit ← namespace: terminal.input, action: submit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">auth.biometric.success ← namespace: auth.biometric, action: success
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">auth.biometric.fallback ← namespace: auth.biometric, action: fallback
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">enrollment.qr.scan ← namespace: enrollment.qr, action: scan&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="namespace-層級">Namespace 層級&lt;/h3>
&lt;p>Namespace 的層級深度依功能結構而定。兩層通常足夠（&lt;code>terminal.connect&lt;/code>），三層用於需要進一步區分的場景（&lt;code>terminal.connect.ws&lt;/code>）。超過三層通常代表 namespace 設計過細，增加認知成本但不增加分析價值。&lt;/p>
&lt;h3 id="action-命名">Action 命名&lt;/h3>
&lt;p>Action 使用動詞（&lt;code>start&lt;/code>、&lt;code>submit&lt;/code>、&lt;code>scan&lt;/code>）或狀態（&lt;code>success&lt;/code>、&lt;code>failed&lt;/code>、&lt;code>timeout&lt;/code>）。同一組動作用配對的 action 名稱：&lt;code>start&lt;/code> / &lt;code>done&lt;/code>（成對的生命週期）、&lt;code>success&lt;/code> / &lt;code>failed&lt;/code>（結果分支）。&lt;/p>
&lt;p>避免在 action 中重複 namespace 的資訊。&lt;code>terminal.connect.terminal_connected&lt;/code> 中 &lt;code>terminal&lt;/code> 重複了；&lt;code>terminal.connect.done&lt;/code> 更簡潔。&lt;/p>
&lt;h2 id="命名一致性的工程價值">命名一致性的工程價值&lt;/h2>
&lt;h3 id="grep-友好">Grep 友好&lt;/h3>
&lt;p>統一的 namespace 結構讓開發者用 &lt;code>grep &amp;quot;terminal.connect&amp;quot;&lt;/code> 就能找到所有連線相關事件，不需要知道每個事件的完整名稱。&lt;/p>
&lt;h3 id="統計友好">統計友好&lt;/h3>
&lt;p>按 namespace 前綴分群統計。&lt;code>terminal.*&lt;/code> 的事件數量 = terminal 功能的使用頻率；&lt;code>auth.*&lt;/code> 的事件數量 = 認證觸發頻率。層級結構讓統計的粒度可以調整。&lt;/p>
&lt;h3 id="文件友好">文件友好&lt;/h3>
&lt;p>事件清單按 namespace 排列就是一份結構化的功能地圖。新加入的開發者讀事件清單就能理解系統有哪些功能模組。&lt;/p>
&lt;h2 id="和商業方案的命名對應">和商業方案的命名對應&lt;/h2>
&lt;p>不同的商業監控方案有各自的命名慣例。自架方案用 namespace.action 格式，接入商業方案時需要做對應。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>商業方案&lt;/th>
 &lt;th>命名慣例&lt;/th>
 &lt;th>對應方式&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>GA4&lt;/td>
 &lt;td>&lt;code>event_name&lt;/code> + parameters&lt;/td>
 &lt;td>namespace.action → &lt;code>event_name&lt;/code>，細節放 parameters&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Sentry&lt;/td>
 &lt;td>transaction name + spans&lt;/td>
 &lt;td>namespace → transaction，action → span&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Mixpanel&lt;/td>
 &lt;td>event name + properties&lt;/td>
 &lt;td>namespace.action → event name&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Datadog RUM&lt;/td>
 &lt;td>action name + view name&lt;/td>
 &lt;td>action → action name，namespace → view&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>對應時保持一個原則：自架方案的事件名稱是 source of truth，商業方案的名稱是它的映射。在自架方案中改名後，映射層跟著改；不要讓商業方案的命名反過來影響自架的命名結構。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>四類事件的定義 → &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;/li>
&lt;li>從需求推導收集策略 → &lt;a href="https://tarrragon.github.io/blog/monitoring/01-mental-model/derive-collection-from-requirements/" data-link-title="從需求推導「該收集哪些事件」" data-link-desc="從 debug 需求、行為分析需求、效能需求、合規需求四個方向推導事件收集策略 — 避免「什麼都收」和「什麼都不收」">從需求推導「該收集哪些事件」&lt;/a>&lt;/li>
&lt;li>商業方案的完整比較 → &lt;a href="https://tarrragon.github.io/blog/monitoring/06-commercial-comparison/" data-link-title="模組六：商業方案對照" data-link-desc="Sentry / Crashlytics / Datadog RUM / Mixpanel — 自架 vs 商業的功能和成本取捨">模組六 商業方案比較&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>事件命名的目的是讓事件可以被 grep、過濾和統計。統一的命名規範讓不同時期、不同開發者加入的事件能在同一個查詢框架中使用。</p>
<h2 id="namespaceaction-格式">namespace.action 格式</h2>
<p>每個事件名稱由兩部分組成：namespace（事件發生的模組或功能區域）和 action（發生了什麼）。用 <code>.</code> 分隔。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">terminal.connect.start      ← namespace: terminal.connect, action: start
</span></span><span class="line"><span class="ln">2</span><span class="cl">terminal.connect.done       ← namespace: terminal.connect, action: <span class="k">done</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">terminal.input.submit       ← namespace: terminal.input, action: submit
</span></span><span class="line"><span class="ln">4</span><span class="cl">auth.biometric.success      ← namespace: auth.biometric, action: success
</span></span><span class="line"><span class="ln">5</span><span class="cl">auth.biometric.fallback     ← namespace: auth.biometric, action: fallback
</span></span><span class="line"><span class="ln">6</span><span class="cl">enrollment.qr.scan          ← namespace: enrollment.qr, action: scan</span></span></code></pre></div><h3 id="namespace-層級">Namespace 層級</h3>
<p>Namespace 的層級深度依功能結構而定。兩層通常足夠（<code>terminal.connect</code>），三層用於需要進一步區分的場景（<code>terminal.connect.ws</code>）。超過三層通常代表 namespace 設計過細，增加認知成本但不增加分析價值。</p>
<h3 id="action-命名">Action 命名</h3>
<p>Action 使用動詞（<code>start</code>、<code>submit</code>、<code>scan</code>）或狀態（<code>success</code>、<code>failed</code>、<code>timeout</code>）。同一組動作用配對的 action 名稱：<code>start</code> / <code>done</code>（成對的生命週期）、<code>success</code> / <code>failed</code>（結果分支）。</p>
<p>避免在 action 中重複 namespace 的資訊。<code>terminal.connect.terminal_connected</code> 中 <code>terminal</code> 重複了；<code>terminal.connect.done</code> 更簡潔。</p>
<h2 id="命名一致性的工程價值">命名一致性的工程價值</h2>
<h3 id="grep-友好">Grep 友好</h3>
<p>統一的 namespace 結構讓開發者用 <code>grep &quot;terminal.connect&quot;</code> 就能找到所有連線相關事件，不需要知道每個事件的完整名稱。</p>
<h3 id="統計友好">統計友好</h3>
<p>按 namespace 前綴分群統計。<code>terminal.*</code> 的事件數量 = terminal 功能的使用頻率；<code>auth.*</code> 的事件數量 = 認證觸發頻率。層級結構讓統計的粒度可以調整。</p>
<h3 id="文件友好">文件友好</h3>
<p>事件清單按 namespace 排列就是一份結構化的功能地圖。新加入的開發者讀事件清單就能理解系統有哪些功能模組。</p>
<h2 id="和商業方案的命名對應">和商業方案的命名對應</h2>
<p>不同的商業監控方案有各自的命名慣例。自架方案用 namespace.action 格式，接入商業方案時需要做對應。</p>
<table>
  <thead>
      <tr>
          <th>商業方案</th>
          <th>命名慣例</th>
          <th>對應方式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GA4</td>
          <td><code>event_name</code> + parameters</td>
          <td>namespace.action → <code>event_name</code>，細節放 parameters</td>
      </tr>
      <tr>
          <td>Sentry</td>
          <td>transaction name + spans</td>
          <td>namespace → transaction，action → span</td>
      </tr>
      <tr>
          <td>Mixpanel</td>
          <td>event name + properties</td>
          <td>namespace.action → event name</td>
      </tr>
      <tr>
          <td>Datadog RUM</td>
          <td>action name + view name</td>
          <td>action → action name，namespace → view</td>
      </tr>
  </tbody>
</table>
<p>對應時保持一個原則：自架方案的事件名稱是 source of truth，商業方案的名稱是它的映射。在自架方案中改名後，映射層跟著改；不要讓商業方案的命名反過來影響自架的命名結構。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>四類事件的定義 → <a href="/blog/monitoring/01-mental-model/four-event-types/" data-link-title="四類事件的完整定義" data-link-desc="Event / Error / Metric / Lifecycle 四類事件各自的語意、觸發時機和典型用途 — 分類是監控體系的統一語言">四類事件的完整定義</a></li>
<li>從需求推導收集策略 → <a href="/blog/monitoring/01-mental-model/derive-collection-from-requirements/" data-link-title="從需求推導「該收集哪些事件」" data-link-desc="從 debug 需求、行為分析需求、效能需求、合規需求四個方向推導事件收集策略 — 避免「什麼都收」和「什麼都不收」">從需求推導「該收集哪些事件」</a></li>
<li>商業方案的完整比較 → <a href="/blog/monitoring/06-commercial-comparison/" data-link-title="模組六：商業方案對照" data-link-desc="Sentry / Crashlytics / Datadog RUM / Mixpanel — 自架 vs 商業的功能和成本取捨">模組六 商業方案比較</a></li>
</ul>
]]></content:encoded></item><item><title>Event Source</title><link>https://tarrragon.github.io/blog/ci/knowledge-cards/event-source/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/knowledge-cards/event-source/</guid><description>&lt;p>Event Source 的核心概念是「觸發執行的事件入口」。它決定 serverless function 或 worker 何時執行、如何重試、如何進入 dead-letter，並影響 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/function-alias/" data-link-title="Function Alias" data-link-desc="說明 serverless function alias 如何把穩定入口指向特定版本並支援流量切換與回復">Function Alias&lt;/a> 的 rollout 與回復策略。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Event Source 位在 queue、topic、HTTP gateway、object storage、scheduler 與 function / worker 之間，負責把外部事件轉成執行請求。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;ul>
&lt;li>函式部署成功，但 invocation 因 trigger 設定失敗。&lt;/li>
&lt;li>Queue event 重試造成同一筆資料被重複處理。&lt;/li>
&lt;li>事件 schema 漂移導致 subscriber 解析失敗。&lt;/li>
&lt;/ul>
&lt;h2 id="接近真實服務的例子">接近真實服務的例子&lt;/h2>
&lt;p>Queue 觸發的 function 以 batch 方式處理訊息。新版本解析失敗時，訊息進入 dead-letter queue；團隊先停用 trigger，再修復 function 或重放事件。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>Event Source 要定義 trigger 條件、batch size、retry、dead-letter、replay、權限與 schema 契約，讓事件驅動發布具備可觀測回復路徑。&lt;/p></description><content:encoded><![CDATA[<p>Event Source 的核心概念是「觸發執行的事件入口」。它決定 serverless function 或 worker 何時執行、如何重試、如何進入 dead-letter，並影響 <a href="/blog/ci/knowledge-cards/function-alias/" data-link-title="Function Alias" data-link-desc="說明 serverless function alias 如何把穩定入口指向特定版本並支援流量切換與回復">Function Alias</a> 的 rollout 與回復策略。</p>
<h2 id="概念位置">概念位置</h2>
<p>Event Source 位在 queue、topic、HTTP gateway、object storage、scheduler 與 function / worker 之間，負責把外部事件轉成執行請求。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<ul>
<li>函式部署成功，但 invocation 因 trigger 設定失敗。</li>
<li>Queue event 重試造成同一筆資料被重複處理。</li>
<li>事件 schema 漂移導致 subscriber 解析失敗。</li>
</ul>
<h2 id="接近真實服務的例子">接近真實服務的例子</h2>
<p>Queue 觸發的 function 以 batch 方式處理訊息。新版本解析失敗時，訊息進入 dead-letter queue；團隊先停用 trigger，再修復 function 或重放事件。</p>
<h2 id="設計責任">設計責任</h2>
<p>Event Source 要定義 trigger 條件、batch size、retry、dead-letter、replay、權限與 schema 契約，讓事件驅動發布具備可觀測回復路徑。</p>
]]></content:encoded></item></channel></rss>