OpenTelemetry (OTel) 官網的開場白是「OpenTelemetry is a collection of APIs, SDKs, and tools.」,本章聚焦在生成階段,整理如何透過各語言的 SDK,特別是自動插樁(Auto Instrumentation),快速地在現有服務中產生 Telemetry Data。

兩種 Instrumentation 模式#

OpenTelemetry 將「在程式中埋設追蹤點」這件事抽象為 Instrumentation(中文常譯為「儀器化」),並提供兩種模式:

  • 手動插樁(Manual Instrumentation):相較於直接呼叫 SDK API,這層封裝較為簡潔,但仍需要在程式碼中明確建立 Span 與屬性。
  • 自動插樁(Auto Instrumentation):不需修改程式碼,搭配特定語言或框架即可自動產生 Telemetry Data,目前覆蓋 .NET、Java、JavaScript、PHP、Python 等主要語言。

由於 Auto Instrumentation 對既有服務的侵入性最低,本章以它為主進行介紹。

自動插樁的資料流向#

當服務套上 Auto Instrumentation 後,整體資料流大致是:

  • Auto Instrumentation 自動生成 Telemetry Data 並送出。
  • Tracing Backend(如 Zipkin、Jaeger、Tempo)負責收集與儲存。
  • 使用者透過對應 UI(Zipkin UI、Jaeger UI、Grafana)查詢與分析。

它通常以 Filter 或 Middleware 的方式套在應用程式外層,自動判斷 Request 是否已帶有 Trace ID,若有則沿用,沒有就生成新的。例如三個串連的服務 APP A → APP B → APP C,當 A、B 都有 Auto Instrumentation 而 C 沒有時,A 與 B 之間的 Span 會以同一組 Trace ID 串聯,但 C 內部就不會被收集。

常用環境變數#

Auto Instrumentation 的設定方式因語言而異,但多半透過環境變數或設定檔。以下是幾個跨語言常用的環境變數:

  • OTEL_TRACES_EXPORTER:選擇 Trace 傳送方式,例如 otlpjaeger
    • OTEL_EXPORTER_OTLP_ENDPOINT:OTLP 對應的 Endpoint,例如 http://localhost:4317
    • OTEL_EXPORTER_JAEGER_ENDPOINT:Jaeger 對應的 Endpoint,例如 http://localhost:14250
  • 服務名稱可透過下列任一方式設定:
    • OTEL_SERVICE_NAME:直接指定服務名稱,例如 service-a
    • OTEL_RESOURCE_ATTRIBUTES:以資源屬性方式設定 service.name=service-a
  • OTEL_PROPAGATORS:設定 Tracing Header 的傳遞格式,可用 , 串接多個,預設為 tracecontext,baggage,跨工具整合時常需調整。

目前內容最完整的環境變數說明是 Java 的 OpenTelemetry SDK Autoconfigure 文件,由於這些變數設計上是跨語言共用,其他語言也可以參考使用。

Log 中加入 Trace ID#

在多執行緒環境下,不同 Request 的 Log 容易交錯,難以追查問題。透過 SDK 與 Log Pattern 的搭配,可以將 Trace ID 寫入 Log,從 Trace 出發後就能用 Trace ID 反查相關 Log。範例如下:

[2021-10-13 10:00:00,000] [INFO] [trace_id=123] [class=Main] [message=Hello World]
[2021-10-13 10:00:01,000] [INFO] [trace_id=456] [class=Worker] [message=Hello World]
[2021-10-13 10:00:02,000] [INFO] [trace_id=456] [class=Worker] [message=Hello World]
[2021-10-13 10:00:03,000] [INFO] [trace_id=123] [class=Worker] [message=Hello World]

不同語言有對應的整合方式,例如 Python 透過 OpenTelemetry Logging Instrumentation,Java 則搭配 Log4j、Logback 與 Logger MDC auto-instrumentation。

Python 自動插樁#

在 Python 中啟用 Auto Instrumentation,至少需要安裝以下三類套件:

  • opentelemetry-distro:一次安裝 API、SDK 與 Instrumentation 的整合套件。
  • opentelemetry-exporter:依後端選擇對應的 Exporter,例如 opentelemetry-exporter-otlpopentelemetry-exporter-jaeger
  • opentelemetry-instrumentation:針對特定套件或框架的 Instrumentation Library,如 Flask、FastAPI、requests 對應的 instrumentation。

也可以使用 opentelemetry-bootstrap 指令掃描環境並自動安裝對應的 Instrumentation Library:

opentelemetry-bootstrap -a install

啟動服務時,使用 opentelemetry-instrument 指令包住原本的 Python 程式:

opentelemetry-instrument python main.py

設定方式有兩種,可使用環境變數,也可使用 CLI 參數:

# 使用 Environment Variables
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 opentelemetry-instrument python main.py

# 使用 CLI arguments
opentelemetry-instrument --exporter_otlp_endpoint http://localhost:4317 python main.py

完整的 CLI 參數可透過 opentelemetry-instrument --help 查詢。

Java 自動插樁#

Java 的 Auto Instrumentation 支援 Java 8 以上版本,啟動後會自動捕捉服務的進出 Request、外部呼叫與資料庫操作等。啟用方式是在執行時透過 -javaagent 指定 OpenTelemetry Instrumentation for Java 的 agent jar:

java -javaagent:path/to/opentelemetry-javaagent.jar -jar myapp.jar

設定方式按優先順序由高到低分為 System Properties、Environment Variables、Configuration File 與 ConfigPropertySource SPI。以指定 OTLP Endpoint 為例:

  • System Properties:
java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.exporter.otlp.endpoint=http://localhost:4317 \
     -jar myapp.jar
  • Environment Variables:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 java -javaagent:path/to/opentelemetry-javaagent.jar -jar myapp.jar
  • Configuration File:
java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.javaagent.configuration-file=path/to/otel.properties \
     -jar myapp.jar

對應 otel.properties 內容例如:

otel.exporter.otlp.endpoint=http://localhost:4317

小結#

OpenTelemetry SDK 與 Auto Instrumentation 的組合,讓既有服務能夠在最少改動下開始輸出 Trace。對於想要快速導入 Tracing 的團隊,先用自動插樁建立全鏈路骨幹,再針對關鍵業務邏輯補上手動插樁,是相對務實的策略。

原文出處#

  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10334220