@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
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: "Install a logger"
3
+ description: "Pick a Logger layer for a development shell, a production process, or a silent test, and understand the two rules every one of them follows: the ambient set is replaced, and the minimum level is left alone."
4
+ sidebar:
5
+ order: 4
6
+ ---
7
+
8
+ `Logger` ships four layers over Effect's own logger machinery. They differ in
9
+ the sink; they agree on the two rules that decide what installing one does to
10
+ the rest of the application.
11
+
12
+ ## Pick a layer
13
+
14
+ ```ts
15
+ import * as Logger from "@smthrs/observability/Logger"
16
+
17
+ // A development shell: colored, human-readable lines.
18
+ const development = Logger.layerPrettyDev()
19
+
20
+ // A production process: one structured JSON object per line.
21
+ const production = Logger.layerStructuredJson()
22
+
23
+ // A test that should print nothing.
24
+ const silent = Logger.layerNoop()
25
+ ```
26
+
27
+ `Logger.layerPrettyDev` chooses colors and mode from the terminal it finds, so
28
+ it degrades to plain text when the output is not a TTY.
29
+ `Logger.layerStructuredJson` is the one to ship: a log shipper can parse it, and
30
+ it is what a collector's log pipeline expects.
31
+
32
+ To install a logger you wrote, or one from another package, use `Logger.layer`:
33
+
34
+ ```ts
35
+ import * as EffectLogger from "effect/Logger"
36
+
37
+ const custom = Logger.layer(
38
+ EffectLogger.make((options) => {
39
+ /* your sink */
40
+ })
41
+ )
42
+ ```
43
+
44
+ ## Rule one: the ambient set is replaced
45
+
46
+ `mergeWithExisting` defaults to `false`, matching Effect's own `Logger.layer`,
47
+ so installing one of these layers replaces the ambient logger set rather than
48
+ adding to it. That is what you want for a process that has exactly one sink,
49
+ and it is the usual explanation for logs disappearing after a layer was added.
50
+
51
+ Pass `true` to keep the loggers already installed:
52
+
53
+ ```ts
54
+ const both = Logger.layerStructuredJson({ mergeWithExisting: true })
55
+ ```
56
+
57
+ The same option is on
58
+ [`JournalLogger.layerJournalForwarding`](./forward-logs-to-the-journal.md), and
59
+ merging is how a control-plane run gets console output and durable
60
+ `telemetry.log` rows from one log call.
61
+
62
+ ## Rule two: the minimum level is left alone
63
+
64
+ A layer that adds a sink has no business overriding the level an application
65
+ chose elsewhere, so `References.MinimumLogLevel` is provided only when you name
66
+ `minimumLogLevel`. Omitted, whatever the application set stands, and Effect's
67
+ own `Info` default applies when nothing set it.
68
+
69
+ ```ts
70
+ // Leaves the application's chosen level in place.
71
+ const inherits = Logger.layerStructuredJson()
72
+
73
+ // Pins Warn for the whole application.
74
+ const pinned = Logger.layerStructuredJson({ minimumLogLevel: "Warn" })
75
+ ```
76
+
77
+ `Logger.layerNoop` is the deliberate exception. Silence is its purpose, so it
78
+ pins `None` unless you name another level. Passing one is how a test silences
79
+ output while keeping a level assertion meaningful:
80
+
81
+ ```ts
82
+ const quietButFiltered = Logger.layerNoop({ minimumLogLevel: "Debug" })
83
+ ```
84
+
85
+ ## Merge when you install more than one sink
86
+
87
+ Installing a logger decides what is rendered locally. It exports nothing on its
88
+ own: log records reach a collector because [`Otlp`](./export-to-a-collector.md)
89
+ adds its own log exporter to the same ambient set, and they reach a run's
90
+ history because
91
+ [`JournalLogger`](./forward-logs-to-the-journal.md) adds a forwarder to it.
92
+
93
+ That shared set is why rule one matters here. A `Logger` layer with the default
94
+ `mergeWithExisting: false` discards every logger the set already held, and
95
+ whether that includes the OTLP exporter depends on which layer the composition
96
+ builds last. Pass `mergeWithExisting: true` on the `Logger` layer whenever
97
+ another sink is installed, and the ordering question does not arise:
98
+
99
+ ```ts
100
+ import * as Effect from "effect/Effect"
101
+
102
+ const outcome = program.pipe(
103
+ Effect.provide(Logger.layerStructuredJson({ mergeWithExisting: true })),
104
+ Effect.provide(telemetry),
105
+ Effect.scoped
106
+ )
107
+ ```
108
+
109
+ One `Effect.logInfo` call then renders locally, posts to the collector's
110
+ `/v1/logs` path, and, with the journal forwarder installed, lands on the run's
111
+ durable history.
@@ -0,0 +1,83 @@
1
+ ---
2
+ title: "Read the runtime metrics"
3
+ description: "The four runtime metric handles this package declares, the exact series names a dashboard binds to, which package advances each one, and how to read a counter in process without an exporter."
4
+ sidebar:
5
+ order: 5
6
+ ---
7
+
8
+ `Metric` declares the runtime signals that cross package boundaries: the
9
+ handles a producer updates and a dashboard reads. Every other metric in
10
+ Smithers belongs to the package that owns the behavior it measures.
11
+
12
+ ## The six handles
13
+
14
+ | Handle | Series name | Kind | Advances when |
15
+ | ---------------------------- | ------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
16
+ | `runThroughput` | `flows_run_throughput` | counter | A run's terminal transition commits in [`@smthrs/run-store`](/api/run-store). |
17
+ | `activeSeats` | `flows_seat_active` | gauge | Held for the lifetime of a production `Agent.run` stream in [`@smthrs/agent`](/api/agent), and released on success, failure, or interruption. |
18
+ | `quotaParks` | `flows_quota_park` | counter | A sealed quota decision is first executed, and not when that decision is replayed after a wake or a process restart. |
19
+ | `structuredOutputRejections` | `flows_agent_structured_output_rejections` | counter | An agent answer is refused by its declared output schema, in the same session or a fresh one. |
20
+ | `structuredOutputExhausted` | `flows_agent_structured_output_exhausted` | counter | An agent step fails after spending every output correction and its repair. |
21
+ | `droppedLogRecords` | `flows_observability_log_dropped` | counter | A log record is lost before durable delivery: once per queue overflow, once per journal delivery failure, and once per defect the forwarding worker recovers from. |
22
+
23
+ `Metric.registry` is the same six as one object, so a host can enumerate them.
24
+ The series names are the dashboard contract; treat them as public API.
25
+
26
+ Step-cache lookup and write counters belong to
27
+ [`@smthrs/step-cache`](/api/step-cache), and the store packages keep their own
28
+ handles. This package does not duplicate any of them.
29
+
30
+ ## Read a counter in process
31
+
32
+ A metric handle is readable without an exporter, which makes it a fine
33
+ assertion target in a test and a fine health check in a host:
34
+
35
+ ```ts
36
+ import * as ObservabilityMetric from "@smthrs/observability/Metric"
37
+ import * as Effect from "effect/Effect"
38
+ import * as Metric from "effect/Metric"
39
+
40
+ const dropped = Effect.gen(function*() {
41
+ const value = yield* Metric.value(ObservabilityMetric.droppedLogRecords)
42
+ return value.count
43
+ })
44
+ ```
45
+
46
+ A counter's value carries `count`; a gauge's carries `value`.
47
+
48
+ ## Read a dimensioned counter through its attribute view
49
+
50
+ Some packages update a counter through a tagged view rather than the bare
51
+ handle. The dispatch counter in [`@smthrs/engine-store`](/api/engine-store) is
52
+ the common example: it updates only the series tagged with the outcome, so
53
+ reading the bare handle reads the attribute-less series and always sees zero.
54
+
55
+ ```ts
56
+ import { EngineStoreMetrics } from "@smthrs/engine-store"
57
+
58
+ const dispatches = Effect.gen(function*() {
59
+ const value = yield* Metric.value(EngineStoreMetrics.dispatch.Success)
60
+ return value.count
61
+ })
62
+ ```
63
+
64
+ Read the exported view, not the parent handle, whenever the owning package
65
+ exports one.
66
+
67
+ ## Isolate the registry in a test
68
+
69
+ Effect keeps metric state in a `MetricRegistry` reference with a
70
+ process-default value, so counters accumulate across tests in one process.
71
+ Provide a fresh map to isolate one run:
72
+
73
+ ```ts
74
+ Effect.provideService(Metric.MetricRegistry, new Map())
75
+ ```
76
+
77
+ ## Where the series go
78
+
79
+ Every registered series exports with the rest of the telemetry: with
80
+ [`Otlp` provided](./export-to-a-collector.md), they post to the collector's
81
+ `/v1/metrics` path under the `service.name` you configured. With no exporter
82
+ installed, they are still collected and still readable in process, and nothing
83
+ leaves the machine.
@@ -0,0 +1,134 @@
1
+ ---
2
+ title: "Test telemetry without a collector"
3
+ description: "Assert on what would have been exported: a recording fetch for OTLP payloads, TestJournal for forwarded log records, a fresh metric registry, and the noop layers that stand in for absent telemetry."
4
+ sidebar:
5
+ order: 6
6
+ ---
7
+
8
+ Telemetry is testable because every outbound edge is a service. Replace the
9
+ edge, keep the wiring, and the assertions are about the payloads a collector
10
+ would have received.
11
+
12
+ ## Record what the exporter posts
13
+
14
+ `Otlp.layerFetch` delivers over the `FetchHttpClient.Fetch` service, so
15
+ providing your own function captures every export request and touches no
16
+ network:
17
+
18
+ ```ts
19
+ import * as Otlp from "@smthrs/observability/Otlp"
20
+ import * as Effect from "effect/Effect"
21
+ import * as Metric from "effect/Metric"
22
+ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient"
23
+
24
+ const recordingFetch = () => {
25
+ const requests: Array<{ url: string; body: string }> = []
26
+ const fetch: typeof globalThis.fetch = (input, init) => {
27
+ const body = typeof init?.body === "string"
28
+ ? init.body
29
+ : new TextDecoder().decode(init?.body as Uint8Array)
30
+ requests.push({ url: String(input), body })
31
+ return Promise.resolve(new Response("{}", { status: 200 }))
32
+ }
33
+ return { requests, fetch }
34
+ }
35
+
36
+ const collector = recordingFetch()
37
+
38
+ await Effect.runPromise(
39
+ program.pipe(
40
+ Effect.provide(Otlp.layerFetch({ baseUrl: "http://collector.invalid:4318" })),
41
+ Effect.provideService(FetchHttpClient.Fetch, collector.fetch),
42
+ Effect.provideService(Metric.MetricRegistry, new Map()),
43
+ Effect.orDie,
44
+ Effect.scoped
45
+ )
46
+ )
47
+ ```
48
+
49
+ Assert after the scope closes, because the shutdown flush is what delivers a
50
+ short program's signals. Filter `collector.requests` by URL suffix to separate
51
+ the three signals, and parse a body to read span or series names. An
52
+ unresolvable host such as `collector.invalid` is a deliberate choice: if the
53
+ service is ever missed, the test fails rather than reaching the network.
54
+
55
+ The fresh `Metric.MetricRegistry` map keeps one test's counters out of the
56
+ next test's export.
57
+
58
+ ## Test the journal forwarder
59
+
60
+ `TestJournal.layer()` from [`@smthrs/journal`](/api/journal) provides the
61
+ production SQLite journal over an in-memory database, so a forwarding test
62
+ exercises the real write path:
63
+
64
+ ```ts
65
+ import * as Journal from "@smthrs/journal/Journal"
66
+ import * as TestJournal from "@smthrs/journal/test/TestJournal"
67
+ import * as JournalLogger from "@smthrs/observability/JournalLogger"
68
+ import * as Effect from "effect/Effect"
69
+ import * as Layer from "effect/Layer"
70
+
71
+ // `runId` is a decoded JournalEvent.RunId, as in the forwarding guide.
72
+ const entries = Effect.gen(function*() {
73
+ const journal = yield* Journal.Journal
74
+ yield* Effect.logInfo("hello")
75
+ const page = yield* journal.entries({ runId, limit: 100 })
76
+ return page.entries
77
+ }).pipe(
78
+ Effect.provide(Layer.provideMerge(JournalLogger.layerJournalForwarding({ runId }), TestJournal.layer())),
79
+ Effect.scoped
80
+ )
81
+ ```
82
+
83
+ Forwarding is asynchronous, so poll until the expected number of entries has
84
+ landed rather than sleeping a fixed interval. To assert on a loss instead,
85
+ read `Metric.value(ObservabilityMetric.droppedLogRecords)`.
86
+
87
+ ## Control time for the retry window
88
+
89
+ Export retries and the 60-second disable window run on Effect's clock, so
90
+ `TestClock` makes them deterministic:
91
+
92
+ ```ts
93
+ import { TestClock } from "effect/testing"
94
+
95
+ const exported = Effect.gen(function*() {
96
+ yield* Effect.void.pipe(Effect.withSpan("exported"))
97
+ // One initial request plus three transient retries completes within four seconds.
98
+ yield* TestClock.adjust("5 seconds")
99
+ })
100
+ ```
101
+
102
+ Provide `TestClock.layer()` alongside the exporter, then advance the clock and
103
+ count the recorded requests.
104
+
105
+ ## Stand telemetry down explicitly
106
+
107
+ A test that is not about telemetry should say so rather than leave the layer
108
+ out and let a type error decide:
109
+
110
+ | Layer | What it does |
111
+ | -------------------- | --------------------------------------------------------------- |
112
+ | `Otlp.layerNoop` | Provides nothing and exports nothing. |
113
+ | `Otel.layerNoop` | The empty provider-neutral OTEL slot. |
114
+ | `Logger.layerNoop()` | Removes the logger set and pins `None` unless you name a level. |
115
+
116
+ `Journal.layerNoop` from [`@smthrs/journal`](/api/journal) is the matching stub
117
+ for the forwarder when the assertion is about queue behavior rather than about
118
+ persistence.
119
+
120
+ ## Assert on refusals at acquisition
121
+
122
+ Both configuration refusals happen while the layer is built, so a test builds
123
+ the layer and inspects the exit rather than running a program:
124
+
125
+ ```ts
126
+ import * as Layer from "effect/Layer"
127
+
128
+ const exit = await Effect.runPromiseExit(
129
+ Effect.scoped(Layer.build(Otlp.layerFetch({ baseUrl: "collector:4318" })))
130
+ )
131
+ ```
132
+
133
+ The failure is an `Endpoint.InvalidExporterEndpoint` whose `path` is `baseUrl`.
134
+ See [Troubleshooting](../troubleshooting.md) for the catalog.
@@ -0,0 +1,220 @@
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 metrics and tracer instrumentation scope, not log or span resource
144
+ attributes. Construct both providers with the intended resource before injection,
145
+ or use the factories above to receive the validated resource.
146
+
147
+ Each of the three is optional and each is bridged only when supplied, so a
148
+ composition with a tracer and no meter installs only the tracer bridge. A
149
+ `metricReader` factory that returns an empty array registers no reader at all
150
+ rather than a misconfigured one.
151
+
152
+ Two options control merge behavior: `loggerMergeWithExisting` keeps the ambient
153
+ Effect loggers alongside the OpenTelemetry logger, and `metricTemporality`
154
+ selects the temporality preference the metric bridge reports.
155
+
156
+ `Otel.layerNoop` is the explicit empty slot for a composition that wants the
157
+ option without the wiring.
158
+
159
+ ## Provide only the resource
160
+
161
+ `Resource.layer` provides the validated OpenTelemetry resource by itself, for a
162
+ composition that assembles the rest of the SDK on its own:
163
+
164
+ ```ts
165
+ import * as Resource from "@smthrs/observability/Resource"
166
+
167
+ const resource = Resource.layer({
168
+ serviceName: "deploy-status",
169
+ attributes: { "deployment.environment.name": "production" }
170
+ })
171
+ ```
172
+
173
+ `Resource.configToAttributes` is the pure projection of the same configuration
174
+ into OpenTelemetry attributes, for code that needs the attribute record rather
175
+ than a layer. It reads no environment variables: attributes come from your
176
+ configuration and the SDK's fixed `telemetry.sdk.name` and
177
+ `telemetry.sdk.language` fields, which are included in the admission budget.
178
+
179
+ ## Default OTLP export limits
180
+
181
+ `Otlp.layer` and `Otlp.layerFetch` share a limit of four active HTTP requests
182
+ across logs, traces, and metrics within each layer acquisition. Each request has
183
+ a ten-second timeout that interrupts the transport and aborts a stalled fetch.
184
+ `shutdownTimeout` separately bounds the final scope flush.
185
+
186
+ Logs and traces flush at 1,000 records or the export interval. The transport has
187
+ no waiting queue: a batch arriving while all four slots are occupied is dropped.
188
+ Serialized JSON payloads larger than 1 MiB are also dropped, limiting active
189
+ request payloads to 4 MiB. This limit applies after serialization; it does not
190
+ bound individual application records, temporary serialization allocations, or
191
+ the application's metric registry.
192
+
193
+ Resource admission caps cumulative encoded metadata at 128 KiB and bounds
194
+ arrays at 256 elements. The byte budget includes SDK-added telemetry fields,
195
+ reserved even for the default Effect exporter. Both the default exporter and
196
+ the Node SDK layer isolate ambient resource configuration after validation.
197
+ The default exporter also budgets the request envelope
198
+ at 8 KiB and reserves `Otlp.reservedBatchBytes` (888 KiB) for signals: roughly
199
+ 900 bytes per record
200
+ in a 1,000-record log or span batch. Every layer validates these resource limits
201
+ before allocating exporters, including injected SDK layers.
202
+
203
+ The Effect counter `flows_observability_otlp_dropped` increments once per batch
204
+ discarded for saturation, payload size, or timeout. Discards are terminal and
205
+ are not retried. Read the counter locally
206
+ with `Metric.value(Metric.counter("flows_observability_otlp_dropped"))` during an
207
+ outage. Its exported value becomes available when the collector recovers.
208
+
209
+ Because that counter shares the export path, each acquisition also emits at
210
+ most one warning every 60 seconds through the ambient loggers captured before
211
+ installing the OTLP logger. The warning has code `otlp_export_discarded`, reason
212
+ `oversized`, `saturated`, or `stalled`, encoded bytes, request limit, and total
213
+ discarded batches. It includes no payload, URL, or inherited annotations and
214
+ cannot re-enter this exporter even during an application-triggered flush. Keep
215
+ an ambient logger installed if loss diagnostics should remain visible during
216
+ an export outage.
217
+
218
+ Ordinary HTTP and network failures retain Effect's retry policy. These limits
219
+ apply to the default `Otlp` layers; SDK processors supplied to the other builders
220
+ retain their own export policies.
@@ -0,0 +1,98 @@
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
+ Not on npm yet; see [Installation](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/flow/docs/installation.md#use-the-libraries).
11
+
12
+ The package requires Node.js 26.4.0 or later and ships as both ESM and
13
+ CommonJS with TypeScript declarations.
14
+
15
+ ## Pin the same Effect release
16
+
17
+ Effect services are identified by module identity, so a composition that
18
+ resolves two copies of `effect` splits its context and a provided layer stops
19
+ satisfying a requirement. Pin `effect` at exactly `4.0.0-rc.115`.
20
+
21
+ `Otlp` is written entirely against `effect`, including its HTTP client and its
22
+ `effect/unstable/observability/Otlp` exporters. The required peers
23
+ `@effect/opentelemetry@4.0.0-rc.115` and `@opentelemetry/api@1.9.1`, plus
24
+ the logs and metrics dependencies, support
25
+ the root `Otel` and `Resource` modules. They install with ordinary peer-aware
26
+ package managers. The default install includes no HTTP exporters or trace SDK.
27
+
28
+ `NodeOtel` selects the optional Node trace SDK and three HTTP exporters:
29
+
30
+ ```bash
31
+ 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
32
+ ```
33
+
34
+ `BrowserOtel` selects the optional browser trace SDK instead:
35
+
36
+ ```bash
37
+ pnpm add @opentelemetry/sdk-trace-base@2.11.0 @opentelemetry/sdk-trace-web@2.11.0
38
+ ```
39
+
40
+ The browser adapter accepts the exporters you supply; those HTTP exporter
41
+ packages are not prerequisites for constructing its layer.
42
+
43
+ ## Import forms
44
+
45
+ The root entry point re-exports seven modules as namespaces:
46
+
47
+ ```ts
48
+ import { Endpoint, JournalLogger, Logger, Metric, Otel, Otlp, Resource } from "@smthrs/observability"
49
+ ```
50
+
51
+ Each is also importable from its own subpath, which is the form the
52
+ [API reference](./api.md) uses:
53
+
54
+ ```ts
55
+ import * as JournalLogger from "@smthrs/observability/JournalLogger"
56
+ import * as Otlp from "@smthrs/observability/Otlp"
57
+ ```
58
+
59
+ `@smthrs/observability/package.json` is exported.
60
+
61
+ ## The two subpath-only modules
62
+
63
+ `NodeOtel` and `BrowserOtel` are not re-exported from the root, and importing
64
+ them by subpath is the only way to reach them:
65
+
66
+ ```ts
67
+ import * as BrowserOtel from "@smthrs/observability/BrowserOtel"
68
+ import * as NodeOtel from "@smthrs/observability/NodeOtel"
69
+ ```
70
+
71
+ `NodeOtel` resolves Node-only host modules: `@effect/opentelemetry/NodeSdk` and
72
+ `@opentelemetry/sdk-trace-node`, which reaches the bare `async_hooks` specifier
73
+ through `@opentelemetry/context-async-hooks`. Re-exporting it from the root
74
+ would put a module a browser bundler cannot resolve in the entry point, and
75
+ break the browser bundle the root guarantees. Nothing the root entry point
76
+ reaches resolves a `node:` built-in, so it bundles for a browser as it is.
77
+
78
+ Import `NodeOtel` only from code that runs on Node, and `BrowserOtel` only from
79
+ code that runs in a browser. `Otlp` is safe in both, because it exports over
80
+ Effect's `HttpClient` and never touches a `node:` built-in.
81
+
82
+ ## What a real composition adds
83
+
84
+ The exporter alone needs nothing else. Two features have a dependency:
85
+
86
+ - `Otlp.layer` requires an Effect `HttpClient` from
87
+ `effect/unstable/http/HttpClient`. `Otlp.layerFetch` supplies the host's
88
+ global `fetch` and is the usual choice; a Node host that wants Undici instead
89
+ provides `NodeHttpClient.layerUndici`, re-exported by
90
+ [`@smthrs/platform-node`](/api/platform-node) as `NodeHost.NodeHttpClient`.
91
+ - `JournalLogger.layerJournalForwarding` requires a `Journal.Journal` service
92
+ from [`@smthrs/journal`](/api/journal). A durable engine composition already
93
+ provides one.
94
+
95
+ ## Next step
96
+
97
+ Export your first trace, log record, and metric series in the
98
+ [Quickstart](./quickstart.md).