<?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>Auto-Intercept on Tarragon</title><link>https://tarrragon.github.io/blog/tags/auto-intercept/</link><description>Recent content in Auto-Intercept 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/auto-intercept/index.xml" rel="self" type="application/rss+xml"/><item><title>自動攔截機制</title><link>https://tarrragon.github.io/blog/monitoring/03-sdk-design/auto-intercept/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/03-sdk-design/auto-intercept/</guid><description>&lt;p>自動攔截機制讓 SDK 在開發者不寫任何 error 上報程式碼的情況下，自動捕獲未處理的例外並記錄為 error 事件。每個平台有各自的全域錯誤處理器，SDK 在 init 時註冊攔截器，捕獲後轉換為統一的 error 事件格式送出。&lt;/p>
&lt;h2 id="各平台的攔截點">各平台的攔截點&lt;/h2>
&lt;h3 id="javascript--typescript">JavaScript / TypeScript&lt;/h3>
&lt;p>JS 環境有兩個全域錯誤攔截點：&lt;/p>
&lt;p>&lt;code>window.onerror&lt;/code> 捕獲同步程式碼中未處理的例外。回呼函式收到 error message、來源 URL、行號、列號和 Error 物件。&lt;/p>
&lt;p>&lt;code>window.onunhandledrejection&lt;/code> 捕獲未處理的 Promise rejection。回呼函式收到 PromiseRejectionEvent，包含 rejection reason。&lt;/p>
&lt;p>SDK 在 init 時註冊這兩個處理器。註冊前先保存原有的處理器（如果有），攔截後先呼叫原有處理器再執行 SDK 的記錄邏輯 — 避免覆蓋應用程式已有的錯誤處理。&lt;/p>
&lt;p>限制：&lt;code>onerror&lt;/code> 對跨域腳本的錯誤只收到 &lt;code>Script error.&lt;/code> 訊息，沒有 stack trace。需要在 &lt;code>&amp;lt;script&amp;gt;&lt;/code> 標籤加 &lt;code>crossorigin&lt;/code> 屬性，server 端的 CORS header 加 &lt;code>Access-Control-Allow-Origin&lt;/code>。&lt;/p>
&lt;h3 id="flutter">Flutter&lt;/h3>
&lt;p>Flutter 有兩個攔截層：&lt;/p>
&lt;p>&lt;code>FlutterError.onError&lt;/code> 捕獲 widget build / layout / paint 過程中的例外。預設行為是在 console 印出錯誤，SDK 替換為記錄 error 事件後再呼叫預設處理器。&lt;/p>
&lt;p>&lt;code>PlatformDispatcher.instance.onError&lt;/code> 捕獲其他非同步區域的未處理例外（Dart 2.15+）。包含 Isolate 內的未捕獲例外。&lt;/p>
&lt;p>&lt;code>runZonedGuarded&lt;/code> 是另一個選項 — 在指定的 Zone 內捕獲所有未處理例外。SDK 可以用 &lt;code>runZonedGuarded&lt;/code> 包住整個 &lt;code>runApp()&lt;/code>，但這和 &lt;code>PlatformDispatcher.onError&lt;/code> 有重疊，需要避免同一個例外被記錄兩次。&lt;/p>
&lt;p>限制：Flutter 的 release mode 會移除 stack trace 的符號資訊（obfuscation）。需要保留 debug symbols 檔案（&lt;code>.dSYM&lt;/code> / &lt;code>mapping.txt&lt;/code>），在 collector 端做 symbolication。&lt;/p>
&lt;h3 id="python">Python&lt;/h3>
&lt;p>&lt;code>sys.excepthook&lt;/code> 處理主執行緒的未捕獲例外。回呼函式收到 exception type、value 和 traceback。&lt;/p>
&lt;p>&lt;code>threading.excepthook&lt;/code>（Python 3.8+）處理子執行緒的未捕獲例外。&lt;/p>
&lt;p>&lt;code>atexit.register&lt;/code> 用於在 Python 程序退出時 flush 剩餘的 buffer。但 &lt;code>atexit&lt;/code> 在 &lt;code>os._exit()&lt;/code> 或 SIGKILL 時不會執行。&lt;/p>
&lt;p>限制：Python 的 GIL 讓 SDK 的網路操作可能阻塞主執行緒。SDK 的 flush 應該在獨立的 daemon thread 中執行，主執行緒只負責把事件放入 buffer。&lt;/p>
&lt;h2 id="攔截後的統一處理">攔截後的統一處理&lt;/h2>
&lt;p>不同平台的錯誤物件格式不同（JS 的 Error、Flutter 的 FlutterErrorDetails、Python 的 sys.exc_info tuple）。SDK 在攔截後把平台特定的錯誤物件轉換為統一的 error 事件格式：&lt;/p>
&lt;ul>
&lt;li>type: &lt;code>&amp;quot;error&amp;quot;&lt;/code>&lt;/li>
&lt;li>name: 從 error class name 推導（&lt;code>TypeError&lt;/code> → &lt;code>error.TypeError&lt;/code>）&lt;/li>
&lt;li>data: 包含 message、stack trace（字串化）、觸發位置&lt;/li>
&lt;/ul>
&lt;p>轉換層是每個平台 SDK 唯一的平台特定程式碼。轉換完成後，事件進入和手動上報相同的 buffer → flush 管線。&lt;/p>
&lt;h2 id="和手動上報的分工">和手動上報的分工&lt;/h2>
&lt;p>自動攔截處理「開發者沒有預期到的錯誤」— 未捕獲的例外、未處理的 rejection。手動上報（&lt;code>Monitor.error()&lt;/code>）處理「開發者知道可能發生但想記錄的錯誤」— 已捕獲的例外、業務邏輯的異常狀態。&lt;/p>
&lt;p>兩者進入同一個 buffer 和 flush 管線，在 collector 端可以用 data 中的 &lt;code>source: &amp;quot;auto&amp;quot;&lt;/code> / &lt;code>source: &amp;quot;manual&amp;quot;&lt;/code> 欄位區分。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>SDK 公開 API → &lt;a href="https://tarrragon.github.io/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 設計&lt;/a>&lt;/li>
&lt;li>各平台的深入適配問題 → &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;/li>
&lt;li>Buffer 和 flush → &lt;a href="https://tarrragon.github.io/blog/monitoring/03-sdk-design/batch-flush/" data-link-title="攢批送出策略" data-link-desc="flush interval / buffer size / flush on close 三個控制點決定事件何時離開 SDK — 平衡即時性和網路效率">攢批送出策略&lt;/a>&lt;/li>
&lt;li>主動感測器設計（和被動攔截互補）→ &lt;a href="https://tarrragon.github.io/blog/monitoring/03-sdk-design/frontend-sensor-design/" data-link-title="前端感測器設計" data-link-desc="什麼行為值得埋感測器、每類感測器的實作方式、取樣策略和效能影響 — 和 auto-intercept 的被動攔截互補">前端感測器設計&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>自動攔截機制讓 SDK 在開發者不寫任何 error 上報程式碼的情況下，自動捕獲未處理的例外並記錄為 error 事件。每個平台有各自的全域錯誤處理器，SDK 在 init 時註冊攔截器，捕獲後轉換為統一的 error 事件格式送出。</p>
<h2 id="各平台的攔截點">各平台的攔截點</h2>
<h3 id="javascript--typescript">JavaScript / TypeScript</h3>
<p>JS 環境有兩個全域錯誤攔截點：</p>
<p><code>window.onerror</code> 捕獲同步程式碼中未處理的例外。回呼函式收到 error message、來源 URL、行號、列號和 Error 物件。</p>
<p><code>window.onunhandledrejection</code> 捕獲未處理的 Promise rejection。回呼函式收到 PromiseRejectionEvent，包含 rejection reason。</p>
<p>SDK 在 init 時註冊這兩個處理器。註冊前先保存原有的處理器（如果有），攔截後先呼叫原有處理器再執行 SDK 的記錄邏輯 — 避免覆蓋應用程式已有的錯誤處理。</p>
<p>限制：<code>onerror</code> 對跨域腳本的錯誤只收到 <code>Script error.</code> 訊息，沒有 stack trace。需要在 <code>&lt;script&gt;</code> 標籤加 <code>crossorigin</code> 屬性，server 端的 CORS header 加 <code>Access-Control-Allow-Origin</code>。</p>
<h3 id="flutter">Flutter</h3>
<p>Flutter 有兩個攔截層：</p>
<p><code>FlutterError.onError</code> 捕獲 widget build / layout / paint 過程中的例外。預設行為是在 console 印出錯誤，SDK 替換為記錄 error 事件後再呼叫預設處理器。</p>
<p><code>PlatformDispatcher.instance.onError</code> 捕獲其他非同步區域的未處理例外（Dart 2.15+）。包含 Isolate 內的未捕獲例外。</p>
<p><code>runZonedGuarded</code> 是另一個選項 — 在指定的 Zone 內捕獲所有未處理例外。SDK 可以用 <code>runZonedGuarded</code> 包住整個 <code>runApp()</code>，但這和 <code>PlatformDispatcher.onError</code> 有重疊，需要避免同一個例外被記錄兩次。</p>
<p>限制：Flutter 的 release mode 會移除 stack trace 的符號資訊（obfuscation）。需要保留 debug symbols 檔案（<code>.dSYM</code> / <code>mapping.txt</code>），在 collector 端做 symbolication。</p>
<h3 id="python">Python</h3>
<p><code>sys.excepthook</code> 處理主執行緒的未捕獲例外。回呼函式收到 exception type、value 和 traceback。</p>
<p><code>threading.excepthook</code>（Python 3.8+）處理子執行緒的未捕獲例外。</p>
<p><code>atexit.register</code> 用於在 Python 程序退出時 flush 剩餘的 buffer。但 <code>atexit</code> 在 <code>os._exit()</code> 或 SIGKILL 時不會執行。</p>
<p>限制：Python 的 GIL 讓 SDK 的網路操作可能阻塞主執行緒。SDK 的 flush 應該在獨立的 daemon thread 中執行，主執行緒只負責把事件放入 buffer。</p>
<h2 id="攔截後的統一處理">攔截後的統一處理</h2>
<p>不同平台的錯誤物件格式不同（JS 的 Error、Flutter 的 FlutterErrorDetails、Python 的 sys.exc_info tuple）。SDK 在攔截後把平台特定的錯誤物件轉換為統一的 error 事件格式：</p>
<ul>
<li>type: <code>&quot;error&quot;</code></li>
<li>name: 從 error class name 推導（<code>TypeError</code> → <code>error.TypeError</code>）</li>
<li>data: 包含 message、stack trace（字串化）、觸發位置</li>
</ul>
<p>轉換層是每個平台 SDK 唯一的平台特定程式碼。轉換完成後，事件進入和手動上報相同的 buffer → flush 管線。</p>
<h2 id="和手動上報的分工">和手動上報的分工</h2>
<p>自動攔截處理「開發者沒有預期到的錯誤」— 未捕獲的例外、未處理的 rejection。手動上報（<code>Monitor.error()</code>）處理「開發者知道可能發生但想記錄的錯誤」— 已捕獲的例外、業務邏輯的異常狀態。</p>
<p>兩者進入同一個 buffer 和 flush 管線，在 collector 端可以用 data 中的 <code>source: &quot;auto&quot;</code> / <code>source: &quot;manual&quot;</code> 欄位區分。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<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/05-platform-adaptation/" data-link-title="模組五：平台適配" data-link-desc="JS CORS / Flutter isolate / Python GIL / Go graceful shutdown — 各平台的特殊考量">模組五 平台適配</a></li>
<li>Buffer 和 flush → <a href="/blog/monitoring/03-sdk-design/batch-flush/" data-link-title="攢批送出策略" data-link-desc="flush interval / buffer size / flush on close 三個控制點決定事件何時離開 SDK — 平衡即時性和網路效率">攢批送出策略</a></li>
<li>主動感測器設計（和被動攔截互補）→ <a href="/blog/monitoring/03-sdk-design/frontend-sensor-design/" data-link-title="前端感測器設計" data-link-desc="什麼行為值得埋感測器、每類感測器的實作方式、取樣策略和效能影響 — 和 auto-intercept 的被動攔截互補">前端感測器設計</a></li>
</ul>
]]></content:encoded></item></channel></rss>