CodeBlanks Logo Icon CodeBlanks

Tracing

Learn the distributed tracing concept.

Distributed tracing

When a request passes through several services, logs and metrics don't say exactly where it slowed down. In tracing each piece of work is a span; nested spans form a trace:

trace a1b2 ─ GET /siparis       120 ms
           ├─ stok-servisi      30 ms
           └─ odeme-servisi     80 ms
              └─ SQL INSERT     65 ms

This view immediately shows that the latency comes from the SQL query in the payment service.

Propagation with context

In Go the active span travels inside context.Context. That's why every traced function takes ctx as its first parameter and passes it down:

func odemeAl(ctx context.Context, tutar int) error {
    ctx, span := tracer.Start(ctx, "odemeAl")
    defer span.End()
    return repo.Kaydet(ctx, tutar)  // the child span opens here
}

Starting a new chain with context.Background() breaks the trace.

Practice A simple span

Write your own mini span: start(name string) func() records the start time and returns a function that prints name + " bitti" when called. Use it in a function with defer start("islem")().

Starter code

main.go
package main

import (
    "fmt"
    "time"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
package main

import (
    "fmt"
    "time"
)

func start(ad string) func() {
    bas := time.Now()
    return func() {
        _ = time.Since(bas)
        fmt.Println(ad + " bitti")
    }
}

func islem() {
    defer start("islem")()
    fmt.Println("çalışıyor")
}

func main() {
    islem()
}

Expected output

çalışıyor
islem bitti

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 How is the trace ID carried from one service to another?

  • By writing it to the database
  • Through the log file
  • It isn't; each service creates a new one
  • In a request header (e.g. traceparent) Correct answer

Explanation: The W3C Trace Context standard defines the traceparent header; the receiving service finds the parent span from it and opens a child span.

2 End the span

Question
ctx, span := tracer.Start(ctx, "kaydet")
____ span.End()
Answer
ctx, span := tracer.Start(ctx, "kaydet")
defer span.End()

Explanation: defer span.End() closes the span's duration when the function ends.

3 Tracing concepts

Term Meaning
Trace A request's whole journey
Span A single unit of work
traceparent Header between services
ctx Carries the span through functions

All lessons in Advanced