Observability 是手段,不是目的。透過 Auto-Instrumentation,我們更接近「讓系統自己說話」的願景。
在 COSCUP 2024 我有幸(不要臉) 再次參與並分享這一年來我在可觀測性實踐上最有趣的內容:「OpenTelemetry 的 Auto-Instrumentation 技術核心與應用實戰」。這篇文章,我會完整拆解 OpenTelemetry SDK 的 Auto-Instrumentation 的原理、架構、實務流程,並從開發者的視角出發,帶你理解什麼是「讓系統自己說話」,希望可以讓想要了解 OTel SDK 底層細節實作的朋友有幫助。
OpenTelemetry 是什麼
OpenTelemetry(簡稱 OTel)是 CNCF(Cloud Native Computing Foundation)旗下的觀測性開源計畫。它整合了 OpenTracing 和 OpenCensus,成為雲原生時代的統一觀測標準。
它主要處理三件事:
- Instrument:幫助你從應用中收集觀測訊號(Signals)
- OTLP:無論是 Trace、Metric 還是 Log,都有標準格式
- Export:支援多種後端(如 Jaeger、Zipkin、Grafana Tempo、Prometheus...)
OpenTelemetry 是目前 CNCF 第二活躍的專案(僅次於 Kubernetes),也是現代 Observability 的標準。
Code-based v.s zero-code
讓程式「可以被觀察」,首先就要「儀表化」程式碼(Instrumentation)。這裡透過一張表整理 Code-based 與 zero-code 兩者的差異,更重要的是實際應用場景
小小建議:「Auto-Instrumentation 優先、Manual 優化補強」Auto-Instrumentation 設計願景
根據 OpenTelemetry .NET Auto-Instrumentation 官方設計文件,這個 SDK 是以五大設計願景(Vision)為核心來開發的,每一個願景都對應到實務中我們真正關心的「導入門檻」、「維運穩定」、「擴充能力」。
高效能(High Performance)- 使用 IL 重寫,不改原始碼
- Lazy Loading 降低資源開銷
- 非同步匯出 Trace 資料
- 內建常見欄位與框架支援
- 啟動即生效
- 錯誤不影響應用
- 具容錯能力與 fallback
- 啟動時列出已啟用套件
- 支援 metrics 與 debug mode
- 插件化結構,支援自定義與社群套件
Auto-Instrumentation 架構與元件 Application & Runtime(應用與執行環境)
- Application IL(中間語言)
.NET 應用程式編譯後的中間碼,是 Auto-Instrumentation 插入追蹤邏輯的目標對象。 - CLR(Common Language Runtime)
.NET 的執行核心,提供 ICorProfilerCallback / ICorProfilerInfo 介面供原生 Profiler 攔截執行事件與注入邏輯。
- 職責: 掛載在 CLR 上,透過 ICorProfiler API 攔截應用啟動流程。
- 功能: 將 Bytecode Instrumentation 插入 Application IL,實現 Zero-code Observability。
- 職責: 為特定框架提供具體的儀表邏輯,例如對 HttpClient、SQLClient、gRPC 注入觀測碼。
- 功能: 在 method 內部插入 OTel API(如 StartSpan、SetAttribute)。
- 職責: 在應用執行階段進行進一步的邏輯注入與監控。
- 用途: 管理細部的 Trace 拓展,例如更細緻的 DB query 或 gRPC 呼叫資訊。
- Source Instrumentation: 指開發者手動使用 OTel API(例如 tracer.StartActiveSpan())插入觀測點。
- OTel SDK: 提供觀測資料處理能力,負責收集、封裝並導出 Trace、Metrics、Logs 至後端。
- 啟動階段: OTel CLR Profiler 掛載至 CLR,監控模組與 method 載入事件。
- 注入階段: Bytecode Instrumentations 對 IL 方法注入 StartSpan 等邏輯。
- 執行階段: Managed Profiler 進一步補強觀測點(如內部呼叫、Async 方法)。
- 資料導出: 所有訊號被 OTel SDK 收集後導出至 Tempo、Jaeger 等觀測平台。
設計重點 : 「模組化、低侵入、高彈性」
三大流程解析
註冊流程 重點:
- 設定環境變數:
- CORECLR_ENABLE_PROFILING=1
- CORECLR_PROFILER=OTel CLSID
- CORECLR_PROFILER_PATH=Profiler DLL 路徑
- CoreCLR 啟動階段:
- 檢查是否啟用 Profiling
- 從 Registry 查找 CLSID 對應 DLL
- 解析出 Profiler 的實際路徑
- 載入與初始化:
- 載入 Profiler DLL
- 呼叫 Initialize 方法註冊
- 透過 ICorProfilerInfo 註冊事件攔截(Set Event Mask)
請求流程 重點 : 系統如何自動蒐集數據 Data (自己說話)
- 應用啟動: CoreCLR 發出多種事件通知,包括類別載入、JIT 編譯、方法進入與離開等。
- OTel CLR Profiler 攔截: 根據事件動態判斷並透過 IL 注入觀測邏輯(Bytecode Instrumentation)。
- Managed Profiler 建立與關閉 Span: 當方法被呼叫(FunctionEnter)時建立 Span;完成(FunctionLeave)後關閉該 Span。
- 外部服務呼叫: 如果方法內呼叫外部服務(API、DB),會建立額外的子 Span 表示呼叫鏈。
- OTel SDK 負責收集與導出: 所有已關閉的 Span 會統一被 SDK 收集並匯出至後端系統,如 Jaeger 或 Grafana Tempo。
- Application: 應用程式啟動,觸發 Auto-Instrumentation。
- OTel CLR Profiler: 原生層級注入元件,處理 IL 攔截與上下文傳遞。
- Bytecode Instrumentation: 插入具體的追蹤邏輯至目標方法(如 HTTP 請求)。
- OTel Managed Profiler: 管理應用邏輯層級的觀測行為,呼叫 Instrumentation Handler。
- OTel SDK: 中央資料處理站,封裝資料並準備匯出。
- Collector: 集中資料後導出至 Jaeger(Trace)或 Prometheus(Metrics)。
ASP.NET Core 實作範例
- services.AddOpenTelemetry()
- .WithTracing(builder => builder
- .AddAspNetCoreInstrumentation()
- .AddHttpClientInstrumentation()
- .AddGrpcClientInstrumentation()
- .AddOtlpExporter());
這段程式會自動收集:
- http.method, http.status_code, http.url
- trace_id, span_id, user_agent.original
- Application : 在應用程式層級攔截整體 ASP.NET Core 的 Middleware Pipeline。自動追蹤整個 HTTP 請求從進入到離開的過程。
- Controller : 對個別 Controller 進行觀測,例如:哪個 endpoint 被呼叫、哪些路由參數被解析
- 程式對外發出的 HTTP 請求(如 API 呼叫)
- gRPC 呼叫事件,包含 method 名、service 名、status code
- 只要你用標準的 HttpClient 或 .NET gRPC,這些都會被攔截、追蹤並補上 TraceContext。
- 把觀測資料送到你的可視化平台
- 例如 : OTLP → Grafana Tempo / Honeycomb / Lightstep / Jaeger / New Relic
Container Component
小結
Auto-Instrumentation 讓開發者可以不用動原始碼,就輕鬆讓系統「說出程式碼執行的狀態」,對於初學者在導入可觀測性文化中重要的環節,希望這篇介紹 Auto-Instrumentation 對各位有幫助,若以上內容有不清處的地方,歡迎留言討論,Hayyp Coding :)
參考
opentelemetry-dotnet
opentelemetry-dotnet-instrumentation
opentelemetry-dotnet-instrumentation/docs/design.md
dotnet/runtime/blob/main/docs/design/coreclr/botr/profiling
0 意見:
張貼留言