[{"data":1,"prerenderedAt":1549},["ShallowReactive",2],{"navigation_docs_en":3,"-en-observability-opentelemetry":342,"-en-observability-opentelemetry-surround":1544},[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":232,"body":344,"description":1537,"extension":1538,"links":1539,"meta":1540,"navigation":1541,"path":233,"seo":1542,"stem":234,"__hash__":1543},"docs_en\u002Fen\u002F7.observability\u002F3.opentelemetry.md",{"type":345,"value":346,"toc":1527},"minimark",[347,355,360,571,574,623,641,656,660,736,747,838,859,863,866,1008,1015,1019,1030,1038,1064,1068,1071,1151,1161,1165,1172,1436,1453,1468,1472,1486,1490,1494,1514,1523],[348,349,350,351,354],"p",{},"OpenTelemetry is the kit's observability backbone: every span, metric and exported log record travels through it, and even ",[352,353,237],"a",{"href":238}," is just an extra exporter on top. In the Go ecosystem, distributed tracing is standard, vendor-neutral infrastructure: the kit switches it on without you having to learn the OTel SDK.",[356,357,359],"h2",{"id":358},"otelx-the-bootstrap","otelx: the bootstrap",[361,362,367],"pre",{"className":363,"code":364,"language":365,"meta":366,"style":366},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fotelx\"\n\nfunc Setup(ctx context.Context, cfg Config, opts ...Option) (*Handle, error)\n\nfunc (h *Handle) SlogHandler() slog.Handler              \u002F\u002F OTLP log bridge (nil in dev mode)\nfunc (h *Handle) Shutdown(ctx context.Context) error     \u002F\u002F flush + stop the providers\n\nfunc WithSpanExporter(exp sdktrace.SpanExporter) Option  \u002F\u002F extra span sink beside the primary OTLP one\n","go","",[368,369,370,390,397,461,466,502,537,542],"code",{"__ignoreMap":366},[371,372,375,379,383,387],"span",{"class":373,"line":374},"line",1,[371,376,378],{"class":377},"s7zQu","import",[371,380,382],{"class":381},"sMK4o"," \"",[371,384,386],{"class":385},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fotelx",[371,388,389],{"class":381},"\"\n",[371,391,393],{"class":373,"line":392},2,[371,394,396],{"emptyLinePlaceholder":395},true,"\n",[371,398,400,403,407,410,414,417,420,423,426,429,432,434,437,440,443,446,449,452,454,458],{"class":373,"line":399},3,[371,401,402],{"class":381},"func",[371,404,406],{"class":405},"s2Zo4"," Setup",[371,408,409],{"class":381},"(",[371,411,413],{"class":412},"sHdIc","ctx",[371,415,416],{"class":385}," context",[371,418,419],{"class":381},".",[371,421,422],{"class":385},"Context",[371,424,425],{"class":381},",",[371,427,428],{"class":412}," cfg",[371,430,431],{"class":385}," Config",[371,433,425],{"class":381},[371,435,436],{"class":412}," opts",[371,438,439],{"class":381}," ...",[371,441,442],{"class":385},"Option",[371,444,445],{"class":381},")",[371,447,448],{"class":381}," (*",[371,450,451],{"class":385},"Handle",[371,453,425],{"class":381},[371,455,457],{"class":456},"spNyl"," error",[371,459,460],{"class":381},")\n",[371,462,464],{"class":373,"line":463},4,[371,465,396],{"emptyLinePlaceholder":395},[371,467,469,471,474,477,480,482,484,487,490,493,495,498],{"class":373,"line":468},5,[371,470,402],{"class":381},[371,472,473],{"class":381}," (",[371,475,476],{"class":412},"h ",[371,478,479],{"class":381},"*",[371,481,451],{"class":385},[371,483,445],{"class":381},[371,485,486],{"class":405}," SlogHandler",[371,488,489],{"class":381},"()",[371,491,492],{"class":385}," slog",[371,494,419],{"class":381},[371,496,497],{"class":385},"Handler",[371,499,501],{"class":500},"sHwdD","              \u002F\u002F OTLP log bridge (nil in dev mode)\n",[371,503,505,507,509,511,513,515,517,520,522,524,526,528,530,532,534],{"class":373,"line":504},6,[371,506,402],{"class":381},[371,508,473],{"class":381},[371,510,476],{"class":412},[371,512,479],{"class":381},[371,514,451],{"class":385},[371,516,445],{"class":381},[371,518,519],{"class":405}," Shutdown",[371,521,409],{"class":381},[371,523,413],{"class":412},[371,525,416],{"class":385},[371,527,419],{"class":381},[371,529,422],{"class":385},[371,531,445],{"class":381},[371,533,457],{"class":456},[371,535,536],{"class":500},"     \u002F\u002F flush + stop the providers\n",[371,538,540],{"class":373,"line":539},7,[371,541,396],{"emptyLinePlaceholder":395},[371,543,545,547,550,552,555,558,560,563,565,568],{"class":373,"line":544},8,[371,546,402],{"class":381},[371,548,549],{"class":405}," WithSpanExporter",[371,551,409],{"class":381},[371,553,554],{"class":412},"exp",[371,556,557],{"class":385}," sdktrace",[371,559,419],{"class":381},[371,561,562],{"class":385},"SpanExporter",[371,564,445],{"class":381},[371,566,567],{"class":385}," Option",[371,569,570],{"class":500},"  \u002F\u002F extra span sink beside the primary OTLP one\n",[348,572,573],{},"One call wires:",[575,576,577,593,617],"ul",{},[578,579,580,584,585,588,589,592],"li",{},[581,582,583],"strong",{},"Resource",": ",[368,586,587],{},"service.name"," \u002F ",[368,590,591],{},"service.version"," plus host detectors, on every signal.",[578,594,595,598,599,602,603,606,607,612,613,616],{},[581,596,597],{},"Tracer, meter and logger providers"," with OTLP exporters; ",[368,600,601],{},"Handle.SlogHandler()"," is the official ",[368,604,605],{},"otelslog"," bridge, which ",[352,608,609],{"href":224},[368,610,611],{},"telemetry"," weaves into the log fanout, so every ",[368,614,615],{},"slog.InfoContext(ctx, ...)"," exports with trace\u002Fspan IDs.",[578,618,619,622],{},[581,620,621],{},"Propagation",": W3C TraceContext + Baggage, so upstream callers' traces continue automatically and yours propagate onward.",[348,624,625,626,629,630,633,634,636,637,640],{},"You rarely call it directly: the chassis runs it through ",[368,627,628],{},"telemetry.Setup",". ",[368,631,632],{},"WithSpanExporter"," too exists primarily for the ",[368,635,611],{}," package: that is how Sentry receives the same spans through a second batcher (a ",[368,638,639],{},"nil"," exporter is silently dropped, so it can be passed unconditionally).",[348,642,643,644,647,648,651,652,655],{},"Application code ",[581,645,646],{},"never imports an OTel SDK package",": the OTel logs SDK is still pre-1.0, and its version churn stays inside the kit's ",[368,649,650],{},"otelx"," package, not in your projects. What you do import is the stable ",[368,653,654],{},"go.opentelemetry.io\u002Fotel"," API (see custom spans below).",[356,657,659],{"id":658},"configuration-two-kit-switches-everything-else-standard","Configuration: two kit switches, everything else standard",[361,661,663],{"className":363,"code":662,"language":365,"meta":366,"style":366},"type Config struct {\n    ServiceName    string `env:\"OTEL_SERVICE_NAME\"`                    \u002F\u002F required outside dev mode\n    ServiceVersion string `env:\"OTEL_SERVICE_VERSION\" envDefault:\"dev\"`\n    Dev            bool   `env:\"OTEL_DEV_MODE\" envDefault:\"false\"`\n}\n",[368,664,665,678,700,715,731],{"__ignoreMap":366},[371,666,667,670,672,675],{"class":373,"line":374},[371,668,669],{"class":381},"type",[371,671,431],{"class":385},[371,673,674],{"class":381}," struct",[371,676,677],{"class":381}," {\n",[371,679,680,684,687,690,694,697],{"class":373,"line":392},[371,681,683],{"class":682},"sTEyZ","    ServiceName    ",[371,685,686],{"class":456},"string",[371,688,689],{"class":381}," `",[371,691,693],{"class":692},"sfazB","env:\"OTEL_SERVICE_NAME\"",[371,695,696],{"class":381},"`",[371,698,699],{"class":500},"                    \u002F\u002F required outside dev mode\n",[371,701,702,705,707,709,712],{"class":373,"line":399},[371,703,704],{"class":682},"    ServiceVersion ",[371,706,686],{"class":456},[371,708,689],{"class":381},[371,710,711],{"class":692},"env:\"OTEL_SERVICE_VERSION\" envDefault:\"dev\"",[371,713,714],{"class":381},"`\n",[371,716,717,720,723,726,729],{"class":373,"line":463},[371,718,719],{"class":682},"    Dev            ",[371,721,722],{"class":456},"bool",[371,724,725],{"class":381},"   `",[371,727,728],{"class":692},"env:\"OTEL_DEV_MODE\" envDefault:\"false\"",[371,730,714],{"class":381},[371,732,733],{"class":373,"line":468},[371,734,735],{"class":381},"}\n",[348,737,738,739,742,743,746],{},"Exporter endpoints are ",[581,740,741],{},"deliberately not"," kit configuration. Exporters are selected by ",[368,744,745],{},"contrib\u002Fexporters\u002Fautoexport"," from the standard OTel variables, so you configure your deployment like any other OTel-instrumented app: your platform team's OTel knowledge and every vendor's documentation apply unchanged:",[361,748,752],{"className":749,"code":750,"language":751,"meta":366,"style":366},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","OTEL_SERVICE_NAME=shop\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Fcollector:4317\n# per-signal overrides (default everywhere: otlp):\nOTEL_TRACES_EXPORTER=otlp\nOTEL_METRICS_EXPORTER=otlp     # or: prometheus → scrape endpoint instead of OTLP push\nOTEL_LOGS_EXPORTER=otlp\n# sampling is OTel-standard too:\nOTEL_TRACES_SAMPLER=parentbased_traceidratio\nOTEL_TRACES_SAMPLER_ARG=0.1\n","sh",[368,753,754,765,775,780,790,803,812,817,827],{"__ignoreMap":366},[371,755,756,759,762],{"class":373,"line":374},[371,757,758],{"class":682},"OTEL_SERVICE_NAME",[371,760,761],{"class":381},"=",[371,763,764],{"class":692},"shop\n",[371,766,767,770,772],{"class":373,"line":392},[371,768,769],{"class":682},"OTEL_EXPORTER_OTLP_ENDPOINT",[371,771,761],{"class":381},[371,773,774],{"class":692},"http:\u002F\u002Fcollector:4317\n",[371,776,777],{"class":373,"line":399},[371,778,779],{"class":500},"# per-signal overrides (default everywhere: otlp):\n",[371,781,782,785,787],{"class":373,"line":463},[371,783,784],{"class":682},"OTEL_TRACES_EXPORTER",[371,786,761],{"class":381},[371,788,789],{"class":692},"otlp\n",[371,791,792,795,797,800],{"class":373,"line":468},[371,793,794],{"class":682},"OTEL_METRICS_EXPORTER",[371,796,761],{"class":381},[371,798,799],{"class":692},"otlp",[371,801,802],{"class":500},"     # or: prometheus → scrape endpoint instead of OTLP push\n",[371,804,805,808,810],{"class":373,"line":504},[371,806,807],{"class":682},"OTEL_LOGS_EXPORTER",[371,809,761],{"class":381},[371,811,789],{"class":692},[371,813,814],{"class":373,"line":539},[371,815,816],{"class":500},"# sampling is OTel-standard too:\n",[371,818,819,822,824],{"class":373,"line":544},[371,820,821],{"class":682},"OTEL_TRACES_SAMPLER",[371,823,761],{"class":381},[371,825,826],{"class":692},"parentbased_traceidratio\n",[371,828,830,833,835],{"class":373,"line":829},9,[371,831,832],{"class":682},"OTEL_TRACES_SAMPLER_ARG",[371,834,761],{"class":381},[371,836,837],{"class":692},"0.1\n",[348,839,840,841,473,844,847,848,851,852,854,855,858],{},"In ",[581,842,843],{},"dev mode",[368,845,846],{},"OTEL_DEV_MODE=true",") no exporters are created at all: traces and metrics are no-ops, there is no OTLP log bridge, and logs go to the ",[352,849,850],{"href":228},"console handler",". No collector, no anything. One exception: when ",[368,853,632],{}," supplies an extra sink (in practice: ",[368,856,857],{},"SENTRY_DSN"," set in dev mode), a dev-only tracer provider is still built and spans go straight there, collector-free.",[356,860,862],{"id":861},"what-the-kit-instruments-on-its-own","What the kit instruments on its own",[348,864,865],{},"This is the \"detailed metrics\" story: you don't write span code, every layer of the kit arrives instrumented.",[867,868,869,885],"table",{},[870,871,872],"thead",{},[873,874,875,879,882],"tr",{},[876,877,878],"th",{},"Layer",[876,880,881],{},"Instrumentation",[876,883,884],{},"What you get",[886,887,888,904,926,941,955,981,995],"tbody",{},[873,889,890,894,901],{},[891,892,893],"td",{},"HTTP (Fiber)",[891,895,896,897,900],{},"the official ",[368,898,899],{},"gofiber\u002Fcontrib\u002Fv3\u002Fotel"," middleware",[891,902,903],{},"a server span per request + HTTP metrics (duration, body sizes, active requests) with standard semantic conventions",[873,905,906,909,915],{},[891,907,908],{},"HTTP (chi)",[891,910,911,914],{},[368,912,913],{},"otelhttp.NewHandler"," around the router",[891,916,917,918,921,922,925],{},"the same on net\u002Fhttp: ",[368,919,920],{},"http.server"," server spans + ",[368,923,924],{},"http.server.request.duration"," and friends",[873,927,928,931,938],{},[891,929,930],{},"PostgreSQL (pgx)",[891,932,933,934,937],{},"the ",[368,935,936],{},"otelpgx"," tracer on the pool",[891,939,940],{},"a span per query, with the SQL (trimmed span name) and timing",[873,942,943,946,952],{},[891,944,945],{},"PostgreSQL (bun)",[891,947,933,948,951],{},[368,949,950],{},"bunotel"," query hook",[891,953,954],{},"the same in bun projects, with formatted queries",[873,956,957,960,974],{},[891,958,959],{},"Queue (asynq)",[891,961,962,963,966,967,970,971],{},"a producer span in ",[368,964,965],{},"Enqueue",", a consumer span in the worker; the ",[368,968,969],{},"Envelope"," carries ",[368,972,973],{},"traceparent",[891,975,976,977,980],{},"the trace ",[581,978,979],{},"crosses Redis",": the listener's span sits inside the originating HTTP request's trace",[873,982,983,986,992],{},[891,984,985],{},"S3",[891,987,933,988,991],{},[368,989,990],{},"otelaws"," middleware on the AWS SDK",[891,993,994],{},"a span per storage call",[873,996,997,1000,1005],{},[891,998,999],{},"Logs",[891,1001,933,1002,1004],{},[368,1003,605],{}," bridge",[891,1006,1007],{},"every ctx-logged record exports with trace\u002Fspan IDs",[348,1009,1010,1011,1014],{},"Metrics are collected by the autoexport-built MeterProvider: OTLP push to the collector by default, or a Prometheus scrape endpoint with ",[368,1012,1013],{},"OTEL_METRICS_EXPORTER=prometheus",". For a Grafana dashboard, the HTTP layer's metrics (request duration histogram, active requests) are there immediately, without you writing a single line of measuring code.",[356,1016,1018],{"id":1017},"follow-the-order-a-single-trace","Follow the order: a single trace",[348,1020,1021,1022,1025,1026,1029],{},"The ",[352,1023,1024],{"href":41},"shop","'s ",[368,1027,1028],{},"POST \u002Fapi\u002Fv1\u002Fshop\u002Forders"," request looks like this in a trace viewer (Jaeger, Grafana Tempo, Sentry, any of them):",[361,1031,1036],{"className":1032,"code":1034,"language":1035,"meta":366},[1033],"language-text","POST \u002Fapi\u002Fv1\u002Fshop\u002Forders                        ← HTTP server span (Fiber\u002Fchi middleware)\n├── INSERT INTO orders ...                      ← otelpgx, inside the transaction\n├── UPDATE inventory SET ...                    ← otelpgx\n├── INSERT INTO outbox ...                      ← otelpgx (the event commits with the transaction)\n└── task event:orderPlaced                      ← consumer span in the worker: the trace crossed the outbox and Redis\n    └── enqueue listener:orderPlaced:sendOrderConfirmation   ← fan-out producer span\n        └── task listener:orderPlaced:sendOrderConfirmation  ← the listener runs here\n            └── (the listener's spans: DB, S3, SMTP, whatever its code does)\n","text",[368,1037,1034],{"__ignoreMap":366},[348,1039,1040,1041,1045,1046,1048,1049,1052,1053,1056,1057,1060,1061,1063],{},"The key is the queue ",[352,1042,1043],{"href":178},[368,1044,969],{},": the dispatcher injects a W3C ",[368,1047,973],{}," into it from the request context, the envelope survives the ",[352,1050,1051],{"href":183},"outbox table"," and Redis, and the worker's consumer span unpacks and continues the trace. (The outbox relay's own producer span belongs to the relay's polling loop, not to this trace: the baton is the envelope itself.) From the HTTP request to the confirmation e-mail, ",[581,1054,1055],{},"a single trace ID",", exactly what the ",[352,1058,1059],{"href":41},"sample app","'s \"follow the order\" table promises. If anything fails along the way, the ",[352,1062,237],{"href":238}," event links to this trace.",[356,1065,1067],{"id":1066},"viewing-traces-locally","Viewing traces locally",[348,1069,1070],{},"In dev mode, tracing is a no-op by default, but there are two cheap paths when you want to see what the kit produces:",[1072,1073,1075,1080,1088,1092,1107,1148],"steps",{"level":1074},"4",[1076,1077,1079],"h4",{"id":1078},"the-fastest-dev-mode-sentry","The fastest: dev mode + Sentry",[348,1081,1082,1083,1085,1086,419],{},"Set a dev Sentry project's DSN alongside ",[368,1084,846],{},": the kit then builds a Sentry-only tracer provider, and spans land in Sentry's trace view without a collector. Details: ",[352,1087,237],{"href":238},[1076,1089,1091],{"id":1090},"the-full-picture-a-local-collector","The full picture: a local collector",[348,1093,1094,1095,1098,1099,1102,1103,1106],{},"The generated ",[368,1096,1097],{},"compose.yml"," has the ",[368,1100,1101],{},"otel-collector"," service commented out. Enable it, drop in the referenced ",[368,1104,1105],{},"deploy\u002Fotel-collector.yaml"," config (a minimal OTLP receiver + an exporter for your favorite backend, Jaeger, Tempo, anything), then:",[361,1108,1110],{"className":749,"code":1109,"language":751,"meta":366,"style":366},"OTEL_DEV_MODE=false OTEL_SERVICE_NAME=shop \\\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317 \\\ngo run .\u002Fcmd\u002Fshop\n",[368,1111,1112,1132,1137],{"__ignoreMap":366},[371,1113,1114,1117,1119,1122,1125,1127,1129],{"class":373,"line":374},[371,1115,1116],{"class":682},"OTEL_DEV_MODE",[371,1118,761],{"class":381},[371,1120,1121],{"class":692},"false",[371,1123,1124],{"class":682}," OTEL_SERVICE_NAME",[371,1126,761],{"class":381},[371,1128,1024],{"class":692},[371,1130,1131],{"class":385}," \\\n",[371,1133,1134],{"class":373,"line":392},[371,1135,1136],{"class":682},"OTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317 \\\n",[371,1138,1139,1142,1145],{"class":373,"line":399},[371,1140,1141],{"class":682},"go ",[371,1143,1144],{"class":692},"run",[371,1146,1147],{"class":692}," .\u002Fcmd\u002Fshop\n",[348,1149,1150],{},"From there the service exports exactly as in production: logs included, over OTLP.",[348,1152,1153,1154,1156,1157,1160],{},"Start the worker binary with the same variables (and its own ",[368,1155,758],{},", e.g. ",[368,1158,1159],{},"shop-worker","), or you will only see the HTTP half of the \"follow the order\" trace.",[356,1162,1164],{"id":1163},"custom-spans-and-metrics","Custom spans and metrics",[348,1166,1167,1168,1171],{},"The kit's principle applies here too: ",[352,1169,1170],{"href":69},"centralize, don't abstract",". There is no kit wrapper around the tracing API: where a business-meaningful measuring point is needed, you call the stable OTel API directly:",[361,1173,1175],{"className":363,"code":1174,"language":365,"meta":366,"style":366},"import (\n    \"go.opentelemetry.io\u002Fotel\"\n    \"go.opentelemetry.io\u002Fotel\u002Fattribute\"\n)\n\nvar tracer = otel.Tracer(\"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\")\nvar meter = otel.Meter(\"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\")\n\nfunc (s *OrderService) PlaceOrder(ctx context.Context, in PlaceOrder) error {\n    ctx, span := tracer.Start(ctx, \"shop.place_order\")\n    defer span.End()\n    span.SetAttributes(attribute.Int(\"order.items\", len(in.Items)))\n\n    \u002F\u002F ... the span is automatically a child of the HTTP server span,\n    \u002F\u002F because you carry the same ctx onward\n}\n",[368,1176,1177,1184,1193,1202,1206,1210,1240,1266,1270,1312,1349,1366,1414,1419,1425,1431],{"__ignoreMap":366},[371,1178,1179,1181],{"class":373,"line":374},[371,1180,378],{"class":377},[371,1182,1183],{"class":381}," (\n",[371,1185,1186,1189,1191],{"class":373,"line":392},[371,1187,1188],{"class":381},"    \"",[371,1190,654],{"class":385},[371,1192,389],{"class":381},[371,1194,1195,1197,1200],{"class":373,"line":399},[371,1196,1188],{"class":381},[371,1198,1199],{"class":385},"go.opentelemetry.io\u002Fotel\u002Fattribute",[371,1201,389],{"class":381},[371,1203,1204],{"class":373,"line":463},[371,1205,460],{"class":381},[371,1207,1208],{"class":373,"line":468},[371,1209,396],{"emptyLinePlaceholder":395},[371,1211,1212,1215,1218,1220,1223,1225,1228,1230,1233,1236,1238],{"class":373,"line":504},[371,1213,1214],{"class":381},"var",[371,1216,1217],{"class":682}," tracer ",[371,1219,761],{"class":381},[371,1221,1222],{"class":682}," otel",[371,1224,419],{"class":381},[371,1226,1227],{"class":405},"Tracer",[371,1229,409],{"class":381},[371,1231,1232],{"class":381},"\"",[371,1234,1235],{"class":692},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop",[371,1237,1232],{"class":381},[371,1239,460],{"class":381},[371,1241,1242,1244,1247,1249,1251,1253,1256,1258,1260,1262,1264],{"class":373,"line":539},[371,1243,1214],{"class":381},[371,1245,1246],{"class":682}," meter ",[371,1248,761],{"class":381},[371,1250,1222],{"class":682},[371,1252,419],{"class":381},[371,1254,1255],{"class":405},"Meter",[371,1257,409],{"class":381},[371,1259,1232],{"class":381},[371,1261,1235],{"class":692},[371,1263,1232],{"class":381},[371,1265,460],{"class":381},[371,1267,1268],{"class":373,"line":544},[371,1269,396],{"emptyLinePlaceholder":395},[371,1271,1272,1274,1276,1279,1281,1284,1286,1289,1291,1293,1295,1297,1299,1301,1304,1306,1308,1310],{"class":373,"line":829},[371,1273,402],{"class":381},[371,1275,473],{"class":381},[371,1277,1278],{"class":412},"s ",[371,1280,479],{"class":381},[371,1282,1283],{"class":385},"OrderService",[371,1285,445],{"class":381},[371,1287,1288],{"class":405}," PlaceOrder",[371,1290,409],{"class":381},[371,1292,413],{"class":412},[371,1294,416],{"class":385},[371,1296,419],{"class":381},[371,1298,422],{"class":385},[371,1300,425],{"class":381},[371,1302,1303],{"class":412}," in",[371,1305,1288],{"class":385},[371,1307,445],{"class":381},[371,1309,457],{"class":456},[371,1311,677],{"class":381},[371,1313,1315,1318,1320,1323,1326,1329,1331,1334,1336,1338,1340,1342,1345,1347],{"class":373,"line":1314},10,[371,1316,1317],{"class":682},"    ctx",[371,1319,425],{"class":381},[371,1321,1322],{"class":682}," span ",[371,1324,1325],{"class":381},":=",[371,1327,1328],{"class":682}," tracer",[371,1330,419],{"class":381},[371,1332,1333],{"class":405},"Start",[371,1335,409],{"class":381},[371,1337,413],{"class":682},[371,1339,425],{"class":381},[371,1341,382],{"class":381},[371,1343,1344],{"class":692},"shop.place_order",[371,1346,1232],{"class":381},[371,1348,460],{"class":381},[371,1350,1352,1355,1358,1360,1363],{"class":373,"line":1351},11,[371,1353,1354],{"class":377},"    defer",[371,1356,1357],{"class":682}," span",[371,1359,419],{"class":381},[371,1361,1362],{"class":405},"End",[371,1364,1365],{"class":381},"()\n",[371,1367,1369,1372,1374,1377,1379,1382,1384,1387,1389,1391,1394,1396,1398,1401,1403,1406,1408,1411],{"class":373,"line":1368},12,[371,1370,1371],{"class":682},"    span",[371,1373,419],{"class":381},[371,1375,1376],{"class":405},"SetAttributes",[371,1378,409],{"class":381},[371,1380,1381],{"class":682},"attribute",[371,1383,419],{"class":381},[371,1385,1386],{"class":405},"Int",[371,1388,409],{"class":381},[371,1390,1232],{"class":381},[371,1392,1393],{"class":692},"order.items",[371,1395,1232],{"class":381},[371,1397,425],{"class":381},[371,1399,1400],{"class":405}," len",[371,1402,409],{"class":381},[371,1404,1405],{"class":682},"in",[371,1407,419],{"class":381},[371,1409,1410],{"class":682},"Items",[371,1412,1413],{"class":381},")))\n",[371,1415,1417],{"class":373,"line":1416},13,[371,1418,396],{"emptyLinePlaceholder":395},[371,1420,1422],{"class":373,"line":1421},14,[371,1423,1424],{"class":500},"    \u002F\u002F ... the span is automatically a child of the HTTP server span,\n",[371,1426,1428],{"class":373,"line":1427},15,[371,1429,1430],{"class":500},"    \u002F\u002F because you carry the same ctx onward\n",[371,1432,1434],{"class":373,"line":1433},16,[371,1435,735],{"class":381},[348,1437,1438,588,1441,1444,1445,1448,1449,1452],{},[368,1439,1440],{},"otel.Tracer",[368,1442,1443],{},"otel.Meter"," work off the global providers that ",[368,1446,1447],{},"Setup"," installed. In dev mode the same code is a no-op, no conditionals needed. For counters and histograms it is ",[368,1450,1451],{},"meter.Int64Counter(...)"," and friends, the same way. The upstream OTel documentation applies verbatim.",[1454,1455,1456,1457,1459,1460,1463,1464,1467],"warning",{},"Always pass your span's context (",[368,1458,413],{},") downward: to repository calls, to ",[368,1461,1462],{},"slog.*Context",", to the dispatcher. Parent-child relationships travel exclusively in the context; a call started with ",[368,1465,1466],{},"context.Background()"," breaks out of the trace.",[356,1469,1471],{"id":1470},"shutdown","Shutdown",[348,1473,1474,1477,1478,1481,1482,1485],{},[368,1475,1476],{},"Handle.Shutdown"," stops the providers in reverse order (logs first, since they may reference spans, traces last), and the chassis calls it at the ",[352,1479,1480],{"href":74},"very end of the lifecycle",", after all your closers. After a ",[368,1483,1484],{},"SIGTERM",", spans opened during shutdown still reach the collector.",[1487,1488,1489],"note",{},"An unreachable collector endpoint does not take the service down: the exporters retry in the background and eventually drop their batches; serving requests is unaffected. Telemetry is best-effort, never the price of availability.",[356,1491,1493],{"id":1492},"patterns-used","Patterns used",[575,1495,1496,1508],{},[578,1497,1498,1501,1502,1504,1505,419],{},[581,1499,1500],{},"Isolation layer"," around the pre-1.0 OTel log SDK (",[368,1503,451],{},"; application code never imports an OTel SDK package); see ",[352,1506,92],{"href":1507},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#functional-options",[578,1509,1510,1513],{},[581,1511,1512],{},"LIFO shutdown via a closer chain",": logs stop first, traces last.",[348,1515,1516,1517,419],{},"OpenTelemetry's Go-specific documentation: ",[352,1518,1522],{"href":1519,"rel":1520},"https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Flanguages\u002Fgo\u002Fgetting-started\u002F",[1521],"nofollow","opentelemetry.io\u002Fdocs\u002Flanguages\u002Fgo",[1524,1525,1526],"style",{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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 .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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":366,"searchDepth":392,"depth":392,"links":1528},[1529,1530,1531,1532,1533,1534,1535,1536],{"id":358,"depth":392,"text":359},{"id":658,"depth":392,"text":659},{"id":861,"depth":392,"text":862},{"id":1017,"depth":392,"text":1018},{"id":1066,"depth":392,"text":1067},{"id":1163,"depth":392,"text":1164},{"id":1470,"depth":392,"text":1471},{"id":1492,"depth":392,"text":1493},"Traces, metrics and logs in one call, HTTP, database, queue and S3 instrumentation, configured via standard OTEL_* variables.","md",null,{},{"icon":235},{"title":232,"description":1537},"BC1KL2dKXwaaDLyYOThF2SPi8CYBJv4GZV5iuixe9uQ",[1545,1547],{"title":227,"path":228,"stem":229,"description":1546,"icon":230,"children":-1},"Standard log\u002Fslog, composed, and a Monolog-format dev console with PHP-style stack traces.",{"title":237,"path":238,"stem":239,"description":1548,"icon":240,"children":-1},"Env-gated error reporting on top of OTel: with errs-code issue grouping and full trace linking.",1784668704005]