@smthrs/observability 0.35.0 → 1.0.0-rc.4

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 +84 -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 +388 -0
  15. package/dist/cjs/JournalLogger.js.map +7 -0
  16. package/dist/cjs/Logger.d.ts +55 -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 +62 -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 +200 -0
  33. package/dist/cjs/Otlp.d.ts.map +1 -0
  34. package/dist/cjs/Otlp.js +235 -0
  35. package/dist/cjs/Otlp.js.map +7 -0
  36. package/dist/cjs/Resource.d.ts +162 -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 +482 -0
  60. package/dist/esm/JournalLogger.js.map +1 -0
  61. package/dist/esm/Logger.d.ts +55 -0
  62. package/dist/esm/Logger.d.ts.map +1 -0
  63. package/dist/esm/Logger.js +60 -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 +62 -0
  74. package/dist/esm/Otel.d.ts.map +1 -0
  75. package/dist/esm/Otel.js +51 -0
  76. package/dist/esm/Otel.js.map +1 -0
  77. package/dist/esm/Otlp.d.ts +200 -0
  78. package/dist/esm/Otlp.d.ts.map +1 -0
  79. package/dist/esm/Otlp.js +350 -0
  80. package/dist/esm/Otlp.js.map +1 -0
  81. package/dist/esm/Resource.d.ts +162 -0
  82. package/dist/esm/Resource.d.ts.map +1 -0
  83. package/dist/esm/Resource.js +237 -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 +162 -0
  94. package/docs/api.md +768 -0
  95. package/docs/concepts/instrumentation-and-export.md +68 -0
  96. package/docs/concepts/layer-map.md +72 -0
  97. package/docs/concepts/validated-acquisition.md +105 -0
  98. package/docs/guides/export-to-a-collector.md +167 -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 +220 -0
  104. package/docs/installation.md +98 -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 +596 -0
  111. package/src/Logger.ts +106 -0
  112. package/src/Metric.ts +88 -0
  113. package/src/NodeOtel.ts +90 -0
  114. package/src/Otel.ts +117 -0
  115. package/src/Otlp.ts +477 -0
  116. package/src/Resource.ts +324 -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
package/docs/api.md ADDED
@@ -0,0 +1,768 @@
1
+ ---
2
+ title: "API reference"
3
+ description: "Every public export of @smthrs/observability: the Otlp exporter layers, endpoint and resource validation, the logger layers, the journal forwarder and its durable schema, the runtime metric handles, and the three OpenTelemetry SDK bridges."
4
+ ---
5
+
6
+ `@smthrs/observability` exports seven modules from its root entry point, and
7
+ each is also importable from `@smthrs/observability/<Module>`:
8
+
9
+ ```ts
10
+ import { Endpoint, JournalLogger, Logger, Metric, Otel, Otlp, Resource } from "@smthrs/observability"
11
+ // or
12
+ import * as Otlp from "@smthrs/observability/Otlp"
13
+ ```
14
+
15
+ Two more modules are subpath-only, because each binds a host-specific
16
+ OpenTelemetry SDK. `@smthrs/observability/package.json` is exported.
17
+
18
+ | Import | Source | Platform |
19
+ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------- |
20
+ | `@smthrs/observability` | [src/index.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/observability/src/index.ts) | any |
21
+ | `@smthrs/observability/NodeOtel` | [src/NodeOtel.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/observability/src/NodeOtel.ts) | Node |
22
+ | `@smthrs/observability/BrowserOtel` | [src/BrowserOtel.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/observability/src/BrowserOtel.ts) | browser |
23
+
24
+ The package is tested with `effect@4.0.0-rc.115`. Layers, services, and schemas
25
+ are Effect constructs: a `Layer` provides services, a scoped layer releases on
26
+ scope close, and a schema decodes to an `Effect`.
27
+
28
+ ## Example
29
+
30
+ ```ts
31
+ import * as Otlp from "@smthrs/observability/Otlp"
32
+
33
+ const telemetry = Otlp.layerFetch({ baseUrl: "http://localhost:4318", serviceName: "deploy-status" })
34
+ const program = Effect.logInfo("deploying the API").pipe(Effect.withSpan("deploy"))
35
+
36
+ await Effect.runPromise(program.pipe(Effect.provide(telemetry), Effect.orDie, Effect.scoped))
37
+ ```
38
+
39
+ ## Otlp
40
+
41
+ The default exporter. `Otlp` composes `effect/unstable/observability/Otlp` and
42
+ nothing else, so it allocates no OpenTelemetry SDK and never resolves a `node:`
43
+ built-in. All three signals are JSON-serialized and posted below the configured
44
+ base URL at `/v1/logs`, `/v1/metrics`, and `/v1/traces`.
45
+
46
+ ### Otlp.Options
47
+
48
+ ```ts
49
+ interface Options {
50
+ readonly baseUrl: string
51
+ readonly serviceName?: string | undefined
52
+ readonly serviceVersion?: string | undefined
53
+ readonly attributes?: Record<string, unknown> | undefined
54
+ readonly headers?: Headers.Input | undefined
55
+ readonly exportInterval?: Duration.Input | undefined
56
+ readonly shutdownTimeout?: Duration.Input | undefined
57
+ }
58
+ ```
59
+
60
+ - `baseUrl`: the collector base URL, for example `http://localhost:4318`. It
61
+ must be an absolute `http://` or `https://` URL without credentials, query,
62
+ fragment, backslashes, spaces, or controls; anything else fails acquisition with
63
+ `Endpoint.InvalidExporterEndpoint` on path `baseUrl`.
64
+ - `serviceName`, `serviceVersion`: the `service.name` and `service.version`
65
+ resource attributes. Default to `defaultServiceName` and
66
+ `defaultServiceVersion`.
67
+ - `attributes`: additional resource attributes attached to every exported
68
+ signal, decoded by `Resource.Attributes`.
69
+ - `headers`: sent with every export request, which is where vendor
70
+ authentication goes. A header whose name names a credential
71
+ (`authorization`, `x-api-key`, `x-honeycomb-team`, any name
72
+ `Redaction.isSensitiveKey` recognizes) requires an `https://` `baseUrl` unless the host is `localhost`,
73
+ `127.0.0.0/8`, or `[::1]`; otherwise acquisition fails with
74
+ `Endpoint.InvalidExporterEndpoint` on path `baseUrl`. The check reads
75
+ header names only: a credential under any other name is sent as given, so
76
+ use `https://` for every remote collector.
77
+ - `exportInterval`: the export cadence applied to all three signals. Omitted,
78
+ each signal keeps Effect's own default.
79
+ - `shutdownTimeout`: upper bound on the flush performed when the layer's scope
80
+ closes.
81
+
82
+ ### Otlp.layer
83
+
84
+ ```ts
85
+ const layer: (options: Options) => Layer.Layer<
86
+ never,
87
+ Resource.InvalidResourceConfiguration | Endpoint.InvalidExporterEndpoint,
88
+ HttpClient.HttpClient
89
+ >
90
+ ```
91
+
92
+ Installs the OTLP logs, metrics, and traces exporters with the flows resource
93
+ defaults filled in. It requires an Effect `HttpClient`, which is how it stays
94
+ platform-neutral: a Node host may provide Undici, a browser or a test provides
95
+ something else. Both configuration inputs are decoded during acquisition, so
96
+ the returned layer either exports or refuses. Ambient `OTEL_RESOURCE_ATTRIBUTES`
97
+ cannot add unvalidated metadata to these explicit resources.
98
+
99
+ Requests over `maxRequestBytes` (1 MiB), stalled for ten seconds, or exceeding
100
+ four in-flight requests are discarded locally. Each discard increments
101
+ `flows_observability_otlp_dropped`. A `Warn` diagnostic with code
102
+ `otlp_export_discarded` reports `reason` (`oversized`, `stalled`, or `saturated`),
103
+ `bytes`, `limit`, and cumulative `dropped` at most once per minute per transport.
104
+ It uses the logger set captured before this exporter is installed, so it cannot
105
+ re-enter this exporter. Request bodies, headers, URLs, and ambient log
106
+ annotations are omitted. Keep an ambient sink outside OTLP at level `Warn` or
107
+ lower to observe loss independently; empty or filtered loggers cannot report it.
108
+
109
+ ### Otlp transport constants
110
+
111
+ ```ts
112
+ const maxRequestBytes: number // 1048576 (1 MiB)
113
+ const maximumEnvelopeBytes: number // 8192 (8 KiB)
114
+ const reservedBatchBytes: number // 909312 (888 KiB)
115
+ ```
116
+
117
+ The resource ceiling is 128 KiB. Another 8 KiB covers JSON wrappers and the
118
+ instrumentation scope, which repeats the service name (at most 6 KiB after
119
+ escaping). The remaining 888 KiB gives each record in the upstream 1,000-record
120
+ log or span batch about 909 bytes, several times a bare record. This guarantees
121
+ room for ordinary signal batches, not arbitrary record sizes or metric registry
122
+ cardinality.
123
+
124
+ ### Otlp.layerFetch
125
+
126
+ ```ts
127
+ const layerFetch: (options: Options) => Layer.Layer<
128
+ never,
129
+ Resource.InvalidResourceConfiguration | Endpoint.InvalidExporterEndpoint
130
+ >
131
+ ```
132
+
133
+ `layer` with `FetchHttpClient.layer` already provided, which binds the host's
134
+ global `fetch`. This is the default wiring on Node 26 and the only one that is
135
+ browser-safe by construction.
136
+
137
+ ```ts
138
+ const Telemetry = Otlp.layerFetch({ baseUrl: "http://localhost:4318" })
139
+ ```
140
+
141
+ ### Otlp.layerEnvironment
142
+
143
+ ```ts
144
+ const layerEnvironment: (
145
+ environment: Readonly<Record<string, string | undefined>>,
146
+ options?: Omit<Options, "baseUrl" | "headers">
147
+ ) => Layer.Layer<never, Otlp.LayerError>
148
+ ```
149
+
150
+ `layerFetch` against `OTEL_EXPORTER_OTLP_ENDPOINT` with the headers
151
+ `Otlp.parseHeaders` reads from `OTEL_EXPORTER_OTLP_HEADERS`. An unset or blank
152
+ endpoint returns `layerNoop`, so no exporter is installed. `LayerError` is
153
+ `Resource.InvalidResourceConfiguration | Endpoint.InvalidExporterEndpoint`.
154
+
155
+ ### Otlp.parseHeaders
156
+
157
+ ```ts
158
+ const parseHeaders: (value: string | undefined) => Record<string, string>
159
+ ```
160
+
161
+ Reads the OpenTelemetry `key=value,key=value` header list and percent-decodes
162
+ each value. Pairs without `=` or with an empty key are skipped; a malformed
163
+ escape is kept verbatim.
164
+
165
+ ### Otlp.layerNoop
166
+
167
+ ```ts
168
+ const layerNoop: Layer.Layer<never>
169
+ ```
170
+
171
+ Provides nothing and exports nothing. The explicit stand-in for a host with no
172
+ collector, so wiring code switches layers rather than branching.
173
+
174
+ ### Otlp.defaultServiceName
175
+
176
+ ```ts
177
+ const defaultServiceName: string // "flows"
178
+ ```
179
+
180
+ The `service.name` attribute installed when the caller supplies none.
181
+
182
+ ### Otlp.defaultServiceVersion
183
+
184
+ ```ts
185
+ const defaultServiceVersion: string // "1.0.0-rc.0"
186
+ ```
187
+
188
+ The `service.version` attribute installed when the caller supplies none. It
189
+ mirrors this package's release version, held as a literal because a published
190
+ package cannot read its own manifest on every runtime it supports.
191
+
192
+ ### Delivery behavior
193
+
194
+ Effect's exporter retries a transient failure three times, honoring a
195
+ `retry-after` response header when one is present, then disables that exporter
196
+ for 60 seconds and logs a `Debug` record. Export failure never fails the
197
+ application effect and never surfaces as an unhandled rejection. Closing the
198
+ layer's scope performs the final flush, bounded by `shutdownTimeout`.
199
+
200
+ ## Endpoint
201
+
202
+ Validated collector endpoints, shared by every OTLP builder. The endpoint is
203
+ the field an operator most often gets wrong, and a wrong one is invisible after
204
+ acquisition, so it is decoded before any exporter exists.
205
+
206
+ ### Endpoint.Endpoint
207
+
208
+ ```ts
209
+ const Endpoint: Schema.String.check(...)
210
+ ```
211
+
212
+ Runtime schema for an absolute `http:` or `https:` collector endpoint of at
213
+ most `maximumEndpointLength` characters that carries no credentials, query,
214
+ fragment, backslashes, spaces, or controls. A base path is allowed;
215
+ authentication belongs in exporter headers. Query and fragment suffixes are
216
+ rejected because appending `/v1/traces` to them does not change the request
217
+ path. A value the WHATWG URL parser would repair rather
218
+ than parse as written is refused, because the repaired URL is not the one the
219
+ exporter would post to.
220
+
221
+ ### Endpoint.maximumEndpointLength
222
+
223
+ ```ts
224
+ const maximumEndpointLength: number // 2048
225
+ ```
226
+
227
+ Largest collector endpoint accepted by a builder.
228
+
229
+ ### Endpoint.decode
230
+
231
+ ```ts
232
+ const decode: (endpoint: unknown, path: string) => Effect.Effect<string, InvalidExporterEndpoint>
233
+ ```
234
+
235
+ Decodes one endpoint into its normalized form. `path` names the option the
236
+ endpoint arrived on, so the refusal points at the caller's own field rather
237
+ than at a shared internal name. The rejected value is not retained in the
238
+ error.
239
+
240
+ ### Endpoint.InvalidExporterEndpoint
241
+
242
+ ```ts
243
+ class InvalidExporterEndpoint {
244
+ readonly code: "invalid_exporter_endpoint"
245
+ readonly path: string
246
+ readonly message: string
247
+ }
248
+ ```
249
+
250
+ The stable exporter-endpoint refusal shared by `Otlp.layer`,
251
+ `Otlp.layerFetch` (`path` is `baseUrl`), and `NodeOtel.layerOtel` (`path` is
252
+ `endpoint`).
253
+
254
+ ### Endpoint.normalize
255
+
256
+ ```ts
257
+ const normalize: (endpoint: string) => string
258
+ ```
259
+
260
+ Removes repeated trailing separators, so `http://host//` and `http://host` both
261
+ produce one signal URL.
262
+
263
+ ### Endpoint.signalUrl
264
+
265
+ ```ts
266
+ const signalUrl: (endpoint: string, signal: "traces" | "metrics" | "logs") => string
267
+ ```
268
+
269
+ Builds the OTLP/HTTP URL one signal is posted to below a decoded endpoint:
270
+ `signalUrl("http://host", "traces")` is `http://host/v1/traces`.
271
+
272
+ ## Resource
273
+
274
+ Explicit, validated OpenTelemetry resource metadata. Every public OTEL builder
275
+ in this package decodes the same `Configuration`. Resource metadata comes from
276
+ the caller and the SDK's fixed telemetry fields. Neither the default exporter
277
+ nor the Node SDK layer merges ambient resource configuration after validation.
278
+
279
+ ### Resource.Configuration
280
+
281
+ ```ts
282
+ const Configuration: Schema.Struct<{
283
+ serviceName: Schema.String
284
+ serviceVersion: Schema.optional<Schema.String>
285
+ attributes: Schema.optional<typeof Attributes>
286
+ }>
287
+ type Configuration = typeof Configuration.Type
288
+ ```
289
+
290
+ The service identity attached to exported telemetry. `serviceName` and
291
+ `serviceVersion` are non-empty, well formed, and at most
292
+ `maximumIdentityLength` UTF-16 code units.
293
+
294
+ ### Resource.Attributes and Resource.AttributeValue
295
+
296
+ ```ts
297
+ const AttributeValue: Schema.Union<[...]>
298
+ const Attributes: Schema.Record<Schema.String, typeof AttributeValue>
299
+ ```
300
+
301
+ `AttributeValue` accepts a string of at most `maximumAttributeStringLength`
302
+ code units, a finite number, a boolean, or a homogeneous array of one of those
303
+ scalar types, with at most `maximumAttributeArrayLength` elements. `Attributes` bounds the record at `maximumAttributes` entries
304
+ with non-empty, well formed keys of at most `maximumAttributeKeyLength` code
305
+ units. NUL and unpaired UTF-16 surrogates are refused in keys and in values;
306
+ valid astral Unicode is preserved.
307
+
308
+ ### Resource constants
309
+
310
+ ```ts
311
+ const maximumIdentityLength: number // 1024
312
+ const maximumAttributeKeyLength: number // 1024
313
+ const maximumAttributeStringLength: number // 65536
314
+ const maximumAttributes: number // 256
315
+ const maximumAttributeArrayLength: number // 256
316
+ const maximumResourceBytes: number // 131072 (128 KiB)
317
+ ```
318
+
319
+ The resource byte limit counts the complete OTLP JSON resource, including
320
+ identity, SDK-added `telemetry.sdk.name` and `telemetry.sdk.language`, attribute
321
+ keys, scalar and array wrappers, escaping, and UTF-8. SDK fields are reserved
322
+ even for the default Effect exporter, and caller attributes that the SDK
323
+ overwrites are conservatively counted too.
324
+ Counting stops at the first fragment over budget to bound intermediate
325
+ allocations; the error reports the measured lower bound and byte limit at path
326
+ `attributes`. Array-length errors report the measured element count and limit
327
+ at the attribute path. No rejected attribute values are retained.
328
+
329
+ All resource-accepting layers and `decode`, `decodeSync`, and
330
+ `configToAttributes` enforce these bounds before exporter acquisition.
331
+ Explicit `serviceName` and `serviceVersion` take precedence over attributes
332
+ with those keys. Admission conservatively counts those redundant attributes.
333
+
334
+ ### Resource.decode
335
+
336
+ ```ts
337
+ const decode: (configuration: unknown) => Effect.Effect<Configuration, InvalidResourceConfiguration>
338
+ ```
339
+
340
+ Decodes one resource configuration without retaining rejected values.
341
+
342
+ ### Resource.decodeSync
343
+
344
+ ```ts
345
+ const decodeSync: (configuration: unknown) => Configuration
346
+ ```
347
+
348
+ The same decoding for the package's pure projection API. Throws
349
+ `InvalidResourceConfiguration` rather than failing an effect.
350
+
351
+ ### Resource.InvalidResourceConfiguration
352
+
353
+ ```ts
354
+ class InvalidResourceConfiguration {
355
+ readonly code: "invalid_resource_configuration"
356
+ readonly path: string
357
+ readonly message: string
358
+ }
359
+ ```
360
+
361
+ The stable resource refusal shared by every layer here. `path` is a dotted
362
+ route into the offending field, such as `serviceName` or `attributes.region`,
363
+ and is the bare `resource` when the whole configuration was malformed.
364
+
365
+ ### Resource.toOpenTelemetryConfiguration
366
+
367
+ ```ts
368
+ const toOpenTelemetryConfiguration: (configuration: Configuration) => {
369
+ readonly serviceName: string
370
+ readonly serviceVersion?: string
371
+ readonly attributes?: Attributes
372
+ }
373
+ ```
374
+
375
+ Projects a decoded resource into the exact optional-property shape the
376
+ OpenTelemetry SDK expects, omitting absent optional fields rather than setting
377
+ them to `undefined`.
378
+
379
+ ### Resource.configToAttributes
380
+
381
+ ```ts
382
+ const configToAttributes: (configuration: Configuration) => Attributes
383
+ ```
384
+
385
+ Converts explicit service metadata into OpenTelemetry resource attributes.
386
+ Invalid metadata throws the same typed `InvalidResourceConfiguration` a layer
387
+ returns during acquisition.
388
+
389
+ ### Resource.layer
390
+
391
+ ```ts
392
+ const layer: (configuration: Configuration) => Layer.Layer<Resource, InvalidResourceConfiguration>
393
+ ```
394
+
395
+ Provides an explicitly validated OpenTelemetry resource, for a composition that
396
+ assembles the rest of the SDK itself.
397
+
398
+ ### Resource.Resource
399
+
400
+ The OpenTelemetry resource service tag, re-exported from
401
+ `@effect/opentelemetry/Resource`.
402
+
403
+ ## Logger
404
+
405
+ Effect logger layers. All four follow two rules: `mergeWithExisting` defaults
406
+ to `false`, so installing one replaces the ambient logger set, and
407
+ `minimumLogLevel` is applied only when the caller names it.
408
+
409
+ ### Logger.Options
410
+
411
+ ```ts
412
+ interface Options {
413
+ readonly minimumLogLevel?: LogLevel.LogLevel | undefined
414
+ readonly mergeWithExisting?: boolean | undefined
415
+ }
416
+ ```
417
+
418
+ - `minimumLogLevel`: pins `References.MinimumLogLevel` for the whole
419
+ application. Omitted, the layer leaves that reference alone and Effect's own
420
+ `Info` default applies.
421
+ - `mergeWithExisting`: keeps the ambient loggers alongside this one. Defaults
422
+ to `false`.
423
+
424
+ ### Logger.layerPrettyDev
425
+
426
+ ```ts
427
+ const layerPrettyDev: (options?: Options) => Layer.Layer<never>
428
+ ```
429
+
430
+ A human-readable development logger, with colors and mode chosen from the
431
+ output it finds.
432
+
433
+ ### Logger.layerStructuredJson
434
+
435
+ ```ts
436
+ const layerStructuredJson: (options?: Options) => Layer.Layer<never>
437
+ ```
438
+
439
+ One structured JSON object per log line.
440
+
441
+ ### Logger.layerNoop
442
+
443
+ ```ts
444
+ const layerNoop: (options?: Pick<Options, "minimumLogLevel">) => Layer.Layer<never>
445
+ ```
446
+
447
+ Removes the active logger set. This is the one exception to the second rule:
448
+ silencing is its purpose, so it pins `None` unless the caller names another
449
+ level.
450
+
451
+ ### Logger.layer
452
+
453
+ ```ts
454
+ const layer: (logger: Logger.Logger<unknown, unknown>, options?: Options) => Layer.Layer<never>
455
+ ```
456
+
457
+ Installs a caller-supplied logger under the same two rules.
458
+
459
+ ## JournalLogger
460
+
461
+ Non-blocking forwarding of bounded operational logs to the durable journal. The
462
+ callback reads the queue's remaining room, snapshots and redacts a bounded
463
+ record synchronously only when a slot is free, then performs only queue
464
+ admission; a forked worker drains the queue into the journal. A record a full
465
+ queue cannot take is counted and discarded without being snapshotted.
466
+
467
+ ### JournalLogger.Options
468
+
469
+ ```ts
470
+ interface Options {
471
+ readonly runId: JournalEvent.RunId
472
+ readonly capacity?: number | undefined
473
+ readonly minimumLogLevel?: LogLevel.LogLevel | undefined
474
+ readonly mergeWithExisting?: boolean | undefined
475
+ }
476
+ ```
477
+
478
+ - `runId`: the run every forwarded record is attributed to.
479
+ - `capacity`: queue depth, 1 through `maximumCapacity`. Defaults to 256.
480
+ - `minimumLogLevel` and `mergeWithExisting`: as on `Logger.Options`.
481
+
482
+ ### JournalLogger.layerJournalForwarding
483
+
484
+ ```ts
485
+ const layerJournalForwarding: (
486
+ options: Options
487
+ ) => Layer.Layer<never, InvalidJournalLoggerOptions, Journal.Journal>
488
+ ```
489
+
490
+ Installs a bounded, drop-on-overflow forwarder for one explicit run.
491
+ Configuration is decoded before a worker starts, so an invalid run id or
492
+ capacity fails acquisition rather than being routed through the lossy worker.
493
+
494
+ Each record becomes one journal entry on the lossy channel, with `eventType`
495
+ `telemetry.log`, source `flows/observability/logger`, and a `TelemetryLog`
496
+ payload. The durable journal allocates the per-source sequence, so a rebuilt or
497
+ concurrently running layer for one run cannot reuse an identity.
498
+
499
+ Overflow, journal delivery failures, and journal defects are telemetry losses
500
+ rather than application failures. Each advances `Metric.droppedLogRecords`; the
501
+ two failure paths also log a warning annotated with the run id, and the worker
502
+ keeps draining. Interruption stays fatal, and closing the scope may drop
503
+ records queued behind an in-flight write.
504
+
505
+ ### JournalLogger.TelemetryLog
506
+
507
+ ```ts
508
+ const TelemetryLog: Schema.Struct<{
509
+ version: Schema.Literal<1>
510
+ level: Schema.Literals<["All", "Fatal", "Error", "Warn", "Info", "Debug", "Trace", "None"]>
511
+ message: Schema.Unknown
512
+ annotations: Schema.Record<Schema.String, Schema.Unknown>
513
+ cause: typeof TelemetryCause
514
+ fiberId: Schema.Int
515
+ traceId: Schema.optionalKey<Schema.String>
516
+ spanId: Schema.optionalKey<Schema.String>
517
+ timestamp: Schema.String
518
+ }>
519
+ type TelemetryLog = typeof TelemetryLog.Type
520
+ ```
521
+
522
+ The durable wire shape of one forwarded log record. `traceId` and `spanId` are
523
+ present only when a span was active. `timestamp` is ISO-8601. Every persisted
524
+ `telemetry.log` payload decodes with this schema: a projection that would not
525
+ degrades to a total record with an empty cause rather than to a payload
526
+ consumers throw on.
527
+
528
+ ### JournalLogger.TelemetryCause
529
+
530
+ ```ts
531
+ const TelemetryCause: Schema.Struct<{
532
+ version: Schema.Literal<1>
533
+ reasons: Schema.Array<typeof TelemetryCauseReason>
534
+ }>
535
+ type TelemetryCause = typeof TelemetryCause.Type
536
+ ```
537
+
538
+ A versioned structural Effect cause. Effect stores composed failures as an
539
+ ordered reason list, and the projection preserves that order and each
540
+ discriminator.
541
+
542
+ ### JournalLogger.TelemetryCauseReason
543
+
544
+ ```ts
545
+ const TelemetryCauseReason: Schema.Union<[
546
+ typeof TelemetryFail,
547
+ typeof TelemetryDie,
548
+ typeof TelemetryInterrupt
549
+ ]>
550
+ type TelemetryCauseReason = typeof TelemetryCauseReason.Type
551
+ ```
552
+
553
+ One reason in a persisted cause. `TelemetryFail` carries `error`,
554
+ `TelemetryDie` carries `defect`, and `TelemetryInterrupt` carries a
555
+ non-negative `fiberId` or `null`. All three are exported individually.
556
+
557
+ ### JournalLogger.InvalidJournalLoggerOptions
558
+
559
+ ```ts
560
+ class InvalidJournalLoggerOptions {
561
+ readonly code: "invalid_journal_logger_options"
562
+ readonly path: string
563
+ readonly message: string
564
+ }
565
+ ```
566
+
567
+ The stable logger-configuration refusal, raised during layer acquisition.
568
+
569
+ ### JournalLogger constants
570
+
571
+ ```ts
572
+ const maximumCapacity: number // 65536
573
+ const maximumSnapshotBytes: number // 1048576
574
+ const maximumSnapshotMembers: number // 4096
575
+ const maximumSnapshotDepth: number // 64
576
+ const unrenderableMarker: string // "[Unrenderable]"
577
+ const truncatedMarker: string // "[Truncated]"
578
+ ```
579
+
580
+ A snapshot admits at most `maximumSnapshotBytes` of encoded data,
581
+ `maximumSnapshotMembers` container members, and `maximumSnapshotDepth`
582
+ container edges. Unreadable values become `unrenderableMarker`, values past a
583
+ ceiling become `truncatedMarker`, and deeper values become the journal's
584
+ `[Deep]` marker. Container-shaped fields keep their shape, so annotations that
585
+ spent the whole budget arrive as `{ "[Truncated]": "[Truncated]" }` rather than
586
+ as a scalar. Text is bounded in one pass that never cuts a surrogate pair, and
587
+ the journal's own redaction rules run before queue admission.
588
+
589
+ ## Metric
590
+
591
+ The runtime signals that cross package boundaries. Producers live in the
592
+ packages that know when to advance them; this module owns only the identifiers
593
+ and the handles.
594
+
595
+ ### Metric handles
596
+
597
+ ```ts
598
+ const runThroughput: Metric.Counter // "flows_run_throughput"
599
+ const activeSeats: Metric.Gauge // "flows_seat_active"
600
+ const quotaParks: Metric.Counter // "flows_quota_park"
601
+ const structuredOutputRejections: Metric.Counter // "flows_agent_structured_output_rejections"
602
+ const structuredOutputExhausted: Metric.Counter // "flows_agent_structured_output_exhausted"
603
+ const droppedLogRecords: Metric.Counter // "flows_observability_log_dropped"
604
+ ```
605
+
606
+ - `runThroughput` advances after a terminal run transition commits in
607
+ [`@smthrs/run-store`](/api/run-store).
608
+ - `activeSeats` is held for the lifetime of a production `Agent.run` stream in
609
+ [`@smthrs/agent`](/api/agent) and released on success, failure, or
610
+ interruption.
611
+ - `quotaParks` advances when a sealed quota decision is first executed, not
612
+ when it is replayed after a wake or a process restart.
613
+ - `structuredOutputRejections` advances once per agent answer its declared
614
+ output schema refuses, in the same session or a fresh one.
615
+ - `structuredOutputExhausted` advances once per agent step that fails after
616
+ spending every output correction and its repair.
617
+ - `droppedLogRecords` advances once per record lost by `JournalLogger`.
618
+
619
+ Step-cache lookup and write counters remain owned by
620
+ [`@smthrs/step-cache`](/api/step-cache); this package does not duplicate those
621
+ handles.
622
+
623
+ ### Metric.registry
624
+
625
+ ```ts
626
+ const registry: {
627
+ readonly runThroughput: typeof runThroughput
628
+ readonly activeSeats: typeof activeSeats
629
+ readonly quotaParks: typeof quotaParks
630
+ readonly structuredOutputRejections: typeof structuredOutputRejections
631
+ readonly structuredOutputExhausted: typeof structuredOutputExhausted
632
+ readonly droppedLogRecords: typeof droppedLogRecords
633
+ }
634
+ ```
635
+
636
+ All six handles as one object, for a host that enumerates them. The six
637
+ series names are the dashboard contract; treat them as public API.
638
+
639
+ ## Otel
640
+
641
+ Provider-neutral composition for OpenTelemetry providers the application
642
+ already built. This module allocates no exporter.
643
+
644
+ ### Otel.Options
645
+
646
+ ```ts
647
+ interface Options {
648
+ readonly resource: Resource.Configuration
649
+ readonly tracerProvider?:
650
+ | Api.TracerProvider
651
+ | ((resource: Resource) => Api.TracerProvider)
652
+ | undefined
653
+ readonly loggerProvider?:
654
+ | LoggerProvider
655
+ | ((resource: Resource) => LoggerProvider)
656
+ | undefined
657
+ readonly metricReader?: (() => MetricReader | ReadonlyArray<MetricReader>) | undefined
658
+ readonly loggerMergeWithExisting?: boolean | undefined
659
+ readonly metricTemporality?: OtelMetrics.TemporalityPreference | undefined
660
+ }
661
+ ```
662
+
663
+ `metricTemporality` is `"cumulative"` or `"delta"`.
664
+
665
+ Ownership differs by field. `tracerProvider` and `loggerProvider` are borrowed:
666
+ the layer bridges onto them and never flushes or shuts one down, including a
667
+ provider a factory returned. `metricReader` is owned: the factory runs once
668
+ during layer acquisition, after resource validation, and closing the layer's
669
+ scope shuts down every reader it returned. Build the readers inside the
670
+ factory. Returning a reader that a longer-lived composition still exports
671
+ through disables that reader when this scope closes.
672
+
673
+ ### Otel.layerOtel
674
+
675
+ ```ts
676
+ const layerOtel: (options: Options) => Layer.Layer<never, Resource.InvalidResourceConfiguration>
677
+ ```
678
+
679
+ Bridges Effect's tracer, logger, and metrics onto the supplied providers and
680
+ the readers the `metricReader` factory returns, over the validated resource.
681
+ Each bridge is installed only when its provider or factory is supplied, and a
682
+ factory that returns an empty array registers no reader at all.
683
+
684
+ ### Otel.layerNoop
685
+
686
+ ```ts
687
+ const layerNoop: Layer.Layer<never>
688
+ ```
689
+
690
+ A no-op OTEL layer, for callers that want an explicit optional slot.
691
+
692
+ ## NodeOtel
693
+
694
+ Node-only OTLP/HTTP OpenTelemetry SDK setup. Import it from
695
+ `@smthrs/observability/NodeOtel`; it is not re-exported from the root, because
696
+ it resolves Node-only host modules and would break the root's browser bundle.
697
+
698
+ ### NodeOtel.Options
699
+
700
+ ```ts
701
+ interface Options {
702
+ readonly endpoint: string
703
+ readonly resource: Resource.Configuration
704
+ readonly shutdownTimeout?: Duration.Input | undefined
705
+ readonly exportIntervalMillis?: number | undefined
706
+ }
707
+ ```
708
+
709
+ `endpoint` is decoded exactly as `Otlp.Options.baseUrl` is, and a refusal names
710
+ the path `endpoint`.
711
+
712
+ ### NodeOtel.layerOtel
713
+
714
+ ```ts
715
+ const layerOtel: (options: Options) => Layer.Layer<
716
+ never,
717
+ Resource.InvalidResourceConfiguration | Endpoint.InvalidExporterEndpoint
718
+ >
719
+ ```
720
+
721
+ Builds a scoped Node OTLP/HTTP layer for all three signals: a
722
+ `BatchSpanProcessor`, a `BatchLogRecordProcessor`, and a
723
+ `PeriodicExportingMetricReader`, each behind its own OTLP exporter. Exporter
724
+ objects are created only when the layer is built. `OTEL_SERVICE_NAME` and
725
+ `OTEL_RESOURCE_ATTRIBUTES` cannot add resource metadata after validation,
726
+ whether supplied by the process environment or an Effect `ConfigProvider`.
727
+ The OpenTelemetry exporters still read the standard transport variables
728
+ (`OTEL_EXPORTER_OTLP_HEADERS`, `_TIMEOUT`, `_COMPRESSION`, `_CERTIFICATE`,
729
+ `_CLIENT_CERTIFICATE`, `_CLIENT_KEY`, and their per-signal forms) from the
730
+ process environment; the explicit `endpoint` always wins over
731
+ `OTEL_EXPORTER_OTLP_ENDPOINT`. Headers set there reach this `endpoint`, so do
732
+ not set them for a different collector. `Otlp.layer` reads none of these.
733
+ Closing the scope
734
+ force-flushes both batch processors and collects the metric reader once, so
735
+ release rather than the interval is the deterministic flush.
736
+
737
+ ## BrowserOtel
738
+
739
+ Browser OpenTelemetry SDK setup with explicitly injected processors. Import it
740
+ from `@smthrs/observability/BrowserOtel`.
741
+
742
+ ### BrowserOtel.Options
743
+
744
+ ```ts
745
+ interface Options {
746
+ readonly resource: Resource.Configuration
747
+ readonly spanProcessor?: (() => SpanProcessor | ReadonlyArray<SpanProcessor>) | undefined
748
+ readonly logRecordProcessor?: (() => LogRecordProcessor | ReadonlyArray<LogRecordProcessor>) | undefined
749
+ readonly metricReader?: (() => MetricReader | ReadonlyArray<MetricReader>) | undefined
750
+ readonly loggerMergeWithExisting?: boolean | undefined
751
+ }
752
+ ```
753
+
754
+ Processors and readers are created by the caller's factories, which keeps this
755
+ module free of Node imports and free of browser exporter policy. Every factory
756
+ is owned: it runs once during layer acquisition, after resource validation, and
757
+ the web SDK shuts down everything it returned when the scope closes. A factory
758
+ that returns an empty array installs nothing for that signal.
759
+
760
+ ### BrowserOtel.layerOtel
761
+
762
+ ```ts
763
+ const layerOtel: (options: Options) => Layer.Layer<never, Resource.InvalidResourceConfiguration>
764
+ ```
765
+
766
+ Builds a scoped browser OpenTelemetry layer over the validated resource. A
767
+ layer with no processor factories at all still builds; it provides the resource
768
+ and bridges nothing.