CodeBlanks Logo Icon CodeBlanks

Summary - Observability

Combine slog and metrics to write an observability layer.

Observability summary

Three pillars: logs (what happened? — slog), metrics (how much, how often? — counter/gauge/histogram) and traces (where did it slow down? — spans). OpenTelemetry unifies all three in one standard. On top of these, /livez and /readyz let the orchestrator manage the service correctly.

Correlating logs with the trace ID (adding trace_id to log lines) makes moving between the three pillars easy.

Request ID middleware

Giving every request an ID and putting it in both the response header and the logs makes it easy to find an error a user reports:

func istekID(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        id := r.Header.Get("X-Request-ID")
        if id == "" { id = yeniID() }
        w.Header().Set("X-Request-ID", id)
        log := slog.With("istek_id", id)
        log.Info("istek", "yol", r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

Practice Request ID

Write istekID(next http.Handler) http.Handler: copy the incoming X-Request-ID header to the response header, using "yeni" if it is empty. Send a request without the header and print the response's X-Request-ID.

Starter code

main.go
package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
)

func istekID(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        id := r.Header.Get("X-Request-ID")
        if id == "" {
            id = "yeni"
        }
        w.Header().Set("X-Request-ID", id)
        next.ServeHTTP(w, r)
    })
}

func main() {
    h := istekID(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
    rec := httptest.NewRecorder()
    h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
    fmt.Println(rec.Header().Get("X-Request-ID"))
}

Expected output

yeni

Questions and answers

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

1 Which answers "did the error rate rise in the last hour?" fastest?

  • Metrics Correct answer
  • A single trace
  • pprof
  • The source code

Explanation: Rates and trends are what metrics are for; to find why it rose you then drill into the related traces and logs.

2 Structured log

Question
slog.____("ödeme başarısız", "hata", err, "tutar", 120)
Answer
slog.Error("ödeme başarısız", "hata", err, "tutar", 120)

Explanation: slog.Error writes a record at error level together with its fields.

3 Pillar and question

Term Meaning
Log What happened?
Metrik How much?
Trace Where is it slow?
/readyz Can it take traffic?

All lessons in Advanced