Logolás
A gpsystemben a default log/slog logger nem csak egy handler: a telemetry.Setup egy rekordot egyszerre három sinkbe fanoutol, egyetlen minimum-szint szűrő mögött. Az alkalmazáskód kizárólag a standard log/slog-ot importálja, semmi framework-specifikusat; maga a kompozíció az önálló logx modulból épül.
A kompozíció
A telemetry.Setup pontosan így építi a default loggert:
slog.SetDefault(slog.New(
logx.LevelFilter(cfg.Log.Level, logx.Fanout(
logx.ConsoleHandler(os.Stdout, cfg.Log, dev, serviceName), // dev vagy LOG_STDOUT esetén
otelHandle.SlogHandler(), // OTLP bridge, prodban
sentryHandle.SlogHandler(), // Sentry capture, ha a DSN be van állítva
)),
))
A LevelFilter azért ül legkívül, mert nem minden leaf-handler szűr magától: az OTLP bridge például mindent továbbít, amit kap. A Fanout minden handlernek a rekord saját klónját adja, és az Enabled-et handlerenkénti gate-ként tiszteli: egyetlen handler esetén allokáció nélkül, önmagaként tér vissza. Mindkét kombinátor, és maga a konzol-handler is, a logx-ből jön; a telemetry csak a másik két handlert adja (az OTel-bridge-et, a Sentry capture handlert), és a hármat drótozza össze, ez az oldal pontosan erről szól.
LOG_FORMAT (egy logx.Config mező) csak a konzol-handler renderelését választja ki: az OTLP-bridge és a Sentry-handler mindig ugyanazt a strukturált rekordot kapja.Chassis-on belül ezt sosem írod meg: a server.Run / worker.Run / realtime.Run megkapja készen. Ha egy nem-chassis binárisban (CLI, migrátor) ugyanezt a konzol-élményt akarod, vagy egy saját plusz sinket (pl. fájl-handlert) fűznél a fanoutba, nyúlj közvetlenül a logx-hez: a Config mezők és a ConsoleHandler/LevelFilter/Fanout kompozíció önállóan, a logx: Áttekintés oldalon van dokumentálva.
A Monolog-formátumú dev konzol
A LOG_FORMAT=monolog-gal (dev módban ezt érdemes) a konzol PHP/Monolog-stílusú sorokat renderel, [dátum] channel.SZINT: üzenet {context}, alatta egy errs hibából kinyert, teljes útvonalú, PHP-ból ismerős stack trace-szel. Ez a formázó a logx/monolog, és a logx többi részével együtt önálló modulba költözött: maga a formátum, a Laravel/Symfony-fogalommegfeleltetés és a "miért csak stdout" indoklás a logx: Monolog-formázó oldalon van.
(Dev módban a kérésenkénti access-log sorokat a framework strukturált slog access logja írja (az accesslog stack-bejegyzés), így követik a LOG_FORMAT-ot, és az OTel bridge-en át ugyanúgy trace-korreláltak, mint minden más rekord.)
Hogyan logolj a service-ekben
Két szabály van, és mindkettő a context.Context-ről szól:
func (s *OrderService) PlaceOrder(ctx context.Context, in PlaceOrder) error {
// 1. Mindig a *Context változatot, a kérés ctx-ével:
slog.InfoContext(ctx, "order placed",
slog.String("order_id", order.ID),
slog.Int("total", order.Total))
// ...
}
slog.InfoContext/WarnContext/ErrorContext, sosemslog.Info. A ctx hordozza az aktív trace-t: az otelslog bridge ebből fűzi a trace/span ID-t a rekordhoz, a Sentry handler ebből linkeli a hibát a trace waterfallhoz, és a breadcrumb-ok is a kérés hubjára kerülnek. Ctx nélküli log = korrelálatlan log.- Hibát
slog.Any("error", err)-rel adj át, neerr.Error()stringgel: így marad meg a strukturált lánc, a stack és a kód minden sink számára, konzol, OTLP és Sentry egyaránt.
Loggert injektálni, konstruálni, DI-ba kötni nem kell: a chassis a slog.Default()-ot állítja be, a csomag-szintű slog.*Context hívások pont jók. Az ERROR szint pedig nem „hangos log": az egyben Sentry event is: 5xx-et a framework logol helyetted, te akkor logolj ERROR-t, ha valami tényleg incidens.
errs hiba 4xx-ként megy ki, request failed sor és Sentry event nélkül.Merre tovább
- logx: Áttekintés: a
Configmezők (LOG_LEVEL/LOG_STDOUT/LOG_FORMAT), és aConsoleHandler/LevelFilter/Fanoutönálló használathoz, telemetry nélkül. - logx: Monolog-formázó: a PHP-stílusú dev konzolformátum, teljes egészében, a Laravel/Symfony-fogalommegfeleltetéssel.
- OpenTelemetry: az OTLP log-bridge, amibe ez az oldal fanoutja táplál.
- Sentry: a capture handler, amibe ez az oldal fanoutja táplál, és a kód-alapú issue-csoportosítás.