前往檢測設備範例

您可以檢測 Go 應用程式,使用 OpenTelemetry SDK 和 OpenTelemetry 收集器收集追蹤記錄和指標資料,並使用 Go 的 slog 套件將相關聯的結構化 JSON 記錄寫入標準輸出內容。如要試用這項檢測功能,您可以下載並執行 Go 範例應用程式,該應用程式會產生記錄、指標和追蹤記錄資料,並匯出至Google Cloud 專案。

關於檢測方法

使用 OpenTelemetry 收集器時,您會透過 SDK 和 SDK 的 OTLP 內建匯出工具檢測應用程式。這項檢測不限於特定供應商。您也會部署 OpenTelemetry 收集器,從程序內匯出工具接收遙測資料,然後將該資料匯出至 Google Cloud 專案。如要進一步瞭解收集器,請參閱「Google 建構的 OpenTelemetry 收集器」。

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

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

關於情境

OpenTelemetry 的結構定義是一種機制,可在程序中的 API 之間傳遞執行範圍值。Context 的重要用途是攜帶目前有效的 Span,以便在建立任何新 Span 時,修改或參照該 Span 做為父項。摘要:

  • 「Context」是指在程序內跨 API 傳播執行範圍值的機制,包括目前有效的 Span。

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

  • 傳播是在服務和程序之間移動情境的機制。

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

Go 的標準程式庫 context.Context 是用來實作 Go 中的 OpenTelemetry Context。

事前準備

  1. 安裝 Google Cloud CLI。

  2. 設定 gcloud CLI,使用您的聯合身分。

    詳情請參閱「 使用聯合身分登入 gcloud CLI」。

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

    gcloud init
  4. 建立或選取 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 專案名稱。

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

  6. 啟用 Cloud Logging、Cloud Monitoring、Cloud Trace 和 Telemetry API (如有任何 API 尚未啟用):

    啟用 API 所需的角色

    您必須具備 serviceusage.services.enable 權限,才能啟用 API。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「Service Usage 管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色。

    gcloud services enable logging.googleapis.com monitoring.googleapis.com cloudtrace.googleapis.com telemetry.googleapis.com
  7. 如要取得讓範例應用程式寫入記錄、指標和追蹤記錄資料所需的權限,請要求管理員授予您下列 IAM 角色:

    如果您在 Cloud Shell、 Google Cloud 資源或本機開發環境中執行範例,這些權限就足夠。如要瞭解如何設定配額專案,請參閱「設定配額專案」。

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

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

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

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

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

  1. 設定 main 函式
  2. 設定 OpenTelemetry
  3. 設定結構化記錄
  4. 為 HTTP 伺服器新增檢測設備
  5. 將追蹤記錄 span 與記錄和指標連結
  6. 在 HTTP 用戶端中加入檢測功能
  7. 寫入結構化記錄檔

設定 main 函式

如要設定應用程式寫入結構化記錄,並使用 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 通訊協定收集及匯出追蹤記錄和指標,請設定全域 TracerProvider 和 MeterProvider 執行個體。下列程式碼範例說明從 main 函式呼叫的 setupOpenTelemetry 函式:

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 追蹤記錄相關資訊格式傳播追蹤記錄相關資訊。這項設定可確保追蹤記錄中的 span 具有正確的父項與子項關係。

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

設定結構化記錄

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

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:與記錄項目相關聯的追蹤記錄中的 span ID。
  • logging.googleapis.com/trace_sampled:這個欄位的值必須是 true 或 false。

如要進一步瞭解這些欄位,請參閱 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 處理常式會使用全域 TracerProvider、MeterProvider 和 TextMapPropagator 執行個體。setupOpenTelemetry 函式會設定這些執行個體。

將追蹤記錄 span 與記錄和指標連結

如要連結伺服器和用戶端 span,以及建立指標和記錄的關聯,請將 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.NewTransport 設定 http.Client,並呼叫 http.NewRequestWithContext 傳遞要求相關資訊。在以下範例中,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 傳輸會使用全域 TracerProvider、MeterProvider 和 TextMapPropagator 例項。setupOpenTelemetry 函式會設定這些執行個體。

寫入結構化記錄檔

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

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

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

範例應用程式中的檢測作業使用不限供應商的格式,例如記錄資料使用 JSON,指標和追蹤記錄資料則使用 OTLP。OpenTelemetry Collector 會使用 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」頁面:

    前往「Metrics Explorer」

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

  2. 在 Google Cloud 控制台的工具列中,選取 Google Cloud 專案。如果是 App Hub 設定,請選取 App Hub 主專案,或已啟用應用程式管理功能的資料夾管理專案。
  3. 在「Metric」(指標) 元素中,展開「Select a metric」(選取指標) 選單,在篩選列中輸入 http_server,然後使用子選單選取特定資源類型和指標:
    1. 在「Active resources」(使用中的資源) 選單中,選取「Prometheus Target」(Prometheus 目標)。
    2. 在「使用中的指標類別」選單中,選取「Http」。
    3. 在「Active metrics」(使用中的指標) 選單中,選取指標。
    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. 在頁面的表格部分,選取 Span 名稱為 /multi 的資料列。
  3. 在「Trace details」(追蹤記錄詳細資料) 面板的甘特圖中,選取標示為 /multi 的 span。

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

  4. 如要查看與這個追蹤記錄相關聯的記錄,請選取「Logs & Events」(記錄和事件) 分頁標籤。

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

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

查看記錄檔

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

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

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

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

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

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

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

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

    記錄資料可能會比追蹤資料早幾分鐘顯示。如果透過 ID 搜尋追蹤記錄或按照這項工作的步驟操作時,在查看追蹤記錄資料時發生錯誤,請稍候一兩分鐘,然後再重試。

如要進一步瞭解如何使用 Logs Explorer,請參閱「使用 Logs Explorer 查看記錄檔」。

後續步驟