GoDasturchi
Request Logging & Correlation IDs

Request Logging & Correlation IDs

So'rovlarni loglash va correlation ID'lar

Bemorga kasalxonaga kelganda BILAKUZUK (wristband) taqib qo'yishadi — undagi RAQAM orqali laboratoriya, rentgen, dorixona — HAR BIR bo'lim bir xil BEMORNING ma'lumotlarini bir-biriga ULAY oladi, garchi ular BUTUNLAY boshqa xonalarda ishlasa ham. Correlation ID — API'da xuddi shu "bilakuzuk": har bir so'rovga BIRINCHI qadamda beriladigan noyob identifikator, va so'rov qaysi handler, middleware yoki ("Distributed Tracing Basics" darsidagi kabi) qaysi MIKROSERVISGA o'tmasin, LOG yozuvlarida BIR XIL ID orqali kuzatiladi.

example.go
package main

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

type ctxKey string

const correlationIDKey ctxKey = "correlationID"

var counter int

// nextCorrelationID — HAR BIR yangi so'rov uchun noyob identifikator yaratadi
func nextCorrelationID() string {
	counter++
	return fmt.Sprintf("req-%d", counter)
}

// loggingMiddleware — HAR BIR so'rovga correlation ID biriktiradi va uni LOGGA yozadi
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id := r.Header.Get("X-Correlation-ID")
		if id == "" {
			id = nextCorrelationID()
		}
		ctx := context.WithValue(r.Context(), correlationIDKey, id)
		w.Header().Set("X-Correlation-ID", id)
		fmt.Printf("[%s] %s %s\n", id, r.Method, r.URL.Path)
		next(w, r.WithContext(ctx))
	}
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /books/{id}", loggingMiddleware(func(w http.ResponseWriter, r *http.Request) {
		id := r.Context().Value(correlationIDKey)
		fmt.Fprintf(w, "handler ichida correlation ID: %s", id)
	}))

	req1 := httptest.NewRequest("GET", "/books/1", nil)
	rec1 := httptest.NewRecorder()
	mux.ServeHTTP(rec1, req1)
	fmt.Println(rec1.Body.String())

	req2 := httptest.NewRequest("GET", "/books/2", nil)
	req2.Header.Set("X-Correlation-ID", "upstream-req-99")
	rec2 := httptest.NewRecorder()
	mux.ServeHTTP(rec2, req2)
	fmt.Println(rec2.Body.String())
}

context.WithValue ("Context Basics" darsini eslang) — correlation ID'ni HANDLER zanjiri bo'ylab, EXPLICIT parametr sifatida uzatmasdan, context.Context ICHIDA "yashirincha" olib o'tadi. Ikkinchi so'rovda X-Correlation-ID: upstream-req-99 sarlavhasi ALLAQACHON BERILGAN — bu HAQIQIY mikroservis arxitekturasida yuz beradigan holat: bitta so'rov BOSHQA servisdan kelayotganda, o'sha servis O'ZINING correlation ID'sini uzatadi, va biz uni YANGISI bilan almashtirmasdan, DAVOM ettiramiz.

Natijada: BIRINCHI so'rov o'zining req-1 ID'sini avtomatik OLADI, IKKINCHI so'rov esa yuqoridan kelgan upstream-req-99 ID'sini SAQLAB QOLADI. Agar keyinchalik ANIQ shu so'rov bilan bog'liq xatoni LOGLARDAN qidirish kerak bo'lsa, BITTA ID orqali BUTUN so'rov "hayoti"ni KUZATISH mumkin.

>_ Exercise

Log qatoriga JAVOB statusini ham qo'shing.

  • statusRecorder struct'ini yozing: http.ResponseWriter'ni EMBED qiling, qo'shimcha status int maydoni bilan
  • statusRecorder uchun WriteHeader(status int) metodini OVERRIDE qiling: status'ni saqlab, so'ng ICHKI ResponseWriter'ning WriteHeader'ini chaqiring
  • loggingMiddleware'ni o'zgartiring: next'ni CHAQIRISHDAN OLDIN emas, next TUGAGANDAN KEYIN, statusRecorder.status bilan birga LOGGA yozing
  • id="1" (200 qaytaradigan) va id="99" (404 qaytaradigan) uchun so'rov yuboring — log qatorlari to'g'ri statusni ko'rsatishi kerak

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Correlation ID — har bir so'rovni context orqali BOSHIDAN OXIRIGACHA kuzatib boradigan noyob identifikator; ResponseWriter'ni EMBED qilib status kodni "ushlab qolish" — middleware'da javobning YAKUNIY natijasini LOGLASH uchun standart naqsh.

NEXT UP

Content Negotiation

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Request Logging & Correlation IDs

So'rovlarni loglash va correlation ID'lar

Bemorga kasalxonaga kelganda BILAKUZUK (wristband) taqib qo'yishadi — undagi RAQAM orqali laboratoriya, rentgen, dorixona — HAR BIR bo'lim bir xil BEMORNING ma'lumotlarini bir-biriga ULAY oladi, garchi ular BUTUNLAY boshqa xonalarda ishlasa ham. Correlation ID — API'da xuddi shu "bilakuzuk": har bir so'rovga BIRINCHI qadamda beriladigan noyob identifikator, va so'rov qaysi handler, middleware yoki ("Distributed Tracing Basics" darsidagi kabi) qaysi MIKROSERVISGA o'tmasin, LOG yozuvlarida BIR XIL ID orqali kuzatiladi.

example.go
package main

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

type ctxKey string

const correlationIDKey ctxKey = "correlationID"

var counter int

// nextCorrelationID — HAR BIR yangi so'rov uchun noyob identifikator yaratadi
func nextCorrelationID() string {
	counter++
	return fmt.Sprintf("req-%d", counter)
}

// loggingMiddleware — HAR BIR so'rovga correlation ID biriktiradi va uni LOGGA yozadi
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id := r.Header.Get("X-Correlation-ID")
		if id == "" {
			id = nextCorrelationID()
		}
		ctx := context.WithValue(r.Context(), correlationIDKey, id)
		w.Header().Set("X-Correlation-ID", id)
		fmt.Printf("[%s] %s %s\n", id, r.Method, r.URL.Path)
		next(w, r.WithContext(ctx))
	}
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /books/{id}", loggingMiddleware(func(w http.ResponseWriter, r *http.Request) {
		id := r.Context().Value(correlationIDKey)
		fmt.Fprintf(w, "handler ichida correlation ID: %s", id)
	}))

	req1 := httptest.NewRequest("GET", "/books/1", nil)
	rec1 := httptest.NewRecorder()
	mux.ServeHTTP(rec1, req1)
	fmt.Println(rec1.Body.String())

	req2 := httptest.NewRequest("GET", "/books/2", nil)
	req2.Header.Set("X-Correlation-ID", "upstream-req-99")
	rec2 := httptest.NewRecorder()
	mux.ServeHTTP(rec2, req2)
	fmt.Println(rec2.Body.String())
}

context.WithValue ("Context Basics" darsini eslang) — correlation ID'ni HANDLER zanjiri bo'ylab, EXPLICIT parametr sifatida uzatmasdan, context.Context ICHIDA "yashirincha" olib o'tadi. Ikkinchi so'rovda X-Correlation-ID: upstream-req-99 sarlavhasi ALLAQACHON BERILGAN — bu HAQIQIY mikroservis arxitekturasida yuz beradigan holat: bitta so'rov BOSHQA servisdan kelayotganda, o'sha servis O'ZINING correlation ID'sini uzatadi, va biz uni YANGISI bilan almashtirmasdan, DAVOM ettiramiz.

Natijada: BIRINCHI so'rov o'zining req-1 ID'sini avtomatik OLADI, IKKINCHI so'rov esa yuqoridan kelgan upstream-req-99 ID'sini SAQLAB QOLADI. Agar keyinchalik ANIQ shu so'rov bilan bog'liq xatoni LOGLARDAN qidirish kerak bo'lsa, BITTA ID orqali BUTUN so'rov "hayoti"ni KUZATISH mumkin.

>_ Exercise

Log qatoriga JAVOB statusini ham qo'shing.

  • statusRecorder struct'ini yozing: http.ResponseWriter'ni EMBED qiling, qo'shimcha status int maydoni bilan
  • statusRecorder uchun WriteHeader(status int) metodini OVERRIDE qiling: status'ni saqlab, so'ng ICHKI ResponseWriter'ning WriteHeader'ini chaqiring
  • loggingMiddleware'ni o'zgartiring: next'ni CHAQIRISHDAN OLDIN emas, next TUGAGANDAN KEYIN, statusRecorder.status bilan birga LOGGA yozing
  • id="1" (200 qaytaradigan) va id="99" (404 qaytaradigan) uchun so'rov yuboring — log qatorlari to'g'ri statusni ko'rsatishi kerak

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Correlation ID — har bir so'rovni context orqali BOSHIDAN OXIRIGACHA kuzatib boradigan noyob identifikator; ResponseWriter'ni EMBED qilib status kodni "ushlab qolish" — middleware'da javobning YAKUNIY natijasini LOGLASH uchun standart naqsh.

NEXT UP

Content Negotiation