[{"data":1,"prerenderedAt":1910},["ShallowReactive",2],{"navigation_docs_en":3,"-en-observability-logging":342,"-en-observability-logging-surround":1905},[4,45,61,96,132,166,196,217,241,265],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F10.reference",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F10.reference\u002F1.configuration","i-lucide-settings",{"title":57,"path":58,"stem":59,"icon":60},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F10.reference\u002F2.dependencies","i-lucide-package",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[67,72,77,82,86,91],{"title":68,"path":69,"stem":70,"icon":71},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture","i-lucide-layers",{"title":73,"path":74,"stem":75,"icon":76},"Application lifecycle","\u002Fen\u002Fconcepts\u002Fapplication-lifecycle","en\u002F2.concepts\u002F2.application-lifecycle","i-lucide-power",{"title":78,"path":79,"stem":80,"icon":81},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F3.error-model","i-lucide-shield-alert",{"title":52,"path":83,"stem":84,"icon":85},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F4.configuration","i-lucide-settings-2",{"title":87,"path":88,"stem":89,"icon":90},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F5.codegen-pipeline","i-lucide-file-json",{"title":92,"path":93,"stem":94,"icon":95},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F6.design-patterns","i-lucide-puzzle",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":44},"HTTP & Routing","i-lucide-globe","\u002Fen\u002Fhttp","en\u002F3.http",[102,107,112,117,122,127],{"title":103,"path":104,"stem":105,"icon":106},"The server core","\u002Fen\u002Fhttp\u002Fserver","en\u002F3.http\u002F1.server","i-lucide-server",{"title":108,"path":109,"stem":110,"icon":111},"The Fiber engine","\u002Fen\u002Fhttp\u002Ffiber","en\u002F3.http\u002F2.fiber","i-lucide-zap",{"title":113,"path":114,"stem":115,"icon":116},"The chi engine","\u002Fen\u002Fhttp\u002Fchi","en\u002F3.http\u002F3.chi","i-lucide-route",{"title":118,"path":119,"stem":120,"icon":121},"Error responses","\u002Fen\u002Fhttp\u002Ferror-responses","en\u002F3.http\u002F4.error-responses","i-lucide-octagon-alert",{"title":123,"path":124,"stem":125,"icon":126},"Validation","\u002Fen\u002Fhttp\u002Fvalidation","en\u002F3.http\u002F5.validation","i-lucide-badge-check",{"title":128,"path":129,"stem":130,"icon":131},"Pagination","\u002Fen\u002Fhttp\u002Fpagination","en\u002F3.http\u002F6.pagination","i-lucide-list-ordered",{"title":133,"icon":134,"path":135,"stem":136,"children":137,"page":44},"Database","i-lucide-database","\u002Fen\u002Fdatabase","en\u002F4.database",[138,142,147,151,156,161],{"title":139,"path":140,"stem":141,"icon":134},"Overview","\u002Fen\u002Fdatabase\u002Foverview","en\u002F4.database\u002F1.overview",{"title":143,"path":144,"stem":145,"icon":146},"pgx","\u002Fen\u002Fdatabase\u002Fpgx","en\u002F4.database\u002F2.pgx","i-lucide-plug",{"title":148,"path":149,"stem":150,"icon":71},"bun","\u002Fen\u002Fdatabase\u002Fbun","en\u002F4.database\u002F3.bun",{"title":152,"path":153,"stem":154,"icon":155},"Transactions","\u002Fen\u002Fdatabase\u002Ftransactions","en\u002F4.database\u002F4.transactions","i-lucide-git-merge",{"title":157,"path":158,"stem":159,"icon":160},"Migrations","\u002Fen\u002Fdatabase\u002Fmigrations","en\u002F4.database\u002F5.migrations","i-lucide-file-stack",{"title":162,"path":163,"stem":164,"icon":165},"Seeders","\u002Fen\u002Fdatabase\u002Fseeding","en\u002F4.database\u002F6.seeding","i-lucide-sprout",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":44},"Async & Background","i-lucide-workflow","\u002Fen\u002Fasync","en\u002F5.async",[172,176,181,186,191],{"title":173,"path":174,"stem":175,"icon":131},"Queue","\u002Fen\u002Fasync\u002Fqueue","en\u002F5.async\u002F1.queue",{"title":177,"path":178,"stem":179,"icon":180},"Events","\u002Fen\u002Fasync\u002Fevents","en\u002F5.async\u002F2.events","i-lucide-radio",{"title":182,"path":183,"stem":184,"icon":185},"Outbox","\u002Fen\u002Fasync\u002Foutbox","en\u002F5.async\u002F3.outbox","i-lucide-inbox",{"title":187,"path":188,"stem":189,"icon":190},"Scheduling","\u002Fen\u002Fasync\u002Fscheduler","en\u002F5.async\u002F4.scheduler","i-lucide-calendar-clock",{"title":192,"path":193,"stem":194,"icon":195},"Worker","\u002Fen\u002Fasync\u002Fworker","en\u002F5.async\u002F5.worker","i-lucide-cog",{"title":197,"icon":198,"path":199,"stem":200,"children":201,"page":44},"Security","i-lucide-shield-check","\u002Fen\u002Fsecurity","en\u002F6.security",[202,207,212],{"title":203,"path":204,"stem":205,"icon":206},"Authentication","\u002Fen\u002Fsecurity\u002Fauthentication","en\u002F6.security\u002F1.authentication","i-lucide-key-round",{"title":208,"path":209,"stem":210,"icon":211},"RBAC","\u002Fen\u002Fsecurity\u002Frbac","en\u002F6.security\u002F2.rbac","i-lucide-users",{"title":213,"path":214,"stem":215,"icon":216},"Policies","\u002Fen\u002Fsecurity\u002Fpolicies","en\u002F6.security\u002F3.policies","i-lucide-gavel",{"title":218,"icon":219,"path":220,"stem":221,"children":222,"page":44},"Observability","i-lucide-activity","\u002Fen\u002Fobservability","en\u002F7.observability",[223,226,231,236],{"title":139,"path":224,"stem":225,"icon":219},"\u002Fen\u002Fobservability\u002Foverview","en\u002F7.observability\u002F1.overview",{"title":227,"path":228,"stem":229,"icon":230},"Logging","\u002Fen\u002Fobservability\u002Flogging","en\u002F7.observability\u002F2.logging","i-lucide-scroll-text",{"title":232,"path":233,"stem":234,"icon":235},"OpenTelemetry","\u002Fen\u002Fobservability\u002Fopentelemetry","en\u002F7.observability\u002F3.opentelemetry","i-lucide-radar",{"title":237,"path":238,"stem":239,"icon":240},"Sentry","\u002Fen\u002Fobservability\u002Fsentry","en\u002F7.observability\u002F4.sentry","i-lucide-bug",{"title":242,"icon":243,"path":244,"stem":245,"children":246,"page":44},"Storage & Mail","i-lucide-hard-drive","\u002Fen\u002Fstorage-mail","en\u002F8.storage-mail",[247,251,256,261],{"title":248,"path":249,"stem":250,"icon":243},"Storage","\u002Fen\u002Fstorage-mail\u002Fstorage","en\u002F8.storage-mail\u002F1.storage",{"title":252,"path":253,"stem":254,"icon":255},"Email","\u002Fen\u002Fstorage-mail\u002Fmail","en\u002F8.storage-mail\u002F2.mail","i-lucide-mail",{"title":257,"path":258,"stem":259,"icon":260},"Notifications","\u002Fen\u002Fstorage-mail\u002Fnotifications","en\u002F8.storage-mail\u002F3.notifications","i-lucide-bell",{"title":262,"path":263,"stem":264,"icon":180},"Realtime","\u002Fen\u002Fstorage-mail\u002Frealtime","en\u002F8.storage-mail\u002F4.realtime",{"title":266,"icon":267,"path":268,"stem":269,"children":270,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F9.cli",[271,274,279,284,289,294,299,303,308,313,318,323,328,333,337],{"title":139,"path":272,"stem":273,"icon":267},"\u002Fen\u002Fcli\u002Foverview","en\u002F9.cli\u002F1.overview",{"title":275,"path":276,"stem":277,"icon":278},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F9.cli\u002F10.add-db","i-lucide-database-zap",{"title":280,"path":281,"stem":282,"icon":283},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F9.cli\u002F11.add-compose","i-lucide-container",{"title":285,"path":286,"stem":287,"icon":288},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F9.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":290,"path":291,"stem":292,"icon":293},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F9.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":295,"path":296,"stem":297,"icon":298},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F9.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":300,"path":301,"stem":302,"icon":165},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F9.cli\u002F15.add-seeder",{"title":304,"path":305,"stem":306,"icon":307},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F9.cli\u002F2.new-project","i-lucide-folder-plus",{"title":309,"path":310,"stem":311,"icon":312},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F9.cli\u002F3.new-module","i-lucide-blocks",{"title":314,"path":315,"stem":316,"icon":317},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F9.cli\u002F4.add-surface","i-lucide-layers-2",{"title":319,"path":320,"stem":321,"icon":322},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F9.cli\u002F5.add-core","i-lucide-box",{"title":324,"path":325,"stem":326,"icon":327},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F9.cli\u002F6.add-handler","i-lucide-webhook",{"title":329,"path":330,"stem":331,"icon":332},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F9.cli\u002F7.new-migration","i-lucide-file-plus",{"title":334,"path":335,"stem":336,"icon":195},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F9.cli\u002F8.worker-generators",{"title":338,"path":339,"stem":340,"icon":341},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F9.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"id":343,"title":227,"body":344,"description":1898,"extension":1899,"links":1900,"meta":1901,"navigation":1902,"path":228,"seo":1903,"stem":229,"__hash__":1904},"docs_en\u002Fen\u002F7.observability\u002F2.logging.md",{"type":345,"value":346,"toc":1888},"minimark",[347,360,387,392,404,414,425,431,434,530,545,553,556,570,643,653,657,675,825,831,980,992,1010,1014,1017,1084,1097,1144,1148,1168,1421,1430,1434,1441,1587,1605,1609,1630,1651,1655,1661,1814,1850,1871,1884],[348,349,350,351,355,356,359],"p",{},"In Go, the first cold shower is often logging: the raw ",[352,353,354],"code",{},"log"," package's one-line, context-free output, or a structured logger's wall of ",[352,357,358],{},"key=value"," where a stack trace collapses into a single escaped string.",[348,361,362,363,370,371,374,375,378,379,382,383,386],{},"The kit's answer has two layers. The base is ",[364,365,366,367],"strong",{},"standard ",[352,368,369],{},"log\u002Fslog",": application code imports only that, nothing kit-specific. On top, the ",[352,372,373],{},"logx"," package adds composition, and a ",[364,376,377],{},"Monolog-format console handler"," (",[352,380,381],{},"logx\u002Fmonolog",") that in dev mode looks exactly like what you know from PHP: ",[352,384,385],{},"[date] channel.LEVEL: message {context}",", followed by a PHP-style stack trace with full file paths.",[388,389,391],"h2",{"id":390},"what-it-looks-like","What it looks like",[348,393,394,395,398,399,403],{},"Set ",[352,396,397],{},"LOG_FORMAT=monolog"," (recommended in dev mode) and the ",[400,401,402],"a",{"href":41},"shop","'s console reads like this:",[405,406,412],"pre",{"className":407,"code":409,"language":410,"meta":411},[408],"language-text","[2026-07-15 10:23:44] shop.INFO: order placed {\"order_id\":\"o_8412\",\"total\":12990}\n[2026-07-15 10:23:45] shop.WARNING: payment provider slow, retrying {\"attempt\":2,\"provider\":\"stripe\"} in \u002Fhome\u002Fyou\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fsurfaces\u002Fapi\u002Fservice\u002Fpayments.go:114\n","text","",[352,413,409],{"__ignoreMap":411},[348,415,416,417,420,421,424],{},"And when ",[352,418,419],{},"PlaceOrder"," runs into our canonical error, ",[352,422,423],{},"ErrOutOfStock",":",[405,426,429],{"className":427,"code":428,"language":410,"meta":411},[408],"[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\":\"\u002Fapi\u002Fv1\u002Fshop\u002Forders\",\"status\":500}\nStack trace:\n#0 \u002Fhome\u002Fyou\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Frepository\u002Finventory.go(87): repository.(*InventoryRepository).Decrement()\n#1 \u002Fhome\u002Fyou\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fcore\u002Forders.go(41): core.(*Service).PlaceOrder()\n#2 \u002Fhome\u002Fyou\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fsurfaces\u002Fapi\u002Fservice\u002Forders.go(52): service.(*OrderService).PlaceOrder()\n#3 \u002Fhome\u002Fyou\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fsurfaces\u002Fapi\u002Fhttp\u002Fhandlers.go(61): http.(*Handler).PlaceOrder()\n#4 {main}\n",[352,430,428],{"__ignoreMap":411},[348,432,433],{},"What's at work in these few lines:",[435,436,437,459,472,482,500,514],"ul",{},[438,439,440,378,443,446,447,450,451,454,455,458],"li",{},[364,441,442],{},"The channel is the service name",[352,444,445],{},"OTEL_SERVICE_NAME",", falling back to ",[352,448,449],{},"app","), so running several services' logs side by side, you can still see who is talking. The ",[352,452,453],{},"WARN"," level renders Monolog-faithfully as ",[352,456,457],{},"WARNING",".",[438,460,461,378,468,471],{},[364,462,463,464,467],{},"The error headline leads with the ",[352,465,466],{},"errs"," code",[352,469,470],{},"shop_out_of_stock: ...","), so the failure mode is identifiable without reading the JSON tail; the code also appears in the JSON context.",[438,473,474,477,478,481],{},[364,475,476],{},"The stack trace is complete, with absolute paths",": most terminals and editors make them clickable. Frames run from the error's point of origin upward; frames from dependencies (the Go module cache) are dimmed, and the runtime entry frames are replaced by the terminal ",[352,479,480],{},"{main}"," line.",[438,483,484,487,488,491,492,495,496,499],{},[364,485,486],{},"The error attr is not duplicated",": the value of ",[352,489,490],{},"slog.Any(\"error\", err)"," goes into the headline and the stack block and is excluded from the JSON context (along with ",[352,493,494],{},"httperr","'s duplicate ",[352,497,498],{},"cause"," attr).",[438,501,502,505,506,509,510,513],{},[364,503,504],{},"Color only on a terminal",": ",[352,507,508],{},"NO_COLOR"," and ",[352,511,512],{},"TERM=dumb"," are honored; piped output carries no escape garbage.",[438,515,516,517,519,520,523,524,526,527,458],{},"A ",[352,518,453],{},"\u002F",[352,521,522],{},"ERROR"," record without an ",[352,525,466],{}," stack still gets a location: its call site is appended as ",[352,528,529],{}," in file:line",[348,531,532,533,535,536,539,540,544],{},"The error above was logged by the ",[352,534,494],{}," error handler (",[352,537,538],{},"request failed",", with method\u002Fpath\u002Fstatus attrs). All you did was return the error from the service. The stack was not captured there: the ",[400,541,542],{"href":79},[352,543,466],{}," error recorded it at birth, and the same full stack is readable from any point of the wrap chain.",[546,547,548,549,552],"note",{},"This is strictly a console format. The OTLP log bridge and the Sentry handler receive the same structured record as before: ",[352,550,551],{},"LOG_FORMAT"," only decides what you see in the terminal.",[388,554,52],{"id":555},"configuration",[348,557,558,561,562,565,566,569],{},[352,559,560],{},"logx.Config"," is the ",[352,563,564],{},"Log"," field of ",[352,567,568],{},"telemetry.Config",", and the variables load unprefixed, at the top level:",[571,572,573,589],"table",{},[574,575,576],"thead",{},[577,578,579,583,586],"tr",{},[580,581,582],"th",{},"Variable",[580,584,585],{},"Default",[580,587,588],{},"Meaning",[590,591,592,608,623],"tbody",{},[577,593,594,600,605],{},[595,596,597],"td",{},[352,598,599],{},"LOG_LEVEL",[595,601,602],{},[352,603,604],{},"INFO",[595,606,607],{},"the default logger's minimum level (applies to every sink)",[577,609,610,615,620],{},[595,611,612],{},[352,613,614],{},"LOG_STDOUT",[595,616,617],{},[352,618,619],{},"false",[595,621,622],{},"also write to the console in production mode (JSON); leave off when a collector scrapes container output, or you ingest twice",[577,624,625,629,636],{},[595,626,627],{},[352,628,551],{},[595,630,631,632,635],{},"empty (",[352,633,634],{},"auto",")",[595,637,638,639,642],{},"the console format: empty means text in dev \u002F JSON in prod; ",[352,640,641],{},"monolog"," → Monolog-style lines regardless of mode",[348,644,645,646,648,649,652],{},"An unknown ",[352,647,551],{}," value fails ",[352,650,651],{},"Config.Validate()"," (and therefore boot) with an error instead of silently falling back.",[388,654,656],{"id":655},"the-composition-fanout-and-levelfilter","The composition: Fanout and LevelFilter",[348,658,659,660,663,664,667,668,670,671,674],{},"In Monolog you assembled logging from channels and stacks (the ",[352,661,662],{},"stack"," driver, several channels grouped under one, with ",[352,665,666],{},"level"," thresholds). ",[352,669,373],{}," gives you the same idea back: just not in YAML, but as three small ",[352,672,673],{},"slog.Handler"," combinators:",[405,676,680],{"className":677,"code":678,"language":679,"meta":411,"style":411},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","func ConsoleHandler(w io.Writer, cfg Config, dev bool, channel string) slog.Handler\nfunc Fanout(handlers ...slog.Handler) slog.Handler          \u002F\u002F ~ Monolog's stack driver\nfunc LevelFilter(min slog.Level, next slog.Handler) slog.Handler \u002F\u002F ~ a channel-level threshold\n","go",[352,681,682,747,783],{"__ignoreMap":411},[683,684,687,691,695,698,702,706,708,711,714,717,720,722,725,729,731,734,737,739,742,744],"span",{"class":685,"line":686},"line",1,[683,688,690],{"class":689},"sMK4o","func",[683,692,694],{"class":693},"s2Zo4"," ConsoleHandler",[683,696,697],{"class":689},"(",[683,699,701],{"class":700},"sHdIc","w",[683,703,705],{"class":704},"sBMFI"," io",[683,707,458],{"class":689},[683,709,710],{"class":704},"Writer",[683,712,713],{"class":689},",",[683,715,716],{"class":700}," cfg",[683,718,719],{"class":704}," Config",[683,721,713],{"class":689},[683,723,724],{"class":700}," dev",[683,726,728],{"class":727},"spNyl"," bool",[683,730,713],{"class":689},[683,732,733],{"class":700}," channel",[683,735,736],{"class":727}," string",[683,738,635],{"class":689},[683,740,741],{"class":704}," slog",[683,743,458],{"class":689},[683,745,746],{"class":704},"Handler\n",[683,748,750,752,755,757,760,763,766,768,771,773,775,777,779],{"class":685,"line":749},2,[683,751,690],{"class":689},[683,753,754],{"class":693}," Fanout",[683,756,697],{"class":689},[683,758,759],{"class":700},"handlers",[683,761,762],{"class":689}," ...",[683,764,765],{"class":704},"slog",[683,767,458],{"class":689},[683,769,770],{"class":704},"Handler",[683,772,635],{"class":689},[683,774,741],{"class":704},[683,776,458],{"class":689},[683,778,770],{"class":704},[683,780,782],{"class":781},"sHwdD","          \u002F\u002F ~ Monolog's stack driver\n",[683,784,786,788,791,793,796,798,800,803,805,808,810,812,814,816,818,820,822],{"class":685,"line":785},3,[683,787,690],{"class":689},[683,789,790],{"class":693}," LevelFilter",[683,792,697],{"class":689},[683,794,795],{"class":700},"min",[683,797,741],{"class":704},[683,799,458],{"class":689},[683,801,802],{"class":704},"Level",[683,804,713],{"class":689},[683,806,807],{"class":700}," next",[683,809,741],{"class":704},[683,811,458],{"class":689},[683,813,770],{"class":704},[683,815,635],{"class":689},[683,817,741],{"class":704},[683,819,458],{"class":689},[683,821,770],{"class":704},[683,823,824],{"class":781}," \u002F\u002F ~ a channel-level threshold\n",[348,826,827,830],{},[352,828,829],{},"telemetry.Setup"," builds the default logger exactly this way:",[405,832,834],{"className":677,"code":833,"language":679,"meta":411,"style":411},"slog.SetDefault(slog.New(\n    logx.LevelFilter(cfg.Log.Level, logx.Fanout(\n        logx.ConsoleHandler(os.Stdout, cfg.Log, dev, serviceName), \u002F\u002F in dev, or with LOG_STDOUT\n        otelHandle.SlogHandler(),   \u002F\u002F OTLP bridge, in prod\n        sentryHandle.SlogHandler(), \u002F\u002F Sentry capture, when the DSN is set\n    )),\n))\n",[352,835,836,858,893,936,953,968,974],{"__ignoreMap":411},[683,837,838,841,843,846,848,850,852,855],{"class":685,"line":686},[683,839,765],{"class":840},"sTEyZ",[683,842,458],{"class":689},[683,844,845],{"class":693},"SetDefault",[683,847,697],{"class":689},[683,849,765],{"class":840},[683,851,458],{"class":689},[683,853,854],{"class":693},"New",[683,856,857],{"class":689},"(\n",[683,859,860,863,865,868,870,873,875,877,879,881,883,886,888,891],{"class":685,"line":749},[683,861,862],{"class":840},"    logx",[683,864,458],{"class":689},[683,866,867],{"class":693},"LevelFilter",[683,869,697],{"class":689},[683,871,872],{"class":840},"cfg",[683,874,458],{"class":689},[683,876,564],{"class":840},[683,878,458],{"class":689},[683,880,802],{"class":840},[683,882,713],{"class":689},[683,884,885],{"class":840}," logx",[683,887,458],{"class":689},[683,889,890],{"class":693},"Fanout",[683,892,857],{"class":689},[683,894,895,898,900,903,905,908,910,913,915,917,919,921,923,925,927,930,933],{"class":685,"line":785},[683,896,897],{"class":840},"        logx",[683,899,458],{"class":689},[683,901,902],{"class":693},"ConsoleHandler",[683,904,697],{"class":689},[683,906,907],{"class":840},"os",[683,909,458],{"class":689},[683,911,912],{"class":840},"Stdout",[683,914,713],{"class":689},[683,916,716],{"class":840},[683,918,458],{"class":689},[683,920,564],{"class":840},[683,922,713],{"class":689},[683,924,724],{"class":840},[683,926,713],{"class":689},[683,928,929],{"class":840}," serviceName",[683,931,932],{"class":689},"),",[683,934,935],{"class":781}," \u002F\u002F in dev, or with LOG_STDOUT\n",[683,937,939,942,944,947,950],{"class":685,"line":938},4,[683,940,941],{"class":840},"        otelHandle",[683,943,458],{"class":689},[683,945,946],{"class":693},"SlogHandler",[683,948,949],{"class":689},"(),",[683,951,952],{"class":781},"   \u002F\u002F OTLP bridge, in prod\n",[683,954,956,959,961,963,965],{"class":685,"line":955},5,[683,957,958],{"class":840},"        sentryHandle",[683,960,458],{"class":689},[683,962,946],{"class":693},[683,964,949],{"class":689},[683,966,967],{"class":781}," \u002F\u002F Sentry capture, when the DSN is set\n",[683,969,971],{"class":685,"line":970},6,[683,972,973],{"class":689},"    )),\n",[683,975,977],{"class":685,"line":976},7,[683,978,979],{"class":689},"))\n",[348,981,982,984,985,987,988,991],{},[352,983,867],{}," sits outermost because not every leaf handler filters on its own: the OTLP bridge, for instance, forwards every record it is given. ",[352,986,890],{}," hands each handler its own clone of the record and honors ",[352,989,990],{},"Enabled"," as a per-handler gate, and with a single handler it returns it as-is, allocation-free.",[348,993,994,995,998,999,998,1002,1005,1006,1009],{},"Inside a chassis you never write this: ",[352,996,997],{},"fiberx.Run"," \u002F ",[352,1000,1001],{},"chix.Run",[352,1003,1004],{},"worker.Run"," ",[400,1007,1008],{"href":224},"get it for free",". You reach for it directly when a non-chassis binary (CLI, migrator) wants the same console experience, or to weave an extra sink (say, a file handler) into the fanout.",[388,1011,1013],{"id":1012},"logxmonolog-up-close","logx\u002Fmonolog up close",[348,1015,1016],{},"The format driver is a standalone package with a single constructor:",[405,1018,1020],{"className":677,"code":1019,"language":679,"meta":411,"style":411},"import \"github.com\u002Fgp-system\u002Fgpsystem\u002Flogx\u002Fmonolog\"\n\nfunc NewHandler(w io.Writer, level slog.Level, channel string) *Handler\n",[352,1021,1022,1037,1043],{"__ignoreMap":411},[683,1023,1024,1028,1031,1034],{"class":685,"line":686},[683,1025,1027],{"class":1026},"s7zQu","import",[683,1029,1030],{"class":689}," \"",[683,1032,1033],{"class":704},"github.com\u002Fgp-system\u002Fgpsystem\u002Flogx\u002Fmonolog",[683,1035,1036],{"class":689},"\"\n",[683,1038,1039],{"class":685,"line":749},[683,1040,1042],{"emptyLinePlaceholder":1041},true,"\n",[683,1044,1045,1047,1050,1052,1054,1056,1058,1060,1062,1065,1067,1069,1071,1073,1075,1077,1079,1082],{"class":685,"line":785},[683,1046,690],{"class":689},[683,1048,1049],{"class":693}," NewHandler",[683,1051,697],{"class":689},[683,1053,701],{"class":700},[683,1055,705],{"class":704},[683,1057,458],{"class":689},[683,1059,710],{"class":704},[683,1061,713],{"class":689},[683,1063,1064],{"class":700}," level",[683,1066,741],{"class":704},[683,1068,458],{"class":689},[683,1070,802],{"class":704},[683,1072,713],{"class":689},[683,1074,733],{"class":700},[683,1076,736],{"class":727},[683,1078,635],{"class":689},[683,1080,1081],{"class":689}," *",[683,1083,746],{"class":704},[348,1085,1086,1087,1089,1090,1093,1094,1096],{},"With ",[352,1088,397],{},", ",[352,1091,1092],{},"logx.ConsoleHandler"," returns this, but you can wire it anywhere a ",[352,1095,673],{}," is expected. Worth knowing:",[435,1098,1099,1119,1138],{},[438,1100,1101,1005,1107,1110,1111,1114,1115,1118],{},[364,1102,1103,1104,1106],{},"It is ",[352,1105,765],{},"-native.",[352,1108,1109],{},"With(...)"," attrs and ",[352,1112,1113],{},"WithGroup(...)"," groups render correctly, as nested JSON in the context part (",[352,1116,1117],{},"\"req\":{\"status\":200}",").",[438,1120,1121,1126,1127,1129,1130,1133,1134,1137],{},[364,1122,1123,1124,458],{},"Stacks come from ",[352,1125,466],{}," The handler pulls out the record's first error-valued attr; if it (or anything in its wrap chain) is an ",[352,1128,466],{}," error, its full-path stack from ",[352,1131,1132],{},"errs.FullFrames"," is rendered. A plain ",[352,1135,1136],{},"errors.New"," error gets no stack block: the log call site goes on the line instead.",[438,1139,1140,1143],{},[364,1141,1142],{},"Lines stay atomic under concurrency",": the handler's clones share a mutex for writes; there are no torn lines.",[388,1145,1147],{"id":1146},"structured-errors-in-logs-none-of-this-without-errs","Structured errors in logs: none of this without errs",[348,1149,1150,1151,1155,1156,1159,1160,1163,1164,1167],{},"The Monolog format mines its stack traces from ",[400,1152,1153],{"href":79},[352,1154,466],{}," errors, and that is not a console privilege: ",[352,1157,1158],{},"*errs.Error"," implements ",[352,1161,1162],{},"slog.LogValuer",", so in ",[364,1165,1166],{},"every"," structured sink (JSON console, OTLP) the error unfolds as a group:",[405,1169,1173],{"className":1170,"code":1171,"language":1172,"meta":411,"style":411},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"error\": {\n  \"msg\": \"shop: place order: inventory: decrement: insufficient stock\",\n  \"code\": \"shop_out_of_stock\",\n  \"public\": \"One or more items are out of stock.\",\n  \"chain\": [ { \"msg\": \"shop: place order\", \"file\": \"service\u002Forders.go\", \"line\": 52, \"...\" : \"…\" }, \"…\" ],\n  \"stack\": [ { \"file\": \"repository\u002Finventory.go\", \"line\": 87, \"...\" : \"…\" }, \"…\" ]\n}\n","json",[352,1174,1175,1191,1213,1232,1252,1347,1416],{"__ignoreMap":411},[683,1176,1177,1180,1184,1186,1188],{"class":685,"line":686},[683,1178,1179],{"class":689},"\"",[683,1181,1183],{"class":1182},"sfazB","error",[683,1185,1179],{"class":689},[683,1187,505],{"class":840},[683,1189,1190],{"class":689},"{\n",[683,1192,1193,1196,1199,1201,1203,1205,1208,1210],{"class":685,"line":749},[683,1194,1195],{"class":689},"  \"",[683,1197,1198],{"class":727},"msg",[683,1200,1179],{"class":689},[683,1202,424],{"class":689},[683,1204,1030],{"class":689},[683,1206,1207],{"class":1182},"shop: place order: inventory: decrement: insufficient stock",[683,1209,1179],{"class":689},[683,1211,1212],{"class":689},",\n",[683,1214,1215,1217,1219,1221,1223,1225,1228,1230],{"class":685,"line":785},[683,1216,1195],{"class":689},[683,1218,352],{"class":727},[683,1220,1179],{"class":689},[683,1222,424],{"class":689},[683,1224,1030],{"class":689},[683,1226,1227],{"class":1182},"shop_out_of_stock",[683,1229,1179],{"class":689},[683,1231,1212],{"class":689},[683,1233,1234,1236,1239,1241,1243,1245,1248,1250],{"class":685,"line":938},[683,1235,1195],{"class":689},[683,1237,1238],{"class":727},"public",[683,1240,1179],{"class":689},[683,1242,424],{"class":689},[683,1244,1030],{"class":689},[683,1246,1247],{"class":1182},"One or more items are out of stock.",[683,1249,1179],{"class":689},[683,1251,1212],{"class":689},[683,1253,1254,1256,1259,1261,1263,1266,1269,1271,1273,1275,1277,1279,1282,1284,1286,1288,1291,1293,1295,1297,1300,1302,1304,1306,1308,1310,1312,1316,1318,1320,1323,1325,1328,1330,1333,1335,1338,1340,1342,1344],{"class":685,"line":955},[683,1255,1195],{"class":689},[683,1257,1258],{"class":727},"chain",[683,1260,1179],{"class":689},[683,1262,424],{"class":689},[683,1264,1265],{"class":689}," [",[683,1267,1268],{"class":689}," {",[683,1270,1030],{"class":689},[683,1272,1198],{"class":704},[683,1274,1179],{"class":689},[683,1276,424],{"class":689},[683,1278,1030],{"class":689},[683,1280,1281],{"class":1182},"shop: place order",[683,1283,1179],{"class":689},[683,1285,713],{"class":689},[683,1287,1030],{"class":689},[683,1289,1290],{"class":704},"file",[683,1292,1179],{"class":689},[683,1294,424],{"class":689},[683,1296,1030],{"class":689},[683,1298,1299],{"class":1182},"service\u002Forders.go",[683,1301,1179],{"class":689},[683,1303,713],{"class":689},[683,1305,1030],{"class":689},[683,1307,685],{"class":704},[683,1309,1179],{"class":689},[683,1311,424],{"class":689},[683,1313,1315],{"class":1314},"sbssI"," 52",[683,1317,713],{"class":689},[683,1319,1030],{"class":689},[683,1321,1322],{"class":704},"...",[683,1324,1179],{"class":689},[683,1326,1327],{"class":689}," :",[683,1329,1030],{"class":689},[683,1331,1332],{"class":1182},"…",[683,1334,1179],{"class":689},[683,1336,1337],{"class":689}," },",[683,1339,1030],{"class":689},[683,1341,1332],{"class":1182},[683,1343,1179],{"class":689},[683,1345,1346],{"class":689}," ],\n",[683,1348,1349,1351,1353,1355,1357,1359,1361,1363,1365,1367,1369,1371,1374,1376,1378,1380,1382,1384,1386,1389,1391,1393,1395,1397,1399,1401,1403,1405,1407,1409,1411,1413],{"class":685,"line":970},[683,1350,1195],{"class":689},[683,1352,662],{"class":727},[683,1354,1179],{"class":689},[683,1356,424],{"class":689},[683,1358,1265],{"class":689},[683,1360,1268],{"class":689},[683,1362,1030],{"class":689},[683,1364,1290],{"class":704},[683,1366,1179],{"class":689},[683,1368,424],{"class":689},[683,1370,1030],{"class":689},[683,1372,1373],{"class":1182},"repository\u002Finventory.go",[683,1375,1179],{"class":689},[683,1377,713],{"class":689},[683,1379,1030],{"class":689},[683,1381,685],{"class":704},[683,1383,1179],{"class":689},[683,1385,424],{"class":689},[683,1387,1388],{"class":1314}," 87",[683,1390,713],{"class":689},[683,1392,1030],{"class":689},[683,1394,1322],{"class":704},[683,1396,1179],{"class":689},[683,1398,1327],{"class":689},[683,1400,1030],{"class":689},[683,1402,1332],{"class":1182},[683,1404,1179],{"class":689},[683,1406,1337],{"class":689},[683,1408,1030],{"class":689},[683,1410,1332],{"class":1182},[683,1412,1179],{"class":689},[683,1414,1415],{"class":689}," ]\n",[683,1417,1418],{"class":685,"line":976},[683,1419,1420],{"class":689},"}\n",[348,1422,1423,1424,1426,1427,458],{},"So the same error is a PHP-style stack trace on the dev console, machine-ready JSON in the prod log, and a code-grouped issue in ",[400,1425,237],{"href":238},", all from a single ",[352,1428,1429],{},"return err",[388,1431,1433],{"id":1432},"monolog-concepts-mapped","Monolog concepts, mapped",[348,1435,1436,1437,1440],{},"If you arrive from ",[352,1438,1439],{},"config\u002Flogging.php",", this is how the concepts map:",[571,1442,1443,1456],{},[574,1444,1445],{},[577,1446,1447,1450,1453],{},[580,1448,1449],{},"Monolog",[580,1451,1452],{},"gpsystem",[580,1454,1455],{},"Where",[590,1457,1458,1475,1492,1511,1528,1547,1562,1576],{},[577,1459,1460,1463,1468],{},[595,1461,1462],{},"channel name",[595,1464,1465,1466,635],{},"the service name (",[352,1467,445],{},[595,1469,1470,1471,1474],{},"the ",[352,1472,1473],{},"shop.INFO"," part of the monolog line",[577,1476,1477,1482,1487],{},[595,1478,1479,1481],{},[352,1480,662],{}," driver (several channels in one)",[595,1483,1484],{},[352,1485,1486],{},"logx.Fanout",[595,1488,1489,1490],{},"built by ",[352,1491,829],{},[577,1493,1494,1500,1508],{},[595,1495,1496,1497,1499],{},"a channel's ",[352,1498,666],{}," threshold",[595,1501,1502,1504,1505],{},[352,1503,599],{}," + ",[352,1506,1507],{},"logx.LevelFilter",[595,1509,1510],{},"env",[577,1512,1513,1522,1525],{},[595,1514,1515,998,1518,1521],{},[352,1516,1517],{},"single",[352,1519,1520],{},"daily"," file driver",[595,1523,1524],{},"none (stdout is the only destination)",[595,1526,1527],{},"see below",[577,1529,1530,1537,1545],{},[595,1531,1532,1533,1536],{},"formatter (",[352,1534,1535],{},"LineFormatter",", JSON)",[595,1538,1539,378,1541,998,1543,635],{},[352,1540,551],{},[352,1542,634],{},[352,1544,641],{},[595,1546,1510],{},[577,1548,1549,1554,1559],{},[595,1550,1551],{},[352,1552,1553],{},"Log::info('msg', ['ctx' => ...])",[595,1555,1556],{},[352,1557,1558],{},"slog.InfoContext(ctx, \"msg\", slog.Any(\"ctx\", ...))",[595,1560,1561],{},"app code",[577,1563,1564,1569,1574],{},[595,1565,1566],{},[352,1567,1568],{},"Log::withContext([...])",[595,1570,1571],{},[352,1572,1573],{},"logger := slog.Default().With(...)",[595,1575,1561],{},[577,1577,1578,1581,1584],{},[595,1579,1580],{},"a Sentry \u002F Slack channel in the stack",[595,1582,1583],{},"the fanout's OTLP and Sentry branches",[595,1585,1586],{},"automatic",[348,1588,1589,1590,1593,1594,1597,1598,1601,1602,1604],{},"There is one twist that never existed in Monolog: ",[364,1591,1592],{},"the context also carries the trace",". The ctx of ",[352,1595,1596],{},"slog.InfoContext"," is not just an attr source: it is what ties the log line to the ",[400,1599,1600],{"href":233},"trace"," and to the ",[400,1603,237],{"href":238}," breadcrumb hub.",[388,1606,1608],{"id":1607},"where-did-the-file-logs-go","Where did the file logs go?",[348,1610,1611,1612,1615,1616,1622,1623,1626,1627,1629],{},"Nowhere, deliberately. There is no ",[352,1613,1614],{},"storage\u002Flogs\u002Fshop.log",": the kit follows the ",[400,1617,1621],{"href":1618,"rel":1619},"https:\u002F\u002F12factor.net\u002Flogs",[1620],"nofollow","12-factor"," principle, logs go to ",[364,1624,1625],{},"stdout as an event stream",", and collection, rotation and retention are the platform's job. In a container the runtime captures stdout anyway; your collector (or ",[352,1628,614],{}," + container logs) takes it from there. In prod, the main channel typically isn't even the console but the OTLP log bridge: logs arrive in the same pipeline as traces and metrics, tied together by trace IDs.",[348,1631,1632,1633,1636,1637,1639,1640,1643,1644,1647,1648,1650],{},"If you still want a local file: ",[352,1634,1635],{},"go run .\u002Fcmd\u002Fshop 2>&1 | tee shop.log",": in a pipe the monolog handler automatically writes without colors. (In dev mode the per-request access-log lines come not from ",[352,1638,765],{}," but from the engine's own request logger (the ",[352,1641,1642],{},"logger"," middleware on Fiber, ",[352,1645,1646],{},"chimiddleware.Logger"," on chi), which is why their format does not follow ",[352,1649,551],{},".)",[388,1652,1654],{"id":1653},"how-to-log-in-your-services","How to log in your services",[348,1656,1657,1658,424],{},"There are two rules, and both are about ",[352,1659,1660],{},"context.Context",[405,1662,1664],{"className":677,"code":1663,"language":679,"meta":411,"style":411},"func (s *OrderService) PlaceOrder(ctx context.Context, in PlaceOrder) error {\n    \u002F\u002F 1. Always the *Context variant, with the request ctx:\n    slog.InfoContext(ctx, \"order placed\",\n        slog.String(\"order_id\", order.ID),\n        slog.Int(\"total\", order.Total))\n    \u002F\u002F ...\n}\n",[352,1665,1666,1714,1719,1744,1776,1805,1810],{"__ignoreMap":411},[683,1667,1668,1670,1672,1675,1678,1681,1683,1686,1688,1691,1694,1696,1699,1701,1704,1706,1708,1711],{"class":685,"line":686},[683,1669,690],{"class":689},[683,1671,378],{"class":689},[683,1673,1674],{"class":700},"s ",[683,1676,1677],{"class":689},"*",[683,1679,1680],{"class":704},"OrderService",[683,1682,635],{"class":689},[683,1684,1685],{"class":693}," PlaceOrder",[683,1687,697],{"class":689},[683,1689,1690],{"class":700},"ctx",[683,1692,1693],{"class":704}," context",[683,1695,458],{"class":689},[683,1697,1698],{"class":704},"Context",[683,1700,713],{"class":689},[683,1702,1703],{"class":700}," in",[683,1705,1685],{"class":704},[683,1707,635],{"class":689},[683,1709,1710],{"class":727}," error",[683,1712,1713],{"class":689}," {\n",[683,1715,1716],{"class":685,"line":749},[683,1717,1718],{"class":781},"    \u002F\u002F 1. Always the *Context variant, with the request ctx:\n",[683,1720,1721,1724,1726,1729,1731,1733,1735,1737,1740,1742],{"class":685,"line":785},[683,1722,1723],{"class":840},"    slog",[683,1725,458],{"class":689},[683,1727,1728],{"class":693},"InfoContext",[683,1730,697],{"class":689},[683,1732,1690],{"class":840},[683,1734,713],{"class":689},[683,1736,1030],{"class":689},[683,1738,1739],{"class":1182},"order placed",[683,1741,1179],{"class":689},[683,1743,1212],{"class":689},[683,1745,1746,1749,1751,1754,1756,1758,1761,1763,1765,1768,1770,1773],{"class":685,"line":938},[683,1747,1748],{"class":840},"        slog",[683,1750,458],{"class":689},[683,1752,1753],{"class":693},"String",[683,1755,697],{"class":689},[683,1757,1179],{"class":689},[683,1759,1760],{"class":1182},"order_id",[683,1762,1179],{"class":689},[683,1764,713],{"class":689},[683,1766,1767],{"class":840}," order",[683,1769,458],{"class":689},[683,1771,1772],{"class":840},"ID",[683,1774,1775],{"class":689},"),\n",[683,1777,1778,1780,1782,1785,1787,1789,1792,1794,1796,1798,1800,1803],{"class":685,"line":955},[683,1779,1748],{"class":840},[683,1781,458],{"class":689},[683,1783,1784],{"class":693},"Int",[683,1786,697],{"class":689},[683,1788,1179],{"class":689},[683,1790,1791],{"class":1182},"total",[683,1793,1179],{"class":689},[683,1795,713],{"class":689},[683,1797,1767],{"class":840},[683,1799,458],{"class":689},[683,1801,1802],{"class":840},"Total",[683,1804,979],{"class":689},[683,1806,1807],{"class":685,"line":970},[683,1808,1809],{"class":781},"    \u002F\u002F ...\n",[683,1811,1812],{"class":685,"line":976},[683,1813,1420],{"class":689},[1815,1816,1817,1838],"ol",{},[438,1818,1819,1833,1834,1837],{},[364,1820,1821,998,1823,998,1826,1829,1830,458],{},[352,1822,1596],{},[352,1824,1825],{},"WarnContext",[352,1827,1828],{},"ErrorContext",", never ",[352,1831,1832],{},"slog.Info"," The ctx carries the active trace: the ",[400,1835,1836],{"href":233},"otelslog bridge"," attaches the trace\u002Fspan ID to the record from it, the Sentry handler links the error to the trace waterfall through it, and breadcrumbs land on the request's hub through it. A ctx-less log is an uncorrelated log.",[438,1839,1840,1845,1846,1849],{},[364,1841,1842,1843],{},"Pass errors with ",[352,1844,490],{},", not as an ",[352,1847,1848],{},"err.Error()"," string: that is what preserves the structured chain, the stack and the code for every sink.",[348,1851,1852,1853,1856,1857,1860,1861,1863,1864,1867,1868,1870],{},"There is no logger to inject, construct or wire into DI: the chassis sets ",[352,1854,1855],{},"slog.Default()",", and the package-level ",[352,1858,1859],{},"slog.*Context"," calls are exactly right. And the ",[352,1862,522],{}," level is not just a \"loud log\": it is also a ",[400,1865,1866],{"href":238},"Sentry event",". The kit logs 5xx for you; you log ",[352,1869,522],{}," when something truly is an incident.",[1872,1873,1874,1875,1880,1881,1883],"tip",{},"Expected, client-fault outcomes (404, 409, validation) you neither log nor need to: a ",[400,1876,1877,1878,1710],{"href":79},"status-mapped ",[352,1879,466],{}," goes out as a 4xx, with no ",[352,1882,538],{}," line and no Sentry event.",[1885,1886,1887],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":411,"searchDepth":749,"depth":749,"links":1889},[1890,1891,1892,1893,1894,1895,1896,1897],{"id":390,"depth":749,"text":391},{"id":555,"depth":749,"text":52},{"id":655,"depth":749,"text":656},{"id":1012,"depth":749,"text":1013},{"id":1146,"depth":749,"text":1147},{"id":1432,"depth":749,"text":1433},{"id":1607,"depth":749,"text":1608},{"id":1653,"depth":749,"text":1654},"Standard log\u002Fslog, composed, and a Monolog-format dev console with PHP-style stack traces.","md",null,{},{"icon":230},{"title":227,"description":1898},"WvGU1oxFIiso7yerAww8y-xh6Pg5xhofz7eR7yOXI74",[1906,1908],{"title":139,"path":224,"stem":225,"description":1907,"icon":219,"children":-1},"The telemetry facade: logging, OpenTelemetry and Sentry in a single call, with one shutdown guarantee.",{"title":232,"path":233,"stem":234,"description":1909,"icon":235,"children":-1},"Traces, metrics and logs in one call, HTTP, database, queue and S3 instrumentation, configured via standard OTEL_* variables.",1784668709968]