Tracing med OpenTelemetry
Integrér OpenTelemetry for at opnå distribueret tracing og visualisere anmodningsforløb fra ende til anden på tværs af services.
Tracing med OpenTelemetry er en gratis gRPC og højtydende API'er-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i gRPC og højtydende API'er, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. gRPC og højtydende API'er-kurset indeholder 4 lektioner i alt.
Mikrotjenester og behovet for tracing
Moderne applikationer består ofte af mange små, indbyrdes forbundne tjenester, der kaldes mikrotjenester. Denne arkitektur giver fleksibilitet, men kan gøre fejlfinding af komplekse interaktioner til en stor udfordring.
Når en brugerforespørgsel bevæger sig gennem flere tjenester, kan det føles som at finde en nål i en høstak at fastslå, hvor en forsinkelse eller fejl opstod.
Følg forespørgslens vej
Distribueret tracing hjælper dig med at visualisere hele en forespørgsels forløb, mens den bevæger sig gennem forskellige tjenester i dit system.
- Det forbinder alle handlinger, der hører til den samme forespørgsel.
- Det viser, hvor lang tid hver del af forespørgslen tog.
- Det hjælper med at identificere flaskehalse i ydeevnen og fejl på tværs af tjenestegrænser.
OpenTelemetry: Standarden for observability
OpenTelemetry (OTel) er et open source-projekt, der giver en standardiseret måde at indsamle telemetridata fra dine applikationer på. Det omfatter traces, metrikker og logge.
I stedet for leverandørspecifikke SDK'er tilbyder OTel ét samlet sæt af API'er, SDK'er og værktøjer til at instrumentere dine tjenester, så dine observability-data kan flyttes mellem forskellige løsninger.
Traces opbygget af spans
I OpenTelemetry repræsenterer en trace hele udførelsesforløbet for en forespørgsel gennem dit system. Det er som hele historien om forespørgslen.
En trace består af en eller flere spans. Hver span repræsenterer én handling eller arbejdsenhed i denne trace, som et trin i historien. Spans har et starttidspunkt, et sluttidspunkt og metadata.
Videregivelse af trace-kontekst
For at spans kan danne en komplet trace på tværs af forskellige tjenester, skal de forbindes. Det sker gennem kontekstvideregivelse.
Når en tjeneste kalder en anden, sender den en "trace-kontekst" med (ofte i HTTP/2-headere for gRPC). Denne kontekst fortæller den modtagende tjeneste, hvilken trace og overordnede span dens nye handlinger hører til, så der oprettes en forælder-barn-relation mellem spans.
Det vigtigste om OTel-tracing
For at implementere tracing arbejder du med disse centrale OpenTelemetry-komponenter:
- TracerProvider: Administrerer
Tracer-instanser og konfigurerer span-processorer og eksportører. - Tracer: Opretter
Span-objekter. - SpanProcessor: Behandler spans, før de eksporteres (f.eks. ved batching).
- Exporter: Sender indsamlede spans til en backend (f.eks. en konsol, Jaeger eller en OTLP-collector).
Opsætning af OTel: TracerProvider og Exporter
Lad os opsætte en grundlæggende OpenTelemetry-TracerProvider i Go. Vi bruger en enkel stdouttrace-eksportør til at udskrive tracedata i konsollen, så du kan se de spans, der bliver genereret.
Dette kodestykke initialiserer den globale TracerProvider og sikrer, at alle spans tømmes, når applikationen afsluttes.
Kør denne kode for at se den grundlæggende opsætning:
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 tracing af gRPC-kald
Hvis gRPC-forespørgsler skal traces automatisk, tilbyder OpenTelemetry interceptors. Det er middleware-funktioner, der omslutter gRPC-kald på både klient- og serversiden.
- Serverinterceptor: Starter en ny span for indgående forespørgsler og forbinder den med trace-konteksten fra klienten.
- Klientinterceptor: Indlejrer den aktuelle trace-kontekst i udgående forespørgsler, så den kan videregives til serveren.
Sådan anvender du dem på din gRPC-server og -klient:
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.")
}Læs historien i en trace
Når du har kørt det forrige eksempel, kan du se et detaljeret JSON-output i konsollen. Dette output repræsenterer tracedataene.
- Se efter
"TraceID": Dette unikke ID forbinder alle spans, der hører til den samme forespørgsel. - Hver post er en
"Span": Den har et"SpanID", et"ParentSpanID"(hvis den ikke er roden), navn, start- og sluttidspunkter samt attributter. - Hierarkiet af spans (forælder-barn) viser udførelsens forløb.
Denne "historie" hjælper dig med at forstå, hvor lang tid hvert trin tog, og hvilken tjeneste der var ansvarlig.
Berigelse af spans med attributter
Selvom automatisk instrumentering giver grundlæggende spans, har du ofte brug for at føje mere specifikke oplysninger til dine traces. Span-attributter (nøgle-værdi-par) gør det muligt.
Du kan registrere oplysninger som bruger-ID'er, forespørgselsparametre eller resultater af specifik forretningslogik direkte på en span. Det gør fejlfinding og analyse langt mere effektiv.
Brug span.SetAttributes() til at tilføje brugerdefinerede 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 af tracing-begreber
Du har lært om distribueret tracing, og hvordan OpenTelemetry hjælper. Lad os teste din forståelse.
Opsummering: Tracing med OpenTelemetry
I denne lektion lærte du, hvordan distribueret tracing hjælper med at navigere i mikrotjenesternes kompleksitet ved at vise en forespørgsels fulde forløb.
Vi undersøgte OpenTelemetry som standarden til indsamling af traces og gennemgik centrale begreber som traces, spans og kontekstvideregivelse. Du så, hvordan man opsætter en OTel-TracerProvider, og hvordan gRPC-interceptors gør det enkelt at instrumentere dine tjenester. Til sidst gennemgik vi, hvordan du beriger dine spans med brugerdefinerede attributter for at få dybere indsigt.
Med OpenTelemetry får du afgørende indsigt i din gRPC-applikations adfærd!
Lær gRPC og højtydende API'er med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 12
- Lektioner
- 48
Ofte stillede spørgsmål
Er lektionen “Tracing med OpenTelemetry” gratis?
Ja — hele teksten til “Tracing med OpenTelemetry” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af gRPC og højtydende API'er-kurset, skal du opgradere til CoddyKit PRO. gRPC og højtydende API'er-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Tracing med OpenTelemetry”?
Integrér OpenTelemetry for at opnå distribueret tracing og visualisere anmodningsforløb fra ende til anden på tværs af services. Du øver dig i gRPC og højtydende API'er med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på gRPC og højtydende API'er?
Der kræves ingen tidligere erfaring. gRPC og højtydende API'er på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Tracing med OpenTelemetry”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne gRPC og højtydende API'er-lektion?
Ja. Alle gRPC og højtydende API'er-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Logning af gRPC-interaktioner
- Tracing med OpenTelemetry
- Overvågning af gRPC-metrikker
- Sundhedstjek og readiness-prober