gRPC og høyytelses-API-er · leksjon

Sporing med OpenTelemetry

Integrer OpenTelemetry for å oppnå distribuert sporing og visualisere ende-til-ende-flyten av forespørsler på tvers av tjenester.

Leksjon 2 av 412 trinn

Sporing med OpenTelemetry er en gratis leksjon i gRPC og høyytelses-API-er på CoddyKit. Dette er leksjon 2 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i gRPC og høyytelses-API-er, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i gRPC og høyytelses-API-er inneholder totalt 4 leksjoner.

Mikrotjenester og behovet for sporing

Moderne applikasjoner består ofte av mange små, sammenkoblede tjenester som kalles mikrotjenester. Denne arkitekturen gir fleksibilitet, men kan gjøre feilsøking av komplekse samspill til en stor utfordring.

Når en brukerforespørsel går gjennom flere tjenester, kan det å finne ut hvor en forsinkelse eller feil oppstod, føles som å lete etter en nål i en høystakk.

Følg forespørselens vei

Distribuert sporing hjelper Dem med å visualisere hele reisen til en forespørsel når den flyter gjennom ulike tjenester i systemet Deres.

  • Den kobler sammen alle operasjoner som tilhører én enkelt forespørsel.
  • Den viser hvor lang tid hver del av forespørselen tok.
  • Dette gjør det enklere å identifisere ytelsesflaskehalser og feil på tvers av tjenestegrenser.

OpenTelemetry: standarden for observerbarhet

OpenTelemetry (OTel) er et åpen kildekode-prosjekt som tilbyr en standardisert måte å samle inn telemetridata fra applikasjonene Deres på. Dette omfatter spor, måledata og logger.

I stedet for leverandørspesifikke SDK-er tilbyr OTel ett samlet sett med API-er, SDK-er og verktøy for å instrumentere tjenestene Deres, slik at observerbarhetsdataene blir portérbare.

Spor bygges opp av spans

I OpenTelemetry representerer et spor hele kjøringsforløpet til en forespørsel gjennom systemet Deres. Det kan sammenlignes med hele historien til forespørselen.

Et spor består av én eller flere spans. Hver span representerer én enkelt operasjon eller arbeidsenhet i sporet, omtrent som et trinn i historien. Spans har et starttidspunkt, et sluttidspunkt og metadata.

Videreføring av sporkontekst

For at spans skal danne et komplett spor på tvers av ulike tjenester, må de kobles sammen. Dette gjøres gjennom kontekstvidereføring.

Når én tjeneste kaller en annen, sender den med en «sporkontekst» (ofte i HTTP/2-headere for gRPC). Denne konteksten forteller den mottakende tjenesten hvilket spor og hvilken overordnet span de nye operasjonene tilhører, og oppretter et overordnet-underordnet-forhold mellom spans.

Det viktigste om OTel-sporing

For å implementere sporing skal De arbeide med disse sentrale OpenTelemetry-komponentene:

  • TracerProvider: Administrerer Tracer-instanser og konfigurerer span-prosessorer og eksportører.
  • Tracer: Oppretter Span-objekter.
  • SpanProcessor: Behandler spans før de eksporteres (for eksempel i grupper).
  • Exporter: Sender innsamlede spans til en backend (for eksempel en konsoll, Jaeger eller en OTLP-samler).

OTel-oppsett: TracerProvider og Exporter

La oss sette opp en grunnleggende OpenTelemetry-TracerProvider i Go. Vi skal bruke en enkel stdouttrace-eksportør til å skrive sporingsdata til konsollen, slik at De kan se spans som blir generert.

Dette kodeeksempelet initialiserer den globale TracerProvider-en og sørger for at alle spans tømmes når applikasjonen avsluttes.

Kjør denne koden for å se det grunnleggende oppsettet:

package main

import (
	"context"
	"log"
	"os"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
	"go.opentelemetry.io/otel/trace"
)

// initTracerProvider initializes an OpenTelemetry TracerProvider
// with a stdout exporter for demonstration.
func initTracerProvider() *sdktrace.TracerProvider {
	// Create stdout exporter to print traces to the console
	exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
	if err != nil {
		log.Fatalf("failed to create stdout exporter: %v", err)
	}

	// Create a new TracerProvider with the exporter and a service name
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter), // Batch spans for efficiency
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName("my-simple-service"),
			attribute.String("environment", "development"),
		)),
	)
	otel.SetTracerProvider(tp) // Set the global TracerProvider

	return tp
}

func main() {
	tp := initTracerProvider()
	defer func() {
		if err := tp.Shutdown(context.Background()); err != nil {
			log.Fatalf("Error shutting down tracer provider: %v", err)
		}
	}()

	// Get a tracer
	tracer := otel.Tracer("my-app-tracer")

	// Create a root span
	ctx, span := tracer.Start(context.Background(), "main-operation")
	defer span.End()

	log.Println("Hello from main-operation with tracing enabled!")
	time.Sleep(100 * time.Millisecond) // Simulate some work

	// Create a child span
	_, childSpan := tracer.Start(ctx, "sub-operation")
	defer childSpan.End()
	childSpan.SetAttributes(attribute.String("task", "processing"))
	log.Println("Doing some sub-operation...")
	time.Sleep(50 * time.Millisecond) // Simulate more work

	log.Println("Trace data will be printed on shutdown.")
}

Automatisk sporing av gRPC-kall

For å spore gRPC-forespørsler automatisk tilbyr OpenTelemetry interceptors. Dette er middleware-funksjoner som pakker inn gRPC-kall på både klient- og serversiden.

  • Serverinterceptor: Starter en ny span for innkommende forespørsler og kobler den til sporkonteksten fra klienten.
  • Klientinterceptor: Setter inn den gjeldende sporkonteksten i utgående forespørsler, slik at den kan videreføres til serveren.

Slik kan De bruke dem på gRPC-serveren og -klienten Deres:

package main

import (
	"context"
	"log"
	"net"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	// OpenTelemetry imports
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.24.0"

	// gRPC OpenTelemetry instrumentation
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

	// For this example, we'll define a simple service in-line
	pb "google.golang.org/grpc/examples/helloworld/helloworld" // Using a standard example proto
)

// initTracerProvider initializes an OpenTelemetry TracerProvider
// with a stdout exporter for demonstration.
func initTracerProvider() *sdktrace.TracerProvider {
	exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
	if err != nil {
		log.Fatalf("failed to create stdout exporter: %v", err)
	}

	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName("grpc-otel-demo"),
			attribute.String("environment", "development"),
		)),
	)
	otel.SetTracerProvider(tp)
	return tp
}

// helloServer is a simple gRPC server for demonstration
type helloServer struct {
	pb.UnimplementedGreeterServer
}

func (s *helloServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	// Simulate some work
	time.Sleep(50 * time.Millisecond)
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	// 1. Initialize OpenTelemetry TracerProvider
	tp := initTracerProvider()
	defer func() {
		if err := tp.Shutdown(context.Background()); err != nil {
			log.Fatalf("Error shutting down tracer provider: %v", err)
		}
	}()

	// 2. Start gRPC Server with OpenTelemetry Interceptor
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer(
		grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), // Apply OTel server interceptor
	)
	pb.RegisterGreeterServer(s, &helloServer{})
	log.Println("Server listening on :50051")
	go func() {
		if err := s.Serve(lis); err != nil {
			log.Fatalf("failed to serve: %v", err)
		}
	}()
	defer s.Stop()

	// Allow server to start
	time.Sleep(1 * time.Second)

	// 3. Create gRPC Client with OpenTelemetry Interceptor
	conn, err := grpc.Dial(
		"localhost:50051",
		grpc.WithInsecure(), // For simplicity, use insecure
		grpc.WithBlock(),
		grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), // Apply OTel client interceptor
	)
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// 4. Make a gRPC call
	log.Println("Making gRPC call...")
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "CoddyKit User"})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())

	// Give some time for spans to be processed and exported
	time.Sleep(1 * time.Second)
	log.Println("Trace data should now be visible in console.")
}

Les sporingshistorien

Etter at De har kjørt det forrige eksempelet, vises en detaljert JSON-utskrift i konsollen. Denne utskriften representerer sporingsdataene.

  • Se etter "TraceID": Denne unike ID-en kobler sammen alle spans som tilhører samme forespørsel.
  • Hver oppføring er en "Span": Den har en "SpanID", "ParentSpanID" (hvis den ikke er roten), navn, start- og sluttidspunkt samt attributter.
  • Hierarkiet mellom spans (overordnet-underordnet) viser kjøringsflyten.

Denne «historien» hjelper Dem med å forstå hvor lang tid hvert trinn tok, og hvilken tjeneste som var ansvarlig.

Berik spans med attributter

Selv om automatisk instrumentering gir grunnleggende spans, trenger De ofte å legge til mer spesifikk informasjon i sporene. Span-attributter (nøkkel-verdi-par) gjør dette mulig.

De kan registrere detaljer som bruker-ID-er, forespørselsparametere eller resultater fra spesifikk forretningslogikk direkte på en span. Dette gjør feilsøking og analyse langt mer effektivt.

Bruk span.SetAttributes() for å legge til egendefinerte attributter.

package main

import (
	"context"
	"log"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
	"go.opentelemetry.io/otel/trace"
)

// initTracerProvider initializes an OpenTelemetry TracerProvider
func initTracerProvider() *sdktrace.TracerProvider {
	exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
	if err != nil {
		log.Fatalf("failed to create stdout exporter: %v", err)
	}
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName("custom-attributes-demo"),
		)),
	)
	otel.SetTracerProvider(tp)
	return tp
}

func main() {
	tp := initTracerProvider()
	defer func() {
		if err := tp.Shutdown(context.Background()); err != nil {
			log.Fatalf("Error shutting down tracer provider: %v", err)
		}
	}()

	tracer := otel.Tracer("my-custom-tracer")

	// Start a root span
	ctx, span := tracer.Start(context.Background(), "process-order")
	defer span.End()

	// Add custom attributes to the root span
	span.SetAttributes(
		attribute.String("user.id", "user123"),
		attribute.Int("order.id", 45678),
		attribute.Bool("is_premium_user", true),
	)
	log.Println("Processing order with custom attributes...")
	time.Sleep(100 * time.Millisecond)

	// Create a child span
	_, childSpan := tracer.Start(ctx, "database-query")
	defer childSpan.End()
	childSpan.SetAttributes(
		attribute.String("db.system", "postgres"),
		attribute.String("db.statement", "SELECT * FROM orders WHERE id=45678"),
	)
	log.Println("Executing database query...")
	time.Sleep(50 * time.Millisecond)

	log.Println("Check the console output for custom attributes in the spans!")
	time.Sleep(500 * time.Millisecond) // Ensure spans are exported
}

Test av sporingskonsepter

De har lært om distribuert sporing og hvordan OpenTelemetry hjelper Dem. La oss teste forståelsen Deres.

Oppsummering: sporing med OpenTelemetry

I denne leksjonen lærte De hvordan distribuert sporing gjør det enklere å håndtere kompleksiteten i mikrotjenester ved å vise hele reisen til en forespørsel.

Vi utforsket OpenTelemetry som standarden for innsamling av spor, og så på sentrale konsepter som spor, spans og kontekstvidereføring. De så hvordan man setter opp en OTel-TracerProvider, og hvordan gRPC-interceptors gjør det enkelt å instrumentere tjenestene Deres. Til slutt så vi på hvordan spans kan berikes med egendefinerte attributter for dypere innsikt.

Med OpenTelemetry får De avgjørende innsyn i hvordan gRPC-applikasjonen Deres oppfører seg!

Gratis å komme i gang

Lær deg gRPC og høyytelses-API-er med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
12
Leksjoner
48

Ofte stilte spørsmål

Er leksjonen «Sporing med OpenTelemetry» gratis?

Ja – hele teksten i «Sporing med OpenTelemetry» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av gRPC og høyytelses-API-er-kurset, kan du oppgradere til CoddyKit PRO. Kurset i gRPC og høyytelses-API-er inneholder totalt 4 leksjoner.

Hva lærer jeg i «Sporing med OpenTelemetry»?

Integrer OpenTelemetry for å oppnå distribuert sporing og visualisere ende-til-ende-flyten av forespørsler på tvers av tjenester. Du øver på gRPC og høyytelses-API-er med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med gRPC og høyytelses-API-er?

Ingen tidligere erfaring er nødvendig. gRPC og høyytelses-API-er på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Sporing med OpenTelemetry»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne gRPC og høyytelses-API-er-leksjonen?

Ja. Alle gRPC og høyytelses-API-er-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Logging av gRPC-samhandlinger
  2. Sporing med OpenTelemetry
  3. Overvåking av gRPC-metrikker
  4. Helsesjekk og beredskapsprober
← Tilbake til gRPC og høyytelses-API-er