logx

Monolog-formázó

Egy PHP/Monolog-stílusú konzol-formázó, egy errs hibából kinyert, teljes útvonalú stack trace-szel.

Go-ban az első hideg zuhany gyakran a logolás: a nyers log csomag egysoros, kontextus nélküli kimenete, vagy egy strukturált logger key=value fala, amiben egy stack trace egyetlen escape-elt stringgé lapul. A logx/monolog a logx válasza erre fejlesztés közben: egy konzol-handler, ami aktív formátumként beállítva pontosan úgy néz ki, mint amit PHP-ból ismersz.

Így néz ki

Állítsd be a Format: "monolog"-ot a logx.Config-on (vagy a LOG_FORMAT=monolog-ot, ha a logx.Config a környezetből töltődik), és a konzol így ír:

[2026-07-15 10:23:44] shop.INFO: order placed {"order_id":"o_8412","total":12990}
[2026-07-15 10:23:45] shop.WARNING: payment provider slow, retrying {"attempt":2,"provider":"stripe"} in /home/you/shop/internal/modules/shop/surfaces/api/service/payments.go:114

És amikor egy becsomagolt errs hiba éri el a loggert:

[2026-07-15 10:23:46] shop.ERROR: request failed: shop_out_of_stock: shop: place order: inventory: decrement: insufficient stock {"code":"shop_out_of_stock","method":"POST","path":"/api/v1/shop/orders","status":500}
Stack trace:
#0 /home/you/shop/internal/modules/shop/repository/inventory.go(87): repository.(*InventoryRepository).Decrement()
#1 /home/you/shop/internal/modules/shop/orders.go(41): shop.(*Service).PlaceOrder()
#2 /home/you/shop/internal/modules/shop/surfaces/api/service/orders.go(52): service.(*OrderService).PlaceOrder()
#3 /home/you/shop/internal/modules/shop/surfaces/api/http/handlers.go(61): http.(*Handler).PlaceOrder()
#4 {main}

Ami ebben a pár sorban dolgozik:

  • A channel nevezi meg a rekord forrását (jellemzően egy service nevét), több service logját egymás mellett futtatva is látod, ki beszél. A WARN szint Monolog-hűen WARNING-ként jelenik meg.
  • A hiba fejléce a errs-kóddal kezdődik (shop_out_of_stock: ...), így a hibamód a JSON-rész elolvasása nélkül azonosítható; a kód a JSON contextben is ott van.
  • A stack trace teljes, abszolút útvonalakkal: a legtöbb terminál és editor kattinthatóvá teszi. A frame-ek a hiba keletkezési pontjától felfelé sorakoznak; a dependency-kből (Go module cache-ből) jövő frame-ek halványítva jelennek meg, a runtime-belépési frame-eket a {main} zárósor helyettesíti.
  • A hiba-attr nem duplázódik: a slog.Any("error", err) értéke a fejlécbe és a stack-blokkba kerül, a JSON contextből kimarad.
  • Szín csak terminálon: a NO_COLOR-t és a TERM=dumb-ot tiszteletben tartja, pipe-olt kimenetben nincs escape-szemét.
  • Egy WARN/ERROR rekord errs stack nélkül is kap lokációt: a hívási helye kerül a sor végére in file:line formában.

logx/monolog közelről

A formátum-driver önálló csomag, egyetlen konstruktorral:

import "github.com/gp-system/logx/monolog"

func NewHandler(w io.Writer, level slog.Level, channel string) *Handler

A logx.ConsoleHandler ezt adja vissza, ha a Config.Format "monolog", de bárhova bekötheted, ahol egy slog.Handler elvárt, a logx többi részével vagy anélkül. Amit érdemes tudni róla:

  • slog-natív. A With(...) attr-ok és a WithGroup(...) csoportok helyesen, beágyazott JSON-ként jelennek meg a context-részben ("req":{"status":200}).
  • A stackek forrása az errs. A handler a rekord első hiba-értékű attr-ját emeli ki; ha az (vagy a wrap-láncában bármi) errs hiba, az errs.FullFrames teljes útvonalú stackje renderelődik. Egy sima errors.New hibánál nincs stack-blokk: helyette a log hívási helye kerül a sorba.
  • Párhuzamos futásban is atomi sorok: a handler klónjai közös mutexen írnak, torn write nincs.

Strukturált hibák a logban: errs nélkül semmi ilyen nincs

A fenti stack trace-eket az errs hibákból nyeri, és ez nem konzol-privilégium: az *errs.Error implementálja a slog.LogValuer-t, így bármely strukturált slog.Handler-ben, nemcsak a logx/monolog-ban, a hiba csoportként bomlik ki:

"error": {
  "msg": "shop: place order: inventory: decrement: insufficient stock",
  "code": "shop_out_of_stock",
  "public": "Egy vagy több tétel nincs elegendő készleten.",
  "chain": [ { "msg": "shop: place order", "file": "service/orders.go", "line": 52, "..." : "" }, "" ],
  "stack": [ { "file": "repository/inventory.go", "line": 87, "..." : "" }, "" ]
}

Ugyanaz a hiba tehát dev konzolon PHP-stílusú stack trace, és gépi feldolgozásra kész JSON bármely más handlerben, amibe fanoutolod (a framework OTel log-bridge-e és Sentry-handlere is köztük van, lásd Telemetry: Logolás), mindez egyetlen return err-ből.

Hova lettek a fájl-logok?

Sehova, és ez szándékos: nincs itt single/daily file driver, a logx/monolog arra az io.Writer-re ír, amit a NewHandler-nek átadsz, jellemzően stdoutra. Ez a 12-factor elvet követi: a logok eseményfolyamként a stdout-ra mennek, a gyűjtés-forgatás-őrzés pedig a platform dolga, nem a loggeré. Konténerben a runtime úgyis elkapja a stdout-ot; egy collector, vagy egy sima shell-redirect, viszi tovább onnantól.

Ha lokálisan mégis fájlba akarod fogni: go run ./cmd/myapp 2>&1 | tee myapp.log; pipe-ban a handler automatikusan színek nélkül ír.

Monolog-fogalmak megfelelői

Ha a config/logging.php felől érkezel, így képződnek le a fogalmak:

MonologgpsystemHol
channel neveamit channel-ként átadsz a NewHandler-nek (a framework az OTEL_SERVICE_NAME-et használja)a monolog-sor shop.INFO része
stack driver (több channel egyben)logx.Fanoutlogx: Áttekintés
channel level küszöblogx.LevelFilterlogx: Áttekintés
single / daily file drivernincs (stdout az egyetlen cél)lásd fentebb
formatter (LineFormatter, JSON)logx.Config.Format (auto / monolog)logx: Áttekintés
Log::info('msg', ['ctx' => ...])slog.InfoContext(ctx, "msg", slog.Any("ctx", ...))app-kód
Log::withContext([...])logger := slog.Default().With(...)app-kód
Sentry / Slack channel a stackbenegy másik handler a fanoutbana saját wiringed, vagy a framework fanoutja, lásd Telemetry: Logolás

Kapcsolódó oldalak

  • logx: Áttekintés: telepítés, Config, és a ConsoleHandler/LevelFilter/Fanout kompozíció, amibe ez a formázó bekapcsolódik.
  • errs: Áttekintés: a hibatípus, amiből ennek a formázónak a stack trace-ei jönnek.
  • Telemetry: Logolás: hogyan fanoutolja a framework ezt a handlert az OTel log-bridge és a Sentry capture handler mellé.
Copyright © 2026