前往檢測設備範例

本文說明如何使用 OpenTelemetry SDK 和 OpenTelemetry 收集器,檢測 Go 應用程式以收集追蹤記錄和指標資料。本文也說明如何將結構化 JSON 記錄寫入標準輸出。如要試用檢測設備,請下載並執行範例應用程式。該應用程式會產生記錄、指標和追蹤記錄資料。

使用 OpenTelemetry 收集器時,請透過 SDK 和 SDK 的 OTLP 處理中匯出工具,檢測應用程式。這項儀表是中立的供應商。您也會部署 OpenTelemetry 收集器,接收來自程序內匯出工具的遙測資料,然後將該遙測資料匯出至 Google Cloud 專案。如要進一步瞭解收集器,請參閱「Google 打造的 OpenTelemetry 收集器」。

如果您的環境支援使用收集器,建議您使用 OpenTelemetry 收集器匯出遙測資料。在某些環境中,您必須使用程序內匯出工具,直接將資料傳送至Google Cloud 專案。如要瞭解程序內檢測,請參閱「從 Trace 匯出工具遷移至 OTLP 端點」。

如要進一步瞭解插樁,請參閱下列文件:

關於情境

OpenTelemetry 的「Context」機制,可在程序內的 API 間傳遞執行範圍的值。脈絡的重要用途是攜帶目前作用中的範圍,以便修改或在建立任何新範圍時,做為這些範圍的父項。摘要:

  • 背景資訊是指在程序中,透過 API 傳播執行範圍值的機制,包括目前有效的範圍。

  • 跨度內容是每個跨度上的不可變動物件,包含追蹤記錄 ID、跨度 ID,以及追蹤記錄的旗標和狀態。

  • 傳播是將內容在服務和程序之間移動的機制。

Go 標準程式庫的 context.Context 也會跨 API 邊界傳輸範圍值。通常,伺服器中的處理常式函式會接收傳入的 Context,並透過呼叫鏈將其傳遞至發出外送要求的任何用戶端。

Go 的標準程式庫 context.Context 用於實作 Go 中的 OpenTelemetry 內容。

事前準備

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. 安裝 Google Cloud CLI。

  3. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  4. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  5. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  6. 確認專案已啟用計費功能 Google Cloud

  7. 啟用 Cloud Logging、Cloud Monitoring、Cloud Trace 和 Telemetry API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable logging.googleapis.com monitoring.googleapis.com cloudtrace.googleapis.com telemetry.googleapis.com
  8. 安裝 Google Cloud CLI。

  9. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  10. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  11. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  12. 確認專案已啟用計費功能 Google Cloud

  13. 啟用 Cloud Logging、Cloud Monitoring、Cloud Trace 和 Telemetry API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable logging.googleapis.com monitoring.googleapis.com cloudtrace.googleapis.com telemetry.googleapis.com
  14. 如果您在 Cloud Shell、 Google Cloud資源或本機開發環境中執行範例,則本節列出的權限就足夠。對於正式版應用程式,通常是服務帳戶提供寫入記錄、指標和追蹤資料的憑證。

    如要取得範例應用程式寫入記錄、指標和追蹤資料所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

    如要取得查看記錄、指標和追蹤資料所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

    如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

    您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

檢測應用程式,收集追蹤記錄、指標和記錄

如要為應用程式進行檢測,以收集追蹤記錄和指標資料,並將結構化 JSON 寫入標準輸出,請按照本文件後續章節所述步驟操作:

  1. 設定主要函式
  2. 設定 OpenTelemetry
  3. 設定結構化記錄
  4. 在 HTTP 伺服器中新增檢測
  5. 將追蹤記錄範圍與記錄和指標連結
  6. 在 HTTP 用戶端中新增檢測
  7. 寫入結構化記錄檔

設定主要函式

如要設定應用程式,使用 OpenTelemetry 寫入結構化記錄,並收集指標和追蹤資料,請更新 main 函式,設定 Go 結構化記錄套件 slog,以及設定 OpenTelemetry。

下列程式碼範例說明 main 函式,該函式會呼叫兩個輔助函式 setupLogging()setupOpenTelemetry()。這些輔助函式會設定記錄套件和 OpenTelemetry。

如要查看完整範例,請按一下「更多」,然後選取「在 GitHub 上查看」

func main() {
	ctx := context.Background()

	// Setup logging
	setupLogging()

	// Setup metrics, tracing, and context propagation
	shutdown, err := setupOpenTelemetry(ctx)
	if err != nil {
		slog.ErrorContext(ctx, "error setting up OpenTelemetry", slog.Any("error", err))
		os.Exit(1)
	}

	// Run the http server, and shutdown and flush telemetry after it exits.
	slog.InfoContext(ctx, "server starting...")
	if err = errors.Join(runServer(), shutdown(ctx)); err != nil {
		slog.ErrorContext(ctx, "server exited with error", slog.Any("error", err))
		os.Exit(1)
	}
}

設定記錄套件後,如要將記錄檔連結至追蹤資料,請將 Go Context 傳遞至記錄器。詳情請參閱本文的「寫入結構化記錄」一節。

設定 OpenTelemetry

如要使用 OTLP 通訊協定收集及匯出追蹤記錄和指標,請設定全域 TracerProviderMeterProvider 例項。下列程式碼範例說明 setupOpenTelemetry 函式,該函式是從 main 函式呼叫:

func setupOpenTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) {
	var shutdownFuncs []func(context.Context) error

	// shutdown combines shutdown functions from multiple OpenTelemetry
	// components into a single function.
	shutdown = func(ctx context.Context) error {
		var err error
		for _, fn := range shutdownFuncs {
			err = errors.Join(err, fn(ctx))
		}
		shutdownFuncs = nil
		return err
	}

	// Configure Context Propagation to use the default W3C traceparent format
	otel.SetTextMapPropagator(autoprop.NewTextMapPropagator())

	// Configure Trace Export to send spans as OTLP
	texporter, err := autoexport.NewSpanExporter(ctx)
	if err != nil {
		err = errors.Join(err, shutdown(ctx))
		return
	}
	tp := trace.NewTracerProvider(trace.WithBatcher(texporter))
	shutdownFuncs = append(shutdownFuncs, tp.Shutdown)
	otel.SetTracerProvider(tp)

	// Configure Metric Export to send metrics as OTLP
	mreader, err := autoexport.NewMetricReader(ctx)
	if err != nil {
		err = errors.Join(err, shutdown(ctx))
		return
	}
	mp := metric.NewMeterProvider(
		metric.WithReader(mreader),
	)
	shutdownFuncs = append(shutdownFuncs, mp.Shutdown)
	otel.SetMeterProvider(mp)

	return shutdown, nil
}

先前的程式碼範例會將全域 TextMapPropagator 設定為使用 W3C 追蹤內容格式,傳播追蹤內容。這項設定可確保追蹤記錄中的範圍具有正確的父項與子項關係。

為確保所有待處理的遙測資料都已排清,且連線已正常關閉,setupOpenTelemetry 函式會傳回名為 shutdown 的函式,執行這些動作。

設定結構化記錄

如要將追蹤資訊納入寫入標準輸出的 JSON 格式記錄,請設定 Go 結構化記錄套件 slog。下列程式碼範例說明 setupLogging 函式,該函式是從 main 函式呼叫:

func setupLogging() {
	// Use json as our base logging format.
	jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ReplaceAttr: replacer})
	// Add span context attributes when Context is passed to logging calls.
	instrumentedHandler := handlerWithSpanContext(jsonHandler)
	// Set this handler as the global slog handler.
	slog.SetDefault(slog.New(instrumentedHandler))
}

先前的程式碼會呼叫 handlerWithSpanContext 函式,該函式會從 Context 例項擷取資訊,並將該資訊做為屬性新增至記錄檔。這些屬性可用於將記錄與追蹤記錄建立關聯:

  • logging.googleapis.com/trace:與記錄項目相關聯的追蹤記錄資源名稱。
  • logging.googleapis.com/spanId:與記錄項目相關聯的追蹤記錄時距 ID。
  • logging.googleapis.com/trace_sampled:這個欄位的值必須是 truefalse

如要進一步瞭解這些欄位,請參閱 LogEntry 結構。

func handlerWithSpanContext(handler slog.Handler) *spanContextLogHandler {
	return &spanContextLogHandler{Handler: handler}
}

// spanContextLogHandler is a slog.Handler which adds attributes from the
// span context.
type spanContextLogHandler struct {
	slog.Handler
}

// Handle overrides slog.Handler's Handle method. This adds attributes from the
// span context to the slog.Record.
func (t *spanContextLogHandler) Handle(ctx context.Context, record slog.Record) error {
	// Get the SpanContext from the context.
	if s := trace.SpanContextFromContext(ctx); s.IsValid() {
		// Add trace context attributes following Cloud Logging structured log format described
		// in https://cloud.google.com/logging/docs/structured-logging#special-payload-fields
		record.AddAttrs(
			slog.Any("logging.googleapis.com/trace", s.TraceID()),
		)
		record.AddAttrs(
			slog.Any("logging.googleapis.com/spanId", s.SpanID()),
		)
		record.AddAttrs(
			slog.Bool("logging.googleapis.com/trace_sampled", s.TraceFlags().IsSampled()),
		)
	}
	return t.Handler.Handle(ctx, record)
}

func replacer(groups []string, a slog.Attr) slog.Attr {
	// Rename attribute keys to match Cloud Logging structured log format
	switch a.Key {
	case slog.LevelKey:
		a.Key = "severity"
		// Map slog.Level string values to Cloud Logging LogSeverity
		// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
		if level := a.Value.Any().(slog.Level); level == slog.LevelWarn {
			a.Value = slog.StringValue("WARNING")
		}
	case slog.TimeKey:
		a.Key = "timestamp"
	case slog.MessageKey:
		a.Key = "message"
	}
	return a
}

在 HTTP 伺服器中新增檢測功能

如要將追蹤記錄和指標檢測作業新增至 HTTP 伺服器處理的要求,請使用 OpenTelemetry。下列範例使用 otelhttp 處理常式傳播內容,並用於追蹤和指標檢測:

func runServer() error {
	handleHTTP("/single", handleSingle)
	handleHTTP("/multi", handleMulti)

	return http.ListenAndServe(":8080", nil)
}

// handleHTTP handles the http HandlerFunc on the specified route, and uses
// otelhttp for context propagation, trace instrumentation, and metric
// instrumentation.
func handleHTTP(route string, handleFn http.HandlerFunc) {
	instrumentedHandler := otelhttp.NewHandler(otelhttp.WithRouteTag(route, handleFn), route)

	http.Handle(route, instrumentedHandler)
}

在先前的程式碼中,otelhttp 處理常式會使用全域 TracerProviderMeterProviderTextMapPropagator 例項。setupOpenTelemetry 函式會設定這些執行個體。

將追蹤記錄範圍與記錄和指標連結

如要連結伺服器和用戶端範圍,並建立指標和記錄檔的關聯,請將 Go Context 執行個體傳遞至 HTTP 要求,並在寫入記錄檔時傳遞。以下範例說明如何使用路由處理常式擷取 Go Context 執行個體,並將該執行個體傳遞至記錄器和 callSingle 函式,以便發出外送 HTTP 要求:

func handleMulti(w http.ResponseWriter, r *http.Request) {
	subRequests := 3 + rand.Intn(4)
	// Write a structured log with the request context, which allows the log to
	// be linked with the trace for this request.
	slog.InfoContext(r.Context(), "handle /multi request", slog.Int("subRequests", subRequests))

	err := computeSubrequests(r, subRequests)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	fmt.Fprintln(w, "ok")
}

在先前的程式碼中,函式呼叫 r.Context() 會從 HTTP 要求擷取 Go Context

在 HTTP 用戶端中新增檢測功能

如要將追蹤內容插入傳出的 HTTP 要求,並新增追蹤和指標檢測,請呼叫 otelhttp.Get 函式。在以下範例中,callSingle 函式會執行這項動作:

func callSingle(ctx context.Context) error {
	// otelhttp.Get makes an http GET request, just like net/http.Get.
	// In addition, it records a span, records metrics, and propagates context.
	res, err := otelhttp.Get(ctx, "http://localhost:8080/single")
	if err != nil {
		return err
	}

	return res.Body.Close()
}

在先前的程式碼中,otelhttp 處理常式會使用全域 TracerProviderMeterProviderTextMapPropagator 例項。setupOpenTelemetry 函式會設定這些執行個體。

寫入結構化記錄檔

如要寫入連結至追蹤記錄的結構化記錄檔,請使用 Go 的結構化記錄檔套件 slog,並將 Go Context 執行個體傳遞至記錄器。如要將記錄檔連結至範圍,必須使用 Go Context 執行個體。 舉例來說,下列陳述式說明如何呼叫 slogInfoContext 方法,並示範如何將 subRequests 欄位新增至 JSON 執行個體:

slog.InfoContext(r.Context(), "handle /multi request", slog.Int("subRequests", subRequests))

執行設定為收集遙測資料的範例應用程式

範例應用程式中的檢測功能使用與供應商無關的格式,例如記錄資料的 JSON,以及指標和追蹤資料的 OTLP。OpenTelemetry Collector 會使用 Google 匯出工具,將記錄和指標資料傳送至專案。並使用 Telemetry API (採用 OTLP) 將追蹤記錄資料傳送至專案。應用程式中的負載產生器會向應用程式的路徑發出要求。

下載及部署應用程式

如要執行範例,請按照下列步驟操作:

  1. 在 Google Cloud 控制台中啟用 Cloud Shell。

    啟用 Cloud Shell

    Google Cloud 主控台底部會開啟一個 Cloud Shell 工作階段,並顯示指令列提示。Cloud Shell 是已安裝 Google Cloud CLI 的殼層環境,並已針對您目前的專案設定好相關值。工作階段可能要幾秒鐘的時間才能初始化。

  2. 複製存放區:

    git clone https://github.com/GoogleCloudPlatform/golang-samples
    
  3. 前往 OpenTelemetry 目錄:

    cd golang-samples/opentelemetry/instrumentation
    
  4. 建構並執行範例:

    docker compose up --abort-on-container-exit
    

    如果不是在 Cloud Shell 上執行,請執行應用程式,並讓 GOOGLE_APPLICATION_CREDENTIALS 環境變數指向憑證檔案。應用程式預設憑證會在 $HOME/.config/gcloud/application_default_credentials.json 提供憑證檔案。

    # Set environment variables
    export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
    export GOOGLE_APPLICATION_CREDENTIALS="$HOME/.config/gcloud/application_default_credentials.json"
    export USERID="$(id -u)"
    
    # Run
    docker compose -f docker-compose.yaml -f docker-compose.creds.yaml up --abort-on-container-exit
    

查看指標

範例應用程式中的 OpenTelemetry 檢測會產生 Prometheus 指標,您可以使用 Metrics Explorer 查看這些指標:

  • Prometheus/http_server_duration_milliseconds/histogram 記錄伺服器要求的持續時間,並將結果儲存在直方圖中。

  • Prometheus/http_client_duration_milliseconds/histogram 記錄用戶端要求的持續時間,並將結果儲存在直方圖中。

  • Prometheus/http_server_response_size_bytes_total/counter 會記錄 /multi/single HTTP 路徑的回應大小長度。這項指標的測量值為累計值,也就是說,每個值都代表自開始收集值以來的總數。

如要查看範例應用程式產生的指標,請按照下列步驟操作:
  1. 前往 Google Cloud 控制台的 「指標探索器」頁面:

    前往 Metrics Explorer

    如果您是使用搜尋列尋找這個頁面,請選取子標題為「Monitoring」的結果

  2. 在 Google Cloud 控制台的工具列中,選取 Google Cloud 專案。 如要進行 App Hub 設定,請選取 App Hub 主專案或已啟用應用程式的資料夾管理專案。
  3. 在「指標」元素中,展開「選取指標」選單, 在篩選列中輸入 http_server, 然後使用子選單選取特定資源類型和指標:
    1. 在「Active resources」(有效資源) 選單中,選取「Prometheus Target」(Prometheus 目標)
    2. 在「使用中的指標類別」選單中,選取「Http」
    3. 在「使用中的指標」選單中,選取指標。
    4. 按一下「套用」
  4. 如要新增篩選器,從查詢結果中移除時間序列,請使用「Filter」元素

  5. 設定資料的顯示方式。

    如果指標的測量值是累計值,Metrics Explorer 會自動以對齊週期將測量資料正規化,因此圖表會顯示比率。詳情請參閱「種類、型別和轉換」一文。

    測量整數或雙精度值時 (例如使用兩個 counter 指標),Metrics Explorer 會自動加總所有時間序列。如要查看 /multi/single HTTP 路由的資料,請將「Aggregation」(彙整) 項目的第一個選單設為「None」(無)

    如要進一步瞭解如何設定圖表,請參閱「使用 Metrics Explorer 時選取指標」。

查看追蹤記錄

追蹤資料可能需要幾分鐘才會顯示。舉例來說,當專案收到追蹤記錄資料時,Google Cloud Observability 可能需要建立資料庫來儲存該資料。資料庫建立作業可能需要幾分鐘才能完成,這段期間內無法查看任何追蹤資料。

如要查看追蹤記錄資料,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的 「Trace Explorer」頁面:

    前往「Trace explorer」(Trace 探索工具)

    您也可以透過搜尋列找到這個頁面。

  2. 在頁面的表格部分,選取跨度名稱為 /multi 的資料列。
  3. 在「Trace details」(追蹤記錄詳細資料) 面板的甘特圖中,選取標示為 /multi 的時距。

    畫面上會開啟一個面板,顯示 HTTP 要求相關資訊。這些詳細資料包括方法、狀態碼、位元組數,以及呼叫者的使用者代理程式。

  4. 如要查看與這項追蹤記錄相關聯的記錄檔,請選取「記錄檔和事件」分頁標籤。

    這個分頁會顯示個別記錄。如要查看記錄項目的詳細資料,請展開記錄項目。您也可以點選「查看記錄」,然後使用 Logs Explorer 查看記錄。

如要進一步瞭解如何使用 Cloud Trace 探索工具,請參閱「尋找及探索追蹤記錄」。

查看記錄檔

您可以在記錄檔探索器中檢查記錄,也可以查看相關聯的追蹤記錄 (如有)。

  1. 前往 Google Cloud 控制台的 「Logs Explorer」頁面

    前往「Logs Explorer」(記錄檔探索工具)

    如果您是使用搜尋列尋找這個頁面,請選取子標題為「Logging」的結果

  2. 找出說明為 handle /multi request 的記錄。

    如要查看記錄詳細資料,請展開記錄項目。jsonPayload 欄位中會顯示標示為 subRequests 的項目。這個項目是由 handleMulti 函式中的陳述式新增。

  3. 在含有「handle /multi request」訊息的記錄項目上,按一下「追蹤記錄」,然後選取「查看追蹤記錄詳細資料」

    系統會開啟「Trace details」(追蹤記錄詳細資料) 面板,並顯示所選追蹤記錄。

    記錄資料可能比追蹤資料早幾分鐘提供。如果查看追蹤記錄資料時發生錯誤 (無論是依 ID 搜尋追蹤記錄,還是按照這項工作中的步驟操作),請稍候一兩分鐘,然後重試。

如要進一步瞭解如何使用記錄檔探索工具,請參閱「使用記錄檔探索工具查看記錄檔」。

後續步驟