Yapılandırılmış Loglama
Yapılandırılmış loglama, düz metin yerine makine tarafından okunabilir log çıktısı (genellikle JSON) üretir. Bu, logları ELK Stack, Datadog veya Grafana Loki gibi log toplama sistemlerinde aramayı, filtrelemeyi ve analiz etmeyi kolaylaştırır.
Neden yapılandırılmış loglama?
Gin’in varsayılan logger’ı, geliştirme için harika olan ancak ölçekte ayrıştırması zor olan insan tarafından okunabilir metin çıktısı verir. Yapılandırılmış loglama size şunları sağlar:
- Sorgulanabilir alanlar — logları durum kodu, gecikme veya kullanıcı kimliğine göre filtreleme
- Tutarlı format — her log girişi aynı şekle sahiptir
- Korelasyon — istek kimliklerini kullanarak hizmetler arasında bir isteği izleme
slog kullanımı (Go 1.21+)
Go’nun standart kütüphanesi, yapılandırılmış loglama için log/slog içerir. Gin ile nasıl kullanılacağı:
package main
import ( "log/slog" "os" "time"
"github.com/gin-gonic/gin")
func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery
c.Next()
logger.Info("request", slog.String("method", c.Request.Method), slog.String("path", path), slog.String("query", query), slog.Int("status", c.Writer.Status()), slog.Duration("latency", time.Since(start)), slog.String("client_ip", c.ClientIP()), slog.Int("body_size", c.Writer.Size()), )
if len(c.Errors) > 0 { for _, err := range c.Errors { logger.Error("request error", slog.String("error", err.Error())) } } }}
func main() { logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
r := gin.New() r.Use(SlogMiddleware(logger)) r.Use(gin.Recovery())
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
r.Run(":8080")}Bu, şu tarz log girişleri üretir:
{"time":"2024-01-15T10:30:00Z","level":"INFO","msg":"request","method":"GET","path":"/ping","query":"","status":200,"latency":"125µs","client_ip":"127.0.0.1","body_size":18}İstek Kimliği / Korelasyon Kimliği
Her log girişine benzersiz bir istek kimliği eklemek, hizmetler arasında istekleri izlemeye yardımcı olur:
package main
import ( "log/slog" "os" "time"
"github.com/gin-gonic/gin" "github.com/google/uuid")
func RequestIDMiddleware() gin.HandlerFunc { return func(c *gin.Context) { requestID := c.GetHeader("X-Request-ID") if requestID == "" { requestID = uuid.New().String() } c.Set("request_id", requestID) c.Header("X-Request-ID", requestID) c.Next() }}
func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now()
c.Next()
requestID, _ := c.Get("request_id") logger.Info("request", slog.String("request_id", requestID.(string)), slog.String("method", c.Request.Method), slog.String("path", c.Request.URL.Path), slog.Int("status", c.Writer.Status()), slog.Duration("latency", time.Since(start)), ) }}
func main() { logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
r := gin.New() r.Use(RequestIDMiddleware()) r.Use(SlogMiddleware(logger)) r.Use(gin.Recovery())
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
r.Run(":8080")}zerolog kullanımı
zerolog, popüler bir sıfır tahsisli JSON logger’dır:
package main
import ( "os" "time"
"github.com/gin-gonic/gin" "github.com/rs/zerolog" "github.com/rs/zerolog/log")
func ZerologMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now()
c.Next()
log.Info(). Str("method", c.Request.Method). Str("path", c.Request.URL.Path). Int("status", c.Writer.Status()). Dur("latency", time.Since(start)). Str("client_ip", c.ClientIP()). Msg("request") }}
func main() { zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
// Pretty logging for development if gin.Mode() == gin.DebugMode { log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) }
r := gin.New() r.Use(ZerologMiddleware()) r.Use(gin.Recovery())
r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) })
r.Run(":8080")}En iyi uygulamalar
- Üretimde JSON formatı kullanın — geliştirme için insan tarafından okunabilir format, üretim log toplama için JSON
- İstek kimlikleri ekleyin — dağıtılmış izleme için
X-Request-IDbaşlıklarını hizmet sınırları boyunca yayın - Uygun düzeylerde loglayın — normal istekler için
Info, 4xx içinWarn, 5xx içinErrorkullanın - Hassas verileri loglamaktan kaçının — şifreleri, tokenları ve kişisel bilgileri log çıktısından hariç tutun
GIN_MODE=releaseayarlayın — bu, üretimde Gin’in varsayılan hata ayıklama loglamasını devre dışı bırakır