@smthrs/observability 0.35.0 → 1.0.0-rc.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE +1 -1
  3. package/README.md +87 -0
  4. package/dist/cjs/BrowserOtel.d.ts +37 -0
  5. package/dist/cjs/BrowserOtel.d.ts.map +1 -0
  6. package/dist/cjs/BrowserOtel.js +47 -0
  7. package/dist/cjs/BrowserOtel.js.map +7 -0
  8. package/dist/cjs/Endpoint.d.ts +70 -0
  9. package/dist/cjs/Endpoint.d.ts.map +1 -0
  10. package/dist/cjs/Endpoint.js +85 -0
  11. package/dist/cjs/Endpoint.js.map +7 -0
  12. package/dist/cjs/JournalLogger.d.ts +232 -0
  13. package/dist/cjs/JournalLogger.d.ts.map +1 -0
  14. package/dist/cjs/JournalLogger.js +415 -0
  15. package/dist/cjs/JournalLogger.js.map +7 -0
  16. package/dist/cjs/Logger.d.ts +56 -0
  17. package/dist/cjs/Logger.d.ts.map +1 -0
  18. package/dist/cjs/Logger.js +72 -0
  19. package/dist/cjs/Logger.js.map +7 -0
  20. package/dist/cjs/Metric.d.ts +67 -0
  21. package/dist/cjs/Metric.d.ts.map +1 -0
  22. package/dist/cjs/Metric.js +68 -0
  23. package/dist/cjs/Metric.js.map +7 -0
  24. package/dist/cjs/NodeOtel.d.ts +42 -0
  25. package/dist/cjs/NodeOtel.d.ts.map +1 -0
  26. package/dist/cjs/NodeOtel.js +78 -0
  27. package/dist/cjs/NodeOtel.js.map +7 -0
  28. package/dist/cjs/Otel.d.ts +63 -0
  29. package/dist/cjs/Otel.d.ts.map +1 -0
  30. package/dist/cjs/Otel.js +75 -0
  31. package/dist/cjs/Otel.js.map +7 -0
  32. package/dist/cjs/Otlp.d.ts +203 -0
  33. package/dist/cjs/Otlp.d.ts.map +1 -0
  34. package/dist/cjs/Otlp.js +251 -0
  35. package/dist/cjs/Otlp.js.map +7 -0
  36. package/dist/cjs/Resource.d.ts +163 -0
  37. package/dist/cjs/Resource.d.ts.map +1 -0
  38. package/dist/cjs/Resource.js +186 -0
  39. package/dist/cjs/Resource.js.map +7 -0
  40. package/dist/cjs/index.d.ts +61 -0
  41. package/dist/cjs/index.d.ts.map +1 -0
  42. package/dist/cjs/index.js +47 -0
  43. package/dist/cjs/index.js.map +7 -0
  44. package/dist/cjs/internal/schemaIssuePath.d.ts +31 -0
  45. package/dist/cjs/internal/schemaIssuePath.d.ts.map +1 -0
  46. package/dist/cjs/internal/schemaIssuePath.js +49 -0
  47. package/dist/cjs/internal/schemaIssuePath.js.map +7 -0
  48. package/dist/cjs/package.json +1 -0
  49. package/dist/esm/BrowserOtel.d.ts +37 -0
  50. package/dist/esm/BrowserOtel.d.ts.map +1 -0
  51. package/dist/esm/BrowserOtel.js +24 -0
  52. package/dist/esm/BrowserOtel.js.map +1 -0
  53. package/dist/esm/Endpoint.d.ts +70 -0
  54. package/dist/esm/Endpoint.d.ts.map +1 -0
  55. package/dist/esm/Endpoint.js +110 -0
  56. package/dist/esm/Endpoint.js.map +1 -0
  57. package/dist/esm/JournalLogger.d.ts +232 -0
  58. package/dist/esm/JournalLogger.d.ts.map +1 -0
  59. package/dist/esm/JournalLogger.js +520 -0
  60. package/dist/esm/JournalLogger.js.map +1 -0
  61. package/dist/esm/Logger.d.ts +56 -0
  62. package/dist/esm/Logger.d.ts.map +1 -0
  63. package/dist/esm/Logger.js +61 -0
  64. package/dist/esm/Logger.js.map +1 -0
  65. package/dist/esm/Metric.d.ts +67 -0
  66. package/dist/esm/Metric.d.ts.map +1 -0
  67. package/dist/esm/Metric.js +80 -0
  68. package/dist/esm/Metric.js.map +1 -0
  69. package/dist/esm/NodeOtel.d.ts +42 -0
  70. package/dist/esm/NodeOtel.d.ts.map +1 -0
  71. package/dist/esm/NodeOtel.js +56 -0
  72. package/dist/esm/NodeOtel.js.map +1 -0
  73. package/dist/esm/Otel.d.ts +63 -0
  74. package/dist/esm/Otel.d.ts.map +1 -0
  75. package/dist/esm/Otel.js +52 -0
  76. package/dist/esm/Otel.js.map +1 -0
  77. package/dist/esm/Otlp.d.ts +203 -0
  78. package/dist/esm/Otlp.d.ts.map +1 -0
  79. package/dist/esm/Otlp.js +384 -0
  80. package/dist/esm/Otlp.js.map +1 -0
  81. package/dist/esm/Resource.d.ts +163 -0
  82. package/dist/esm/Resource.d.ts.map +1 -0
  83. package/dist/esm/Resource.js +238 -0
  84. package/dist/esm/Resource.js.map +1 -0
  85. package/dist/esm/index.d.ts +61 -0
  86. package/dist/esm/index.d.ts.map +1 -0
  87. package/dist/esm/index.js +61 -0
  88. package/dist/esm/index.js.map +1 -0
  89. package/dist/esm/internal/schemaIssuePath.d.ts +31 -0
  90. package/dist/esm/internal/schemaIssuePath.d.ts.map +1 -0
  91. package/dist/esm/internal/schemaIssuePath.js +59 -0
  92. package/dist/esm/internal/schemaIssuePath.js.map +1 -0
  93. package/docs/README.md +164 -0
  94. package/docs/api.md +780 -0
  95. package/docs/concepts/instrumentation-and-export.md +98 -0
  96. package/docs/concepts/layer-map.md +73 -0
  97. package/docs/concepts/validated-acquisition.md +106 -0
  98. package/docs/guides/export-to-a-collector.md +190 -0
  99. package/docs/guides/forward-logs-to-the-journal.md +226 -0
  100. package/docs/guides/install-a-logger.md +111 -0
  101. package/docs/guides/read-runtime-metrics.md +83 -0
  102. package/docs/guides/testing.md +134 -0
  103. package/docs/guides/wire-an-opentelemetry-sdk.md +226 -0
  104. package/docs/installation.md +102 -0
  105. package/docs/quickstart.md +145 -0
  106. package/docs/troubleshooting.md +168 -0
  107. package/package.json +221 -32
  108. package/src/BrowserOtel.ts +51 -0
  109. package/src/Endpoint.ts +131 -0
  110. package/src/JournalLogger.ts +635 -0
  111. package/src/Logger.ts +107 -0
  112. package/src/Metric.ts +88 -0
  113. package/src/NodeOtel.ts +90 -0
  114. package/src/Otel.ts +118 -0
  115. package/src/Otlp.ts +514 -0
  116. package/src/Resource.ts +325 -0
  117. package/src/index.ts +67 -0
  118. package/src/internal/schemaIssuePath.ts +65 -0
  119. package/docker-compose.otel.yml +0 -104
  120. package/grafana/dashboards/smithers-dashboard.json +0 -453
  121. package/grafana/provisioning/dashboards/dashboards.yml +0 -12
  122. package/grafana/provisioning/datasources/datasources.yml +0 -49
  123. package/loki/loki-config.yaml +0 -35
  124. package/otel-collector-config.yml +0 -38
  125. package/prometheus/prometheus.yml +0 -8
  126. package/src/MetricName.ts +0 -1
  127. package/src/MetricsServiceLive.js +0 -9
  128. package/src/README.md +0 -28
  129. package/src/ResolvedSmithersObservabilityOptions.ts +0 -12
  130. package/src/SmithersEvent.ts +0 -843
  131. package/src/SmithersLogFormat.ts +0 -1
  132. package/src/SmithersMetricDefinition.ts +0 -15
  133. package/src/SmithersMetricType.ts +0 -1
  134. package/src/SmithersMetricUnit.ts +0 -1
  135. package/src/SmithersObservability.js +0 -15
  136. package/src/SmithersObservabilityOptions.ts +0 -12
  137. package/src/SmithersObservabilityService.ts +0 -13
  138. package/src/_coreCorrelation/CorrelationContext.ts +0 -10
  139. package/src/_coreCorrelation/CorrelationContextLive.js +0 -11
  140. package/src/_coreCorrelation/CorrelationContextService.js +0 -15
  141. package/src/_coreCorrelation/CorrelationContextServiceShape.ts +0 -12
  142. package/src/_coreCorrelation/CorrelationPatch.ts +0 -3
  143. package/src/_coreCorrelation/README.md +0 -20
  144. package/src/_coreCorrelation/_correlationStorage.js +0 -4
  145. package/src/_coreCorrelation/correlationContextFiberRef.js +0 -5
  146. package/src/_coreCorrelation/correlationContextToLogAnnotations.js +0 -18
  147. package/src/_coreCorrelation/getCurrentCorrelationContext.js +0 -9
  148. package/src/_coreCorrelation/getCurrentCorrelationContextEffect.js +0 -11
  149. package/src/_coreCorrelation/index.js +0 -14
  150. package/src/_coreCorrelation/mergeCorrelationContext.js +0 -51
  151. package/src/_coreCorrelation/runWithCorrelationContext.js +0 -14
  152. package/src/_coreCorrelation/updateCurrentCorrelationContext.js +0 -17
  153. package/src/_coreCorrelation/withCorrelationContext.js +0 -38
  154. package/src/_coreCorrelation/withCurrentCorrelationContext.js +0 -11
  155. package/src/_coreMetrics.js +0 -14
  156. package/src/_coreMetricsShape.ts +0 -44
  157. package/src/_corePrometheus.js +0 -91
  158. package/src/_corePrometheusShape.ts +0 -11
  159. package/src/_coreTracing.js +0 -132
  160. package/src/_coreTracingShape.ts +0 -17
  161. package/src/_otelLogBuilders.js +0 -102
  162. package/src/_sessionFileResolvers.js +0 -164
  163. package/src/_smithersSpanAttributeAliases.js +0 -19
  164. package/src/_smithersTraceSpanStorage.js +0 -3
  165. package/src/_traceEventNormalizers.js +0 -499
  166. package/src/_traceRedaction.js +0 -162
  167. package/src/agentSessionEventToOtelLogRecord.js +0 -55
  168. package/src/agentTrace.ts +0 -144
  169. package/src/agentTraceCapabilities.js +0 -151
  170. package/src/annotateSmithersTrace.js +0 -11
  171. package/src/canonicalTraceEventToOtelLogRecord.js +0 -55
  172. package/src/correlation.js +0 -56
  173. package/src/createSmithersObservabilityLayer.js +0 -59
  174. package/src/createSmithersOtelLayer.js +0 -23
  175. package/src/createSmithersRuntimeLayer.js +0 -2
  176. package/src/detectAgentFamily.js +0 -26
  177. package/src/detectCaptureMode.js +0 -29
  178. package/src/emitOtelLogRecord.js +0 -19
  179. package/src/getCurrentSmithersTraceAnnotations.js +0 -14
  180. package/src/getCurrentSmithersTraceSpan.js +0 -7
  181. package/src/index.d.ts +0 -1392
  182. package/src/index.js +0 -137
  183. package/src/kindPhase.js +0 -17
  184. package/src/logging.js +0 -264
  185. package/src/makeSmithersSpanAttributes.js +0 -20
  186. package/src/metrics/README.md +0 -22
  187. package/src/metrics/SmithersMetricDefinition.ts +0 -17
  188. package/src/metrics/SmithersMetricType.ts +0 -1
  189. package/src/metrics/SmithersMetricUnit.ts +0 -1
  190. package/src/metrics/_asyncExternalWaitCounts.js +0 -4
  191. package/src/metrics/_buckets.js +0 -37
  192. package/src/metrics/_incrementGauge.js +0 -11
  193. package/src/metrics/_processStartMs.js +0 -1
  194. package/src/metrics/activeNodes.js +0 -2
  195. package/src/metrics/activeRuns.js +0 -2
  196. package/src/metrics/agentActionsTotal.js +0 -2
  197. package/src/metrics/agentDurationMs.js +0 -3
  198. package/src/metrics/agentErrorsTotal.js +0 -2
  199. package/src/metrics/agentEventsTotal.js +0 -2
  200. package/src/metrics/agentInvocationsTotal.js +0 -2
  201. package/src/metrics/agentRetriesTotal.js +0 -2
  202. package/src/metrics/agentSessionsTotal.js +0 -2
  203. package/src/metrics/agentTokensTotal.js +0 -2
  204. package/src/metrics/alertDeliveriesAttempted.js +0 -2
  205. package/src/metrics/alertDeliveriesSuppressed.js +0 -2
  206. package/src/metrics/alertsAcknowledgedTotal.js +0 -2
  207. package/src/metrics/alertsActive.js +0 -2
  208. package/src/metrics/alertsEscalatedTotal.js +0 -2
  209. package/src/metrics/alertsFiredTotal.js +0 -2
  210. package/src/metrics/alertsReopenedTotal.js +0 -2
  211. package/src/metrics/alertsResolvedTotal.js +0 -2
  212. package/src/metrics/alertsSilencedTotal.js +0 -2
  213. package/src/metrics/approvalPending.js +0 -2
  214. package/src/metrics/approvalWaitDuration.js +0 -5
  215. package/src/metrics/approvalsDenied.js +0 -2
  216. package/src/metrics/approvalsGranted.js +0 -2
  217. package/src/metrics/approvalsRequested.js +0 -2
  218. package/src/metrics/attemptDuration.js +0 -3
  219. package/src/metrics/attentionBacklog.js +0 -2
  220. package/src/metrics/cacheHits.js +0 -2
  221. package/src/metrics/cacheMisses.js +0 -2
  222. package/src/metrics/dbQueryDuration.js +0 -3
  223. package/src/metrics/dbRetries.js +0 -2
  224. package/src/metrics/dbTransactionDuration.js +0 -3
  225. package/src/metrics/dbTransactionRetries.js +0 -2
  226. package/src/metrics/dbTransactionRollbacks.js +0 -2
  227. package/src/metrics/devtoolsActiveSubscribers.js +0 -2
  228. package/src/metrics/devtoolsBackpressureDisconnectTotal.js +0 -2
  229. package/src/metrics/devtoolsDeltaBuildMs.js +0 -3
  230. package/src/metrics/devtoolsEventBytes.js +0 -3
  231. package/src/metrics/devtoolsEventTotal.js +0 -2
  232. package/src/metrics/devtoolsSnapshotBuildMs.js +0 -5
  233. package/src/metrics/devtoolsSubscribeTotal.js +0 -2
  234. package/src/metrics/errorsTotal.js +0 -2
  235. package/src/metrics/eventsEmittedTotal.js +0 -2
  236. package/src/metrics/externalWaitAsyncPending.js +0 -2
  237. package/src/metrics/gatewayApprovalDecisionsTotal.js +0 -2
  238. package/src/metrics/gatewayAuthEventsTotal.js +0 -2
  239. package/src/metrics/gatewayConnectionsActive.js +0 -2
  240. package/src/metrics/gatewayConnectionsClosedTotal.js +0 -2
  241. package/src/metrics/gatewayConnectionsTotal.js +0 -2
  242. package/src/metrics/gatewayCronTriggersTotal.js +0 -2
  243. package/src/metrics/gatewayErrorsTotal.js +0 -2
  244. package/src/metrics/gatewayHeartbeatTicksTotal.js +0 -2
  245. package/src/metrics/gatewayMessagesReceivedTotal.js +0 -2
  246. package/src/metrics/gatewayMessagesSentTotal.js +0 -2
  247. package/src/metrics/gatewayRpcCallsTotal.js +0 -2
  248. package/src/metrics/gatewayRpcDuration.js +0 -3
  249. package/src/metrics/gatewayRunEventBackpressureDisconnectTotal.js +0 -4
  250. package/src/metrics/gatewayRunsCompletedTotal.js +0 -2
  251. package/src/metrics/gatewayRunsStartedTotal.js +0 -2
  252. package/src/metrics/gatewaySignalsTotal.js +0 -2
  253. package/src/metrics/gatewayWebhooksReceivedTotal.js +0 -2
  254. package/src/metrics/gatewayWebhooksRejectedTotal.js +0 -2
  255. package/src/metrics/gatewayWebhooksVerifiedTotal.js +0 -2
  256. package/src/metrics/heartbeatDataSizeBytes.js +0 -5
  257. package/src/metrics/heartbeatIntervalMs.js +0 -3
  258. package/src/metrics/hotReloadDuration.js +0 -3
  259. package/src/metrics/hotReloadFailures.js +0 -2
  260. package/src/metrics/hotReloads.js +0 -2
  261. package/src/metrics/httpRequestDuration.js +0 -3
  262. package/src/metrics/httpRequests.js +0 -2
  263. package/src/metrics/index.d.ts +0 -1222
  264. package/src/metrics/index.js +0 -168
  265. package/src/metrics/memoryFactReads.js +0 -3
  266. package/src/metrics/memoryFactWrites.js +0 -3
  267. package/src/metrics/memoryMessageSaves.js +0 -3
  268. package/src/metrics/memoryRecallDuration.js +0 -11
  269. package/src/metrics/memoryRecallQueries.js +0 -3
  270. package/src/metrics/metricsServiceAdapter.js +0 -181
  271. package/src/metrics/nodeDuration.js +0 -3
  272. package/src/metrics/nodeRetriesTotal.js +0 -2
  273. package/src/metrics/nodesFailed.js +0 -2
  274. package/src/metrics/nodesFinished.js +0 -2
  275. package/src/metrics/nodesStarted.js +0 -2
  276. package/src/metrics/openApiToolCallErrorsTotal.js +0 -3
  277. package/src/metrics/openApiToolCallsTotal.js +0 -3
  278. package/src/metrics/openApiToolDuration.js +0 -9
  279. package/src/metrics/processHeapUsedBytes.js +0 -2
  280. package/src/metrics/processMemoryRssBytes.js +0 -2
  281. package/src/metrics/processUptimeSeconds.js +0 -2
  282. package/src/metrics/promptSizeBytes.js +0 -3
  283. package/src/metrics/replaysStarted.js +0 -3
  284. package/src/metrics/responseSizeBytes.js +0 -3
  285. package/src/metrics/rewindDurationMs.js +0 -3
  286. package/src/metrics/rewindFramesDeleted.js +0 -3
  287. package/src/metrics/rewindRollbackTotal.js +0 -2
  288. package/src/metrics/rewindSandboxesReverted.js +0 -3
  289. package/src/metrics/rewindTotal.js +0 -2
  290. package/src/metrics/runDuration.js +0 -3
  291. package/src/metrics/runForksCreated.js +0 -3
  292. package/src/metrics/runsAncestryDepth.js +0 -3
  293. package/src/metrics/runsCancelledTotal.js +0 -2
  294. package/src/metrics/runsCarriedStateBytes.js +0 -5
  295. package/src/metrics/runsContinuedTotal.js +0 -2
  296. package/src/metrics/runsFailedTotal.js +0 -2
  297. package/src/metrics/runsFinishedTotal.js +0 -2
  298. package/src/metrics/runsResumedTotal.js +0 -2
  299. package/src/metrics/runsTotal.js +0 -2
  300. package/src/metrics/sandboxActive.js +0 -2
  301. package/src/metrics/sandboxBundleSizeBytes.js +0 -5
  302. package/src/metrics/sandboxCompletedTotal.js +0 -2
  303. package/src/metrics/sandboxCreatedTotal.js +0 -2
  304. package/src/metrics/sandboxDurationMs.js +0 -3
  305. package/src/metrics/sandboxPatchCount.js +0 -3
  306. package/src/metrics/sandboxTransportDurationMs.js +0 -5
  307. package/src/metrics/schedulerConcurrencyUtilization.js +0 -2
  308. package/src/metrics/schedulerQueueDepth.js +0 -2
  309. package/src/metrics/schedulerWaitDuration.js +0 -5
  310. package/src/metrics/scorerDuration.js +0 -9
  311. package/src/metrics/scorerEventsFailed.js +0 -2
  312. package/src/metrics/scorerEventsFinished.js +0 -2
  313. package/src/metrics/scorerEventsStarted.js +0 -2
  314. package/src/metrics/scorersFailed.js +0 -3
  315. package/src/metrics/scorersFinished.js +0 -3
  316. package/src/metrics/scorersStarted.js +0 -3
  317. package/src/metrics/smithersMetricCatalog.js +0 -893
  318. package/src/metrics/smithersMetricCatalogByKey.js +0 -2
  319. package/src/metrics/smithersMetricCatalogByName.js +0 -2
  320. package/src/metrics/smithersMetricCatalogByPrometheusName.js +0 -4
  321. package/src/metrics/snapshotDuration.js +0 -9
  322. package/src/metrics/snapshotsCaptured.js +0 -3
  323. package/src/metrics/supervisorPollDuration.js +0 -5
  324. package/src/metrics/supervisorPollsTotal.js +0 -2
  325. package/src/metrics/supervisorResumeLag.js +0 -5
  326. package/src/metrics/supervisorResumedTotal.js +0 -2
  327. package/src/metrics/supervisorSkippedTotal.js +0 -2
  328. package/src/metrics/supervisorStaleDetected.js +0 -2
  329. package/src/metrics/taskHeartbeatTimeoutTotal.js +0 -2
  330. package/src/metrics/taskHeartbeatsTotal.js +0 -2
  331. package/src/metrics/timerDelayDuration.js +0 -3
  332. package/src/metrics/timersCancelled.js +0 -2
  333. package/src/metrics/timersCreated.js +0 -2
  334. package/src/metrics/timersFired.js +0 -2
  335. package/src/metrics/timersPending.js +0 -2
  336. package/src/metrics/toPrometheusMetricName.js +0 -8
  337. package/src/metrics/tokensCacheReadTotal.js +0 -2
  338. package/src/metrics/tokensCacheWriteTotal.js +0 -2
  339. package/src/metrics/tokensContextWindowBucketTotal.js +0 -2
  340. package/src/metrics/tokensContextWindowPerCall.js +0 -5
  341. package/src/metrics/tokensInputPerCall.js +0 -3
  342. package/src/metrics/tokensInputTotal.js +0 -2
  343. package/src/metrics/tokensOutputPerCall.js +0 -3
  344. package/src/metrics/tokensOutputTotal.js +0 -2
  345. package/src/metrics/tokensReasoningTotal.js +0 -2
  346. package/src/metrics/toolCallErrorsTotal.js +0 -2
  347. package/src/metrics/toolCallsTotal.js +0 -2
  348. package/src/metrics/toolDuration.js +0 -3
  349. package/src/metrics/toolOutputTruncatedTotal.js +0 -2
  350. package/src/metrics/trackEvent.js +0 -608
  351. package/src/metrics/updateAsyncExternalWaitPending.js +0 -18
  352. package/src/metrics/updateProcessMetrics.js +0 -20
  353. package/src/metrics/vcsDuration.js +0 -3
  354. package/src/normalizeStructuredEvent.js +0 -15
  355. package/src/prometheusContentType.js +0 -1
  356. package/src/renderPrometheusMetrics.js +0 -212
  357. package/src/resolveAgentTraceCapabilities.js +0 -59
  358. package/src/resolveSmithersObservabilityOptions.js +0 -109
  359. package/src/smithersMetrics.js +0 -2
  360. package/src/smithersSpanNames.js +0 -6
  361. package/src/unsupportedKindsForCapabilities.js +0 -32
  362. package/src/withSmithersSpan.js +0 -17
  363. package/tempo/tempo.yml +0 -17
@@ -0,0 +1,226 @@
1
+ ---
2
+ title: "Wire an OpenTelemetry SDK"
3
+ description: "Use NodeOtel, BrowserOtel, or Otel when a collector endpoint is not enough: the Node OTLP/HTTP layer, browser processors you construct, and bridging providers an application already built."
4
+ sidebar:
5
+ order: 2
6
+ ---
7
+
8
+ [`Otlp`](./export-to-a-collector.md) covers a collector endpoint and nothing
9
+ else. Three builders exist for the cases it does not cover: existing
10
+ OpenTelemetry instrumentation you must feed, a vendor exporter that is not
11
+ OTLP/HTTP JSON, and a provider a framework hands you already constructed.
12
+
13
+ All three validate `Resource.Configuration`. `NodeOtel` and `BrowserOtel`
14
+ construct providers with that resource. `Otel` supplies it to provider factories
15
+ and metrics; already-created providers retain their own resource.
16
+
17
+ ## Node: build the SDK for me
18
+
19
+ `NodeOtel.layerOtel` allocates the whole Node OpenTelemetry SDK: a
20
+ `BatchSpanProcessor`, a `BatchLogRecordProcessor`, and a
21
+ `PeriodicExportingMetricReader`, each behind its own OTLP/HTTP exporter.
22
+
23
+ ```ts
24
+ import * as NodeOtel from "@smthrs/observability/NodeOtel"
25
+ import * as Effect from "effect/Effect"
26
+
27
+ const telemetry = NodeOtel.layerOtel({
28
+ endpoint: "http://localhost:4318",
29
+ resource: { serviceName: "deploy-status", serviceVersion: "2.4.1" },
30
+ exportIntervalMillis: 60_000,
31
+ shutdownTimeout: "10 seconds"
32
+ })
33
+
34
+ const outcome = program.pipe(Effect.provide(telemetry), Effect.scoped)
35
+ ```
36
+
37
+ The exporters are created when the scoped layer is built, not when the module
38
+ is imported, so holding the builder costs nothing. Closing the scope
39
+ force-flushes both batch processors and collects the metric reader once, which
40
+ makes release, rather than the interval, the deterministic flush.
41
+
42
+ The endpoint option is named `endpoint` here and `baseUrl` on `Otlp`; each
43
+ refusal names the option it arrived on, so the message points at your own
44
+ field.
45
+
46
+ `NodeOtel` takes no `headers` option. The OpenTelemetry exporters read the
47
+ standard `OTEL_EXPORTER_OTLP_HEADERS`, `_TIMEOUT`, `_COMPRESSION`, and TLS
48
+ certificate variables from the process environment and send them to your
49
+ explicit `endpoint`, which always wins over `OTEL_EXPORTER_OTLP_ENDPOINT`.
50
+ Set those variables only for this collector. `Otlp` reads none of them.
51
+
52
+ Import `NodeOtel` only from code that runs on Node. See
53
+ [the layer map](../concepts/layer-map.md) for why it is absent from the root
54
+ entry point.
55
+
56
+ ## Browser: bring your own processors
57
+
58
+ `BrowserOtel.layerOtel` builds the web SDK around processors and readers the
59
+ application constructs. That keeps browser exporter policy, and every exporter
60
+ package a bundle would have to carry, in the application rather than in this
61
+ one.
62
+
63
+ ```ts
64
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"
65
+ import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"
66
+ import * as BrowserOtel from "@smthrs/observability/BrowserOtel"
67
+
68
+ const telemetry = BrowserOtel.layerOtel({
69
+ resource: { serviceName: "console-ui" },
70
+ spanProcessor: () =>
71
+ new BatchSpanProcessor(
72
+ new OTLPTraceExporter({ url: "https://otlp.example.com/v1/traces" })
73
+ )
74
+ })
75
+ ```
76
+
77
+ Every processor field is optional, and a layer with none still builds: it
78
+ provides the resource and bridges nothing. Return an array to install several
79
+ processors for one signal. Each field is a factory because the layer owns what
80
+ it returns: the factory runs once at acquisition, and the web SDK shuts down
81
+ every processor and reader when the scope closes.
82
+
83
+ If all you need in a browser is OTLP delivery, use `Otlp.layerFetch` instead.
84
+ It is smaller, needs no SDK, and is browser-safe by construction.
85
+
86
+ ## Bridge providers you control
87
+
88
+ `Otel.layerOtel` allocates no exporter at all. It takes an OpenTelemetry
89
+ `TracerProvider` and `LoggerProvider`, plus a factory that builds the metric
90
+ readers, and bridges Effect's tracer, logger, and metrics onto them. Provider
91
+ fields also accept synchronous factories. Every factory runs during layer
92
+ acquisition, after resource validation, and the provider factories receive the
93
+ same resource as the metric producer. Pass it to the SDK constructor to export
94
+ all signals with the configured service identity:
95
+
96
+ ```ts
97
+ import { LoggerProvider } from "@opentelemetry/sdk-logs"
98
+ import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"
99
+ import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base"
100
+ import * as Otel from "@smthrs/observability/Otel"
101
+ import * as Effect from "effect/Effect"
102
+
103
+ let tracerProvider: BasicTracerProvider | undefined
104
+ let loggerProvider: LoggerProvider | undefined
105
+ const telemetry = Otel.layerOtel({
106
+ resource: {
107
+ serviceName: "deploy-status",
108
+ serviceVersion: "2.4.1",
109
+ attributes: { region: "us-west" }
110
+ },
111
+ tracerProvider: (resource) =>
112
+ tracerProvider = new BasicTracerProvider({
113
+ resource,
114
+ spanProcessors: [spanProcessor]
115
+ }),
116
+ loggerProvider: (resource) =>
117
+ loggerProvider = new LoggerProvider({
118
+ resource,
119
+ processors: [logRecordProcessor]
120
+ }),
121
+ metricReader: () => new PeriodicExportingMetricReader({ exporter: metricExporter }),
122
+ metricTemporality: "cumulative"
123
+ })
124
+
125
+ try {
126
+ await Effect.runPromise(program.pipe(Effect.provide(telemetry), Effect.scoped))
127
+ } finally {
128
+ await Promise.all([tracerProvider?.shutdown(), loggerProvider?.shutdown()])
129
+ }
130
+ ```
131
+
132
+ Ownership splits between the two kinds of field. Providers are borrowed: the
133
+ application owns their flushing and shutdown, including providers returned by
134
+ factories, and this layer never shuts one down. Readers are owned: the
135
+ `metricReader` factory runs once during acquisition, and closing the scope shuts
136
+ down every reader it returned. Build the readers inside the factory rather than
137
+ handing over one a longer-lived composition still exports through, which that
138
+ shutdown would disable. Construct `spanProcessor` and `logRecordProcessor` with
139
+ your exporters and give them to the provider you build.
140
+
141
+ You can still pass existing providers directly. The layer cannot change the
142
+ resource they captured at construction. In that form, the resource option
143
+ controls only the metric resource, not log or span resource attributes.
144
+ Whichever form you use, spans and log records carry the instrumentation scope
145
+ `effect` with the Effect version, and the span status and log attributes
146
+ described in
147
+ [What the collector receives](./export-to-a-collector.md#what-the-collector-receives). Construct both providers with the intended resource before injection,
148
+ or use the factories above to receive the validated resource.
149
+
150
+ Each of the three is optional and each is bridged only when supplied, so a
151
+ composition with a tracer and no meter installs only the tracer bridge. A
152
+ `metricReader` factory that returns an empty array registers no reader at all
153
+ rather than a misconfigured one.
154
+
155
+ Two options control merge behavior: `loggerMergeWithExisting` keeps the ambient
156
+ Effect loggers alongside the OpenTelemetry logger, and `metricTemporality`
157
+ selects the temporality preference the metric bridge reports.
158
+
159
+ `Otel.layerNoop` is the explicit empty slot for a composition that wants the
160
+ option without the wiring.
161
+
162
+ ## Provide only the resource
163
+
164
+ `Resource.layer` provides the validated OpenTelemetry resource by itself, for a
165
+ composition that assembles the rest of the SDK on its own:
166
+
167
+ ```ts
168
+ import * as Resource from "@smthrs/observability/Resource"
169
+
170
+ const resource = Resource.layer({
171
+ serviceName: "deploy-status",
172
+ attributes: { "deployment.environment.name": "production" }
173
+ })
174
+ ```
175
+
176
+ `Resource.configToAttributes` is the pure projection of the same configuration
177
+ into OpenTelemetry attributes, for code that needs the attribute record rather
178
+ than a layer. It reads no environment variables: attributes come from your
179
+ configuration and the SDK's `telemetry.sdk.name`, `telemetry.sdk.language` and
180
+ `telemetry.sdk.version` fields, which are included in the admission budget. An
181
+ attribute of yours with one of those three names replaces the SDK's value.
182
+
183
+ ## Default OTLP export limits
184
+
185
+ `Otlp.layer` and `Otlp.layerFetch` share a limit of four active HTTP requests
186
+ across logs, traces, and metrics within each layer acquisition. Each request has
187
+ a ten-second timeout that interrupts the transport and aborts a stalled fetch.
188
+ A request ends when the collector's status arrives: the response body is not
189
+ read, so a collector that never finishes its answer holds no slot.
190
+ `shutdownTimeout` separately bounds the final scope flush.
191
+
192
+ Logs and traces flush at 1,000 records or the export interval. The transport has
193
+ no waiting queue: a batch arriving while all four slots are occupied is dropped.
194
+ Serialized JSON payloads larger than 1 MiB are also dropped, limiting active
195
+ request payloads to 4 MiB. This limit applies after serialization; it does not
196
+ bound individual application records, temporary serialization allocations, or
197
+ the application's metric registry.
198
+
199
+ Resource admission caps cumulative encoded metadata at 128 KiB and bounds
200
+ arrays at 256 elements. The byte budget includes SDK-added telemetry fields,
201
+ reserved even for the default Effect exporter. Both the default exporter and
202
+ the Node SDK layer isolate ambient resource configuration after validation.
203
+ The default exporter also budgets the request envelope
204
+ at 8 KiB and reserves `Otlp.reservedBatchBytes` (888 KiB) for signals: roughly
205
+ 900 bytes per record
206
+ in a 1,000-record log or span batch. Every layer validates these resource limits
207
+ before allocating exporters, including injected SDK layers.
208
+
209
+ The Effect counter `flows_observability_otlp_dropped` increments once per batch
210
+ discarded for saturation, payload size, or timeout. Discards are terminal and
211
+ are not retried. Read the counter locally
212
+ with `Metric.value(Metric.counter("flows_observability_otlp_dropped"))` during an
213
+ outage. Its exported value becomes available when the collector recovers.
214
+
215
+ Because that counter shares the export path, each acquisition also emits at
216
+ most one warning every 60 seconds through the ambient loggers captured before
217
+ installing the OTLP logger. The warning has code `otlp_export_discarded`, reason
218
+ `oversized`, `saturated`, or `stalled`, encoded bytes, request limit, and total
219
+ discarded batches. It includes no payload, URL, or inherited annotations and
220
+ cannot re-enter this exporter even during an application-triggered flush. Keep
221
+ an ambient logger installed if loss diagnostics should remain visible during
222
+ an export outage.
223
+
224
+ Ordinary HTTP and network failures retain Effect's retry policy. These limits
225
+ apply to the default `Otlp` layers; SDK processors supplied to the other builders
226
+ retain their own export policies.
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: "Installation"
3
+ description: "Install @smthrs/observability, its runtime requirements and Effect version, its import forms, and the rule that keeps the root entry point bundling for a browser."
4
+ sidebar:
5
+ order: 1
6
+ ---
7
+
8
+ ## Install the package
9
+
10
+ ```bash
11
+ npm install @smthrs/observability@next effect
12
+ ```
13
+
14
+ The `next` tag carries the 1.0 release candidates.
15
+
16
+ The package requires Node.js 26.4.0 or later and ships as both ESM and
17
+ CommonJS with TypeScript declarations.
18
+
19
+ ## Install one Effect release
20
+
21
+ Effect services are identified by module identity, so a composition that
22
+ resolves two copies of `effect` splits its context and a provided layer stops
23
+ satisfying a requirement. Install one `effect` in the range `^4.0.4`.
24
+
25
+ `Otlp` is written entirely against `effect`, including its HTTP client and its
26
+ `effect/observability/Otlp` exporters. The `@effect/opentelemetry@4.0.4`
27
+ dependency, the required `@opentelemetry/api@1.9.1` peer, and the logs and
28
+ metrics dependencies support the root `Otel` and `Resource` modules. They
29
+ install with ordinary peer-aware package managers. `@effect/opentelemetry`
30
+ 4.0.4 accepts any `effect` in `^4.0.4`. The default install includes no HTTP exporters or trace SDK.
31
+
32
+ `NodeOtel` selects the optional Node trace SDK and three HTTP exporters:
33
+
34
+ ```bash
35
+ pnpm add @opentelemetry/exporter-logs-otlp-http@0.222.0 @opentelemetry/exporter-metrics-otlp-http@0.222.0 @opentelemetry/exporter-trace-otlp-http@0.222.0 @opentelemetry/sdk-trace-base@2.11.0 @opentelemetry/sdk-trace-node@2.11.0
36
+ ```
37
+
38
+ `BrowserOtel` selects the optional browser trace SDK instead:
39
+
40
+ ```bash
41
+ pnpm add @opentelemetry/sdk-trace-base@2.11.0 @opentelemetry/sdk-trace-web@2.11.0
42
+ ```
43
+
44
+ The browser adapter accepts the exporters you supply; those HTTP exporter
45
+ packages are not prerequisites for constructing its layer.
46
+
47
+ ## Import forms
48
+
49
+ The root entry point re-exports seven modules as namespaces:
50
+
51
+ ```ts
52
+ import { Endpoint, JournalLogger, Logger, Metric, Otel, Otlp, Resource } from "@smthrs/observability"
53
+ ```
54
+
55
+ Each is also importable from its own subpath, which is the form the
56
+ [API reference](./api.md) uses:
57
+
58
+ ```ts
59
+ import * as JournalLogger from "@smthrs/observability/JournalLogger"
60
+ import * as Otlp from "@smthrs/observability/Otlp"
61
+ ```
62
+
63
+ `@smthrs/observability/package.json` is exported.
64
+
65
+ ## The two subpath-only modules
66
+
67
+ `NodeOtel` and `BrowserOtel` are not re-exported from the root, and importing
68
+ them by subpath is the only way to reach them:
69
+
70
+ ```ts
71
+ import * as BrowserOtel from "@smthrs/observability/BrowserOtel"
72
+ import * as NodeOtel from "@smthrs/observability/NodeOtel"
73
+ ```
74
+
75
+ `NodeOtel` resolves Node-only host modules: `@effect/opentelemetry/NodeSdk` and
76
+ `@opentelemetry/sdk-trace-node`, which reaches the bare `async_hooks` specifier
77
+ through `@opentelemetry/context-async-hooks`. Re-exporting it from the root
78
+ would put a module a browser bundler cannot resolve in the entry point, and
79
+ break the browser bundle the root guarantees. Nothing the root entry point
80
+ reaches resolves a `node:` built-in, so it bundles for a browser as it is.
81
+
82
+ Import `NodeOtel` only from code that runs on Node, and `BrowserOtel` only from
83
+ code that runs in a browser. `Otlp` is safe in both, because it exports over
84
+ Effect's `HttpClient` and never touches a `node:` built-in.
85
+
86
+ ## What a real composition adds
87
+
88
+ The exporter alone needs nothing else. Two features have a dependency:
89
+
90
+ - `Otlp.layer` requires an Effect `HttpClient` from
91
+ `effect/http/HttpClient`. `Otlp.layerFetch` supplies the host's
92
+ global `fetch` and is the usual choice; a Node host that wants Undici instead
93
+ provides `NodeHttpClient.layerUndici`, re-exported by
94
+ [`@smthrs/platform-node`](/api/platform-node) as `NodeHost.NodeHttpClient`.
95
+ - `JournalLogger.layerJournalForwarding` requires a `Journal.Journal` service
96
+ from [`@smthrs/journal`](/api/journal). A durable engine composition already
97
+ provides one.
98
+
99
+ ## Next step
100
+
101
+ Export your first trace, log record, and metric series in the
102
+ [Quickstart](./quickstart.md).
@@ -0,0 +1,145 @@
1
+ ---
2
+ title: "Quickstart"
3
+ description: "Export a trace, a log record, and a metric series to a collector you can watch, using a thirty-line collector stand-in and one Effect layer."
4
+ sidebar:
5
+ order: 2
6
+ ---
7
+
8
+ This quickstart exports all three signals from one small program and shows you
9
+ what arrived. It needs no Docker, no vendor account, and no OpenTelemetry SDK:
10
+ a twelve-line Node server stands in for the collector so you can read the
11
+ delivery with your own eyes, and swapping in a real collector is a one-line
12
+ change at the end.
13
+
14
+ ## Prerequisites
15
+
16
+ - Node.js 26.4.0 or later, which runs a `.ts` file directly by stripping its
17
+ types.
18
+ - A package whose `package.json` sets `"type": "module"`, with the
19
+ dependencies installed: `npm install @smthrs/observability@next effect`.
20
+
21
+ ## Start a collector stand-in
22
+
23
+ An OTLP/HTTP collector is an HTTP server that accepts JSON on three paths.
24
+ Create `collector.mjs`:
25
+
26
+ ```js
27
+ import { createServer } from "node:http"
28
+
29
+ createServer((request, response) => {
30
+ const chunks = []
31
+ request.on("data", (chunk) => chunks.push(chunk))
32
+ request.on("end", () => {
33
+ const body = JSON.parse(Buffer.concat(chunks).toString("utf8"))
34
+ console.log(request.url, Object.keys(body).join(" "))
35
+ response.writeHead(200, { "content-type": "application/json" })
36
+ response.end("{}")
37
+ })
38
+ }).listen(4318, "127.0.0.1")
39
+ ```
40
+
41
+ Run it in its own terminal, and leave it running:
42
+
43
+ ```bash
44
+ node collector.mjs
45
+ ```
46
+
47
+ ## Write the program
48
+
49
+ Create `quickstart.ts`. The program opens a span, writes a log record, and
50
+ advances a counter. None of those three lines mentions telemetry: they are
51
+ ordinary Effect, and they are exactly what the Smithers packages already do on
52
+ their own hot paths.
53
+
54
+ ```ts
55
+ import * as Otlp from "@smthrs/observability/Otlp"
56
+ import * as Effect from "effect/Effect"
57
+ import * as Metric from "effect/Metric"
58
+
59
+ const deployments = Metric.counter("quickstart/deployments", {
60
+ description: "Deployments this program recorded"
61
+ })
62
+
63
+ const deploy = Effect.gen(function*() {
64
+ yield* Effect.logInfo("deploying the API")
65
+ yield* Metric.update(deployments, 1)
66
+ }).pipe(Effect.withSpan("deploy"))
67
+ ```
68
+
69
+ Now add the exporter and run it. `layerFetch` posts over the host's global
70
+ `fetch`, so there is nothing else to provide:
71
+
72
+ ```ts
73
+ const telemetry = Otlp.layerFetch({
74
+ baseUrl: "http://localhost:4318",
75
+ serviceName: "quickstart",
76
+ serviceVersion: "1.0.0"
77
+ })
78
+
79
+ await Effect.runPromise(
80
+ deploy.pipe(Effect.provide(telemetry), Effect.orDie, Effect.scoped)
81
+ )
82
+ ```
83
+
84
+ `Effect.orDie` says that an unusable collector endpoint is a startup defect
85
+ rather than something this program recovers from. The layer is scoped, so
86
+ `Effect.scoped` gives it a lifetime, and closing that scope is what flushes.
87
+
88
+ ## Run it
89
+
90
+ ```bash
91
+ node quickstart.ts
92
+ ```
93
+
94
+ The collector terminal prints one line per signal. The three arrive in
95
+ whatever order the exporters flush:
96
+
97
+ ```text
98
+ /v1/traces resourceSpans
99
+ /v1/logs resourceLogs
100
+ /v1/metrics resourceMetrics
101
+ ```
102
+
103
+ If you print a whole body instead of its top-level key, every payload carries
104
+ the resource you named: `service.name` is `quickstart` and `service.version` is
105
+ `1.0.0`.
106
+
107
+ ## What just happened
108
+
109
+ One layer installed three of Effect's own OTLP exporters against your base URL.
110
+ Each signal posts below it on its own path, so `http://localhost:4318` becomes
111
+ `/v1/traces`, `/v1/logs`, and `/v1/metrics`. The exporters batch, so nothing
112
+ was delivered while the program ran; closing the layer's scope force-flushed
113
+ all three, which is why `Effect.scoped` is where the output comes from.
114
+
115
+ The program never mentioned a tracer, a meter, or a logger provider. Effect's
116
+ own tracer and metric registry were already collecting; the layer is only the
117
+ delivery.
118
+
119
+ ## Point it at a real collector
120
+
121
+ Change one field:
122
+
123
+ ```ts
124
+ const telemetry = Otlp.layerFetch({
125
+ baseUrl: "https://otlp.example.com",
126
+ serviceName: "quickstart",
127
+ headers: { authorization: "Bearer YOUR_TOKEN" }
128
+ })
129
+ ```
130
+
131
+ Replace `YOUR_TOKEN` with the token your vendor issued. The endpoint must be an
132
+ absolute `http:` or `https:` URL carrying no credentials; anything else refuses
133
+ the layer at acquisition rather than failing silently later. See
134
+ [Export to an OTLP collector](./guides/export-to-a-collector.md) for the rest
135
+ of the options.
136
+
137
+ ## Next steps
138
+
139
+ - [Export to an OTLP collector](./guides/export-to-a-collector.md): service
140
+ identity, authentication headers, export cadence, and what happens when a
141
+ collector is down.
142
+ - [Instrumentation and export](./concepts/instrumentation-and-export.md): why
143
+ the exporter is one layer and what is already instrumented without it.
144
+ - [Forward logs to the run journal](./guides/forward-logs-to-the-journal.md):
145
+ the second delivery path, durable and readable in process.
@@ -0,0 +1,168 @@
1
+ ---
2
+ title: "Troubleshooting"
3
+ description: "The typed refusals @smthrs/observability reports and the silent failures it cannot: nothing arriving at a collector, a bundler that cannot resolve async_hooks, logs that stopped, and a counter that reads zero."
4
+ ---
5
+
6
+ Two kinds of problem show up here. A typed refusal names its own cause and
7
+ happens while the layer is built. A silent failure is the harder one, because
8
+ export is absorbed by design and a broken exporter looks exactly like a working
9
+ one.
10
+
11
+ ## InvalidExporterEndpoint
12
+
13
+ **What happened.** A builder was handed a collector endpoint it will not
14
+ export to. The failure carries `code` `invalid_exporter_endpoint`, the `path`
15
+ of the option it arrived on (`baseUrl` for `Otlp`, `endpoint` for `NodeOtel`),
16
+ and a message. The rejected value is not in the error.
17
+
18
+ **What to change.** Pass an absolute `http:` or `https:` URL of at most 2,048
19
+ characters that carries no username or password and no spaces or control
20
+ characters. The usual culprits, in order:
21
+
22
+ - A trailing newline off a config file, or a leading space off a paste. Trim
23
+ the value. This one is refused rather than repaired precisely because the
24
+ URL parser would repair it into a URL nobody typed.
25
+ - A missing scheme: `collector:4318` instead of `http://collector:4318`.
26
+ - A signal path already appended. Pass the base URL; the builder adds
27
+ `/v1/traces`, `/v1/metrics`, and `/v1/logs`.
28
+ - Credentials in the URL. Move them to the `headers` option.
29
+
30
+ ## InvalidResourceConfiguration
31
+
32
+ **What happened.** The service identity or the resource attributes failed
33
+ decoding. The failure carries `code` `invalid_resource_configuration` and a
34
+ `path` naming the offending field, such as `serviceName` or an attribute key.
35
+
36
+ **What to change.** Check the value against the bounds: a non-empty service
37
+ name and version of at most 1,024 UTF-16 code units, at most 256 attributes,
38
+ attribute values that are strings of at most 65,536 code units, finite numbers,
39
+ booleans, or homogeneous arrays of those with at most 256 elements. The complete
40
+ resource must fit 128 KiB of OTLP JSON, including keys, identity, the SDK-added
41
+ `telemetry.sdk.name`, `telemetry.sdk.language` and `telemetry.sdk.version`
42
+ fields, wrappers, escaping and UTF-8. Many individually valid values can exceed this budget;
43
+ remove or shorten attributes. The refusal names `attributes`, the measured
44
+ lower bound in bytes and the limit, without retaining values. NUL and unpaired surrogates are
45
+ refused anywhere. An empty `serviceName` is the common one, usually an
46
+ environment variable that was not set.
47
+
48
+ ## InvalidJournalLoggerOptions
49
+
50
+ **What happened.** `JournalLogger.layerJournalForwarding` was given a run id or
51
+ a capacity it will not start a worker for. The failure carries `code`
52
+ `invalid_journal_logger_options` and the offending `path`.
53
+
54
+ **What to change.** Decode the run id through `JournalEvent.RunId` rather than
55
+ casting a string, and keep `capacity` between 1 and 65,536. The refusal happens
56
+ before any record is queued, so nothing was silently dropped.
57
+
58
+ ## Nothing arrives at the collector
59
+
60
+ **What happened.** The layer built, the program ran, and the collector holds
61
+ nothing. Export failure is absorbed by design, so this is not reported anywhere
62
+ by default.
63
+
64
+ **What to check, in order.**
65
+
66
+ 1. **Did the scope close?** Exporters batch. A short program delivers on the
67
+ shutdown flush, so read the collector only after `Effect.scoped` completes.
68
+ A program killed with `SIGKILL` never flushes.
69
+ 2. **Is the base URL what you think?** Signals post below it, so
70
+ `http://collector:4318` posts to `http://collector:4318/v1/traces`. If your
71
+ collector expects a prefix, include it in `baseUrl`.
72
+ 3. **Is the collector answering?** Run at `Debug`. The exporter logs
73
+ `Disabling exporter for 60 seconds` when it gives up after three retries.
74
+ 4. **Is the layer actually provided?** A composition that swapped in
75
+ `Otlp.layerNoop` behaves exactly like a healthy one that delivers nothing.
76
+
77
+ ## An OTLP export batch was discarded
78
+
79
+ A `Warn` record with code `otlp_export_discarded` means the transport discarded
80
+ a batch because it exceeded 1 MiB (`oversized`), stalled for ten seconds
81
+ (`stalled`), or found all four request slots occupied (`saturated`). The
82
+ `flows_observability_otlp_dropped` counter records every discarded batch. The
83
+ warning carries the request byte size, limit and running drop count, and is
84
+ limited to one per minute per transport.
85
+
86
+ Warnings go only to the loggers captured before exporter acquisition, without
87
+ logging into this exporter. Keep an ambient sink outside OTLP at level `Warn`
88
+ or lower: it remains useful even when the drop counter cannot reach the
89
+ collector. An empty ambient logger set or a higher minimum level suppresses
90
+ warnings. Reduce unusually large records or metric cardinality for oversized
91
+ batches; check collector availability and latency for stalls and saturation.
92
+ The resource budget reserves 888 KiB for ordinary batches, but cannot bound
93
+ application record sizes.
94
+
95
+ ## Log records stopped reaching the collector
96
+
97
+ **What happened.** Spans and metric series still arrive, and logs do not, after
98
+ a `Logger` layer was added.
99
+
100
+ **What to change.** `Otlp` adds its log exporter to the ambient logger set, and
101
+ a `Logger` layer with the default `mergeWithExisting: false` replaces that set.
102
+ Whether the exporter survives depends on which layer the composition builds
103
+ last, which is not worth reasoning about: pass `mergeWithExisting: true` on the
104
+ `Logger` layer whenever another sink is installed. See
105
+ [Install a logger](./guides/install-a-logger.md).
106
+
107
+ ## A bundler cannot resolve `async_hooks`
108
+
109
+ **What happened.** A browser or edge build failed on `async_hooks`,
110
+ `node:async_hooks`, or a module under `@opentelemetry/context-async-hooks`.
111
+
112
+ **What to change.** Something in the graph imports
113
+ `@smthrs/observability/NodeOtel`, directly or through a module that does.
114
+ `NodeOtel` binds the Node OpenTelemetry SDK and cannot bundle for a browser.
115
+ Use `Otlp.layerFetch` for browser delivery, or `BrowserOtel` when you need the
116
+ web SDK, and keep the `NodeOtel` import behind a Node-only entry point. The
117
+ root entry point itself resolves no `node:` built-in and bundles for a browser
118
+ as it is.
119
+
120
+ ## `Metric.value` reads zero
121
+
122
+ **What happened.** The system is clearly doing work, and a counter reads zero.
123
+
124
+ **What to check.**
125
+
126
+ - **A dimensioned counter read through its bare handle.** Some packages update
127
+ only an attribute-tagged series, so the attribute-less parent stays at zero.
128
+ Read the exported view, for example `EngineStoreMetrics.dispatch.Success`
129
+ from [`@smthrs/engine-store`](/api/engine-store).
130
+ - **A registry provided per test.** Providing `Metric.MetricRegistry` with a
131
+ fresh map isolates state; a read outside that scope sees a different
132
+ registry.
133
+ - **A gauge read as a counter.** A gauge's value is `value`, a counter's is
134
+ `count`.
135
+
136
+ ## `droppedLogRecords` keeps climbing
137
+
138
+ **What happened.** `flows_observability_log_dropped` advances during a run,
139
+ which means log records are not reaching the journal.
140
+
141
+ **What to change.** The counter advances for three distinct losses, and the
142
+ last two also emit a warning annotated with the run id:
143
+
144
+ - **Queue overflow**, with no warning. Raise `capacity` above the default 256,
145
+ up to 65,536.
146
+ - **A journal delivery failure.** Read the warning; the journal itself is the
147
+ problem, not the logger.
148
+ - **A defect from the journal implementation.** Read the warning. The worker
149
+ keeps draining, so the run continues with gaps.
150
+
151
+ Records queued behind an in-flight write can also be dropped when the layer's
152
+ scope closes, and the forwarder exposes no drain barrier. `journal.flush`
153
+ settles only the entries the journal has already admitted, so it returns while
154
+ a record is still waiting in the forwarder's queue. Poll the journal for the
155
+ records you expect while the layer's scope is open, as
156
+ [Forward logs to the run journal](./guides/forward-logs-to-the-journal.md#assert-on-a-short-lived-run)
157
+ shows.
158
+
159
+ ## Reading a refusal's path
160
+
161
+ `path` is a dotted route into the value that failed, built from the decoder's
162
+ own issue path. `serviceName` names the identity field;
163
+ `attributes.region` names the `region` entry inside the `attributes` record. When the decoder cannot attribute the failure to a field,
164
+ the path is the bare `resource`, which means the whole configuration was
165
+ malformed: `null`, or not an object at all.
166
+
167
+ Neither refusal carries the rejected value, so pair the path with the value you
168
+ passed on that field.