<?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>Feature-Flag on Tarragon</title><link>https://tarrragon.github.io/blog/tags/feature-flag/</link><description>Recent content in Feature-Flag on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Sat, 20 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/feature-flag/index.xml" rel="self" type="application/rss+xml"/><item><title>感測器生命週期管理</title><link>https://tarrragon.github.io/blog/monitoring/03-sdk-design/sensor-lifecycle-management/</link><pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/03-sdk-design/sensor-lifecycle-management/</guid><description>&lt;p>感測器的啟用組合隨產品階段變化。早期開發只需要 error 和 lifecycle 幫助 debug，production 上線後需要商業事件和效能量測，A/B 測試期間需要實驗專用感測器。把所有感測器一次全開會浪費頻寬和儲存、產生大量低價值事件；全程只開 error 則在需要行為分析時發現沒有資料。感測器的啟停是設計決策，由 SDK config、collector 下發和 feature flag 三層機制控制。&lt;/p>
&lt;h2 id="五個階段">五個階段&lt;/h2>
&lt;h3 id="早期開發">早期開發&lt;/h3>
&lt;p>開發期的首要需求是 debug — 程式碼寫完跑起來、出問題時能定位。&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>error&lt;/td>
 &lt;td>全開&lt;/td>
 &lt;td>每個例外都要看到&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>lifecycle&lt;/td>
 &lt;td>全開&lt;/td>
 &lt;td>app 啟動、連線、狀態轉換的步驟紀錄&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>event&lt;/td>
 &lt;td>按需&lt;/td>
 &lt;td>正在開發的功能手動加埋點，其他關閉&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>metric&lt;/td>
 &lt;td>關閉&lt;/td>
 &lt;td>效能量測在功能穩定前沒有意義&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>開發期的取樣率全部設 1.0（全收）— 事件量極低（開發者自己操作），不需要取樣。&lt;/p>
&lt;h3 id="功能測試">功能測試&lt;/h3>
&lt;p>針對被測功能開啟完整感測器，驗證功能的行為事件和效能指標是否正確觸發。&lt;/p>
&lt;p>被測功能的 event 和 metric 全開。其他功能維持開發期設定。測試期間的感測器設定通常由測試 config 檔覆寫 SDK 預設值。&lt;/p>
&lt;h3 id="production-上線">Production 上線&lt;/h3>
&lt;p>上線後的感測器組合平衡覆蓋率和成本：&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>error&lt;/td>
 &lt;td>全收&lt;/td>
 &lt;td>每個 production error 都有 debug 價值&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>lifecycle&lt;/td>
 &lt;td>全收&lt;/td>
 &lt;td>session 分析和環境資訊需要完整紀錄&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>event（核心操作）&lt;/td>
 &lt;td>全收&lt;/td>
 &lt;td>漏斗關鍵步驟、轉換事件不能漏&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>event（高頻 UI）&lt;/td>
 &lt;td>取樣&lt;/td>
 &lt;td>scroll、mousemove、hover 等高頻操作只取部分&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>metric&lt;/td>
 &lt;td>取樣&lt;/td>
 &lt;td>效能指標按時間取樣（每 30 秒一次而非每 frame）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>安全事件&lt;/td>
 &lt;td>全收&lt;/td>
 &lt;td>auth 失敗、權限越界、敏感操作不取樣&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="ab-測試">A/B 測試&lt;/h3>
&lt;p>實驗感測器只對 treatment group 啟用。Control group 不觸發實驗事件，避免污染對照組資料。&lt;/p>
&lt;p>實驗專用事件（&lt;code>experiment.pricing_test.assigned&lt;/code>、&lt;code>experiment.pricing_test.converted&lt;/code>）由 feature flag 控制 — flag 開啟時 SDK 才送這些事件。實驗結束後 flag 關閉，感測器自動停止。&lt;/p>
&lt;p>實驗事件的保留期和實驗週期綁定，實驗結束 + 分析完成後可以 purge。&lt;/p>
&lt;h3 id="功能下線">功能下線&lt;/h3>
&lt;p>功能移除時，對應的感測器 config 一起移除。Collector 端 purge 該功能的歷史事件（或降級到聚合摘要）。&lt;/p>
&lt;p>移除 checklist：SDK config 移除事件名稱 → SDK 版本部署 → 確認 collector 不再收到該事件 → purge 歷史資料（可選）。&lt;/p>
&lt;h2 id="控制機制">控制機制&lt;/h2>
&lt;p>三層控制機制各自適合不同的變更頻率：&lt;/p>
&lt;h3 id="sdk-init-config靜態">SDK init config（靜態）&lt;/h3>
&lt;p>隨 app 版本部署的本地設定檔。變更需要發新版本。適合穩定的感測器組合。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="nt">sensors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">error&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled: true, sampling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">lifecycle&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled: true, sampling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">event&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">funnel.*&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled: true, sampling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">click.*&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled: true, sampling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.1&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metric&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">duration&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled: true, sampling&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.5&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">experiment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pricing_test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>{&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w"> &lt;/span>}&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="collector-端下發動態">Collector 端下發（動態）&lt;/h3>
&lt;p>SDK 啟動時從 collector 的 &lt;code>/config&lt;/code> endpoint 拉取當前的感測器設定。Collector 端修改設定後，下一次 SDK 重啟或定期 refresh（每 5 分鐘）時生效。適合需要動態調整但不值得接 feature flag 服務的場景。&lt;/p></description><content:encoded><![CDATA[<p>感測器的啟用組合隨產品階段變化。早期開發只需要 error 和 lifecycle 幫助 debug，production 上線後需要商業事件和效能量測，A/B 測試期間需要實驗專用感測器。把所有感測器一次全開會浪費頻寬和儲存、產生大量低價值事件；全程只開 error 則在需要行為分析時發現沒有資料。感測器的啟停是設計決策，由 SDK config、collector 下發和 feature flag 三層機制控制。</p>
<h2 id="五個階段">五個階段</h2>
<h3 id="早期開發">早期開發</h3>
<p>開發期的首要需求是 debug — 程式碼寫完跑起來、出問題時能定位。</p>
<table>
  <thead>
      <tr>
          <th>感測器類型</th>
          <th>啟用</th>
          <th>理由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>error</td>
          <td>全開</td>
          <td>每個例外都要看到</td>
      </tr>
      <tr>
          <td>lifecycle</td>
          <td>全開</td>
          <td>app 啟動、連線、狀態轉換的步驟紀錄</td>
      </tr>
      <tr>
          <td>event</td>
          <td>按需</td>
          <td>正在開發的功能手動加埋點，其他關閉</td>
      </tr>
      <tr>
          <td>metric</td>
          <td>關閉</td>
          <td>效能量測在功能穩定前沒有意義</td>
      </tr>
  </tbody>
</table>
<p>開發期的取樣率全部設 1.0（全收）— 事件量極低（開發者自己操作），不需要取樣。</p>
<h3 id="功能測試">功能測試</h3>
<p>針對被測功能開啟完整感測器，驗證功能的行為事件和效能指標是否正確觸發。</p>
<p>被測功能的 event 和 metric 全開。其他功能維持開發期設定。測試期間的感測器設定通常由測試 config 檔覆寫 SDK 預設值。</p>
<h3 id="production-上線">Production 上線</h3>
<p>上線後的感測器組合平衡覆蓋率和成本：</p>
<table>
  <thead>
      <tr>
          <th>感測器類型</th>
          <th>策略</th>
          <th>理由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>error</td>
          <td>全收</td>
          <td>每個 production error 都有 debug 價值</td>
      </tr>
      <tr>
          <td>lifecycle</td>
          <td>全收</td>
          <td>session 分析和環境資訊需要完整紀錄</td>
      </tr>
      <tr>
          <td>event（核心操作）</td>
          <td>全收</td>
          <td>漏斗關鍵步驟、轉換事件不能漏</td>
      </tr>
      <tr>
          <td>event（高頻 UI）</td>
          <td>取樣</td>
          <td>scroll、mousemove、hover 等高頻操作只取部分</td>
      </tr>
      <tr>
          <td>metric</td>
          <td>取樣</td>
          <td>效能指標按時間取樣（每 30 秒一次而非每 frame）</td>
      </tr>
      <tr>
          <td>安全事件</td>
          <td>全收</td>
          <td>auth 失敗、權限越界、敏感操作不取樣</td>
      </tr>
  </tbody>
</table>
<h3 id="ab-測試">A/B 測試</h3>
<p>實驗感測器只對 treatment group 啟用。Control group 不觸發實驗事件，避免污染對照組資料。</p>
<p>實驗專用事件（<code>experiment.pricing_test.assigned</code>、<code>experiment.pricing_test.converted</code>）由 feature flag 控制 — flag 開啟時 SDK 才送這些事件。實驗結束後 flag 關閉，感測器自動停止。</p>
<p>實驗事件的保留期和實驗週期綁定，實驗結束 + 分析完成後可以 purge。</p>
<h3 id="功能下線">功能下線</h3>
<p>功能移除時，對應的感測器 config 一起移除。Collector 端 purge 該功能的歷史事件（或降級到聚合摘要）。</p>
<p>移除 checklist：SDK config 移除事件名稱 → SDK 版本部署 → 確認 collector 不再收到該事件 → purge 歷史資料（可選）。</p>
<h2 id="控制機制">控制機制</h2>
<p>三層控制機制各自適合不同的變更頻率：</p>
<h3 id="sdk-init-config靜態">SDK init config（靜態）</h3>
<p>隨 app 版本部署的本地設定檔。變更需要發新版本。適合穩定的感測器組合。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">sensors</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">error</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled: true, sampling</span><span class="p">:</span><span class="w"> </span><span class="m">1.0</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="nt">lifecycle</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled: true, sampling</span><span class="p">:</span><span class="w"> </span><span class="m">1.0</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="nt">event</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">funnel.*</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled: true, sampling</span><span class="p">:</span><span class="w"> </span><span class="m">1.0</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">click.*</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled: true, sampling</span><span class="p">:</span><span class="w"> </span><span class="m">0.1</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">metric</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">duration</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled: true, sampling</span><span class="p">:</span><span class="w"> </span><span class="m">0.5</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="nt">experiment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="nt">pricing_test</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w"> </span>}</span></span></code></pre></div><h3 id="collector-端下發動態">Collector 端下發（動態）</h3>
<p>SDK 啟動時從 collector 的 <code>/config</code> endpoint 拉取當前的感測器設定。Collector 端修改設定後，下一次 SDK 重啟或定期 refresh（每 5 分鐘）時生效。適合需要動態調整但不值得接 feature flag 服務的場景。</p>
<p>MVP 階段跳過 collector 下發，只用 SDK 本地 config。下發 API 的定義和實作標為第二階段 — 感測器的開關在 SDK 本地 config 已經能完全控制。</p>
<h3 id="feature-flag-服務整合">Feature flag 服務整合</h3>
<p>SDK 在送出事件前查詢 feature flag 判斷感測器是否啟用。適合 A/B 測試 — flag 可以按使用者 / 百分比 / 條件分群啟用。</p>
<h3 id="優先順序">優先順序</h3>
<p>三層控制的覆蓋優先順序：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Feature flag &gt; Collector 下發 &gt; SDK 本地 config</span></span></code></pre></div><p>SDK 本地 config 是 baseline。Collector 下發覆蓋 baseline 的特定欄位。Feature flag 覆蓋一切 — 即使本地 config 和 collector 都說啟用，flag 說關閉就關閉。</p>
<h2 id="取樣率設計">取樣率設計</h2>
<p>取樣率決定「多少比例的事件會被實際送出」。取樣在 SDK 端執行 — 不送的事件不佔頻寬和儲存。</p>
<h3 id="全收sampling-10">全收（sampling: 1.0）</h3>
<p>每筆事件都送。適用於：</p>
<ul>
<li><strong>error</strong>：每個 production error 都有 debug 價值，漏掉的 error 可能是最嚴重的那個</li>
<li><strong>安全事件</strong>：auth 失敗、權限越界的取樣可能讓攻擊嘗試隱形</li>
<li><strong>漏斗關鍵步驟</strong>：funnel 分析的轉換率計算需要精確的步驟計數</li>
</ul>
<h3 id="百分比取樣001-05">百分比取樣（0.01-0.5）</h3>
<p>只送一定比例的事件。適用於高頻且個別事件價值低的場景：</p>
<ul>
<li>scroll / mousemove / hover：每秒觸發數十次，全收會產生大量事件。取樣 1-10% 足以分析使用者行為模式</li>
<li>frame rate 量測：每幀一筆 metric 太多，每秒或每 30 秒取一筆足夠</li>
</ul>
<p>取樣的實作用 SDK 端的隨機數 — <code>if random() &lt; sampling_rate then send(event)</code> — 不需要 server 端參與。</p>
<h3 id="條件取樣retrospective-full-capture">條件取樣（retrospective full capture）</h3>
<p>正常情況取樣，但發生 error 時回溯收集該 session 的全部事件。實作方式是 SDK 在記憶體中保留最近 N 筆事件的環形 buffer，觸發 error 時把 buffer 中的事件一併送出。</p>
<p>條件取樣讓「error session 的上下文完整」和「正常 session 不過度收集」兩個目標共存。</p>
<h2 id="感測器開關的可觀察性">感測器開關的可觀察性</h2>
<p>感測器本身的狀態變化需要被觀察 — 如果感測器靜默失效（config 錯誤導致某類事件停送），開發者可能很久後才發現「怎麼最近沒有 funnel 資料」。</p>
<h3 id="啟動時-log-感測器清單">啟動時 log 感測器清單</h3>
<p>SDK 初始化完成時 log 當前啟用的感測器清單和取樣率。開發者在 debug console 就能看到「哪些感測器在跑」。</p>
<h3 id="config-變更事件">Config 變更事件</h3>
<p>感測器 config 變更時（collector 下發新 config、或 feature flag 變化），SDK 送一個 lifecycle 事件：</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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;lifecycle&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;sensor.config.changed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</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">5</span><span class="cl">    <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="s2">&#34;collector_push&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nt">&#34;changed&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;click.*&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;sampling&#34;</span><span class="p">:</span> <span class="s2">&#34;0.1 → 0.05&#34;</span><span class="p">}},</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nt">&#34;active_sensors&#34;</span><span class="p">:</span> <span class="mi">12</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>這筆事件讓開發者在查詢時能看到「某個時間點感測器 config 改變了」，和事件量的變化做交叉比對。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>感測器偵測哪些行為 → <a href="/blog/monitoring/03-sdk-design/frontend-sensor-design/" data-link-title="前端感測器設計" data-link-desc="什麼行為值得埋感測器、每類感測器的實作方式、取樣策略和效能影響 — 和 auto-intercept 的被動攔截互補">前端感測器設計</a></li>
<li>SDK 的公開 API → <a href="/blog/monitoring/03-sdk-design/public-api/" data-link-title="SDK 公開 API 設計" data-link-desc="init / event / error / metric / flush / close 六個方法構成 SDK 的完整生命週期 — 跨平台共用相同 API 介面">SDK 公開 API 設計</a></li>
<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/event-enumeration-method/" data-link-title="事件枚舉與補齊檢查" data-link-desc="從操作盤點系統性地推導出完整的事件清單 — 四類補齊檢查確保沒有遺漏、粒度判準確保每個事件只記一個事實">事件枚舉與補齊檢查</a></li>
</ul>
]]></content:encoded></item><item><title>Feature Flag</title><link>https://tarrragon.github.io/blog/backend/knowledge-cards/feature-flag/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/knowledge-cards/feature-flag/</guid><description>&lt;p>Feature flag 的核心概念是「把功能啟用控制與部署分離」。它可用於灰度發布、A/B 測試與緊急關閉。 可先對照 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/full-text-search/" data-link-title="Full-Text Search" data-link-desc="說明全文檢索如何處理關鍵字匹配、語言分析與排序">Full-Text Search&lt;/a>。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>常出現在高風險功能、實驗功能與跨租戶差異化控制。 可先對照 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/full-text-search/" data-link-title="Full-Text Search" data-link-desc="說明全文檢索如何處理關鍵字匹配、語言分析與排序">Full-Text Search&lt;/a>。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>設計時要定義旗標生命週期、預設值、回退策略與清理節點，避免旗標長期堆積。&lt;/p></description><content:encoded><![CDATA[<p>Feature flag 的核心概念是「把功能啟用控制與部署分離」。它可用於灰度發布、A/B 測試與緊急關閉。 可先對照 <a href="/blog/backend/knowledge-cards/full-text-search/" data-link-title="Full-Text Search" data-link-desc="說明全文檢索如何處理關鍵字匹配、語言分析與排序">Full-Text Search</a>。</p>
<h2 id="概念位置">概念位置</h2>
<p>常出現在高風險功能、實驗功能與跨租戶差異化控制。 可先對照 <a href="/blog/backend/knowledge-cards/full-text-search/" data-link-title="Full-Text Search" data-link-desc="說明全文檢索如何處理關鍵字匹配、語言分析與排序">Full-Text Search</a>。</p>
<h2 id="設計責任">設計責任</h2>
<p>設計時要定義旗標生命週期、預設值、回退策略與清理節點，避免旗標長期堆積。</p>
]]></content:encoded></item></channel></rss>