Tek örnekte slog
log/slog (Go 1.21) yapılandırılmış kayıtlar yazar: bir mesaj, bir seviye ve anahtar-değer nitelikleri.
Her satır time=... level=INFO msg="user logged in" user=ada attempts=1 olarak çıkar. Her değer ayrı bir alan olduğu için bir log toplayıcı (Loki, Elasticsearch, CloudWatch, Datadog) serbest metin üzerinde düzenli ifadeler kullanmadan user=ada ya da level=ERROR ile filtreleyebilir.
Bu sayfadaki örnekler, çıktı sırayla görünsün diye os.Stdout'a yazar. Gerçek bir serviste loglar genellikle varsayılan logger'ın da yazdığı yer olan os.Stderr'e gider.
Seviyeler
| Seviye | Değer | Kullanım |
|---|---|---|
slog.LevelDebug | -4 | geliştiriciler için ayrıntılar, production'da kapalı |
slog.LevelInfo | 0 | normal olaylar: başladı, istek karşılandı, iş bitti |
slog.LevelWarn | 4 | programın ele aldığı beklenmedik bir şey |
slog.LevelError | 8 | bir işlem başarısız oldu |
Handler minimum seviyesinin altındaki kayıtları atar ve varsayılan minimum Info'dur. Level: slog.LevelDebug ile bir handler yapılandırana kadar slog.Debug(...)'ın hiçbir şey yazdırmamasının nedeni budur. Değerler arasındaki boşluklar slog.Level(2) gibi özel seviyelere yer bırakır.
Seviyeyi çalışma zamanında (bir bayraktan, bir yönetim endpoint'inden ya da bir sinyalden) değiştirmek için seçeneklere bir slog.LevelVar koyun ve daha sonra onun üzerinde Set çağırın:
var level slog.LevelVar // zero value: Info
logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: &level}))
level.Set(slog.LevelDebug) // from now on, debug records are written
Text mi, JSON mu
slog.NewTextHandler, terminalde okunması kolay key=value çiftleri yazar. slog.NewJSONHandler, çoğu log hattının beklediği biçim olan satır başına bir JSON nesnesi yazar. Loglama çağrıları aynı kalır; yalnızca handler değişir.
Değerler tiplerini korur: JSON çıktısında status bir sayı, retry bir boolean'dır; bir time.Duration text'te 42ms, JSON'da nanosaniye olarak yazdırılır ve bir error mesajını yazdırır. ReplaceAttr, nitelikleri yeniden yazmak ya da kaldırmak için kancadır; burada zaman damgasını atmak için, pratikte ise anahtarları yeniden adlandırmak (msg'yi message yapmak) ya da değerleri maskelemek için kullanılır.
Nitelikler
Gevşek tipli biçim anahtarları ve değerleri sırayla yazar: "user", "ada", "attempts", 3. Kısadır ve tek bir başarısızlık biçimi vardır: tek sayıda argüman. Artan değer !BADKEY anahtarı altında loglanır. go vet bunu yakalar:
./main.go:14:2: call to slog.Info missing a final value
Tip güvenliği ve biraz daha az bellek ayırma için nitelik kurucularını, sık çalışan bir yolda loglarken de LogAttrs'ı kullanın:
logger.Info("order placed",
slog.Int("order_id", 1017),
slog.String("currency", "EUR"),
slog.Float64("total", 59.90),
slog.Duration("took", elapsed),
)
logger.LogAttrs(ctx, slog.LevelInfo, "order placed", slog.Int("order_id", 1017))
Kod tabanı genelinde anahtarlar için tek bir adlandırma geleneği kullanın (bir pakette userID, bir başkasında uid değil, her yerde user_id). Log sisteminizdeki sorgular buna bağlıdır.
With: bağlam taşıyan logger'lar
logger.With(attrs...), bu nitelikleri her kayda ekleyen yeni bir logger döndürür. İstek ya da iş başına bir tane oluşturun, yazdığı her satır birbirine bağlanabilir:
Her satır, her çağrıda tekrarlanmadan service, version, request_id ve user taşır. slog.Group nitelikleri iç içe koyar; JSON handler'ı bunu iç içe bir nesne olarak ("payment":{"amount":25,"currency":"USD"}), text handler'ı ise noktalı anahtarlar olarak (payment.amount=25) yazar. logger.WithGroup("db"), o logger'ın sonraki her niteliğini bir grubun altına koyar.
İstek kapsamlı logger'ı bir parametre ya da struct alanı olarak aşağıya aktarın. Onu bir context.Context içinde saklamak mümkündür ama bağımlılığı gizler; slog'un InfoContext(ctx, ...) metotları context'i handler'a aktarır, özel bir handler da bunu trace ID'lerini çıkarmak için kullanabilir.
LogValuer ile sırları gizlemek
Bir tip slog.LogValuer'ı gerçekleştirerek nasıl loglanacağını kontrol edebilir. Bu, değeri kim loglarsa loglasın parolaları ve token'ları logların dışında tutar:
User yalnızca ID'sini ve e-postasını loglar, tek başına loglanan bir Token ise REDACTED yazdırır. Handler LogValue'yu yalnızca kayıt gerçekten yazıldığında çağırır, bu yüzden hesaplanması pahalı değerler için de işe yarar.
Klasik log paketi
log, slog'dan eskidir ve küçük programlar ve betikler için hâlâ uygundur. Standart hataya tarih ve saat önekiyle satırlar yazar:
| Bayrak | Ekledikleri |
|---|---|
log.LstdFlags (varsayılan) | 2009/11/10 23:00:00 tarih ve saat |
log.Lmicroseconds | saate mikrosaniyeler |
log.LUTC | UTC cinsinden saat |
log.Lshortfile / log.Llongfile | main.go:14 / tam yol |
log.Lmsgprefix | öneki satırın başına değil mesajın önüne koyar |
Üç fonksiyon çıkış yapar ya da panic olur ve fark önemlidir:
log.Fatal,log.Fatalf,log.Fatallnyazdırır ve sonraos.Exit(1)çağırır. Ertelenmiş çağrılar çalışmaz. Onları başlangıç başarısızlıkları içinmainiçinde kullanın, kütüphane kodunda ya da istek handler'larında asla kullanmayın.log.Panicve benzerleri yazdırır ve sonra panic yapar, bu yüzden ertelenmiş çağrılar çalışır ve panic recover edilebilir.- Diğer her fonksiyon yalnızca bir satır yazar.
Bir dosyaya loglamak için onu açıp log.New'a ya da log.SetOutput'a aktarın; io.MultiWriter(os.Stderr, f) ikisine birden yazar.
log ve slog birlikte
slog.SetDefault(logger), logger'ı üst seviye slog.Info fonksiyonları için varsayılan yapar ve log paketinin çıktısını da onun üzerinden yönlendirir. Kodunuzdaki ya da bağımlılıklardaki var olan log.Printf çağrıları o zaman Info seviyesinde yapılandırılmış kayıtlar olarak çıkar:
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, nil)))
log.Printf("legacy message") // {"time":"...","level":"INFO","msg":"legacy message"}
SetDefault'tan önce varsayılan slog logger'ı log paketi üzerinden yazar; çıplak bir slog.Info("hi")'ın 2026/09/23 14:30:00 INFO hi yazdırmasının nedeni budur.
Pratik kurallar
- Bir hatayı ya loglayın ya döndürün, ikisini birden değil. Bir hatayı loglayıp döndüren bir fonksiyon aynı başarısızlığın çağrı yığınının her seviyesinde loglanmasına yol açar. Hataları bağlamla yukarı döndürün ve ele alındıkları yerde bir kez loglayın.
- Değişken veriyi mesaja değil niteliklere koyun.
logger.Info("user created", "user_id", id)bir log sisteminde iyi gruplanır;logger.Info(fmt.Sprintf("user %d created", id))her kullanıcı için farklı bir mesaj oluşturur. - Sırları ya da tam istek gövdelerini asla loglamayın. Maskelemek için
LogValuerya daReplaceAttrkullanın. - Production'da JSON, geliştirmede text kullanın. Handler'ı başlangıçta bir bayraktan ya da bir ortam değişkeninden seçin.
- Seviyeleri bilinçli seçin. Her şey Error seviyesinde loglanırsa hatalar üzerindeki alarmlar gürültüye dönüşür.
Sıkça Sorulan Sorular
Go'da slog nedir?
log/slog, Go 1.21'de standart kütüphaneye eklenen yapılandırılmış loglama paketidir. Biçimlendirilmiş string'ler yerine her kaydın bir mesajı, bir seviyesi (Debug, Info, Warn, Error) ve anahtar-değer nitelikleri vardır ve bir handler onu key=value metni ya da JSON olarak yazar: slog.Info("login", "user", "ada", "attempts", 3).
slog'da debug logları nasıl açılır?
Varsayılan minimum seviye Info'dur, bu yüzden slog.Debug hiçbir şey yazdırmaz. Daha düşük seviyeli bir handler oluşturun ve onu varsayılan yapın: slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug}))). Program çalışırken seviyeyi değiştirmek istiyorsanız bir sabit yerine bir slog.LevelVar kullanın.
Go'da log ile slog arasındaki fark nedir?
log, isteğe bağlı bir zaman damgası önekiyle serbest biçimli satırlar yazar ve seviyeleri yoktur. slog, log toplayıcıların ayrıştırıp filtreleyebileceği seviyeli ve tipli anahtar-değer nitelikli kayıtlar yazar. İkisi de standart kütüphanededir; slog.SetDefault, log paketinin çıktısını da slog handler'ı üzerinden yönlendirir.
log.Fatal ertelenmiş fonksiyonları çalıştırır mı?
Hayır. log.Fatal ve log.Fatalf mesajı yazdırır ve tüm ertelenmiş çağrıları atlayan os.Exit(1)'i çağırır. Onları yalnızca temizlenecek bir şeyin olmadığı main ya da kurulum kodunda kullanın. log.Panic ise panic yapar, bu yüzden ertelenmiş çağrılar çalışır.