Migrasi ke Go OpenTelemetry - AWS X-Ray

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Migrasi ke Go OpenTelemetry

Gunakan contoh kode berikut untuk mengarahkan aplikasi Go Anda secara manual dengan OpenTelemetry SDK saat bermigrasi dari X-Ray.

Instrumentasi manual dengan SDK

Tracing setup with X-Ray SDK

Saat menggunakan X-Ray SDK for Go, plugin layanan atau aturan pengambilan sampel lokal harus dikonfigurasi sebelum menginstrumentasi kode Anda.

func init() { if os.Getenv("ENVIRONMENT") == "production" { ec2.Init() } xray.Configure(xray.Config{ DaemonAddr: "127.0.0.1:2000", ServiceVersion: "1.2.3", }) }
Set up tracing with OpenTelemetry SDK

Konfigurasikan OpenTelemetry SDK dengan membuat instance TracerProvider dan mendaftarkannya sebagai penyedia pelacak global. Kami merekomendasikan untuk mengonfigurasi komponen-komponen berikut:

  • OTLP Trace Exporter - Diperlukan untuk mengekspor jejak ke Agen atau Kolektor CloudWatch OpenTelemetry

  • X-Ray Propagator — Diperlukan untuk menyebarkan konteks jejak ke AWS layanan yang terintegrasi dengan X-Ray

  • X-Ray Remote Sampler — Diperlukan untuk permintaan sampling menggunakan aturan sampling X-Ray

  • Detektor sumber daya - Untuk mendeteksi metadata host yang menjalankan aplikasi Anda

import ( "go.opentelemetry.io/contrib/detectors/aws/ec2" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/contrib/samplers/aws/xray" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/trace" ) func setupTracing() error { ctx := context.Background() exporterEndpoint := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") if exporterEndpoint == "" { exporterEndpoint = "localhost:4317" } traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(exporterEndpoint)) if err != nil { return fmt.Errorf("failed to create OTLP trace exporter: %v", err) } remoteSampler, err := xray.NewRemoteSampler(ctx, "my-service-name", "ec2") if err != nil { return fmt.Errorf("failed to create X-Ray Remote Sampler: %v", err) } ec2Resource, err := ec2.NewResourceDetector().Detect(ctx) if err != nil { return fmt.Errorf("failed to detect EC2 resource: %v", err) } tp := trace.NewTracerProvider( trace.WithSampler(remoteSampler), trace.WithBatcher(traceExporter), trace.WithResource(ec2Resource), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(xray.Propagator{}) return nil }

Menelusuri permintaan yang masuk (instrumentasi penangan HTTP)

With X-Ray SDK

Untuk instrumen handler HTTP dengan X-Ray, metode handler X-Ray digunakan untuk menghasilkan segmen menggunakan. NewFixedSegmentNamer

func main() { http.Handle("/", xray.Handler(xray.NewFixedSegmentNamer("myApp"), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello!")) }))) http.ListenAndServe(":8000", nil) }
With OpenTelemetry SDK

Untuk instrumen handler HTTP dengan OpenTelemetry, gunakan metode NewHandler untuk membungkus kode handler asli Anda. OpenTelemetry

import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) helloHandler := func(w http.ResponseWriter, req *http.Request) { ctx := req.Context() span := trace.SpanFromContext(ctx) span.SetAttributes(attribute.Bool("isHelloHandlerSpan", true), attribute.String("attrKey", "attrValue")) _, _ = io.WriteString(w, "Hello World!\n") } otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello") http.Handle("/hello", otelHandler) err = http.ListenAndServe(":8080", nil) if err != nil { log.Fatal(err) }

AWS Instrumentasi SDK for Go v2

With X-Ray SDK

Untuk menginstrumentasi AWS permintaan keluar dari AWS SDK, klien Anda diinstrumentasi sebagai berikut:

// Create a segment ctx, root := xray.BeginSegment(context.TODO(), "AWSSDKV2_Dynamodb") defer root.Close(nil) cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-west-2")) if err != nil { log.Fatalf("unable to load SDK config, %v", err) } // Instrumenting AWS SDK v2 awsv2.AWSV2Instrumentor(&cfg.APIOptions) // Using the Config value, create the DynamoDB client svc := dynamodb.NewFromConfig(cfg) // Build the request with its input parameters _, err = svc.ListTables(ctx, &dynamodb.ListTablesInput{ Limit: aws.Int32(5), }) if err != nil { log.Fatalf("failed to list tables, %v", err) }
With OpenTelemetry SDK

Menelusuri dukungan untuk panggilan AWS SDK hilir disediakan oleh SDK for AWS Go OpenTelemetry v2 Instrumentation. Berikut adalah contoh penelusuran panggilan klien S3:

import ( ... "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" "go.opentelemetry.io/otel" oteltrace "go.opentelemetry.io/otel/trace" awsConfig "github.com/aws/aws-sdk-go-v2/config" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" ) ... // init aws config cfg, err := awsConfig.LoadDefaultConfig(ctx) if err != nil { panic("configuration error, " + err.Error()) } // instrument all aws clients otelaws.AppendMiddlewares(&.APIOptions) // Call to S3 s3Client := s3.NewFromConfig(cfg) input := &s3.ListBucketsInput{} result, err := s3Client.ListBuckets(ctx, input) if err != nil { fmt.Printf("Got an error retrieving buckets, %v", err) return }

Instrumentasi panggilan HTTP keluar

With X-Ray SDK

Untuk instrumen panggilan HTTP keluar dengan X-Ray, Xray.client digunakan untuk membuat salinan klien HTTP yang disediakan.

myClient := xray.Client(http-client) resp, err := ctxhttp.Get(ctx, xray.Client(nil), url)
With OpenTelemetry SDK

Untuk instrumen klien HTTP dengan OpenTelemetry, gunakan OpenTelemetry otelhttp. NewTransport metode untuk membungkus http. DefaultTransport.

import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) // Create an instrumented HTTP client. httpClient := &http.Client{ Transport: otelhttp.NewTransport( http.DefaultTransport, ), } req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/repos/aws-observability/aws-otel-go/releases/latest", nil) if err != nil { fmt.Printf("failed to create http request, %v\n", err) } res, err := httpClient.Do(req) if err != nil { fmt.Printf("failed to make http request, %v\n", err) } // Request body must be closed defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { fmt.Printf("failed to close http response body, %v\n", err) } }(res.Body)

Dukungan instrumentasi untuk perpustakaan lain

Anda dapat menemukan daftar lengkap instrumentasi pustaka yang didukung untuk OpenTelemetry Go di bawah paket Instrumentasi.

Atau, Anda dapat mencari OpenTelemetry registri untuk mengetahui apakah OpenTelemetry mendukung instrumentasi untuk perpustakaan Anda di bawah Registry.

Membuat data jejak secara manual

With X-Ray SDK

Dengan X-Ray SDK, BeginSubsegment metode BeginSegment dan diperlukan untuk membuat segmen dan sub-segmen X-Ray secara manual.

// Start a segment ctx, seg := xray.BeginSegment(context.Background(), "service-name") // Start a subsegment subCtx, subSeg := xray.BeginSubsegment(ctx, "subsegment-name") // Add metadata or annotation here if necessary xray.AddAnnotation(subCtx, "annotationKey", "annotationValue") xray.AddMetadata(subCtx, "metadataKey", "metadataValue") subSeg.Close(nil) // Close the segment seg.Close(nil)
With OpenTelemetry SDK

Gunakan rentang kustom untuk memantau kinerja aktivitas internal yang tidak ditangkap oleh pustaka instrumentasi. Perhatikan bahwa hanya rentang jenis Server yang diubah menjadi segmen X-Ray, semua rentang lainnya diubah menjadi sub-segmen X-Ray.

Pertama, Anda perlu membuat Tracer untuk menghasilkan bentang, yang dapat Anda peroleh melalui metode iniotel.Tracer. Ini akan memberikan instance Tracer dari TracerProvider yang terdaftar secara global dalam contoh Tracing Setup. Anda dapat membuat instance Tracer sebanyak yang diperlukan, tetapi biasanya memiliki satu Tracer untuk seluruh aplikasi.

tracer := otel.Tracer("application-tracer")
import ( ... oteltrace "go.opentelemetry.io/otel/trace" ) ... var attributes = []attribute.KeyValue{ attribute.KeyValue{Key: "metadataKey", Value: attribute.StringValue("metadataValue")}, attribute.KeyValue{Key: "annotationKey", Value: attribute.StringValue("annotationValue")}, attribute.KeyValue{Key: "aws.xray.annotations", Value: attribute.StringSliceValue([]string{"annotationKey"})}, } ctx := context.Background() parentSpanContext, parentSpan := tracer.Start(ctx, "ParentSpan", oteltrace.WithSpanKind(oteltrace.SpanKindServer), oteltrace.WithAttributes(attributes...)) _, childSpan := tracer.Start(parentSpanContext, "ChildSpan", oteltrace.WithSpanKind(oteltrace.SpanKindInternal)) // ... childSpan.End() parentSpan.End()

Menambahkan anotasi dan metadata ke jejak dengan SDK OpenTelemetry

Dalam contoh di atas, WithAttributes metode ini digunakan untuk menambahkan atribut ke setiap rentang. Perhatikan bahwa secara default, semua atribut rentang diubah menjadi metadata dalam data mentah X-Ray. Untuk memastikan bahwa atribut diubah menjadi anotasi dan bukan metadata, tambahkan kunci atribut ke daftar atribut. aws.xray.annotations Untuk informasi selengkapnya, lihat Mengaktifkan Anotasi X-Ray yang Disesuaikan.

Instrumentasi manual Lambda

With X-Ray SDK

Dengan X-Ray SDK, setelah Lambda Anda mengaktifkan Active Tracing, tidak ada konfigurasi tambahan yang diperlukan untuk menggunakan X-Ray SDK. Lambda membuat segmen yang mewakili pemanggilan penangan Lambda, dan Anda membuat sub-segmen menggunakan X-Ray SDK tanpa konfigurasi tambahan.

With OpenTelemetry SDK

Kode fungsi Lambda berikut (tanpa instrumentasi) membuat ListBuckets panggilan Amazon S3 dan permintaan HTTP keluar.

package main import ( "context" "encoding/json" "fmt" "io" "net/http" "os" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) func lambdaHandler(ctx context.Context) (interface{}, error) { // Initialize AWS config. cfg, err := awsconfig.LoadDefaultConfig(ctx) if err != nil { panic("configuration error, " + err.Error()) } s3Client := s3.NewFromConfig(cfg) // Create an HTTP client. httpClient := &http.Client{ Transport: http.DefaultTransport, } input := &s3.ListBucketsInput{} result, err := s3Client.ListBuckets(ctx, input) if err != nil { fmt.Printf("Got an error retrieving buckets, %v", err) } fmt.Println("Buckets:") for _, bucket := range result.Buckets { fmt.Println(*bucket.Name + ": " + bucket.CreationDate.Format("2006-01-02 15:04:05 Monday")) } fmt.Println("End Buckets.") req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/repos/aws-observability/aws-otel-go/releases/latest", nil) if err != nil { fmt.Printf("failed to create http request, %v\n", err) } res, err := httpClient.Do(req) if err != nil { fmt.Printf("failed to make http request, %v\n", err) } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { fmt.Printf("failed to close http response body, %v\n", err) } }(res.Body) var data map[string]interface{} err = json.NewDecoder(res.Body).Decode(&data) if err != nil { fmt.Printf("failed to read http response body, %v\n", err) } fmt.Printf("Latest ADOT Go Release is '%s'\n", data["name"]) return events.APIGatewayProxyResponse{ StatusCode: http.StatusOK, Body: os.Getenv("_X_AMZN_TRACE_ID"), }, nil } func main() { lambda.Start(lambdaHandler) }

Untuk menginstruksikan handler Lambda Anda dan klien Amazon S3 secara manual, lakukan hal berikut:

  1. Di main (), buat instance a TracerProvider (tp) dan daftarkan sebagai penyedia pelacak global. TracerProvider Disarankan untuk dikonfigurasi dengan:

    1. Prosesor Rentang Sederhana dengan eksportir rentang UDP X-Ray untuk mengirim Jejak ke titik akhir X-Ray UDP Lambda

    2. Sumber daya dengan service.name disetel ke nama fungsi Lambda

  2. Ubah penggunaan lambda.Start(lambdaHandler) kelambda.Start(otellambda.InstrumentHandler(lambdaHandler, xrayconfig.WithRecommendedOptions(tp)...)).

  3. Instrumentasikan klien Amazon S3 dengan instrumentasi OpenTemetry AWS SDK dengan menambahkan OpenTelemetry middleware ke dalam aws-sdk-go-v2 konfigurasi klien Amazon S3.

  4. Instrumen klien http dengan menggunakan OpenTelemetry otelhttp.NewTransport metode untuk membungkushttp.DefaultTransport.

Kode berikut adalah contoh bagaimana Fungsi Lambda akan terlihat seperti setelah perubahan. Anda dapat secara manual membuat rentang kustom tambahan selain rentang yang disediakan secara otomatis.

package main import ( "context" "encoding/json" "fmt" "io" "net/http" "os" "github.com/aws-observability/aws-otel-go/exporters/xrayudp" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" ) func lambdaHandler(ctx context.Context) (interface{}, error) { // Initialize AWS config. cfg, err := awsconfig.LoadDefaultConfig(ctx) if err != nil { panic("configuration error, " + err.Error()) } // Instrument all AWS clients. otelaws.AppendMiddlewares(&cfg.APIOptions) // Create an instrumented S3 client from the config. s3Client := s3.NewFromConfig(cfg) // Create an instrumented HTTP client. httpClient := &http.Client{ Transport: otelhttp.NewTransport( http.DefaultTransport, ), } // return func(ctx context.Context) (interface{}, error) { input := &s3.ListBucketsInput{} result, err := s3Client.ListBuckets(ctx, input) if err != nil { fmt.Printf("Got an error retrieving buckets, %v", err) } fmt.Println("Buckets:") for _, bucket := range result.Buckets { fmt.Println(*bucket.Name + ": " + bucket.CreationDate.Format("2006-01-02 15:04:05 Monday")) } fmt.Println("End Buckets.") req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/repos/aws-observability/aws-otel-go/releases/latest", nil) if err != nil { fmt.Printf("failed to create http request, %v\n", err) } res, err := httpClient.Do(req) if err != nil { fmt.Printf("failed to make http request, %v\n", err) } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { fmt.Printf("failed to close http response body, %v\n", err) } }(res.Body) var data map[string]interface{} err = json.NewDecoder(res.Body).Decode(&data) if err != nil { fmt.Printf("failed to read http response body, %v\n", err) } fmt.Printf("Latest ADOT Go Release is '%s'\n", data["name"]) return events.APIGatewayProxyResponse{ StatusCode: http.StatusOK, Body: os.Getenv("_X_AMZN_TRACE_ID"), }, nil } func main() { ctx := context.Background() detector := lambdadetector.NewResourceDetector() lambdaResource, err := detector.Detect(context.Background()) if err != nil { fmt.Printf("failed to detect lambda resources: %v\n", err) } var attributes = []attribute.KeyValue{ attribute.KeyValue{Key: semconv.ServiceNameKey, Value: attribute.StringValue(os.Getenv("AWS_LAMBDA_FUNCTION_NAME"))}, } customResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) mergedResource, _ := resource.Merge(lambdaResource, customResource) xrayUdpExporter, _ := xrayudp.NewSpanExporter(ctx) tp := trace.NewTracerProvider( trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(xrayUdpExporter)), trace.WithResource(mergedResource), ) defer func(ctx context.Context) { err := tp.Shutdown(ctx) if err != nil { fmt.Printf("error shutting down tracer provider: %v", err) } }(ctx) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(xray.Propagator{}) lambda.Start(otellambda.InstrumentHandler(lambdaHandler, xrayconfig.WithRecommendedOptions(tp)...)) }

Saat memanggil Lambda, Anda akan melihat jejak berikut Trace Map di CloudWatch konsol:

Lacak peta di CloudWatch konsol untuk Golang.